Commit 2aaeb81d by Shahbaz Youssefi Committed by Commit Bot

Vulkan: loadOp=DONT_CARE + unused D/S => invalidate D/S

If depth/stencil is not loaded, and it's not written to during the render pass, then treat it as if it was invalidated so storeOp can be set to DONT_CARE and its corresponding resolve attachment (if any) removed. This is especially useful for MSRTT as a resolve attachment is added at the start of render pass, and this optimization will give it a chance to undo that if depth/stencil was not actually used in the render pass. This situation can arise for example if a render pass is created for the sole purpose of clearing color. This change includes a bug fix for missing depth/stencil on*Access in the UtilsVk blit/resolve path. Bug: angleproject:4836 Change-Id: Ifc8eea3e6ffb3eb4bba19f03d1358f151ec69c44 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2453468Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent a8c5d295
...@@ -609,7 +609,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -609,7 +609,7 @@ class ContextVk : public ContextImpl, public vk::Context
vk::CommandBufferHelper &getStartedRenderPassCommands() vk::CommandBufferHelper &getStartedRenderPassCommands()
{ {
ASSERT(hasStartedRenderPass()); ASSERT(mRenderPassCommands->started());
return *mRenderPassCommands; return *mRenderPassCommands;
} }
......
...@@ -1710,6 +1710,24 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk, ...@@ -1710,6 +1710,24 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk,
contextVk->onImageRenderPassRead(src->getAspectFlags(), vk::ImageLayout::FragmentShaderReadOnly, contextVk->onImageRenderPassRead(src->getAspectFlags(), vk::ImageLayout::FragmentShaderReadOnly,
src); src);
vk::CommandBufferHelper *renderPassCommands = &contextVk->getStartedRenderPassCommands();
if (blitDepth)
{
// Explicitly mark a depth write because we are modifying the depth buffer.
renderPassCommands->onDepthAccess(vk::ResourceAccess::Write);
}
if (blitStencil)
{
// Explicitly mark a stencil write because we are modifying the stencil buffer.
renderPassCommands->onStencilAccess(vk::ResourceAccess::Write);
}
if (blitDepth || blitStencil)
{
// Because we may have changed the depth stencil access mode, update read only depth mode
// now.
framebuffer->updateRenderPassReadOnlyDepthMode(contextVk, renderPassCommands);
}
VkDescriptorImageInfo imageInfos[2] = {}; VkDescriptorImageInfo imageInfos[2] = {};
if (blitColor) if (blitColor)
......
...@@ -1066,9 +1066,13 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1066,9 +1066,13 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex]; PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
// Depth/Stencil buffer optimizations: // Depth/Stencil buffer optimizations:
//
// First, if the attachment is invalidated, skip the store op. // If the attachment is invalidated, skip the store op. If we are not loading or clearing the
if (isInvalidated(mDepthCmdSizeInvalidated, mDepthCmdSizeDisabled)) // attachment and the attachment has not been used, auto-invalidate it.
const bool depthNotLoaded = dsOps.loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE &&
!mRenderPassDesc.hasDepthUnresolveAttachment();
if (isInvalidated(mDepthCmdSizeInvalidated, mDepthCmdSizeDisabled) ||
(depthNotLoaded && mDepthAccess != ResourceAccess::Write))
{ {
dsOps.storeOp = RenderPassStoreOp::DontCare; dsOps.storeOp = RenderPassStoreOp::DontCare;
dsOps.isInvalidated = true; dsOps.isInvalidated = true;
...@@ -1079,7 +1083,10 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1079,7 +1083,10 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
// are now defined so a future render pass would use loadOp=LOAD. // are now defined so a future render pass would use loadOp=LOAD.
restoreDepthContent(); restoreDepthContent();
} }
if (isInvalidated(mStencilCmdSizeInvalidated, mStencilCmdSizeDisabled)) const bool stencilNotLoaded = dsOps.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE &&
!mRenderPassDesc.hasStencilUnresolveAttachment();
if (isInvalidated(mStencilCmdSizeInvalidated, mStencilCmdSizeDisabled) ||
(stencilNotLoaded && mStencilAccess != ResourceAccess::Write))
{ {
dsOps.stencilStoreOp = RenderPassStoreOp::DontCare; dsOps.stencilStoreOp = RenderPassStoreOp::DontCare;
dsOps.isStencilInvalidated = true; dsOps.isStencilInvalidated = true;
...@@ -1106,8 +1113,8 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1106,8 +1113,8 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
} }
} }
// Second, if we are loading or clearing the attachment, but the attachment has not been used, // If we are loading or clearing the attachment, but the attachment has not been used, and the
// and the data has also not been stored back into attachment, then just skip the load/clear op. // data has also not been stored back into attachment, then just skip the load/clear op.
if (mDepthAccess == ResourceAccess::Unused && dsOps.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE) if (mDepthAccess == ResourceAccess::Unused && dsOps.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)
{ {
dsOps.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; dsOps.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
...@@ -1120,7 +1127,8 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1120,7 +1127,8 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
} }
// Ensure we don't write to a read-only RenderPass. (ReadOnly -> !Write) // Ensure we don't write to a read-only RenderPass. (ReadOnly -> !Write)
ASSERT(!mReadOnlyDepthStencilMode || mDepthAccess != ResourceAccess::Write); ASSERT(!mReadOnlyDepthStencilMode ||
(mDepthAccess != ResourceAccess::Write && mStencilAccess != ResourceAccess::Write));
} }
void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount, void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
......
...@@ -780,8 +780,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisable) ...@@ -780,8 +780,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisable)
const rx::vk::PerfCounters &counters = hackANGLE(); const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected; rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+1) // Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 1, &expected); setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 0, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer; GLFramebuffer framebuffer;
...@@ -883,8 +883,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnableDraw) ...@@ -883,8 +883,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnableDraw)
const rx::vk::PerfCounters &counters = hackANGLE(); const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected; rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+1) // Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 1, &expected); setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 0, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer; GLFramebuffer framebuffer;
...@@ -938,8 +938,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnable) ...@@ -938,8 +938,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnable)
const rx::vk::PerfCounters &counters = hackANGLE(); const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected; rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+1) // Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 1, &expected); setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 0, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer; GLFramebuffer framebuffer;
...@@ -1114,8 +1114,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableEnableDraw) ...@@ -1114,8 +1114,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableEnableDraw)
const rx::vk::PerfCounters &counters = hackANGLE(); const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected; rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+1) // Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 1, &expected); setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 0, 0, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer; GLFramebuffer framebuffer;
...@@ -1193,8 +1193,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateAndClear) ...@@ -1193,8 +1193,8 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateAndClear)
swapBuffers(); swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected); compareDepthStencilCountersForInvalidateTest(counters, expected);
// Expect rpCount+1, depth(Clears+0, Loads+1, Stores+1), stencil(Clears+0, Load+0, Stores+1) // Expect rpCount+1, depth(Clears+0, Loads+1, Stores+1), stencil(Clears+0, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 0, 0, 1, 1, 0, 0, 1, &expected); setExpectedCountersForInvalidateTest(counters, 0, 0, 1, 1, 0, 0, 0, &expected);
// Bind FBO again and try to use the depth buffer without clear. This should result in // Bind FBO again and try to use the depth buffer without clear. This should result in
// loadOp=LOAD and StoreOP=STORE // loadOp=LOAD and StoreOP=STORE
...@@ -2224,6 +2224,81 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureInvalidate) ...@@ -2224,6 +2224,81 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureInvalidate)
compareCountersForUnresolveResolveTest(counters, expected); compareCountersForUnresolveResolveTest(counters, expected);
} }
// Tests counters when uninitialized multisampled-render-to-texture depth/stencil renderbuffers are
// unused but not invalidated.
TEST_P(VulkanPerformanceCounterTest, RenderToTextureUninitializedAndUnusedDepthStencil)
{
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, no depth/stencil clear, load or store.
setExpectedCountersForInvalidateTest(counters, 1, 0, 0, 0, 0, 0, 0, &expected);
// Additionally, expect only color resolve.
setExpectedCountersForUnresolveResolveTest(counters, 0, 0, 0, 1, 0, 0, &expected);
GLFramebuffer FBO;
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
constexpr GLsizei kSize = 6;
// Create multisampled framebuffer to draw into, with both color and depth attachments.
GLTexture colorMS;
glBindTexture(GL_TEXTURE_2D, colorMS);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLRenderbuffer depthStencilMS;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
colorMS, 0, 4);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencilMS);
ASSERT_GL_NO_ERROR();
// Set up texture for copy operation that breaks the render pass
GLTexture copyTex;
glBindTexture(GL_TEXTURE_2D, copyTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// Set viewport and clear color only
glViewport(0, 0, kSize, kSize);
glClearColor(0, 0, 0, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Disable depth/stencil testing.
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Set up program
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);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.75f);
ASSERT_GL_NO_ERROR();
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Verify the counters
compareLoadCountersForInvalidateTest(counters, expected);
compareCountersForUnresolveResolveTest(counters, expected);
}
// Ensures we use read-only depth layout when there is no write // Ensures we use read-only depth layout when there is no write
TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout) TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
{ {
......
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