Commit 46107d3e by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Delay defining D/S content to endRenderPass

Take the following situation: 1. Start RP with D/S undefined: loadOp = DONT_CARE, storeOp = STORE * At this point, onDepthStencilWrite calls image->onWrite, setting depth/stencil contents defined. 2. At endRP, observe depth/stencil is not used: storeOp = DONT_CARE 3. Start another RP with D/S: loadOp = LOAD, storeOp = STORE Because the call to image->onWrite was done at startRP, the contents of the depth/stencil image is marked as defined, and the next render pass is loading these data. This change moves image->onWrite to endRenderPass, and only calls it if storeOp = STORE, taking advantage of all the opportunistic optimizations that try to set storeOp to another value. Bug: angleproject:4836 Change-Id: I9858e5caa6b1f67f841a5c6356e66927356ef469 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2548319Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent e0619360
...@@ -2464,11 +2464,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2464,11 +2464,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
// This must be called after hasDefined*Content() since it will set content to valid. We are // This must be called after hasDefined*Content() since it will set content to valid. If
// tracking content valid very loosely here that as long as it is attached, it assumes will // the attachment ends up not used in the render pass, contents will be marked undefined at
// have valid content. The only time it has undefined content is between swap and // endRenderPass. The actual layout determination is also deferred until the same time.
// startNewRenderPass
// The actual layout determination will be deferred until endRenderPass time
depthStencilRenderTarget->onDepthStencilDraw(contextVk); depthStencilRenderTarget->onDepthStencilDraw(contextVk);
} }
......
...@@ -888,7 +888,6 @@ void CommandBufferHelper::depthStencilImagesDraw(ResourceUseList *resourceUseLis ...@@ -888,7 +888,6 @@ void CommandBufferHelper::depthStencilImagesDraw(ResourceUseList *resourceUseLis
// defer the image layout changes until endRenderPass time or when images going away so that we // defer the image layout changes until endRenderPass time or when images going away so that we
// only insert layout change barrier once. // only insert layout change barrier once.
image->retain(resourceUseList); image->retain(resourceUseList);
image->onWrite(level, 1, layer, 1, kDepthStencilAspects);
mRenderPassUsedImages.insert(image->getImageSerial().getValue()); mRenderPassUsedImages.insert(image->getImageSerial().getValue());
mDepthStencilImage = image; mDepthStencilImage = image;
mDepthStencilLevelIndex = level; mDepthStencilLevelIndex = level;
...@@ -900,7 +899,6 @@ void CommandBufferHelper::depthStencilImagesDraw(ResourceUseList *resourceUseLis ...@@ -900,7 +899,6 @@ void CommandBufferHelper::depthStencilImagesDraw(ResourceUseList *resourceUseLis
// depth/stencil image as currently it can only ever come from // depth/stencil image as currently it can only ever come from
// multisampled-render-to-texture renderbuffers. // multisampled-render-to-texture renderbuffers.
resolveImage->retain(resourceUseList); resolveImage->retain(resourceUseList);
resolveImage->onWrite(level, 1, layer, 1, kDepthStencilAspects);
mRenderPassUsedImages.insert(resolveImage->getImageSerial().getValue()); mRenderPassUsedImages.insert(resolveImage->getImageSerial().getValue());
mDepthStencilResolveImage = resolveImage; mDepthStencilResolveImage = resolveImage;
} }
...@@ -1068,6 +1066,28 @@ void CommandBufferHelper::finalizeDepthStencilImageLayout() ...@@ -1068,6 +1066,28 @@ void CommandBufferHelper::finalizeDepthStencilImageLayout()
mPipelineBarrierMask.set(barrierIndex); mPipelineBarrierMask.set(barrierIndex);
} }
} }
if (!mReadOnlyDepthStencilMode)
{
ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
// If the image is being written to, mark its contents defined.
VkImageAspectFlags definedAspects = 0;
if (dsOps.storeOp == VK_ATTACHMENT_STORE_OP_STORE)
{
definedAspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (dsOps.stencilStoreOp == VK_ATTACHMENT_STORE_OP_STORE)
{
definedAspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (definedAspects != 0)
{
mDepthStencilImage->onWrite(mDepthStencilLevelIndex, 1, mDepthStencilLayerIndex, 1,
definedAspects);
}
}
} }
void CommandBufferHelper::finalizeDepthStencilResolveImageLayout() void CommandBufferHelper::finalizeDepthStencilResolveImageLayout()
...@@ -1089,6 +1109,28 @@ void CommandBufferHelper::finalizeDepthStencilResolveImageLayout() ...@@ -1089,6 +1109,28 @@ void CommandBufferHelper::finalizeDepthStencilResolveImageLayout()
{ {
mPipelineBarrierMask.set(barrierIndex); mPipelineBarrierMask.set(barrierIndex);
} }
if (!mReadOnlyDepthStencilMode)
{
ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
// If the image is being written to, mark its contents defined.
VkImageAspectFlags definedAspects = 0;
if (!dsOps.isInvalidated)
{
definedAspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (!dsOps.isStencilInvalidated)
{
definedAspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (definedAspects != 0)
{
mDepthStencilResolveImage->onWrite(mDepthStencilLevelIndex, 1, mDepthStencilLayerIndex,
1, definedAspects);
}
}
} }
void CommandBufferHelper::onImageHelperRelease(const vk::ImageHelper *image) void CommandBufferHelper::onImageHelperRelease(const vk::ImageHelper *image)
...@@ -1138,16 +1180,6 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1138,16 +1180,6 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
return; return;
} }
// Do depth stencil layout change.
if (mDepthStencilImage)
{
finalizeDepthStencilImageLayout();
}
if (mDepthStencilResolveImage)
{
finalizeDepthStencilResolveImageLayout();
}
PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex]; PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
// Depth/Stencil buffer optimizations: // Depth/Stencil buffer optimizations:
...@@ -1213,6 +1245,16 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1213,6 +1245,16 @@ 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 || ASSERT(!mReadOnlyDepthStencilMode ||
(mDepthAccess != ResourceAccess::Write && mStencilAccess != ResourceAccess::Write)); (mDepthAccess != ResourceAccess::Write && mStencilAccess != ResourceAccess::Write));
// Do depth stencil layout change.
if (mDepthStencilImage)
{
finalizeDepthStencilImageLayout();
}
if (mDepthStencilResolveImage)
{
finalizeDepthStencilResolveImageLayout();
}
} }
void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount, void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
......
...@@ -2466,6 +2466,65 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout) ...@@ -2466,6 +2466,65 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
EXPECT_EQ(expectedReadOnlyDepthStencilCount, actualReadOnlyDepthStencilCount); EXPECT_EQ(expectedReadOnlyDepthStencilCount, actualReadOnlyDepthStencilCount);
} }
// Ensures depth/stencil is not loaded after storeOp=DONT_CARE due to optimization (as opposed to
// invalidate)
TEST_P(VulkanPerformanceCounterTest, RenderPassAfterRenderPassWithoutDepthStencilWrite)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+0, Loads+0, Stores+0), stencil(Clears+0, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 0, 0, 0, 0, 0, 0, &expected);
constexpr GLsizei kSize = 64;
// Create FBO with color, depth and stencil. Leave depth/stencil uninitialized.
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();
// Draw to the FBO, without enabling depth/stencil.
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();
glViewport(0, 0, kSize, kSize);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f);
// Break the render pass and ensure no depth/stencil load/store was done.
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Expect rpCount+1, depth(Clears+0, Loads+0, Stores+0), stencil(Clears+0, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 0, 0, 0, 0, 0, 0, &expected);
// Draw again with similar conditions, and again make sure no load/store is done.
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f);
// Break the render pass and ensure no depth/stencil load/store was done.
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Ensures repeated clears of various kind (all attachments, some attachments, scissored, masked // Ensures repeated clears of various kind (all attachments, some attachments, scissored, masked
// etc) don't break the render pass. // etc) don't break the render pass.
TEST_P(VulkanPerformanceCounterTest, ClearAfterClearDoesNotBreakRenderPass) TEST_P(VulkanPerformanceCounterTest, ClearAfterClearDoesNotBreakRenderPass)
......
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