Commit f8070feb by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Use depthClamp to clear depth where available

This will avoid breaking render pass if clearing depth in clearWithDraw. Bug: angleproject:4836 Change-Id: I50242d1115efc91059923143f6ae5fd25fb3d36f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2462717 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent dd4b6445
......@@ -2019,7 +2019,9 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{
if (clearDepth)
RendererVk *renderer = contextVk->getRenderer();
if (clearDepth && !renderer->getPhysicalDeviceFeatures().depthClamp)
{
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
......@@ -2031,15 +2033,18 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
// Force start a new render pass for the depth clear to take effect.
// UtilsVk::clearFramebuffer may not start a new render pass if there's one already started.
ANGLE_TRY(flushDeferredClears(contextVk, clearArea));
clearDepth = false;
}
UtilsVk::ClearFramebufferParameters params = {};
params.clearArea = clearArea;
params.colorClearValue = clearColorValue;
params.stencilClearValue = static_cast<uint8_t>(clearDepthStencilValue.stencil);
params.stencilMask = stencilMask;
params.depthStencilClearValue = clearDepthStencilValue;
params.stencilMask = stencilMask;
params.clearColor = true;
params.clearDepth = clearDepth;
params.clearStencil = clearStencil;
const auto &colorRenderTargets = mRenderTargetCache.getColors();
......@@ -2060,12 +2065,13 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
// Clear stencil only once!
// Clear depth/stencil only once!
params.clearDepth = false;
params.clearStencil = false;
}
// If there was no color clear, clear stencil alone.
if (params.clearStencil)
// If there was no color clear, clear depth/stencil alone.
if (params.clearDepth || params.clearStencil)
{
params.clearColor = false;
ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
......
......@@ -1336,6 +1336,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.shaderClipDistance = mPhysicalDeviceFeatures.shaderClipDistance;
// Used to support OES_sample_shading
enabledFeatures.features.sampleRateShading = mPhysicalDeviceFeatures.sampleRateShading;
// Used to support depth clears through draw calls.
enabledFeatures.features.depthClamp = mPhysicalDeviceFeatures.depthClamp;
if (!vk::CommandBuffer::ExecutesInline())
{
......
......@@ -1402,14 +1402,21 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
ANGLE_TRY(contextVk->startRenderPass(scissoredRenderArea, &commandBuffer));
}
if (params.clearStencil)
if (params.clearStencil || params.clearDepth)
{
vk::CommandBufferHelper *renderpassCommands;
renderpassCommands = &contextVk->getStartedRenderPassCommands();
// Because clear is not affected by stencil test, we have to explicitly mark stencil write
// here.
renderpassCommands->onStencilAccess(vk::ResourceAccess::Write);
// Because clear is not affected by depth/stencil test, we have to explicitly mark
// depth/stencil write here.
if (params.clearDepth)
{
renderpassCommands->onDepthAccess(vk::ResourceAccess::Write);
}
if (params.clearStencil)
{
renderpassCommands->onStencilAccess(vk::ResourceAccess::Write);
}
// We may have changed depth stencil access mode, so update read only depth stencil mode
// here.
......@@ -1433,11 +1440,25 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
// used.
pipelineDesc.setSubpass(contextVk->getCurrentSubpassIndex());
// Clear depth by enabling depth clamping and setting the viewport depth range to the clear
// value.
if (params.clearDepth)
{
// This path requires the depthClamp Vulkan feature.
ASSERT(contextVk->getRenderer()->getPhysicalDeviceFeatures().depthClamp);
pipelineDesc.setDepthTestEnabled(true);
pipelineDesc.setDepthWriteEnabled(true);
pipelineDesc.setDepthFunc(VK_COMPARE_OP_ALWAYS);
pipelineDesc.setDepthClampEnabled(true);
}
// Clear stencil by enabling stencil write with the right mask.
if (params.clearStencil)
{
const uint8_t compareMask = 0xFF;
const uint8_t clearStencilValue = params.stencilClearValue;
const uint8_t compareMask = 0xFF;
const uint8_t clearStencilValue =
static_cast<uint8_t>(params.depthStencilClearValue.stencil);
pipelineDesc.setStencilTestEnabled(true);
pipelineDesc.setStencilFrontFuncs(clearStencilValue, VK_COMPARE_OP_ALWAYS, compareMask);
......@@ -1453,8 +1474,11 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
VkViewport viewport;
gl::Rectangle completeRenderArea = framebuffer->getRotatedCompleteRenderArea(contextVk);
bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
gl_vk::GetViewport(completeRenderArea, 0.0f, 1.0f, invertViewport, completeRenderArea.height,
&viewport);
// Set depth range to clear value. If clearing depth, the vertex shader depth output is clamped
// to this value, thus clearing the depth buffer to the desired clear value.
const float clearDepthValue = params.depthStencilClearValue.depth;
gl_vk::GetViewport(completeRenderArea, clearDepthValue, clearDepthValue, invertViewport,
completeRenderArea.height, &viewport);
pipelineDesc.setViewport(viewport);
pipelineDesc.setScissor(gl_vk::GetRect(params.clearArea));
......@@ -2576,13 +2600,14 @@ angle::Result UtilsVk::allocateDescriptorSet(ContextVk *contextVk,
UtilsVk::ClearFramebufferParameters::ClearFramebufferParameters()
: clearColor(false),
clearDepth(false),
clearStencil(false),
stencilMask(0),
colorMaskFlags(0),
colorAttachmentIndexGL(0),
colorFormat(nullptr),
colorClearValue{},
stencilClearValue(0)
depthStencilClearValue{}
{}
} // namespace rx
......@@ -20,7 +20,7 @@
// resolve on depth/stencil images.
// - Generate mipmap: Used by TextureVk::generateMipmapsWithCompute().
// - Overlay Cull/Draw: Used by OverlayVk to efficiently draw a UI for debugging.
// - Mipmap generation: Not yet implemented
// - Mipmap generation: Used by TextureVk to generate mipmaps more efficiently in compute.
//
#ifndef LIBANGLE_RENDERER_VULKAN_UTILSVK_H_
......@@ -95,8 +95,10 @@ class UtilsVk : angle::NonCopyable
gl::Rectangle clearArea;
// Note that depth clear is never needed to be done with a draw call.
// Note that depth clear is only possible if the depthClamp Vulkan feature is supported. If
// needs be, this can be emulated by exporting depth from shaders/src/ImageClear.frag.
bool clearColor;
bool clearDepth;
bool clearStencil;
uint8_t stencilMask;
......@@ -105,7 +107,7 @@ class UtilsVk : angle::NonCopyable
const angle::Format *colorFormat;
VkClearColorValue colorClearValue;
uint8_t stencilClearValue;
VkClearDepthStencilValue depthStencilClearValue;
};
struct BlitResolveParameters
......
......@@ -2178,6 +2178,11 @@ void GraphicsPipelineDesc::setDepthFunc(VkCompareOp op)
SetBitField(mDepthStencilStateInfo.depthCompareOp, op);
}
void GraphicsPipelineDesc::setDepthClampEnabled(bool enabled)
{
mRasterizationAndMultisampleStateInfo.bits.depthClampEnable = enabled;
}
void GraphicsPipelineDesc::setStencilTestEnabled(bool enabled)
{
mDepthStencilStateInfo.enable.stencilTest = enabled;
......
......@@ -623,6 +623,7 @@ class GraphicsPipelineDesc final
void setDepthTestEnabled(bool enabled);
void setDepthWriteEnabled(bool enabled);
void setDepthFunc(VkCompareOp op);
void setDepthClampEnabled(bool enabled);
void setStencilTestEnabled(bool enabled);
void setStencilFrontFuncs(uint8_t reference, VkCompareOp compareOp, uint8_t compareMask);
void setStencilBackFuncs(uint8_t reference, VkCompareOp compareOp, uint8_t compareMask);
......
......@@ -46,20 +46,25 @@ class VulkanPerformanceCounterTest : public ANGLETest
return rx::GetImplAs<const rx::ContextVk>(context)->getPerfCounters();
}
static constexpr GLsizei kInvalidateTestSize = 16;
void setupClearAndDrawForInvalidateTest(GLProgram *program,
GLFramebuffer *framebuffer,
GLTexture *texture,
GLRenderbuffer *renderbuffer)
GLRenderbuffer *renderbuffer,
bool clearStencil)
{
glUseProgram(*program);
// Setup to draw to color, depth, and stencil
glBindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kInvalidateTestSize, kInvalidateTestSize, 0,
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0);
glBindRenderbuffer(GL_RENDERBUFFER, *renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 16, 16);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kInvalidateTestSize,
kInvalidateTestSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
*renderbuffer);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
......@@ -70,7 +75,10 @@ class VulkanPerformanceCounterTest : public ANGLETest
glDepthFunc(GL_GEQUAL);
glClearDepthf(0.99f);
glEnable(GL_STENCIL_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearStencil(0xAA);
glViewport(0, 0, kInvalidateTestSize, kInvalidateTestSize);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
(clearStencil ? GL_STENCIL_BUFFER_BIT : 0));
drawQuad(*program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
}
......@@ -545,7 +553,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDraw)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -592,7 +600,7 @@ TEST_P(VulkanPerformanceCounterTest, DisableInvalidateDraw)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -639,7 +647,7 @@ TEST_P(VulkanPerformanceCounterTest, DisableDrawInvalidateEnable)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -697,7 +705,7 @@ TEST_P(VulkanPerformanceCounterTest, Invalidate)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -736,7 +744,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDraw)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -784,7 +792,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisable)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -834,7 +842,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnable)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -887,7 +895,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnableDraw)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -942,7 +950,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnable)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -998,7 +1006,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidate)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -1056,7 +1064,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidateDraw)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -1118,7 +1126,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableEnableDraw)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Execute the scenario that this test is for:
......@@ -1170,7 +1178,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateAndClear)
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Disable depth test but with depth mask enabled so that clear should still work.
glDisable(GL_DEPTH_TEST);
......@@ -1202,8 +1210,69 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateAndClear)
ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
// Should pass depth test: (0.5+1.0)/2.0=0.75 < 1.0
drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(5, 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kInvalidateTestSize / 2, kInvalidateTestSize / 2, GLColor::blue);
compareDepthStencilCountersForInvalidateTest(counters, expected);
}
// Tests that the draw path for clear after invalidate and disabling depth/stencil test keeps
// content stored.
TEST_P(VulkanPerformanceCounterTest, InvalidateAndMaskedClear)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+1, Load+0, Stores+1)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 1, 0, 1, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, true);
// Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false)
const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards);
ASSERT_GL_NO_ERROR();
// Disable depth/stencil test but make stencil masked
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDepthMask(GL_TRUE);
glStencilMask(0xF0);
// Enable scissor for the draw path to be taken.
glEnable(GL_SCISSOR_TEST);
glScissor(kInvalidateTestSize / 4, kInvalidateTestSize / 4, kInvalidateTestSize / 2,
kInvalidateTestSize / 2);
// Do in-renderpass clear. This should result in StoreOp=STORE
glClearDepthf(1.0f);
glClearStencil(0x55);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Expect rpCount+1, depth(Clears+0, Loads+1, Stores+1), stencil(Clears+0, Load+1, Stores+1)
setExpectedCountersForInvalidateTest(counters, 0, 0, 1, 1, 0, 1, 1, &expected);
// Bind FBO again and try to use the depth buffer without clear. This should result in
// loadOp=LOAD and StoreOP=STORE
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x50, 0xF0);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.95f);
EXPECT_PIXEL_COLOR_EQ(kInvalidateTestSize / 2, kInvalidateTestSize / 2, GLColor::blue);
// TODO: After fixing ANGLE per https://issuetracker.google.com/issues/167275320, uncomment:
// compareDepthStencilCountersForInvalidateTest(counters, expected);
}
// Tests whether depth-stencil ContentDefined will be correct when:
......@@ -1314,7 +1383,7 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawAndDeleteRenderbuffer)
// Declare the RAII-based GLRenderbuffer object within this set of curly braces, so that it
// will be deleted early (at the close-curly-brace)
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer, false);
// Invalidate (storeOp = DONT_CARE; mContentDefined = false)
const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
......
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