Commit df8f71d1 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Don't break the render pass on scissored clears

clearImmediatelyWithRenderPassOp is removed and the draw path is used for the scissor. That path was added to avoid creating a large number of graphics pipelines due to the scissor state. This is now done by using dynamic state for scissor in the draw path for clear. Running the following dEQP tests without and with dynamic state for scissor: dEQP-GLES3.functional.fragment_ops.depth_stencil.stencil_ops.* the number of graphics pipelines is reduced from 95392 to 16. Bug: angleproject:4617 Bug: angleproject:4836 Change-Id: Ib373d8cd23ca2b67e6fd26aa2a1103f281f7e473 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2463985 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 62bba4ae
...@@ -550,13 +550,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -550,13 +550,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
} }
} }
if (scissoredClear && !maskedClearColor && !maskedClearStencil)
{
return clearImmediatelyWithRenderPassOp(contextVk, scissoredRenderArea, clearColorBuffers,
clearDepth, clearStencil, clearColorValue,
clearDepthStencilValue);
}
// The most costly clear mode is when we need to mask out specific color channels or stencil // The most costly clear mode is when we need to mask out specific color channels or stencil
// bits. This can only be done with a draw call. // bits. This can only be done with a draw call.
return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepth, return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepth,
...@@ -1975,40 +1968,6 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, ...@@ -1975,40 +1968,6 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result FramebufferVk::clearImmediatelyWithRenderPassOp(
ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{
for (size_t colorIndexGL : clearColorBuffers)
{
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
mDeferredClears.store(static_cast<uint32_t>(colorIndexGL), VK_IMAGE_ASPECT_COLOR_BIT,
clearValue);
}
if (clearDepth)
{
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
mDeferredClears.store(vk::kUnpackedDepthIndex, VK_IMAGE_ASPECT_DEPTH_BIT, clearValue);
}
if (clearStencil)
{
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
mDeferredClears.store(vk::kUnpackedStencilIndex, VK_IMAGE_ASPECT_STENCIL_BIT, clearValue);
}
// Ensure the clear happens immediately.
return flushDeferredClears(contextVk, clearArea);
}
angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk, angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea, const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
......
...@@ -172,15 +172,6 @@ class FramebufferVk : public FramebufferImpl ...@@ -172,15 +172,6 @@ class FramebufferVk : public FramebufferImpl
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearImmediatelyWithRenderPassOp(
ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk, angle::Result clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea, const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
......
...@@ -1490,7 +1490,10 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -1490,7 +1490,10 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
completeRenderArea.height, &viewport); completeRenderArea.height, &viewport);
pipelineDesc.setViewport(viewport); pipelineDesc.setViewport(viewport);
pipelineDesc.setScissor(gl_vk::GetRect(params.clearArea)); // Scissored clears can create a large number of pipelines in some tests. Use dynamic state for
// scissors.
pipelineDesc.setDynamicScissor();
const VkRect2D scissor = gl_vk::GetRect(params.clearArea);
vk::ShaderLibrary &shaderLibrary = contextVk->getShaderLibrary(); vk::ShaderLibrary &shaderLibrary = contextVk->getShaderLibrary();
vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr; vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr;
...@@ -1512,6 +1515,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -1512,6 +1515,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
// Make sure this draw call doesn't count towards occlusion query results. // Make sure this draw call doesn't count towards occlusion query results.
ANGLE_TRY(contextVk->pauseOcclusionQueryIfActive()); ANGLE_TRY(contextVk->pauseOcclusionQueryIfActive());
commandBuffer->setScissor(0, 1, &scissor);
commandBuffer->draw(3, 0); commandBuffer->draw(3, 0);
return contextVk->resumeOcclusionQueryIfActive(); return contextVk->resumeOcclusionQueryIfActive();
} }
......
...@@ -32,6 +32,13 @@ namespace vk ...@@ -32,6 +32,13 @@ namespace vk
namespace namespace
{ {
constexpr int32_t kDynamicScissorSentinel = std::numeric_limits<int32_t>::min();
bool IsScissorStateDynamic(const VkRect2D &scissor)
{
return scissor.offset.x == kDynamicScissorSentinel;
}
uint8_t PackGLBlendOp(GLenum blendOp) uint8_t PackGLBlendOp(GLenum blendOp)
{ {
switch (blendOp) switch (blendOp)
...@@ -1754,7 +1761,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -1754,7 +1761,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
viewportState.viewportCount = 1; viewportState.viewportCount = 1;
viewportState.pViewports = &viewport; viewportState.pViewports = &viewport;
viewportState.scissorCount = 1; viewportState.scissorCount = 1;
viewportState.pScissors = &mScissor; viewportState.pScissors = IsScissorStateDynamic(mScissor) ? nullptr : &mScissor;
const PackedRasterizationAndMultisampleStateInfo &rasterAndMS = const PackedRasterizationAndMultisampleStateInfo &rasterAndMS =
mRasterizationAndMultisampleStateInfo; mRasterizationAndMultisampleStateInfo;
...@@ -1890,7 +1897,17 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -1890,7 +1897,17 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
Int4Array_Get<VkColorComponentFlags>(inputAndBlend.colorWriteMaskBits, colorIndexGL); Int4Array_Get<VkColorComponentFlags>(inputAndBlend.colorWriteMaskBits, colorIndexGL);
} }
// We would define dynamic state here if it were to be used. // Dynamic state
angle::FixedVector<VkDynamicState, 1> dynamicStateList;
if (IsScissorStateDynamic(mScissor))
{
dynamicStateList.push_back(VK_DYNAMIC_STATE_SCISSOR);
}
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStateList.size());
dynamicState.pDynamicStates = dynamicStateList.data();
createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
createInfo.flags = 0; createInfo.flags = 0;
...@@ -1904,7 +1921,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -1904,7 +1921,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
createInfo.pMultisampleState = &multisampleState; createInfo.pMultisampleState = &multisampleState;
createInfo.pDepthStencilState = &depthStencilState; createInfo.pDepthStencilState = &depthStencilState;
createInfo.pColorBlendState = &blendState; createInfo.pColorBlendState = &blendState;
createInfo.pDynamicState = nullptr; createInfo.pDynamicState = dynamicStateList.empty() ? nullptr : &dynamicState;
createInfo.layout = pipelineLayout.getHandle(); createInfo.layout = pipelineLayout.getHandle();
createInfo.renderPass = compatibleRenderPass.getHandle(); createInfo.renderPass = compatibleRenderPass.getHandle();
createInfo.subpass = mRasterizationAndMultisampleStateInfo.bits.subpass; createInfo.subpass = mRasterizationAndMultisampleStateInfo.bits.subpass;
...@@ -2393,6 +2410,14 @@ void GraphicsPipelineDesc::updateDepthRange(GraphicsPipelineTransitionBits *tran ...@@ -2393,6 +2410,14 @@ void GraphicsPipelineDesc::updateDepthRange(GraphicsPipelineTransitionBits *tran
transition->set(ANGLE_GET_TRANSITION_BIT(mViewport, maxDepth)); transition->set(ANGLE_GET_TRANSITION_BIT(mViewport, maxDepth));
} }
void GraphicsPipelineDesc::setDynamicScissor()
{
mScissor.offset.x = kDynamicScissorSentinel;
mScissor.offset.y = 0;
mScissor.extent.width = 0;
mScissor.extent.height = 0;
}
void GraphicsPipelineDesc::setScissor(const VkRect2D &scissor) void GraphicsPipelineDesc::setScissor(const VkRect2D &scissor)
{ {
mScissor = scissor; mScissor = scissor;
......
...@@ -685,6 +685,7 @@ class GraphicsPipelineDesc final ...@@ -685,6 +685,7 @@ class GraphicsPipelineDesc final
void updateDepthRange(GraphicsPipelineTransitionBits *transition, void updateDepthRange(GraphicsPipelineTransitionBits *transition,
float nearPlane, float nearPlane,
float farPlane); float farPlane);
void setDynamicScissor();
void setScissor(const VkRect2D &scissor); void setScissor(const VkRect2D &scissor);
void updateScissor(GraphicsPipelineTransitionBits *transition, const VkRect2D &scissor); void updateScissor(GraphicsPipelineTransitionBits *transition, const VkRect2D &scissor);
...@@ -703,6 +704,8 @@ class GraphicsPipelineDesc final ...@@ -703,6 +704,8 @@ class GraphicsPipelineDesc final
PackedDepthStencilStateInfo mDepthStencilStateInfo; PackedDepthStencilStateInfo mDepthStencilStateInfo;
PackedInputAssemblyAndColorBlendStateInfo mInputAssemblyAndColorBlendStateInfo; PackedInputAssemblyAndColorBlendStateInfo mInputAssemblyAndColorBlendStateInfo;
VkViewport mViewport; VkViewport mViewport;
// The special value of .offset.x == INT_MIN for scissor implies dynamic scissor that needs to
// be set through vkCmdSetScissor.
VkRect2D mScissor; VkRect2D mScissor;
}; };
......
...@@ -1552,6 +1552,104 @@ TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass) ...@@ -1552,6 +1552,104 @@ TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass)
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::blue);
} }
// Tests that scissored clears don't break the RP.
TEST_P(VulkanPerformanceCounterTest, ScissoredClearDoesNotBreakRenderPass)
{
const rx::vk::PerfCounters &counters = hackANGLE();
constexpr GLsizei kSize = 64;
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLRenderbuffer renderbuffer;
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
renderbuffer);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
uint32_t expectedRenderPassCount = counters.renderPasses + 1;
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor());
glUseProgram(program);
GLint colorUniformLocation =
glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
ASSERT_NE(-1, colorUniformLocation);
ASSERT_GL_NO_ERROR();
// Clear the framebuffer with a draw call to start a render pass.
glViewport(0, 0, kSize, kSize);
glDepthFunc(GL_ALWAYS);
glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f);
// Issue a scissored clear.
glEnable(GL_SCISSOR_TEST);
glScissor(kSize / 4, kSize / 4, kSize / 2, kSize / 2);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClearDepthf(0.0f);
glClearStencil(0x3F);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Make sure the render pass wasn't broken.
EXPECT_EQ(expectedRenderPassCount, counters.renderPasses);
// Verify that clear was done correctly.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::green);
glDisable(GL_SCISSOR_TEST);
// Make sure the border has depth = 1.0f, stencil = 0x55
glDepthFunc(GL_LESS);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
// Make sure the center has depth = 0.0f, stencil = 0x3F
glDepthFunc(GL_GREATER);
glStencilFunc(GL_EQUAL, 0x3F, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 1.0f, 1.0f);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.05f);
ASSERT_GL_NO_ERROR();
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);
EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::magenta);
}
// Tests that draw buffer change with all color channel mask off should not break renderpass // Tests that draw buffer change with all color channel mask off should not break renderpass
TEST_P(VulkanPerformanceCounterTest, DrawbufferChangeWithAllColorMaskDisabled) TEST_P(VulkanPerformanceCounterTest, DrawbufferChangeWithAllColorMaskDisabled)
{ {
......
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