Fix glCopyTexSubImage3D.
Two bugs were present in our implementation. We were using the y offset
for z in ensureSubImageInitialized. And for our D3D back-end we were
potentially reading from the wrong image index.
Bug: chromium:947342
Change-Id: If39671a911e08fcc641b9ba6f5910e3a2c16eb5d
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1558671
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 7954dee..d86b8bc 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -3726,10 +3726,11 @@
Offset destOffset(xoffset, yoffset, 0);
Rectangle sourceArea(x, y, width, height);
+ ImageIndex index = ImageIndex::MakeFromTarget(target, level);
+
Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture = getTargetTexture(TextureTargetToType(target));
- ANGLE_CONTEXT_TRY(
- texture->copySubImage(this, target, level, destOffset, sourceArea, framebuffer));
+ ANGLE_CONTEXT_TRY(texture->copySubImage(this, index, destOffset, sourceArea, framebuffer));
}
void Context::copyTexSubImage3D(TextureType target,
@@ -3753,10 +3754,11 @@
Offset destOffset(xoffset, yoffset, zoffset);
Rectangle sourceArea(x, y, width, height);
+ ImageIndex index = ImageIndex::MakeFromType(target, level, zoffset);
+
Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture = getTargetTexture(target);
- ANGLE_CONTEXT_TRY(texture->copySubImage(this, NonCubeTextureTypeToTarget(target), level,
- destOffset, sourceArea, framebuffer));
+ ANGLE_CONTEXT_TRY(texture->copySubImage(this, index, destOffset, sourceArea, framebuffer));
}
void Context::framebufferTexture2D(GLenum target,
diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp
index 9122a61..4854c6b 100644
--- a/src/libANGLE/Texture.cpp
+++ b/src/libANGLE/Texture.cpp
@@ -1147,24 +1147,22 @@
}
angle::Result Texture::copySubImage(Context *context,
- TextureTarget target,
- GLint level,
+ const ImageIndex &index,
const Offset &destOffset,
const Rectangle &sourceArea,
Framebuffer *source)
{
- ASSERT(TextureTargetToType(target) == mState.mType);
+ ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
// Ensure source FBO is initialized.
ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
- Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1);
- ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
-
- ImageIndex index = ImageIndex::MakeFromTarget(target, level);
+ Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceArea.width, sourceArea.height, 1);
+ ANGLE_TRY(
+ ensureSubImageInitialized(context, index.getTarget(), index.getLevelIndex(), destBox));
ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
- ANGLE_TRY(handleMipmapGenerationHint(context, level));
+ ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
return angle::Result::Continue;
}
diff --git a/src/libANGLE/Texture.h b/src/libANGLE/Texture.h
index ec5f625..e381140 100644
--- a/src/libANGLE/Texture.h
+++ b/src/libANGLE/Texture.h
@@ -349,8 +349,7 @@
GLenum internalFormat,
Framebuffer *source);
angle::Result copySubImage(Context *context,
- TextureTarget target,
- GLint level,
+ const ImageIndex &index,
const Offset &destOffset,
const Rectangle &sourceArea,
Framebuffer *source);
diff --git a/src/tests/gl_tests/CopyTexImageTest.cpp b/src/tests/gl_tests/CopyTexImageTest.cpp
index 3c8c33c..45b230e 100644
--- a/src/tests/gl_tests/CopyTexImageTest.cpp
+++ b/src/tests/gl_tests/CopyTexImageTest.cpp
@@ -512,6 +512,40 @@
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
+// Test CopyTexImage3D with some simple parameters with a 2D array texture.
+TEST_P(CopyTexImageTestES3, 2DArraySubImage)
+{
+ // Seems to fail on AMD OpenGL Windows.
+ ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() & IsWindows());
+
+ GLTexture tex;
+ glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
+
+ constexpr GLsizei kTexSize = 4;
+ constexpr GLsizei kLayerOffset = 1;
+ constexpr GLsizei kLayers = 2;
+
+ // Clear screen to green.
+ glClearColor(0, 1, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Initialize a two-layer 2D array texture with red.
+ std::vector<GLColor> red(kTexSize * kTexSize * kLayers, GLColor::red);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kTexSize, kTexSize, kLayers, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, red.data());
+ glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, kLayerOffset, 0, 0, kTexSize, kTexSize);
+ ASSERT_GL_NO_ERROR();
+
+ // Check level 0 (red from image data) and 1 (green from backbuffer clear).
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 1);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+ ASSERT_GL_NO_ERROR();
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(CopyTexImageTest,