Implemented glCopyTex[Sub]Image for non-renderable formats.

TRAC #13792 Signed-off-by: Daniel Koch Author: Nicolas Capens git-svn-id: https://angleproject.googlecode.com/svn/trunk@461 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 73a5db67
...@@ -413,14 +413,8 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const ...@@ -413,14 +413,8 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const
return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
} }
RECT d3dSourceRect;
d3dSourceRect.left = sourceRect.left;
d3dSourceRect.right = sourceRect.right;
d3dSourceRect.top = sourceRect.top;
d3dSourceRect.bottom = sourceRect.bottom;
display->endScene(); display->endScene();
result = device->StretchRect(surface, &d3dSourceRect, textureSurface, NULL, D3DTEXF_NONE); result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
textureSurface->Release(); textureSurface->Release();
......
...@@ -180,6 +180,27 @@ bool Texture::isFloatingPoint() const ...@@ -180,6 +180,27 @@ bool Texture::isFloatingPoint() const
return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES); return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
} }
bool Texture::isRenderableFormat() const
{
D3DFORMAT format = getD3DFormat();
switch(format)
{
case D3DFMT_L8:
case D3DFMT_A8L8:
case D3DFMT_DXT1:
return false;
case D3DFMT_A8R8G8B8:
case D3DFMT_A16B16G16R16F:
case D3DFMT_A32B32G32R32F:
return true;
default:
UNREACHABLE();
}
return false;
}
// Selects an internal Direct3D 9 format for storing an Image // Selects an internal Direct3D 9 format for storing an Image
D3DFORMAT Texture::selectFormat(GLenum format, GLenum type) D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
{ {
...@@ -883,6 +904,121 @@ bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GL ...@@ -883,6 +904,121 @@ bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GL
return true; return true;
} }
// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
{
IDirect3DDevice9 *device = getDevice();
IDirect3DSurface9 *surface = NULL;
D3DSURFACE_DESC description;
renderTarget->GetDesc(&description);
HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
if (!SUCCEEDED(result))
{
ERR("Could not create matching destination surface.");
return error(GL_OUT_OF_MEMORY);
}
result = device->GetRenderTargetData(renderTarget, surface);
if (!SUCCEEDED(result))
{
ERR("GetRenderTargetData unexpectedly failed.");
surface->Release();
return error(GL_OUT_OF_MEMORY);
}
D3DLOCKED_RECT sourceLock = {0};
RECT sourceRect = {x, y, x + width, y + height};
result = surface->LockRect(&sourceLock, &sourceRect, 0);
if (FAILED(result))
{
ERR("Failed to lock the source surface (rectangle might be invalid).");
surface->UnlockRect();
surface->Release();
return error(GL_OUT_OF_MEMORY);
}
if (!image->surface)
{
createSurface(width, height, internalFormat, mType, image);
}
if (image->surface == NULL)
{
ERR("Failed to create an image surface.");
surface->UnlockRect();
surface->Release();
return error(GL_OUT_OF_MEMORY);
}
D3DLOCKED_RECT destLock = {0};
RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
result = image->surface->LockRect(&destLock, &destRect, 0);
if (FAILED(result))
{
ERR("Failed to lock the destination surface (rectangle might be invalid).");
surface->UnlockRect();
surface->Release();
return error(GL_OUT_OF_MEMORY);
}
if (destLock.pBits && sourceLock.pBits)
{
unsigned char *source = (unsigned char*)sourceLock.pBits;
unsigned char *dest = (unsigned char*)destLock.pBits;
switch (description.Format)
{
case D3DFMT_X8R8G8B8:
case D3DFMT_A8R8G8B8:
switch(getD3DFormat())
{
case D3DFMT_L8:
for(int y = 0; y < height; y++)
{
for(int x = 0; x < height; x++)
{
dest[x] = source[x * 4 + 2];
}
source += sourceLock.Pitch;
dest += destLock.Pitch;
}
break;
case D3DFMT_A8L8:
for(int y = 0; y < height; y++)
{
for(int x = 0; x < height; x++)
{
dest[x * 2 + 0] = source[x * 4 + 2];
dest[x * 2 + 1] = source[x * 4 + 3];
}
source += sourceLock.Pitch;
dest += destLock.Pitch;
}
break;
default:
UNREACHABLE();
}
break;
default:
UNREACHABLE();
}
image->dirty = true;
mDirtyMetaData = true;
}
image->surface->UnlockRect();
surface->UnlockRect();
surface->Release();
}
D3DFORMAT Texture::getD3DFormat() const D3DFORMAT Texture::getD3DFormat() const
{ {
return selectFormat(getFormat(), mType); return selectFormat(getFormat(), mType);
...@@ -1123,29 +1259,47 @@ void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GL ...@@ -1123,29 +1259,47 @@ void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GL
void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
{ {
if (redefineTexture(level, internalFormat, width, height, mType)) IDirect3DSurface9 *renderTarget = source->getRenderTarget();
if (!renderTarget)
{ {
convertToRenderTarget(); ERR("Failed to retrieve the render target.");
pushTexture(mTexture, true); return error(GL_OUT_OF_MEMORY);
} }
else
bool redefined = redefineTexture(level, internalFormat, width, height, mType);
if (!isRenderableFormat())
{ {
needRenderTarget(); needRenderTarget();
copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
} }
else
if (width != 0 && height != 0 && level < levelCount())
{ {
RECT sourceRect; if (redefined)
sourceRect.left = x; {
sourceRect.right = x + width; convertToRenderTarget();
sourceRect.top = y; pushTexture(mTexture, true);
sourceRect.bottom = y + height; }
else
{
needRenderTarget();
}
if (width != 0 && height != 0 && level < levelCount())
{
RECT sourceRect;
sourceRect.left = x;
sourceRect.right = x + width;
sourceRect.top = y;
sourceRect.bottom = y + height;
IDirect3DSurface9 *dest; IDirect3DSurface9 *dest;
HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest); getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
dest->Release(); dest->Release();
}
} }
mImageArray[level].width = width; mImageArray[level].width = width;
...@@ -1160,29 +1314,46 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo ...@@ -1160,29 +1314,46 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType)) IDirect3DSurface9 *renderTarget = source->getRenderTarget();
if (!renderTarget)
{ {
convertToRenderTarget(); ERR("Failed to retrieve the render target.");
pushTexture(mTexture, true); return error(GL_OUT_OF_MEMORY);
} }
else
bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
if (!isRenderableFormat())
{ {
needRenderTarget(); copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
} }
else
if (level < levelCount())
{ {
RECT sourceRect; if (redefined)
sourceRect.left = x; {
sourceRect.right = x + width; convertToRenderTarget();
sourceRect.top = y; pushTexture(mTexture, true);
sourceRect.bottom = y + height; }
else
{
needRenderTarget();
}
if (level < levelCount())
{
RECT sourceRect;
sourceRect.left = x;
sourceRect.right = x + width;
sourceRect.top = y;
sourceRect.bottom = y + height;
IDirect3DSurface9 *dest; IDirect3DSurface9 *dest;
HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest); getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
dest->Release(); dest->Release();
}
} }
} }
...@@ -1898,32 +2069,48 @@ bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei ...@@ -1898,32 +2069,48 @@ bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei
void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
{ {
IDirect3DSurface9 *renderTarget = source->getRenderTarget();
if (!renderTarget)
{
ERR("Failed to retrieve the render target.");
return error(GL_OUT_OF_MEMORY);
}
unsigned int faceindex = faceIndex(target); unsigned int faceindex = faceIndex(target);
bool redefined = redefineTexture(level, internalFormat, width);
if (redefineTexture(level, internalFormat, width)) if (!isRenderableFormat())
{ {
convertToRenderTarget(); copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
pushTexture(mTexture, true);
} }
else else
{ {
needRenderTarget(); if (redefined)
} {
convertToRenderTarget();
pushTexture(mTexture, true);
}
else
{
needRenderTarget();
}
ASSERT(width == height); ASSERT(width == height);
if (width > 0 && level < levelCount()) if (width > 0 && level < levelCount())
{ {
RECT sourceRect; RECT sourceRect;
sourceRect.left = x; sourceRect.left = x;
sourceRect.right = x + width; sourceRect.right = x + width;
sourceRect.top = y; sourceRect.top = y;
sourceRect.bottom = y + height; sourceRect.bottom = y + height;
IDirect3DSurface9 *dest = getCubeMapSurface(target, level); IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest); getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
dest->Release(); dest->Release();
}
} }
mImageArray[faceindex][level].width = width; mImageArray[faceindex][level].width = width;
...@@ -1971,28 +2158,46 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi ...@@ -1971,28 +2158,46 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width)) IDirect3DSurface9 *renderTarget = source->getRenderTarget();
if (!renderTarget)
{ {
convertToRenderTarget(); ERR("Failed to retrieve the render target.");
pushTexture(mTexture, true); return error(GL_OUT_OF_MEMORY);
} }
else
unsigned int faceindex = faceIndex(target);
bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
if (!isRenderableFormat())
{ {
needRenderTarget(); copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);
} }
else
if (level < levelCount())
{ {
RECT sourceRect; if (redefined)
sourceRect.left = x; {
sourceRect.right = x + width; convertToRenderTarget();
sourceRect.top = y; pushTexture(mTexture, true);
sourceRect.bottom = y + height; }
else
{
needRenderTarget();
}
IDirect3DSurface9 *dest = getCubeMapSurface(target, level); if (level < levelCount())
{
RECT sourceRect;
sourceRect.left = x;
sourceRect.right = x + width;
sourceRect.top = y;
sourceRect.bottom = y + height;
IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest); getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
dest->Release(); dest->Release();
}
} }
} }
......
...@@ -63,6 +63,7 @@ class Texture : public RefCountObject ...@@ -63,6 +63,7 @@ class Texture : public RefCountObject
virtual bool isComplete() const = 0; virtual bool isComplete() const = 0;
virtual bool isCompressed() const = 0; virtual bool isCompressed() const = 0;
bool isFloatingPoint() const; bool isFloatingPoint() const;
bool isRenderableFormat() const;
D3DFORMAT getD3DFormat() const; D3DFORMAT getD3DFormat() const;
IDirect3DBaseTexture9 *getTexture(); IDirect3DBaseTexture9 *getTexture();
...@@ -120,6 +121,7 @@ class Texture : public RefCountObject ...@@ -120,6 +121,7 @@ class Texture : public RefCountObject
bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img); bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img);
void setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img); void setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img);
bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img); bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img);
void copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget);
void needRenderTarget(); void needRenderTarget();
...@@ -136,6 +138,7 @@ class Texture : public RefCountObject ...@@ -136,6 +138,7 @@ class Texture : public RefCountObject
void dropTexture(); void dropTexture();
void pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable); void pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable);
void createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img);
Blit *getBlitter(); Blit *getBlitter();
...@@ -149,6 +152,8 @@ class Texture : public RefCountObject ...@@ -149,6 +152,8 @@ class Texture : public RefCountObject
GLenum mWrapT; GLenum mWrapT;
GLenum mType; GLenum mType;
bool mDirtyMetaData;
private: private:
DISALLOW_COPY_AND_ASSIGN(Texture); DISALLOW_COPY_AND_ASSIGN(Texture);
...@@ -194,14 +199,10 @@ class Texture : public RefCountObject ...@@ -194,14 +199,10 @@ class Texture : public RefCountObject
void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
size_t inputPitch, const void *input, size_t outputPitch, void *output) const; size_t inputPitch, const void *input, size_t outputPitch, void *output) const;
void createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img);
IDirect3DBaseTexture9 *mBaseTexture; // This is a weak pointer. The derived class is assumed to own a strong pointer. IDirect3DBaseTexture9 *mBaseTexture; // This is a weak pointer. The derived class is assumed to own a strong pointer.
bool mDirty; bool mDirty;
bool mDirtyMetaData;
bool mIsRenderable; bool mIsRenderable;
}; };
class Texture2D : public Texture class Texture2D : public Texture
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment