Restrict use of TexStorage more in CopyImage.
We were being too permissive in some copyImage methods when checking
if we can create a render target or not. This would lead us to trying
to use an inconsistent TexStorage in some cases.
Note that we do need to create inconsistent TexStorage in cases where
we are doing a FBO copy *from* a mipmap-incomplete texture attachment.
BUG=angle:780
Change-Id: I5a849b5d8c53713e38cb5f5052a8bb88b3f56260
Reviewed-on: https://chromium-review.googlesource.com/224480
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
diff --git a/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
index 85deb28..9adfc37 100644
--- a/src/libGLESv2/renderer/d3d/TextureD3D.cpp
+++ b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
@@ -431,6 +431,13 @@
return gl::Error(GL_NO_ERROR);
}
+bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
+{
+ rx::Image *image = getImage(index);
+ bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
+ return (image->isRenderableFormat() && levelsComplete);
+}
+
TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
: TextureD3D(renderer)
{
@@ -640,8 +647,9 @@
redefineImage(level, sizedInternalFormat, width, height);
gl::Rectangle sourceRect(x, y, width, height);
+ gl::ImageIndex index = gl::ImageIndex::Make2D(level);
- if (!mImageArray[level]->isRenderableFormat())
+ if (!canCreateRenderTargetForImage(index))
{
gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
if (error.isError())
@@ -681,11 +689,11 @@
// can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
- bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
gl::Rectangle sourceRect(x, y, width, height);
+ gl::ImageIndex index = gl::ImageIndex::Make2D(level);
- if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
+ if (!canCreateRenderTargetForImage(index))
{
gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
if (error.isError())
@@ -872,6 +880,11 @@
return true;
}
+bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
+{
+ return isLevelComplete(index.mipIndex);
+}
+
// Constructs a native texture resource from the texture images
gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
{
@@ -1177,8 +1190,9 @@
redefineImage(faceIndex, level, sizedInternalFormat, width, height);
gl::Rectangle sourceRect(x, y, width, height);
+ gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
- if (!mImageArray[faceIndex][level]->isRenderableFormat())
+ if (!canCreateRenderTargetForImage(index))
{
gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
if (error.isError())
@@ -1218,14 +1232,10 @@
{
int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
- // We can only make our texture storage to a render target if the level we're copying *to* is complete
- // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
- // rely on the "getBaseLevel*" methods reliably otherwise.
- bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
-
gl::Rectangle sourceRect(x, y, width, height);
+ gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
- if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
+ if (!canCreateRenderTargetForImage(index))
{
gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
if (error.isError())
@@ -1526,6 +1536,11 @@
return true;
}
+bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
+{
+ return isFaceLevelComplete(index.layerIndex, index.mipIndex);
+}
+
gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
{
ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
@@ -1826,13 +1841,10 @@
{
ASSERT(target == GL_TEXTURE_3D);
- // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
- // the current level we're copying to is defined (with appropriate format, width & height)
- bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
-
gl::Rectangle sourceRect(x, y, width, height);
+ gl::ImageIndex index = gl::ImageIndex::Make3D(level);
- if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
+ if (canCreateRenderTargetForImage(index))
{
gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
if (error.isError())
@@ -2106,6 +2118,11 @@
return true;
}
+bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
+{
+ return isLevelComplete(index.mipIndex);
+}
+
gl::Error TextureD3D_3D::updateStorageLevel(int level)
{
ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
@@ -2368,13 +2385,10 @@
{
ASSERT(target == GL_TEXTURE_2D_ARRAY);
- // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
- // the current level we're copying to is defined (with appropriate format, width & height)
- bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
-
gl::Rectangle sourceRect(x, y, width, height);
+ gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
- if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
+ if (canCreateRenderTargetForImage(index))
{
gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
if (error.isError())
@@ -2645,6 +2659,11 @@
return true;
}
+bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
+{
+ return isLevelComplete(index.mipIndex);
+}
+
gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
{
ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));