Commit 265c5fa9 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix scissor update in FramebufferVk::syncState

A previous change [1] made FramebufferVk::syncState update scissor and rasterization samples only when the DRAW framebuffer is synced. This is incorrect as the READ framebuffer is synced before the DRAW framebuffer, and if the two are the same, the latter is discarded. Very few functions sync both READ and DRAW framebuffers when they are identical. A test is tailored to expose this bug. [1]: https://chromium-review.googlesource.com/c/angle/angle/+/2510013 Bug: angleproject:4988 Change-Id: I6123ac18dded938171bc90a04d4d81f1b42a1694 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2515742 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent dc1c1cb5
...@@ -3630,8 +3630,19 @@ void ContextVk::invalidateDriverUniforms() ...@@ -3630,8 +3630,19 @@ void ContextVk::invalidateDriverUniforms()
mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING); mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
} }
void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk) angle::Result ContextVk::onFramebufferChange(FramebufferVk *framebufferVk)
{ {
// This is called from FramebufferVk::syncState. Skip these updates if the framebuffer being
// synced is:
//
// - The read framebuffer (which is not equal the draw framebuffer)
// - A newly bound draw framebuffer. ContextVk::syncState which follows will update all these
// states, so this is redundant.
if (framebufferVk != mDrawFramebuffer)
{
return angle::Result::Continue;
}
// Ensure that the pipeline description is updated. // Ensure that the pipeline description is updated.
if (mGraphicsPipelineDesc->getRasterizationSamples() != if (mGraphicsPipelineDesc->getRasterizationSamples() !=
static_cast<uint32_t>(framebufferVk->getSamples())) static_cast<uint32_t>(framebufferVk->getSamples()))
...@@ -3640,7 +3651,12 @@ void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk) ...@@ -3640,7 +3651,12 @@ void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk)
framebufferVk->getSamples()); framebufferVk->getSamples());
} }
// Update scissor.
ANGLE_TRY(updateScissor(mState));
onDrawFramebufferRenderPassDescChange(framebufferVk); onDrawFramebufferRenderPassDescChange(framebufferVk);
return angle::Result::Continue;
} }
void ContextVk::onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk) void ContextVk::onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk)
......
...@@ -360,7 +360,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -360,7 +360,7 @@ class ContextVk : public ContextImpl, public vk::Context
void invalidateDefaultAttribute(size_t attribIndex); void invalidateDefaultAttribute(size_t attribIndex);
void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask); void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask);
void onDrawFramebufferChange(FramebufferVk *framebufferVk); angle::Result onFramebufferChange(FramebufferVk *framebufferVk);
void onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk); void onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk);
void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; } void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; }
......
...@@ -1763,13 +1763,6 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -1763,13 +1763,6 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
// The FBO's new attachment may have changed the renderable area
if (binding == GL_DRAW_FRAMEBUFFER)
{
const gl::State &glState = context->getState();
ANGLE_TRY(contextVk->updateScissor(glState));
}
if (command != gl::Command::Blit) if (command != gl::Command::Blit)
{ {
// Don't end the render pass when handling a blit to resolve, since we may be able to // Don't end the render pass when handling a blit to resolve, since we may be able to
...@@ -1783,14 +1776,12 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -1783,14 +1776,12 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
updateRenderPassDesc(); updateRenderPassDesc();
// Notify the ContextVk to update the pipeline desc.
if (binding == GL_DRAW_FRAMEBUFFER)
{
contextVk->onDrawFramebufferChange(this);
}
// Deactivate Framebuffer // Deactivate Framebuffer
mFramebuffer = nullptr; mFramebuffer = nullptr;
// Notify the ContextVk to update the pipeline desc.
ANGLE_TRY(contextVk->onFramebufferChange(this));
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -2354,6 +2354,75 @@ TEST_P(FramebufferTest_ES3, DisabledAttachmentRedefinition) ...@@ -2354,6 +2354,75 @@ TEST_P(FramebufferTest_ES3, DisabledAttachmentRedefinition)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
} }
// Test that changing the attachment of a framebuffer then sync'ing both READ and DRAW framebuffer
// (currently possible with glInvalidateFramebuffer) updates the scissor correctly.
TEST_P(FramebufferTest_ES3, ChangeAttachmentThenInvalidateAndDraw)
{
constexpr GLsizei kSizeLarge = 32;
constexpr GLsizei kSizeSmall = 16;
GLTexture color1;
glBindTexture(GL_TEXTURE_2D, color1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kSizeSmall, kSizeSmall, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
GLTexture color2;
glBindTexture(GL_TEXTURE_2D, color2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kSizeLarge, kSizeLarge, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color1, 0);
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);
glViewport(0, 0, kSizeLarge, kSizeLarge);
// Draw red into the framebuffer.
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Change the attachment, invalidate it and draw green.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color2, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
std::array<GLenum, 1> attachments = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments.data());
ASSERT_GL_NO_ERROR();
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Validate the result.
EXPECT_PIXEL_RECT_EQ(0, 0, kSizeLarge, kSizeLarge, GLColor::green);
// Do the same, but changing from the large to small attachment.
// Draw red into the framebuffer.
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Change the attachment, invalidate it and draw blue.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color1, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments.data());
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Validate the result.
EXPECT_PIXEL_RECT_EQ(0, 0, kSizeSmall, kSizeSmall, GLColor::blue);
}
class FramebufferTest : public ANGLETest class FramebufferTest : public ANGLETest
{}; {};
......
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