Vulkan: Correctly determine mip level in resolveColorWithCommand()
FramebufferVk::resolveColorWithCommand() is currently using the wrong
mip level value by using the GL index value, rather than calculating the
VK value from (index value - the base level).
Bug: angleproject:4753
Test: FramebufferTest_ES31::MultisampleResolveIntoMipMapWithBlit()
Change-Id: I8ddaeb21c4957b46880f5ef5f6a78242c04b4dcd
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2349951
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Tim Van Patten <timvp@google.com>
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
index 3290c2b..70fd7f6 100644
--- a/src/tests/gl_tests/FramebufferTest.cpp
+++ b/src/tests/gl_tests/FramebufferTest.cpp
@@ -1129,6 +1129,62 @@
ASSERT_GL_NO_ERROR();
}
+// Test resolving a multisampled texture into a mipmaped texture with blit
+TEST_P(FramebufferTest_ES31, MultisampleResolveIntoMipMapWithBlit)
+{
+ // FBO 1 is attached to a 64x64 texture
+ // FBO 2 attached to level 1 of a 128x128 texture
+
+ constexpr int kSize = 64;
+ glViewport(0, 0, kSize, kSize);
+
+ // Create the textures early and call glGenerateMipmap() so it doesn't break the render pass
+ // between the drawQuad() and glBlitFramebuffer(), so we can test the resolve with subpass path
+ // in the Vulkan back end.
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture.get());
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false);
+ ASSERT_GL_NO_ERROR();
+
+ GLTexture resolveTexture;
+ glBindTexture(GL_TEXTURE_2D, resolveTexture);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ ASSERT_GL_NO_ERROR();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ GLFramebuffer msaaFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get());
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
+ texture.get(), 0);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(),
+ essl31_shaders::fs::RedGreenGradient());
+ drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
+ ASSERT_GL_NO_ERROR();
+
+ // Create another FBO to resolve the multisample buffer into.
+ GLFramebuffer resolveFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 1);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
+ glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO);
+ EXPECT_PIXEL_NEAR(0, 0, 0, 0, 0, 255, 1.0); // Black
+ EXPECT_PIXEL_NEAR(kSize - 1, 1, 251, 0, 0, 255, 1.0); // Red
+ EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 251, 0, 255, 1.0); // Green
+ EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 251, 251, 0, 255, 1.0); // Yellow
+}
+
// If there are no attachments, rendering will be limited to a rectangle having a lower left of
// (0, 0) and an upper right of(width, height), where width and height are the framebuffer
// object's default width and height.