Vulkan: Fix resolve-with-subpass with non-zero read attachment
The draw framebuffer's color index was used to get the read buffer of
the source framebuffer.
Bug: b/159903491
Change-Id: I7a1626e6732367c14d46f1e1be4057998fdbf011
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2390440
Reviewed-by: Tim Van Patten <timvp@google.com>
Reviewed-by: Charlie Lao <cclao@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index c69cba2..151fb62 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -387,13 +387,11 @@
}
}
-size_t FramebufferState::getReadIndex() const
+uint32_t FramebufferState::getReadIndex() const
{
ASSERT(mReadBufferState == GL_BACK ||
(mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
- size_t readIndex = (mReadBufferState == GL_BACK
- ? 0
- : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
+ uint32_t readIndex = mReadBufferState == GL_BACK ? 0 : mReadBufferState - GL_COLOR_ATTACHMENT0;
ASSERT(readIndex < mColorAttachments.size());
return readIndex;
}
@@ -405,7 +403,7 @@
return nullptr;
}
- size_t readIndex = getReadIndex();
+ uint32_t readIndex = getReadIndex();
const gl::FramebufferAttachment &framebufferAttachment =
isDefault() ? mDefaultFramebufferReadAttachment : mColorAttachments[readIndex];
diff --git a/src/libANGLE/Framebuffer.h b/src/libANGLE/Framebuffer.h
index 1be2714..904d62d 100644
--- a/src/libANGLE/Framebuffer.h
+++ b/src/libANGLE/Framebuffer.h
@@ -58,7 +58,7 @@
~FramebufferState();
const std::string &getLabel() const;
- size_t getReadIndex() const;
+ uint32_t getReadIndex() const;
const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const;
const FramebufferAttachment *getReadAttachment() const;
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 09d6e81..c2c36ce 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -1230,28 +1230,29 @@
// render pass subpass. Due to this, we currently only support using resolve attachments when
// there is a single draw attachment enabled.
ASSERT(mState.getEnabledDrawBuffers().count() == 1);
- uint32_t colorIndexGL = static_cast<uint32_t>(*mState.getEnabledDrawBuffers().begin());
+ uint32_t drawColorIndexGL = static_cast<uint32_t>(*mState.getEnabledDrawBuffers().begin());
const gl::State &glState = contextVk->getState();
const gl::Framebuffer *srcFramebuffer = glState.getReadFramebuffer();
FramebufferVk *srcFramebufferVk = vk::GetImpl(srcFramebuffer);
+ uint32_t readColorIndexGL = srcFramebuffer->getState().getReadIndex();
// Use the draw FBO's color attachments as resolve attachments in the read FBO.
// - Assign the draw FBO's color attachment Serial to the read FBO's resolve attachment
// - Deactivate the source Framebuffer, since the description changed
// - Update the renderpass description to indicate there's a resolve attachment
vk::ImageViewSubresourceSerial resolveImageViewSerial =
- mCurrentFramebufferDesc.getColorImageViewSerial(colorIndexGL);
+ mCurrentFramebufferDesc.getColorImageViewSerial(drawColorIndexGL);
ASSERT(resolveImageViewSerial.imageViewSerial.valid());
- srcFramebufferVk->updateColorResolveAttachment(colorIndexGL, resolveImageViewSerial);
+ srcFramebufferVk->updateColorResolveAttachment(readColorIndexGL, resolveImageViewSerial);
- // Since tha source FBO was updated with a resolve attachment it didn't have when the render
+ // Since the source FBO was updated with a resolve attachment it didn't have when the render
// pass was started, we need to:
// 1. Get the new framebuffer
// - The draw framebuffer's ImageView will be used as the resolve attachment, so pass it along
// in case vkCreateFramebuffer() needs to be called to create a new vkFramebuffer with the new
// resolve attachment.
- RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
+ RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[drawColorIndexGL];
const vk::ImageView *resolveImageView = nullptr;
ANGLE_TRY(drawRenderTarget->getImageView(contextVk, &resolveImageView));
vk::Framebuffer *newSrcFramebuffer = nullptr;
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
index d5cabce9..2945c5c 100644
--- a/src/tests/gl_tests/FramebufferTest.cpp
+++ b/src/tests/gl_tests/FramebufferTest.cpp
@@ -1175,10 +1175,6 @@
GLFramebuffer resolveFBO;
glBindTexture(GL_TEXTURE_2D, resolveTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- 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);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
@@ -1242,10 +1238,6 @@
GLFramebuffer resolveFBO;
glBindTexture(GL_TEXTURE_2D, resolveTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- 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);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
@@ -1292,10 +1284,6 @@
GLFramebuffer resolveFBO1;
glBindTexture(GL_TEXTURE_2D, resolveTexture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- 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);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture1, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
@@ -1313,10 +1301,6 @@
GLFramebuffer resolveFBO2;
glBindTexture(GL_TEXTURE_2D, resolveTexture2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- 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);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture2, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
@@ -1352,10 +1336,6 @@
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());
@@ -1386,7 +1366,7 @@
EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 251, 251, 0, 255, 1.0); // Yellow
}
-// Test resolving a multisampled texture with blit after drawing to mulitiple FBOs.
+// Test resolving a multisampled texture with blit after drawing to multiple FBOs.
TEST_P(FramebufferTest_ES31, MultipleTextureMultisampleResolveWithBlitMultipleResolves)
{
// Attach two MSAA textures to FBO1
@@ -1440,10 +1420,6 @@
GLFramebuffer resolveFBO1;
glBindTexture(GL_TEXTURE_2D, resolveTexture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- 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);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture1, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
@@ -1462,10 +1438,6 @@
GLFramebuffer resolveFBO2;
glBindTexture(GL_TEXTURE_2D, resolveTexture2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- 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);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture2, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
@@ -1480,6 +1452,94 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
+// Test resolving a multisampled texture with blit after drawing to multiple FBOs, with color
+// attachment 1 resolved first.
+TEST_P(FramebufferTest_ES31,
+ MultipleTextureMultisampleResolveWithBlitMultipleResolvesAttachment1First)
+{
+ // Attach two MSAA textures to FBO1
+ // Set read buffer 1
+ // Resolve into FBO2
+ // Set read buffer 0
+ // Resolve into FBO3
+
+ ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_draw_buffers"));
+
+ constexpr int kSize = 16;
+ glViewport(0, 0, kSize, kSize);
+
+ GLFramebuffer msaaFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get());
+
+ GLTexture msaaTextureRed;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msaaTextureRed.get());
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false);
+ ASSERT_GL_NO_ERROR();
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
+ msaaTextureRed.get(), 0);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ GLTexture msaaTextureGreen;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msaaTextureGreen.get());
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false);
+ ASSERT_GL_NO_ERROR();
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE,
+ msaaTextureGreen.get(), 0);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ // Setup program to render red into attachment 0 and green into attachment 1.
+ const char *fs = R"(#extension GL_EXT_draw_buffers : enable
+precision highp float;
+void main()
+{
+ gl_FragData[0] = vec4(1.0, 0.0, 0.0, 1.0); // attachment 0: red
+ gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0); // attachment 1: green
+})";
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), fs);
+ glUseProgram(program);
+ constexpr GLenum kDrawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
+ glDrawBuffers(2, kDrawBuffers);
+
+ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
+ ASSERT_GL_NO_ERROR();
+
+ // Create another FBO to resolve the multisample buffer into.
+ GLTexture resolveTexture1;
+ GLFramebuffer resolveFBO1;
+ glBindTexture(GL_TEXTURE_2D, resolveTexture1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO1);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture1, 0);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO1);
+ glReadBuffer(GL_COLOR_ATTACHMENT1); // Green
+ glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO1);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+ // Create another FBO to resolve the multisample buffer into.
+ GLTexture resolveTexture2;
+ GLFramebuffer resolveFBO2;
+ glBindTexture(GL_TEXTURE_2D, resolveTexture2);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO2);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture2, 0);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO2);
+ glReadBuffer(GL_COLOR_ATTACHMENT0); // Red
+ glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO2);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+}
+
// 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.