Commit d701eae2 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix resolve with different formats

vkCmdResolveImage and subpass resolve attachments cannot be used if the source and destination formats aren't identical per Vulkan spec: vkCmdResolveImage: > srcImage and dstImage must have been created with the same image > format VkSubpassDescription: > each resolve attachment that is not VK_ATTACHMENT_UNUSED must have the > same VkFormat as its corresponding color attachment Bug: chromium:1123524 Change-Id: Iaf7182dbcad0420483ac2c23d0acf8c109688565 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2390781Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarNicolas Capens <capn@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 543a3962
...@@ -79,6 +79,17 @@ bool AreSrcAndDstColorChannelsBlitCompatible(RenderTargetVk *srcRenderTarget, ...@@ -79,6 +79,17 @@ bool AreSrcAndDstColorChannelsBlitCompatible(RenderTargetVk *srcRenderTarget,
(dstFormat.alphaBits > 0 || srcFormat.alphaBits == 0); (dstFormat.alphaBits > 0 || srcFormat.alphaBits == 0);
} }
// Returns false if formats are not identical. vkCmdResolveImage and resolve attachments both
// require identical formats between source and destination. vkCmdBlitImage additionally requires
// the same for depth/stencil formats.
bool AreSrcAndDstFormatsIdentical(RenderTargetVk *srcRenderTarget, RenderTargetVk *dstRenderTarget)
{
const vk::Format &srcFormat = srcRenderTarget->getImageFormat();
const vk::Format &dstFormat = dstRenderTarget->getImageFormat();
return srcFormat.vkImageFormat == dstFormat.vkImageFormat;
}
bool AreSrcAndDstDepthStencilChannelsBlitCompatible(RenderTargetVk *srcRenderTarget, bool AreSrcAndDstDepthStencilChannelsBlitCompatible(RenderTargetVk *srcRenderTarget,
RenderTargetVk *dstRenderTarget) RenderTargetVk *dstRenderTarget)
{ {
...@@ -1043,6 +1054,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context, ...@@ -1043,6 +1054,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
HasSrcBlitFeature(renderer, readRenderTarget) && HasSrcBlitFeature(renderer, readRenderTarget) &&
(rotation == SurfaceRotation::Identity); (rotation == SurfaceRotation::Identity);
bool areChannelsBlitCompatible = true; bool areChannelsBlitCompatible = true;
bool areFormatsIdentical = true;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
{ {
RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL]; RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
...@@ -1051,6 +1063,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context, ...@@ -1051,6 +1063,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
areChannelsBlitCompatible = areChannelsBlitCompatible =
areChannelsBlitCompatible && areChannelsBlitCompatible &&
AreSrcAndDstColorChannelsBlitCompatible(readRenderTarget, drawRenderTarget); AreSrcAndDstColorChannelsBlitCompatible(readRenderTarget, drawRenderTarget);
areFormatsIdentical = AreSrcAndDstFormatsIdentical(readRenderTarget, drawRenderTarget);
} }
// Now that all flipping is done, adjust the offsets for resolve and prerotation // Now that all flipping is done, adjust the offsets for resolve and prerotation
...@@ -1072,7 +1085,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context, ...@@ -1072,7 +1085,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
} }
// If we're not flipping or rotating, use Vulkan's builtin resolve. // If we're not flipping or rotating, use Vulkan's builtin resolve.
else if (isColorResolve && !flipX && !flipY && areChannelsBlitCompatible && else if (isColorResolve && !flipX && !flipY && areChannelsBlitCompatible &&
(rotation == SurfaceRotation::Identity)) areFormatsIdentical && rotation == SurfaceRotation::Identity)
{ {
// Resolving with a subpass resolve attachment has a few restrictions: // Resolving with a subpass resolve attachment has a few restrictions:
// 1.) glBlitFramebuffer() needs to copy the read color attachment to all enabled // 1.) glBlitFramebuffer() needs to copy the read color attachment to all enabled
...@@ -1138,6 +1151,9 @@ angle::Result FramebufferVk::blit(const gl::Context *context, ...@@ -1138,6 +1151,9 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
bool areChannelsBlitCompatible = bool areChannelsBlitCompatible =
AreSrcAndDstDepthStencilChannelsBlitCompatible(readRenderTarget, drawRenderTarget); AreSrcAndDstDepthStencilChannelsBlitCompatible(readRenderTarget, drawRenderTarget);
// glBlitFramebuffer requires that depth/stencil blits have matching formats.
ASSERT(AreSrcAndDstFormatsIdentical(readRenderTarget, drawRenderTarget));
if (canBlitWithCommand && areChannelsBlitCompatible) if (canBlitWithCommand && areChannelsBlitCompatible)
{ {
ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget, ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
......
...@@ -1191,6 +1191,52 @@ TEST_P(FramebufferTest_ES31, MultisampleResolveWithBlit) ...@@ -1191,6 +1191,52 @@ TEST_P(FramebufferTest_ES31, MultisampleResolveWithBlit)
EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 239, 239, 0, 255, 1.0); // Yellow EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 239, 239, 0, 255, 1.0); // Yellow
} }
// Test resolving a multisampled texture with blit to a different format
TEST_P(FramebufferTest_ES31, MultisampleResolveWithBlitDifferentFormats)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_BGRA8888"));
constexpr int kSize = 16;
glViewport(0, 0, kSize, kSize);
GLFramebuffer msaaFBO;
glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get());
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture.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,
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.
GLTexture resolveTexture;
GLFramebuffer resolveFBO;
glBindTexture(GL_TEXTURE_2D, resolveTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA8_EXT, kSize, kSize, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
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, 239, 0, 0, 255, 1.0); // Red
EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 239, 0, 255, 1.0); // Green
EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 239, 239, 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 mulitiple FBOs.
TEST_P(FramebufferTest_ES31, MultisampleResolveWithBlitMultipleFBOs) TEST_P(FramebufferTest_ES31, MultisampleResolveWithBlitMultipleFBOs)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment