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,
}
}
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
// bits. This can only be done with a draw call.
return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepth,
......@@ -1975,40 +1968,6 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
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,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
......
......@@ -172,15 +172,6 @@ class FramebufferVk : public FramebufferImpl
const VkClearColorValue &clearColorValue,
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,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
......
......@@ -1490,7 +1490,10 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
completeRenderArea.height, &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::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr;
......@@ -1512,6 +1515,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
// Make sure this draw call doesn't count towards occlusion query results.
ANGLE_TRY(contextVk->pauseOcclusionQueryIfActive());
commandBuffer->setScissor(0, 1, &scissor);
commandBuffer->draw(3, 0);
return contextVk->resumeOcclusionQueryIfActive();
}
......
......@@ -32,6 +32,13 @@ namespace vk
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)
{
switch (blendOp)
......@@ -1754,7 +1761,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &mScissor;
viewportState.pScissors = IsScissorStateDynamic(mScissor) ? nullptr : &mScissor;
const PackedRasterizationAndMultisampleStateInfo &rasterAndMS =
mRasterizationAndMultisampleStateInfo;
......@@ -1890,7 +1897,17 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
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.flags = 0;
......@@ -1904,7 +1921,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
createInfo.pMultisampleState = &multisampleState;
createInfo.pDepthStencilState = &depthStencilState;
createInfo.pColorBlendState = &blendState;
createInfo.pDynamicState = nullptr;
createInfo.pDynamicState = dynamicStateList.empty() ? nullptr : &dynamicState;
createInfo.layout = pipelineLayout.getHandle();
createInfo.renderPass = compatibleRenderPass.getHandle();
createInfo.subpass = mRasterizationAndMultisampleStateInfo.bits.subpass;
......@@ -2393,6 +2410,14 @@ void GraphicsPipelineDesc::updateDepthRange(GraphicsPipelineTransitionBits *tran
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)
{
mScissor = scissor;
......
......@@ -685,6 +685,7 @@ class GraphicsPipelineDesc final
void updateDepthRange(GraphicsPipelineTransitionBits *transition,
float nearPlane,
float farPlane);
void setDynamicScissor();
void setScissor(const VkRect2D &scissor);
void updateScissor(GraphicsPipelineTransitionBits *transition, const VkRect2D &scissor);
......@@ -703,6 +704,8 @@ class GraphicsPipelineDesc final
PackedDepthStencilStateInfo mDepthStencilStateInfo;
PackedInputAssemblyAndColorBlendStateInfo mInputAssemblyAndColorBlendStateInfo;
VkViewport mViewport;
// The special value of .offset.x == INT_MIN for scissor implies dynamic scissor that needs to
// be set through vkCmdSetScissor.
VkRect2D mScissor;
};
......
......@@ -1552,6 +1552,104 @@ TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass)
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
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