Commit 2f3d18f2 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix unresolve disagreement between FB and RP

FramebufferVk::updateRenderPass reset the render pass description, but not the framebuffer description. This caused a disagreement between the two regarding which attachments need to be unresolved. Later, FramebufferVk::startNewRenderPass could miscalculate whether a new framebuffer needs to be generated based on changes in unresolve attachments. For example: - say in the first render pass color needs to be unresolved. Both RP and FB desc would remember this (each being keys for their respective caches). - A following operation triggers syncState such that FB desc changes (for example rebind of attachment), which cleared RP desc but not FB desc's unresolve attachment state. - If the next render pass does not require an unresolve (for example due to a clear or invalidate), then the framebuffer is not recreated because according to RP desc at the start and end of FramebufferVk::startNewRenderPass there has been no change in unresolve mask. * At start there's no unresolve because of syncState clearing it. * At end there's no unresolve because there's no need for unresolve. - In the end, the framebuffer used for the first render pass would be used for the second render pass as well. Note that: * The first render pass included an unresolve, i.e. two subpasses. * The second render pass requires one subpass according to its RP desc. It's quite easy to accidentally have the framebuffer correctly recreated (based on the reset RP desc) before FramebufferVk::startNewRenderPass. Note that since syncState has called updateRenderPass, FB desc has necessarily changed, and mFramebuffer is nullptr, so any call to FramebufferVk::getFramebuffer would recreate the framebuffer. Both clear and invalidate call FramebufferVk::getFramebuffer. The issue is reproducible in situations where clear/invalidate has been called before the framebuffer is modified, and then draw is issued after the modification. An ASSERT is added to catch discrepencies between RP desc and FB desc to catch bugs even when the issue doesn't manifest itself as a VVL error. Bug: angleproject:4836 Change-Id: I8a0d116402a6c298377d03e0908baa942019ccd5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2442379Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 527064f1
...@@ -271,6 +271,21 @@ bool HasResolveAttachment(const gl::AttachmentArray<RenderTargetVk *> &colorRend ...@@ -271,6 +271,21 @@ bool HasResolveAttachment(const gl::AttachmentArray<RenderTargetVk *> &colorRend
} }
return false; return false;
} }
vk::FramebufferNonResolveAttachmentMask MakeUnresolveAttachmentMask(const vk::RenderPassDesc &desc)
{
vk::FramebufferNonResolveAttachmentMask unresolveMask(
desc.getColorUnresolveAttachmentMask().bits());
if (desc.hasDepthUnresolveAttachment())
{
unresolveMask.set(vk::kUnpackedDepthIndex);
}
if (desc.hasStencilUnresolveAttachment())
{
unresolveMask.set(vk::kUnpackedStencilIndex);
}
return unresolveMask;
}
} // anonymous namespace } // anonymous namespace
// static // static
...@@ -1821,6 +1836,8 @@ void FramebufferVk::updateRenderPassDesc() ...@@ -1821,6 +1836,8 @@ void FramebufferVk::updateRenderPassDesc()
mRenderPassDesc.packDepthStencilResolveAttachment(hasDepth, hasStencil); mRenderPassDesc.packDepthStencilResolveAttachment(hasDepth, hasStencil);
} }
} }
mCurrentFramebufferDesc.updateUnresolveMask({});
} }
angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
...@@ -2248,6 +2265,10 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2248,6 +2265,10 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
bool previousUnresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment(); bool previousUnresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
bool previousUnresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment(); bool previousUnresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
// Make sure render pass and framebuffer are in agreement w.r.t unresolve attachments.
ASSERT(mCurrentFramebufferDesc.getUnresolveAttachmentMask() ==
MakeUnresolveAttachmentMask(mRenderPassDesc));
// Color attachments. // Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors(); const auto &colorRenderTargets = mRenderTargetCache.getColors();
vk::PackedAttachmentIndex colorIndexVk(0); vk::PackedAttachmentIndex colorIndexVk(0);
...@@ -2471,17 +2492,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2471,17 +2492,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Make sure framebuffer is recreated. // Make sure framebuffer is recreated.
mFramebuffer = nullptr; mFramebuffer = nullptr;
vk::FramebufferNonResolveAttachmentMask unresolveMask(unresolveColorMask.bits()); mCurrentFramebufferDesc.updateUnresolveMask(MakeUnresolveAttachmentMask(mRenderPassDesc));
if (unresolveDepth)
{
unresolveMask.set(vk::kUnpackedDepthIndex);
}
if (unresolveStencil)
{
unresolveMask.set(vk::kUnpackedStencilIndex);
}
mCurrentFramebufferDesc.updateUnresolveMask(unresolveMask);
} }
vk::Framebuffer *framebuffer = nullptr; vk::Framebuffer *framebuffer = nullptr;
......
...@@ -2649,6 +2649,11 @@ uint32_t FramebufferDesc::attachmentCount() const ...@@ -2649,6 +2649,11 @@ uint32_t FramebufferDesc::attachmentCount() const
return count; return count;
} }
FramebufferNonResolveAttachmentMask FramebufferDesc::getUnresolveAttachmentMask() const
{
return mUnresolveAttachmentMask;
}
// SamplerDesc implementation. // SamplerDesc implementation.
SamplerDesc::SamplerDesc() SamplerDesc::SamplerDesc()
{ {
......
...@@ -1086,7 +1086,6 @@ class FramebufferDesc ...@@ -1086,7 +1086,6 @@ class FramebufferDesc
void updateDepthStencil(ImageViewSubresourceSerial serial); void updateDepthStencil(ImageViewSubresourceSerial serial);
void updateDepthStencilResolve(ImageViewSubresourceSerial serial); void updateDepthStencilResolve(ImageViewSubresourceSerial serial);
size_t hash() const; size_t hash() const;
void reset();
bool operator==(const FramebufferDesc &other) const; bool operator==(const FramebufferDesc &other) const;
...@@ -1098,7 +1097,10 @@ class FramebufferDesc ...@@ -1098,7 +1097,10 @@ class FramebufferDesc
return mSerials[kFramebufferDescColorIndexOffset + index]; return mSerials[kFramebufferDescColorIndexOffset + index];
} }
FramebufferNonResolveAttachmentMask getUnresolveAttachmentMask() const;
private: private:
void reset();
void update(uint32_t index, ImageViewSubresourceSerial serial); void update(uint32_t index, ImageViewSubresourceSerial serial);
// Note: this is an exclusive index. If there is one index it will be "1". // Note: this is an exclusive index. If there is one index it will be "1".
......
...@@ -157,6 +157,8 @@ class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTes ...@@ -157,6 +157,8 @@ class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTes
protected: protected:
void readPixelsTestCommon(bool useRenderbuffer); void readPixelsTestCommon(bool useRenderbuffer);
void blitFramebufferTestCommon(bool useRenderbuffer); void blitFramebufferTestCommon(bool useRenderbuffer);
void drawCopyDrawAttachInvalidatedThenDrawCommon(bool useRenderbuffer);
void drawCopyDrawAttachDepthStencilClearThenDrawCommon(bool useRenderbuffer);
void depthStencilClearThenDrawCommon(bool useRenderbuffer); void depthStencilClearThenDrawCommon(bool useRenderbuffer);
void colorAttachment1Common(bool useRenderbuffer); void colorAttachment1Common(bool useRenderbuffer);
void colorAttachments0And3Common(bool useRenderbuffer); void colorAttachments0And3Common(bool useRenderbuffer);
...@@ -1015,8 +1017,7 @@ void MultisampledRenderToTextureTest::drawCopyThenBlendCommon(bool useRenderbuff ...@@ -1015,8 +1017,7 @@ void MultisampledRenderToTextureTest::drawCopyThenBlendCommon(bool useRenderbuff
// For completeness, verify that the texture used as copy target is red. // For completeness, verify that the texture used as copy target is red.
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
const GLColor kExpectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, kExpectedCopyResult, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
...@@ -1326,6 +1327,381 @@ TEST_P(MultisampledRenderToTextureTest, RenderbufferDrawCopyDrawThenMaskedClear) ...@@ -1326,6 +1327,381 @@ TEST_P(MultisampledRenderToTextureTest, RenderbufferDrawCopyDrawThenMaskedClear)
drawCopyDrawThenMaskedClearCommon(true); drawCopyDrawThenMaskedClearCommon(true);
} }
void MultisampledRenderToTextureES3Test::drawCopyDrawAttachInvalidatedThenDrawCommon(
bool useRenderbuffer)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
// Create multisampled framebuffer to draw into
GLTexture textureMS;
GLRenderbuffer renderbufferMS;
createAndAttachColorAttachment(useRenderbuffer, kSize, GL_COLOR_ATTACHMENT0, nullptr,
&textureMS, &renderbufferMS);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Draw red into the multisampled color buffer.
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Clear and draw into framebuffer.
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Create a texture and copy into it.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Draw green into framebuffer. This will unresolve color.
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Create multisampled framebuffer and invalidate its attachment.
GLFramebuffer invalidateFboMS;
glBindFramebuffer(GL_FRAMEBUFFER, invalidateFboMS);
// Create multisampled framebuffer to draw into
GLTexture invalidateTextureMS;
GLRenderbuffer invalidateRenderbufferMS;
createAndAttachColorAttachment(useRenderbuffer, kSize, GL_COLOR_ATTACHMENT0, nullptr,
&invalidateTextureMS, &invalidateRenderbufferMS);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Invalidate the attachment.
GLenum invalidateAttachments[] = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, invalidateAttachments);
// Replace the original framebuffer's attachment with the invalidated one.
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
if (useRenderbuffer)
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
invalidateRenderbufferMS);
}
else
{
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
invalidateTextureMS, 0, 4);
}
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Draw blue into the multisampled color buffer.
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now blue
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue);
// For completeness, verify that the texture used as copy target is red.
ASSERT_GL_NO_ERROR();
verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR();
}
// Draw, copy, draw, attach an invalidated image then draw. The second draw will need to unresolve
// color. Attaching an invalidated image changes the framebuffer, and the following draw doesn't
// require an unresolve. In the Vulkan backend, mismatches in unresolve state between framebuffer
// and render pass will result in an ASSERT.
TEST_P(MultisampledRenderToTextureES3Test, DrawCopyDrawAttachInvalidatedThenDraw)
{
drawCopyDrawAttachInvalidatedThenDrawCommon(false);
}
// Same as DrawCopyDrawAttachInvalidatedThenDraw but with renderbuffers
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDrawCopyDrawAttachInvalidatedThenDraw)
{
drawCopyDrawAttachInvalidatedThenDrawCommon(true);
}
void MultisampledRenderToTextureES3Test::drawCopyDrawAttachDepthStencilClearThenDrawCommon(
bool useRenderbuffer)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
constexpr GLsizei kSize = 64;
// http://anglebug.com/4935
ANGLE_SKIP_TEST_IF(IsD3D11());
setupCopyTexProgram();
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
// Create multisampled framebuffer to draw into
GLTexture textureMS;
GLRenderbuffer renderbufferMS;
createAndAttachColorAttachment(useRenderbuffer, kSize, GL_COLOR_ATTACHMENT0, nullptr,
&textureMS, &renderbufferMS);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Draw red into the multisampled color buffer.
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Clear and draw into framebuffer. There is no unresolve due to clear. The clear value is
// irrelevant as the contents are immediately overdrawn with the draw call.
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Create a texture and copy into it.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Draw green into framebuffer. This will unresolve color.
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Attach a depth/stencil attachment.
GLTexture dsTextureMS;
GLRenderbuffer dsRenderbufferMS;
createAndAttachDepthStencilAttachment(useRenderbuffer, kSize, &dsTextureMS, &dsRenderbufferMS);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear all attachments, so no unresolve would be necessary.
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClearDepthf(1);
glClearStencil(0x55);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not cleared to 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Blend half-transparent green into the multisampled color buffer.
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 0.5f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now cyan
const GLColor kExpected2(0, 127, 127, 191);
EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected2, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected2, 1);
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected2, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected2, 1);
// For completeness, verify that the texture used as copy target is red.
ASSERT_GL_NO_ERROR();
verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR();
}
// Draw, copy, draw, attach depth/stencil, clear then draw. The second draw will need to unresolve
// color. Attaching depth/stencil changes the framebuffer, and the following clear ensures no
// unresolve is necessary. In the Vulkan backend, mismatches in unresolve state between framebuffer
// and render pass will result in an ASSERT.
TEST_P(MultisampledRenderToTextureES3Test, DrawCopyDrawAttachDepthStencilClearThenDraw)
{
drawCopyDrawAttachDepthStencilClearThenDrawCommon(false);
}
// Same as DrawCopyDrawAttachDepthStencilClearThenDraw but with renderbuffers
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDrawCopyDrawAttachDepthStencilClearThenDraw)
{
drawCopyDrawAttachDepthStencilClearThenDrawCommon(true);
}
// Draw, copy, redefine the color attachment with a different format, clear, copy then draw. The
// initial draw will need to unresolve color as the color attachment is preinitilized with data.
// Redefining the color attachment forces framebuffer to recreate when the clear is called. The
// second copy resolves the clear and the final draw unresolves again. In the Vulkan backend,
// mismatches in unresolve state between framebuffer and render pass will result in an ASSERT and a
// validation error (if ASSERT is removed).
TEST_P(MultisampledRenderToTextureES3Test, DrawCopyRedefineClearCopyThenDraw)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
std::vector<GLColor> initialColorData(kSize * kSize, GLColor::black);
// Create multisampled framebuffer to draw into
GLTexture colorMS;
glBindTexture(GL_TEXTURE_2D, colorMS);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
initialColorData.data());
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
colorMS, 0, 4);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Draw red into the multisampled color buffer.
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw into framebuffer. This will unresolve color.
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Create a texture and copy into it.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Incompatibly redefine the texture, forcing its image to be recreated.
glBindTexture(GL_TEXTURE_2D, colorMS);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kSize, kSize, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Create another texture and copy into it.
GLTexture texture2;
glBindTexture(GL_TEXTURE_2D, texture2);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, kSize, kSize, 0);
// Clear to green and blend blue into the multisampled color buffer.
glUseProgram(drawColor);
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now cyan
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::cyan);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::cyan);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::cyan);
// For completeness, verify that the texture used as copy target is red.
ASSERT_GL_NO_ERROR();
verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR();
}
// Draw, copy, rebind the attachment, clear then draw. The initial draw will need to unresolve
// color. The framebuffer attachment is temporary changed and then reset back to the original.
// This causes the framebuffer to be recreated on the following clear and draw. The clear prevents
// the final draw from doing an unresolve. In the Vulkan backend, mismatches in unresolve state
// between framebuffer and render pass will result in an ASSERT and a validation error (if ASSERT is
// removed).
TEST_P(MultisampledRenderToTextureES3Test, DrawCopyRebindAttachmentClearThenDraw)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
std::vector<GLColor> initialColorData(kSize * kSize, GLColor::black);
// Create multisampled framebuffer to draw into
GLTexture colorMS;
glBindTexture(GL_TEXTURE_2D, colorMS);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
initialColorData.data());
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
colorMS, 0, 4);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Draw red into the multisampled color buffer.
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw into framebuffer. This will unresolve color.
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Create a texture and copy into it.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Bind the framebuffer to another texture.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Do whatever.
glClear(GL_COLOR_BUFFER_BIT);
// Rebind the framebuffer back to the original texture.
glBindTexture(GL_TEXTURE_2D, colorMS);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
colorMS, 0, 4);
// Clear to green and blend blue into the multisampled color buffer.
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(drawColor);
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now cyan
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::cyan);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::cyan);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::cyan);
// For completeness, verify that the texture used as copy target is red.
ASSERT_GL_NO_ERROR();
verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR();
}
void MultisampledRenderToTextureTest::clearThenBlendCommon(bool useRenderbuffer) void MultisampledRenderToTextureTest::clearThenBlendCommon(bool useRenderbuffer)
{ {
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture")); ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
...@@ -1441,8 +1817,7 @@ void MultisampledRenderToTextureES3Test::depthStencilClearThenDrawCommon(bool us ...@@ -1441,8 +1817,7 @@ void MultisampledRenderToTextureES3Test::depthStencilClearThenDrawCommon(bool us
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Verify. // Verify.
const GLColor expectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize);
} }
// Clear depth stencil, then draw. The clear should be applied correctly. // Clear depth stencil, then draw. The clear should be applied correctly.
...@@ -1545,8 +1920,7 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy ...@@ -1545,8 +1920,7 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1); EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is red. // For completeness, verify that the texture used as copy target is red.
const GLColor expectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize);
} }
// Draw, copy, then clear&blend. This tests uses a depth/stencil buffer and makes sure the second // Draw, copy, then clear&blend. This tests uses a depth/stencil buffer and makes sure the second
...@@ -2154,8 +2528,7 @@ TEST_P(MultisampledRenderToTextureTest, DepthReadWriteToggleWithStartedRenderPas ...@@ -2154,8 +2528,7 @@ TEST_P(MultisampledRenderToTextureTest, DepthReadWriteToggleWithStartedRenderPas
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Verify the color has all three color in it. // Verify the color has all three color in it.
const GLColor expectedCopyResult(255, 255, 255, 255); EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::white);
EXPECT_PIXEL_COLOR_EQ(1, 1, expectedCopyResult);
} }
void MultisampledRenderToTextureES3Test::colorAttachment1Common(bool useRenderbuffer) void MultisampledRenderToTextureES3Test::colorAttachment1Common(bool useRenderbuffer)
...@@ -2227,8 +2600,7 @@ void MultisampledRenderToTextureES3Test::colorAttachment1Common(bool useRenderbu ...@@ -2227,8 +2600,7 @@ void MultisampledRenderToTextureES3Test::colorAttachment1Common(bool useRenderbu
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1); EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is red. // For completeness, verify that the texture used as copy target is red.
const GLColor kExpectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, kExpectedCopyResult, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -2331,8 +2703,7 @@ void MultisampledRenderToTextureES3Test::colorAttachments0And3Common(bool useRen ...@@ -2331,8 +2703,7 @@ void MultisampledRenderToTextureES3Test::colorAttachments0And3Common(bool useRen
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1); EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is red. // For completeness, verify that the texture used as copy target is red.
const GLColor kExpectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, kExpectedCopyResult, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -2501,8 +2872,7 @@ TEST_P(MultisampledRenderToTextureES31Test, MixedMultisampledAndMultisampledRend ...@@ -2501,8 +2872,7 @@ TEST_P(MultisampledRenderToTextureES31Test, MixedMultisampledAndMultisampledRend
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1); EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is red. // For completeness, verify that the texture used as copy target is red.
const GLColor kExpectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, kExpectedCopyResult, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -2997,8 +3367,7 @@ precision highp float; ...@@ -2997,8 +3367,7 @@ precision highp float;
} }
// For completeness, verify that the texture used as copy target is red. // For completeness, verify that the texture used as copy target is red.
const GLColor kExpectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, kExpectedCopyResult, kSize, 0, 0, kSize, kSize);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
...@@ -3124,8 +3493,7 @@ void MultisampledRenderToTextureES3Test::renderbufferUnresolveColorAndDepthStenc ...@@ -3124,8 +3493,7 @@ void MultisampledRenderToTextureES3Test::renderbufferUnresolveColorAndDepthStenc
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1); EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is red. // For completeness, verify that the texture used as copy target is red.
const GLColor expectedCopyResult(255, 0, 0, 255); verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize);
// Now create a framebuffer with two color attachments and do something similar. This makes // Now create a framebuffer with two color attachments and do something similar. This makes
// sure that the fact that both these framebuffers have 2 attachments does not cause confusion, // sure that the fact that both these framebuffers have 2 attachments does not cause confusion,
...@@ -3190,8 +3558,7 @@ void MultisampledRenderToTextureES3Test::renderbufferUnresolveColorAndDepthStenc ...@@ -3190,8 +3558,7 @@ void MultisampledRenderToTextureES3Test::renderbufferUnresolveColorAndDepthStenc
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected2, 1); EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected2, 1);
// For completeness, verify that the texture used as copy target is blue. // For completeness, verify that the texture used as copy target is blue.
const GLColor expectedCopyResult2(0, 0, 255, 255); verifyResults(texture, GLColor::blue, kSize, 0, 0, kSize, kSize);
verifyResults(texture, expectedCopyResult2, kSize, 0, 0, kSize, kSize);
} }
// Draw, copy, then blend once on a framebuffer with color and depth attachments, and once with two // Draw, copy, then blend once on a framebuffer with color and depth attachments, and once with two
......
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