From 7c35fff457edc0047cb9aca532f904c7a1bf27e6 Mon Sep 17 00:00:00 2001 From: xurui Date: Thu, 1 Feb 2024 19:12:36 +0800 Subject: [PATCH] =?UTF-8?q?fixed=20be08f0d=20from=20https://gitee.com/clea?= =?UTF-8?q?r=5Faddr/chromium=5Fthird=5Fparty=5Fangle/pulls/14=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DCVE-2024-0222?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: xurui --- src/libANGLE/renderer/vulkan/TextureVk.cpp | 23 ++++++++- .../angle_end2end_tests_expectations.txt | 2 + src/tests/gl_tests/CopyTexImageTest.cpp | 50 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp index 29aa230..b45a1e3 100644 --- a/src/libANGLE/renderer/vulkan/TextureVk.cpp +++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp @@ -575,8 +575,28 @@ angle::Result TextureVk::copyImage(const gl::Context *context, gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); const vk::Format &vkFormat = renderer->getFormat(internalFormatInfo.sizedInternalFormat); + // The texture level being redefined might be the same as the one bound to the framebuffer. + // This _could_ be supported by using a temp image before redefining the level (and potentially + // discarding the image). However, this is currently unimplemented. + FramebufferVk *framebufferVk = vk::GetImpl(source); + RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget(); + vk::ImageHelper *srcImage = &colorReadRT->getImageForCopy(); + const bool isCubeMap = index.getType() == gl::TextureType::CubeMap; + gl::LevelIndex levelIndex(getNativeImageIndex(index).getLevelIndex()); + const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0; + const uint32_t redefinedFace = isCubeMap ? layerIndex : 0; + const uint32_t sourceFace = isCubeMap ? colorReadRT->getLayerIndex() : 0; + const bool isSelfCopy = mImage == srcImage && levelIndex == colorReadRT->getLevelIndex() && + redefinedFace == sourceFace; + ANGLE_TRY(redefineLevel(context, index, vkFormat, newImageSize)); + if (isSelfCopy) + { + UNIMPLEMENTED(); + return angle::Result::Continue; + } + return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo, source); } @@ -1640,7 +1660,8 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context, mImage->getLevelCount() == 1 && mImage->getFirstAllocatedLevel() == levelIndexGL; // If incompatible, and redefining the single-level image, release it so it can be - // recreated immediately. This is an optimization to avoid an extra copy. + // recreated immediately. This is needed so that the texture can be reallocated with + // the correct format/size. if (!isCompatibleRedefinition && isUpdateToSingleLevelImage) { releaseImage(contextVk); diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt index 7e38e04..750d43c 100644 --- a/src/tests/angle_end2end_tests_expectations.txt +++ b/src/tests/angle_end2end_tests_expectations.txt @@ -27,6 +27,8 @@ 6347 GLES : FramebufferTestWithFormatFallback.RGBA4444_BlitCopyTexImage/* = SKIP 6989 OPENGL : BlitFramebufferTestES31.OOBResolve/* = SKIP 6989 GLES : BlitFramebufferTestES31.OOBResolve/* = SKIP +// Incorrectly handled pretty much in all backends +8446 : CopyTexImageTestES3.RedefineSameLevel/* = SKIP 6743 OPENGL : SimpleStateChangeTestES3.RespecifyBufferAfterBeginTransformFeedback/* = SKIP 6743 GLES : SimpleStateChangeTestES3.RespecifyBufferAfterBeginTransformFeedback/* = SKIP diff --git a/src/tests/gl_tests/CopyTexImageTest.cpp b/src/tests/gl_tests/CopyTexImageTest.cpp index 951f642..6b3fd5b 100644 --- a/src/tests/gl_tests/CopyTexImageTest.cpp +++ b/src/tests/gl_tests/CopyTexImageTest.cpp @@ -1208,6 +1208,56 @@ TEST_P(CopyTexImageTestES3, 3DSubImageDrawMismatchedTextureTypes) glBindTexture(GL_TEXTURE_3D, 0); } +// Make sure a single-level texture can be redefined through glCopyTexImage2D from a framebuffer +// bound to the same texture. Regression test for a bug in the Vulkan backend where the texture was +// released before the copy. +TEST_P(CopyTexImageTestES3, RedefineSameLevel) +{ + constexpr GLsizei kSize = 32; + constexpr GLsizei kHalfSize = kSize / 2; + + // Create a single-level texture with four colors in different regions. + std::vector initData(kSize * kSize); + for (GLsizei y = 0; y < kSize; ++y) + { + const bool isTop = y < kHalfSize; + for (GLsizei x = 0; x < kSize; ++x) + { + const bool isLeft = x < kHalfSize; + + GLColor color = isLeft && isTop ? GLColor::red + : isLeft && !isTop ? GLColor::green + : !isLeft && isTop ? GLColor::blue + : GLColor::yellow; + color.A = 123; + initData[y * kSize + x] = color; + } + } + + GLTexture tex; + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, + initData.data()); + + // Bind the framebuffer to the same texture + GLFramebuffer framebuffer; + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); + + // Redefine the texture + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kHalfSize / 2, kHalfSize / 2, kHalfSize, kHalfSize, + 0); + + // Verify copy is done correctly. + ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); + + EXPECT_PIXEL_RECT_EQ(0, 0, kHalfSize / 2, kHalfSize / 2, GLColor::red); + EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, 0, kHalfSize / 2, kHalfSize / 2, GLColor::blue); + EXPECT_PIXEL_RECT_EQ(0, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, GLColor::green); + EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, + GLColor::yellow); +} + ANGLE_INSTANTIATE_TEST(CopyTexImageTest, ANGLE_ALL_TEST_PLATFORMS_ES2, ES2_D3D11_PRESENT_PATH_FAST(), -- Gitee