Commit 30622479 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix crash with deferred clears and MSRTT

The following scenario was mishandled: - MSRTT draw with an unresolve operation (i.e. has two subpasses) - Deferred clear - Flush deferred clear with MSRTT framebuffer not needing unresolve (i.e. has one subpass) Bug: chromium:1178693 Change-Id: If3548e99897d698d61dfafbe9f86193723d06e5a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2697648 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent e153063d
...@@ -3043,7 +3043,7 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -3043,7 +3043,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
mGraphicsPipelineDesc->updateStencilBackWriteMask( mGraphicsPipelineDesc->updateStencilBackWriteMask(
&mGraphicsPipelineTransition, depthStencilState, drawFramebuffer); &mGraphicsPipelineTransition, depthStencilState, drawFramebuffer);
mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition); mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
onDrawFramebufferRenderPassDescChange(mDrawFramebuffer); onDrawFramebufferRenderPassDescChange(mDrawFramebuffer, nullptr);
break; break;
} }
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING: case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
...@@ -3538,17 +3538,28 @@ void ContextVk::onFramebufferChange(FramebufferVk *framebufferVk) ...@@ -3538,17 +3538,28 @@ void ContextVk::onFramebufferChange(FramebufferVk *framebufferVk)
// Update scissor. // Update scissor.
updateScissor(mState); updateScissor(mState);
onDrawFramebufferRenderPassDescChange(framebufferVk); onDrawFramebufferRenderPassDescChange(framebufferVk, nullptr);
invalidateCurrentGraphicsPipeline();
} }
void ContextVk::onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk) void ContextVk::onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk,
bool *renderPassDescChangedOut)
{ {
mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
framebufferVk->getRenderPassDesc()); framebufferVk->getRenderPassDesc());
const gl::Box &dimensions = framebufferVk->getState().getDimensions(); const gl::Box &dimensions = framebufferVk->getState().getDimensions();
mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, dimensions.width, mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, dimensions.width,
dimensions.height); dimensions.height);
if (renderPassDescChangedOut)
{
// If render pass desc has changed while processing the dirty bits, notify the caller.
*renderPassDescChangedOut = true;
}
else
{
// Otherwise mark the pipeline as dirty.
invalidateCurrentGraphicsPipeline();
}
} }
void ContextVk::invalidateCurrentTransformFeedbackBuffers() void ContextVk::invalidateCurrentTransformFeedbackBuffers()
......
...@@ -317,7 +317,8 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -317,7 +317,8 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
void invalidateDefaultAttribute(size_t attribIndex); void invalidateDefaultAttribute(size_t attribIndex);
void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask); void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask);
void onFramebufferChange(FramebufferVk *framebufferVk); void onFramebufferChange(FramebufferVk *framebufferVk);
void onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk); void onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk,
bool *renderPassDescChangedOut);
void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; } void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; }
void invalidateCurrentTransformFeedbackBuffers(); void invalidateCurrentTransformFeedbackBuffers();
......
...@@ -2598,9 +2598,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2598,9 +2598,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (unresolveChanged || anyUnresolve) if (unresolveChanged || anyUnresolve)
{ {
contextVk->onDrawFramebufferRenderPassDescChange(this); contextVk->onDrawFramebufferRenderPassDescChange(this, renderPassDescChangedOut);
// Notify that the render pass desc has changed.
*renderPassDescChangedOut = true;
} }
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -1492,9 +1492,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -1492,9 +1492,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
} }
else else
{ {
bool renderPassDescChanged = false; ANGLE_TRY(contextVk->startRenderPass(scissoredRenderArea, &commandBuffer, nullptr));
ANGLE_TRY(contextVk->startRenderPass(scissoredRenderArea, &commandBuffer,
&renderPassDescChanged));
} }
if (params.clearStencil || params.clearDepth) if (params.clearStencil || params.clearDepth)
......
...@@ -3676,6 +3676,64 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferUnresolveColorAndDepthSte ...@@ -3676,6 +3676,64 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferUnresolveColorAndDepthSte
renderbufferUnresolveColorAndDepthStencilThenTwoColors(true, true); renderbufferUnresolveColorAndDepthStencilThenTwoColors(true, true);
} }
// Make sure deferred clears are flushed correctly when the framebuffer switches between
// needing unresolve and not needing it.
TEST_P(MultisampledRenderToTextureES3Test, ClearThenMaskedClearFramebufferTest)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
constexpr GLsizei kSize = 16;
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
// Create multisampled framebuffer to use as source.
GLRenderbuffer depthMS;
glBindRenderbuffer(GL_RENDERBUFFER, depthMS);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT24, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthMS);
ASSERT_GL_NO_ERROR();
GLTexture textureMS;
GLRenderbuffer renderbufferMS;
createAndAttachColorAttachment(false, kSize, GL_COLOR_ATTACHMENT0, nullptr, &textureMS,
&renderbufferMS);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear depth to 0.5 and color to green.
glClearDepthf(0.5f);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Break the render pass.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Draw red into the multisampled color buffer. An unresolve operation is needed.
ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_EQUAL);
drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Break the render pass.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
// Clear color to transparent blue.
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Clear both color and depth, with color masked.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
glClearDepthf(0.3f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Make sure the result is blue.
EXPECT_PIXEL_RECT_EQ(0, 0, kSize - 1, kSize - 1, GLColor::blue);
ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(MultisampledRenderToTextureTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(MultisampledRenderToTextureTest);
ANGLE_INSTANTIATE_TEST_ES3(MultisampledRenderToTextureES3Test); ANGLE_INSTANTIATE_TEST_ES3(MultisampledRenderToTextureES3Test);
ANGLE_INSTANTIATE_TEST_ES31(MultisampledRenderToTextureES31Test); ANGLE_INSTANTIATE_TEST_ES31(MultisampledRenderToTextureES31Test);
......
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