Skip to content

Commit 4a41204

Browse files
ianelliottusCommit Bot
authored andcommitted
Vulkan: Improve invalidate for depth/stencil
Improve state tracking when the depth and/or stencil attachments are invalidated. Since no draw-time tracking is done, we use the number of command-buffer commands to determine when an attachment is drawn to. That allows all cases to be handled for store ops. Still need to handle mContentDefined at endRP time (we have the data, just not the plumbing). Test: angle_white_box_tests --gtest_filter=VulkanPerformanceCounterTest.*Invalidate*/* Test: angle_deqp_gles3_tests --gtest_filter=dEQP.GLES3/functional_fbo_invalidate_* --use-angle=vulkan Bug: b/167276207 Change-Id: Iae10857dbb4d43b934c51ad7e400b71ae0db4f55 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2378670 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Ian Elliott <ianelliott@google.com>
1 parent 36b884e commit 4a41204

File tree

6 files changed

+793
-141
lines changed

6 files changed

+793
-141
lines changed

src/libANGLE/renderer/vulkan/ContextVk.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,8 +2490,9 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
24902490
if (depthStencilRenderTarget)
24912491
{
24922492
// Change depthstencil attachment storeOp to DONT_CARE
2493-
mRenderPassCommands->invalidateRenderPassStencilAttachment();
2494-
mRenderPassCommands->invalidateRenderPassDepthAttachment();
2493+
const gl::DepthStencilState &dsState = mState.getDepthStencilState();
2494+
mRenderPassCommands->invalidateRenderPassStencilAttachment(dsState);
2495+
mRenderPassCommands->invalidateRenderPassDepthAttachment(dsState);
24952496
// Mark content as invalid so that we will not load them in next renderpass
24962497
depthStencilRenderTarget->invalidateEntireContent();
24972498
}
@@ -2908,11 +2909,9 @@ angle::Result ContextVk::syncState(const gl::Context *context,
29082909
if (mRenderPassCommands->started())
29092910
{
29102911
vk::ResourceAccess access = GetStencilAccess(mState.getDepthStencilState());
2911-
mRenderPassCommands->onStencilAccess(access);
2912-
// Did this depth-state change undo a previous invalidation of the depth-stencil
2913-
// attachment?
2914-
if (mRenderPassCommands->shouldRestoreDepthStencilAttachment())
2912+
if (mRenderPassCommands->onStencilAccess(access))
29152913
{
2914+
// The attachment is no longer invalidated, so set mContentDefined to true
29162915
mDrawFramebuffer->restoreDepthStencilDefinedContents();
29172916
}
29182917
}
@@ -4914,11 +4913,9 @@ angle::Result ContextVk::updateRenderPassDepthAccess()
49144913
}
49154914
else
49164915
{
4917-
mRenderPassCommands->onDepthAccess(access);
4918-
// Did this depth-state change undo a previous invalidation of the depth-stencil
4919-
// attachment?
4920-
if (mRenderPassCommands->shouldRestoreDepthStencilAttachment())
4916+
if (mRenderPassCommands->onDepthAccess(access))
49214917
{
4918+
// The attachment is no longer invalidated, so set mContentDefined to true
49224919
mDrawFramebuffer->restoreDepthStencilDefinedContents();
49234920
}
49244921
}

src/libANGLE/renderer/vulkan/FramebufferVk.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,14 +1483,17 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
14831483

14841484
if (depthStencilRenderTarget)
14851485
{
1486+
const gl::DepthStencilState &dsState = contextVk->getState().getDepthStencilState();
14861487
if (invalidateDepthBuffer)
14871488
{
1488-
contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment();
1489+
contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment(
1490+
dsState);
14891491
}
14901492

14911493
if (invalidateStencilBuffer)
14921494
{
1493-
contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment();
1495+
contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment(
1496+
dsState);
14941497
}
14951498
}
14961499
if (invalidateColorBuffers.any())

src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,14 @@ class SecondaryCommandBuffer final : angle::NonCopyable
693693

694694
static bool CanKnowIfEmpty() { return true; }
695695
bool empty() const { return mCommands.size() == 0 || mCommands[0]->id == CommandID::Invalid; }
696+
// The following is used to give the size of the command buffer in bytes
697+
uint32_t getCommandBufferSize() const
698+
{
699+
ASSERT(mCommands.size() > 0 || mCurrentBytesRemaining == 0);
700+
uint32_t rtn =
701+
static_cast<uint32_t>((mCommands.size() * kBlockSize) - mCurrentBytesRemaining);
702+
return rtn;
703+
}
696704

697705
private:
698706
void commonDebugUtilsLabel(CommandID cmd, const VkDebugUtilsLabelEXT &label);

src/libANGLE/renderer/vulkan/vk_helpers.cpp

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -561,10 +561,10 @@ CommandBufferHelper::CommandBufferHelper()
561561
mIsRenderPassCommandBuffer(false),
562562
mDepthStartAccess(ResourceAccess::Unused),
563563
mStencilStartAccess(ResourceAccess::Unused),
564-
mDepthEnabled(false),
565-
mDepthInvalidatedState(NeverInvalidated),
566-
mStencilEnabled(false),
567-
mStencilInvalidatedState(NeverInvalidated),
564+
mDepthCmdSizeInvalidated(kInfiniteCmdSize),
565+
mDepthCmdSizeDisabled(kInfiniteCmdSize),
566+
mStencilCmdSizeInvalidated(kInfiniteCmdSize),
567+
mStencilCmdSizeDisabled(kInfiniteCmdSize),
568568
mDepthStencilAttachmentIndex(kInvalidAttachmentIndex)
569569
{}
570570

@@ -704,70 +704,67 @@ void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList,
704704
}
705705
}
706706

707-
void CommandBufferHelper::onDepthAccess(ResourceAccess access)
707+
bool CommandBufferHelper::onDepthAccess(ResourceAccess access)
708708
{
709-
// TODO(ianelliott): Rework the handling of invalidated attachments in a follow-up CL, using
710-
// the count of commands in the SecondaryCommandBuffer.
711-
// See https://issuetracker.google.com/issues/163854287
712-
InvalidatedState invalidatedState;
713-
714-
if (access == vk::ResourceAccess::Write)
715-
{
716-
// This handles various scenarios that an app/test can do with valid GLES usage. For
717-
// example, consider an app that invalidates, doesn't disable the functionality, and draws
718-
// again. In that case, the drawing that occurs after the invalidate means that there is
719-
// once again valid content in the attachment (i.e. that should not be discarded). Since
720-
// we don't track draws, we must be conservative and assume that a draw may have occured
721-
// since invalidation unless the functionality has also been disabled and the re-enabled.
722-
invalidatedState = (!mDepthEnabled) ? NoLongerInvalidated : Invalidated;
723-
// Keep track of whether depth functionality is enabled
724-
mDepthEnabled = true;
725-
}
726-
else
727-
{
728-
invalidatedState = Invalidated;
729-
// Keep track of whether depth functionality is enabled
730-
mDepthEnabled = false;
731-
}
732-
733709
// Update the access for optimizing this render pass's loadOp
734710
UpdateAccess(&mDepthStartAccess, access);
735711
ASSERT((mRenderPassDesc.getDepthStencilAccess() != ResourceAccess::ReadOnly) ||
736712
mDepthStartAccess != ResourceAccess::Write);
713+
737714
// Update the invalidate state for optimizing this render pass's storeOp
738-
UpdateInvalidatedState(&mDepthInvalidatedState, invalidatedState);
715+
return onDepthStencilAccess(access, &mDepthCmdSizeInvalidated, &mDepthCmdSizeDisabled);
739716
}
740717

741-
void CommandBufferHelper::onStencilAccess(ResourceAccess access)
718+
bool CommandBufferHelper::onStencilAccess(ResourceAccess access)
742719
{
743-
// TODO(ianelliott): Rework the handling of invalidated attachments in a follow-up CL, using
744-
// the count of commands in the SecondaryCommandBuffer.
745-
// See https://issuetracker.google.com/issues/163854287
746-
InvalidatedState invalidatedState;
720+
// Update the access for optimizing this render pass's loadOp
721+
UpdateAccess(&mStencilStartAccess, access);
747722

723+
// Update the invalidate state for optimizing this render pass's stencilStoreOp
724+
return onDepthStencilAccess(access, &mStencilCmdSizeInvalidated, &mStencilCmdSizeDisabled);
725+
}
726+
727+
bool CommandBufferHelper::onDepthStencilAccess(ResourceAccess access,
728+
uint32_t *cmdCountInvalidated,
729+
uint32_t *cmdCountDisabled)
730+
{
731+
if (*cmdCountInvalidated == kInfiniteCmdSize)
732+
{
733+
// If never invalidated or no longer invalidated, return early.
734+
return false;
735+
}
748736
if (access == vk::ResourceAccess::Write)
749737
{
750-
// This handles various scenarios that an app/test can do with valid GLES usage. For
751-
// example, consider an app that invalidates, doesn't disable the functionality, and draws
752-
// again. In that case, the drawing that occurs after the invalidate means that there is
753-
// once again valid content in the attachment (i.e. that should not be discarded). Since
754-
// we don't track draws, we must be conservative and assume that a draw may have occured
755-
// since invalidation unless the functionality has also been disabled and the re-enabled.
756-
invalidatedState = (!mStencilEnabled) ? NoLongerInvalidated : Invalidated;
757-
// Keep track of whether stencil functionality is enabled
758-
mStencilEnabled = true;
738+
// Drawing to this attachment is being enabled. Assume that drawing will immediately occur
739+
// after this attachment is enabled, and that means that the attachment will no longer be
740+
// invalidated.
741+
*cmdCountInvalidated = kInfiniteCmdSize;
742+
*cmdCountDisabled = kInfiniteCmdSize;
743+
// Return true to indicate that the store op should remain STORE and that mContentDefined
744+
// should be set to true;
745+
return true;
759746
}
760747
else
761748
{
762-
invalidatedState = Invalidated;
763-
// Keep track of whether stencil functionality is enabled
764-
mStencilEnabled = false;
749+
// Drawing to this attachment is being disabled.
750+
if (isNoLongerInvalidated(*cmdCountInvalidated, *cmdCountDisabled))
751+
{
752+
// The attachment was previously drawn while enabled, and so is no longer invalidated.
753+
*cmdCountInvalidated = kInfiniteCmdSize;
754+
*cmdCountDisabled = kInfiniteCmdSize;
755+
// Return true to indicate that the store op should remain STORE and that
756+
// mContentDefined should be set to true;
757+
return true;
758+
}
759+
else
760+
{
761+
// Get the latest CmdSize at the start of being disabled. At the end of the render
762+
// pass, cmdCountDisabled is <= the actual command buffer size, and so it's compared
763+
// with cmdCountInvalidated. If the same, the attachment is still invalidated.
764+
*cmdCountDisabled = mCommandBuffer.getCommandBufferSize();
765+
return false;
766+
}
765767
}
766-
767-
// Update the access for optimizing this render pass's loadOp
768-
UpdateAccess(&mStencilStartAccess, access);
769-
// Update the invalidate state for optimizing this render pass's stencilStoreOp
770-
UpdateInvalidatedState(&mStencilInvalidatedState, invalidatedState);
771768
}
772769

773770
void CommandBufferHelper::executeBarriers(ContextVk *contextVk, PrimaryCommandBuffer *primary)
@@ -863,19 +860,20 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
863860

864861
PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
865862

866-
// Address invalidated depth/stencil attachments
867-
if (mDepthInvalidatedState == Invalidated)
863+
// Depth/Stencil buffer optimizations:
864+
//
865+
// First, if the attachment is invalidated, skip the store op.
866+
if (isInvalidated(mDepthCmdSizeInvalidated, mDepthCmdSizeDisabled))
868867
{
869868
dsOps.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
870869
}
871-
if (mStencilInvalidatedState == Invalidated)
870+
if (isInvalidated(mStencilCmdSizeInvalidated, mStencilCmdSizeDisabled))
872871
{
873872
dsOps.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
874873
}
875874

876-
// Depth/Stencil buffer optimization: if we are loading or clearing the buffer, but the
877-
// buffer has not been used, and the data has also not been stored back into buffer, then
878-
// just skip the load/clear op.
875+
// Second, if we are loading or clearing the attachment, but the attachment has not been used,
876+
// and the data has also not been stored back into attachment, then just skip the load/clear op.
879877
if (mDepthStartAccess == ResourceAccess::Unused &&
880878
dsOps.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)
881879
{
@@ -1099,10 +1097,10 @@ void CommandBufferHelper::reset()
10991097
mRebindTransformFeedbackBuffers = false;
11001098
mDepthStartAccess = ResourceAccess::Unused;
11011099
mStencilStartAccess = ResourceAccess::Unused;
1102-
mDepthInvalidatedState = NeverInvalidated;
1103-
mDepthEnabled = false;
1104-
mStencilInvalidatedState = NeverInvalidated;
1105-
mStencilEnabled = false;
1100+
mDepthCmdSizeInvalidated = kInfiniteCmdSize;
1101+
mDepthCmdSizeDisabled = kInfiniteCmdSize;
1102+
mStencilCmdSizeInvalidated = kInfiniteCmdSize;
1103+
mStencilCmdSizeDisabled = kInfiniteCmdSize;
11061104
mDepthStencilAttachmentIndex = kInvalidAttachmentIndex;
11071105
mRenderPassUsedImages.clear();
11081106
}

src/libANGLE/renderer/vulkan/vk_helpers.h

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -875,26 +875,10 @@ enum class AliasingMode
875875
Disallowed,
876876
};
877877

878-
enum InvalidatedState
879-
{
880-
// The attachment has been invalidated and is currently still invalid.
881-
Invalidated,
882-
// The attachment was previously invalidated, but has since been used while enabled for
883-
// drawing, meaning that it has valid contents (and therefore this render pass should STORE it,
884-
// and a future render pass should LOAD it).
885-
NoLongerInvalidated,
886-
// The attachment has never been invalidated. Since this is the highest value, it should never
887-
// be given to UpdateInvalidatedState(). Instead, it should only be set starting a render pass.
888-
NeverInvalidated,
889-
};
878+
// The following are used to help track the state of an invalidated attachment.
890879

891-
inline void UpdateInvalidatedState(InvalidatedState *oldState, InvalidatedState newState)
892-
{
893-
if (newState > *oldState)
894-
{
895-
*oldState = newState;
896-
}
897-
}
880+
// This value indicates an "infinite" CmdSize that is not valid for comparing
881+
constexpr uint32_t kInfiniteCmdSize = 0xffffffff;
898882

899883
// CommandBufferHelper (CBH) class wraps ANGLE's custom command buffer
900884
// class, SecondaryCommandBuffer. This provides a way to temporarily
@@ -983,29 +967,42 @@ class CommandBufferHelper : angle::NonCopyable
983967
SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
984968
}
985969

986-
void invalidateRenderPassDepthAttachment()
970+
void invalidateRenderPassDepthAttachment(const gl::DepthStencilState &dsState)
987971
{
988972
ASSERT(mIsRenderPassCommandBuffer);
989-
mDepthInvalidatedState = Invalidated;
973+
// Keep track of the size of commands in the command buffer. If the size grows in the
974+
// future, that implies that drawing occured since invalidated.
975+
mDepthCmdSizeInvalidated = mCommandBuffer.getCommandBufferSize();
976+
// Also track the size if the attachment is currently disabled.
977+
mDepthCmdSizeDisabled =
978+
(dsState.depthTest && dsState.depthMask) ? kInfiniteCmdSize : mDepthCmdSizeInvalidated;
990979
}
991980

992-
void invalidateRenderPassStencilAttachment()
981+
void invalidateRenderPassStencilAttachment(const gl::DepthStencilState &dsState)
993982
{
994983
ASSERT(mIsRenderPassCommandBuffer);
995-
mStencilInvalidatedState = Invalidated;
984+
// Keep track of the size of commands in the command buffer. If the size grows in the
985+
// future, that implies that drawing occured since invalidated.
986+
mStencilCmdSizeInvalidated = mCommandBuffer.getCommandBufferSize();
987+
// Also track the size if the attachment is currently disabled.
988+
mStencilCmdSizeDisabled =
989+
dsState.stencilTest ? kInfiniteCmdSize : mStencilCmdSizeInvalidated;
996990
}
997991

998-
bool shouldRestoreDepthStencilAttachment()
992+
bool isNoLongerInvalidated(uint32_t cmdCountInvalidated, uint32_t cmdCountDisabled)
999993
{
1000994
ASSERT(mIsRenderPassCommandBuffer);
1001-
// Return true when both depth and stencil attachments were previously-invalidated, and at
1002-
// least one of those attachments are no longer invalidated. When invalidated,
1003-
// RenderTargetVk::mContentDefined is set to false, which will result in the loadOp and
1004-
// stencilLoadOp of a future render pass being set to DONT_CARE. ContextVk::syncState()
1005-
// will call this method to determine if RenderTargetVk::mContentDefined should be set back
1006-
// to true (i.e. use LOAD).
1007-
return mDepthInvalidatedState == NoLongerInvalidated ||
1008-
mStencilInvalidatedState == NoLongerInvalidated;
995+
return (cmdCountInvalidated != kInfiniteCmdSize &&
996+
std::min(cmdCountDisabled, mCommandBuffer.getCommandBufferSize()) !=
997+
cmdCountInvalidated);
998+
}
999+
1000+
bool isInvalidated(uint32_t cmdCountInvalidated, uint32_t cmdCountDisabled)
1001+
{
1002+
ASSERT(mIsRenderPassCommandBuffer);
1003+
return cmdCountInvalidated != kInfiniteCmdSize &&
1004+
std::min(cmdCountDisabled, mCommandBuffer.getCommandBufferSize()) ==
1005+
cmdCountInvalidated;
10091006
}
10101007

10111008
void updateRenderPassAttachmentFinalLayout(size_t attachmentIndex, ImageLayout finalLayout)
@@ -1049,8 +1046,8 @@ class CommandBufferHelper : angle::NonCopyable
10491046
// Dumping the command stream is disabled by default.
10501047
static constexpr bool kEnableCommandStreamDiagnostics = false;
10511048

1052-
void onDepthAccess(ResourceAccess access);
1053-
void onStencilAccess(ResourceAccess access);
1049+
bool onDepthAccess(ResourceAccess access);
1050+
bool onStencilAccess(ResourceAccess access);
10541051

10551052
void updateRenderPassForResolve(vk::Framebuffer *newFramebuffer,
10561053
const vk::RenderPassDesc &renderPassDesc);
@@ -1064,6 +1061,11 @@ class CommandBufferHelper : angle::NonCopyable
10641061

10651062
private:
10661063
void addCommandDiagnostics(ContextVk *contextVk);
1064+
1065+
bool onDepthStencilAccess(ResourceAccess access,
1066+
uint32_t *cmdCountInvalidated,
1067+
uint32_t *cmdCountDisabled);
1068+
10671069
// Allocator used by this class. Using a pool allocator per CBH to avoid threading issues
10681070
// that occur w/ shared allocator between multiple CBHs.
10691071
angle::PoolAllocator mAllocator;
@@ -1095,10 +1097,10 @@ class CommandBufferHelper : angle::NonCopyable
10951097
ResourceAccess mStencilStartAccess;
10961098

10971099
// State tracking for whether to optimize the storeOp to DONT_CARE
1098-
bool mDepthEnabled;
1099-
InvalidatedState mDepthInvalidatedState;
1100-
bool mStencilEnabled;
1101-
InvalidatedState mStencilInvalidatedState;
1100+
uint32_t mDepthCmdSizeInvalidated;
1101+
uint32_t mDepthCmdSizeDisabled;
1102+
uint32_t mStencilCmdSizeInvalidated;
1103+
uint32_t mStencilCmdSizeDisabled;
11021104

11031105
// Keep track of the depth/stencil attachment index
11041106
uint32_t mDepthStencilAttachmentIndex;

0 commit comments

Comments
 (0)