Commit 4a41204d by Ian Elliott Committed by Commit Bot

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/+/2378670Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Commit-Queue: Ian Elliott <ianelliott@google.com>
parent 36b884e6
...@@ -2490,8 +2490,9 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle) ...@@ -2490,8 +2490,9 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
// Change depthstencil attachment storeOp to DONT_CARE // Change depthstencil attachment storeOp to DONT_CARE
mRenderPassCommands->invalidateRenderPassStencilAttachment(); const gl::DepthStencilState &dsState = mState.getDepthStencilState();
mRenderPassCommands->invalidateRenderPassDepthAttachment(); mRenderPassCommands->invalidateRenderPassStencilAttachment(dsState);
mRenderPassCommands->invalidateRenderPassDepthAttachment(dsState);
// Mark content as invalid so that we will not load them in next renderpass // Mark content as invalid so that we will not load them in next renderpass
depthStencilRenderTarget->invalidateEntireContent(); depthStencilRenderTarget->invalidateEntireContent();
} }
...@@ -2908,11 +2909,9 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -2908,11 +2909,9 @@ angle::Result ContextVk::syncState(const gl::Context *context,
if (mRenderPassCommands->started()) if (mRenderPassCommands->started())
{ {
vk::ResourceAccess access = GetStencilAccess(mState.getDepthStencilState()); vk::ResourceAccess access = GetStencilAccess(mState.getDepthStencilState());
mRenderPassCommands->onStencilAccess(access); if (mRenderPassCommands->onStencilAccess(access))
// Did this depth-state change undo a previous invalidation of the depth-stencil
// attachment?
if (mRenderPassCommands->shouldRestoreDepthStencilAttachment())
{ {
// The attachment is no longer invalidated, so set mContentDefined to true
mDrawFramebuffer->restoreDepthStencilDefinedContents(); mDrawFramebuffer->restoreDepthStencilDefinedContents();
} }
} }
...@@ -4914,11 +4913,9 @@ angle::Result ContextVk::updateRenderPassDepthAccess() ...@@ -4914,11 +4913,9 @@ angle::Result ContextVk::updateRenderPassDepthAccess()
} }
else else
{ {
mRenderPassCommands->onDepthAccess(access); if (mRenderPassCommands->onDepthAccess(access))
// Did this depth-state change undo a previous invalidation of the depth-stencil
// attachment?
if (mRenderPassCommands->shouldRestoreDepthStencilAttachment())
{ {
// The attachment is no longer invalidated, so set mContentDefined to true
mDrawFramebuffer->restoreDepthStencilDefinedContents(); mDrawFramebuffer->restoreDepthStencilDefinedContents();
} }
} }
......
...@@ -1483,14 +1483,17 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk, ...@@ -1483,14 +1483,17 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
const gl::DepthStencilState &dsState = contextVk->getState().getDepthStencilState();
if (invalidateDepthBuffer) if (invalidateDepthBuffer)
{ {
contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment(); contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment(
dsState);
} }
if (invalidateStencilBuffer) if (invalidateStencilBuffer)
{ {
contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment(); contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment(
dsState);
} }
} }
if (invalidateColorBuffers.any()) if (invalidateColorBuffers.any())
......
...@@ -693,6 +693,14 @@ class SecondaryCommandBuffer final : angle::NonCopyable ...@@ -693,6 +693,14 @@ class SecondaryCommandBuffer final : angle::NonCopyable
static bool CanKnowIfEmpty() { return true; } static bool CanKnowIfEmpty() { return true; }
bool empty() const { return mCommands.size() == 0 || mCommands[0]->id == CommandID::Invalid; } bool empty() const { return mCommands.size() == 0 || mCommands[0]->id == CommandID::Invalid; }
// The following is used to give the size of the command buffer in bytes
uint32_t getCommandBufferSize() const
{
ASSERT(mCommands.size() > 0 || mCurrentBytesRemaining == 0);
uint32_t rtn =
static_cast<uint32_t>((mCommands.size() * kBlockSize) - mCurrentBytesRemaining);
return rtn;
}
private: private:
void commonDebugUtilsLabel(CommandID cmd, const VkDebugUtilsLabelEXT &label); void commonDebugUtilsLabel(CommandID cmd, const VkDebugUtilsLabelEXT &label);
......
...@@ -561,10 +561,10 @@ CommandBufferHelper::CommandBufferHelper() ...@@ -561,10 +561,10 @@ CommandBufferHelper::CommandBufferHelper()
mIsRenderPassCommandBuffer(false), mIsRenderPassCommandBuffer(false),
mDepthStartAccess(ResourceAccess::Unused), mDepthStartAccess(ResourceAccess::Unused),
mStencilStartAccess(ResourceAccess::Unused), mStencilStartAccess(ResourceAccess::Unused),
mDepthEnabled(false), mDepthCmdSizeInvalidated(kInfiniteCmdSize),
mDepthInvalidatedState(NeverInvalidated), mDepthCmdSizeDisabled(kInfiniteCmdSize),
mStencilEnabled(false), mStencilCmdSizeInvalidated(kInfiniteCmdSize),
mStencilInvalidatedState(NeverInvalidated), mStencilCmdSizeDisabled(kInfiniteCmdSize),
mDepthStencilAttachmentIndex(kInvalidAttachmentIndex) mDepthStencilAttachmentIndex(kInvalidAttachmentIndex)
{} {}
...@@ -704,70 +704,67 @@ void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList, ...@@ -704,70 +704,67 @@ void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList,
} }
} }
void CommandBufferHelper::onDepthAccess(ResourceAccess access) bool CommandBufferHelper::onDepthAccess(ResourceAccess access)
{ {
// TODO(ianelliott): Rework the handling of invalidated attachments in a follow-up CL, using
// the count of commands in the SecondaryCommandBuffer.
// See https://issuetracker.google.com/issues/163854287
InvalidatedState invalidatedState;
if (access == vk::ResourceAccess::Write)
{
// This handles various scenarios that an app/test can do with valid GLES usage. For
// example, consider an app that invalidates, doesn't disable the functionality, and draws
// again. In that case, the drawing that occurs after the invalidate means that there is
// once again valid content in the attachment (i.e. that should not be discarded). Since
// we don't track draws, we must be conservative and assume that a draw may have occured
// since invalidation unless the functionality has also been disabled and the re-enabled.
invalidatedState = (!mDepthEnabled) ? NoLongerInvalidated : Invalidated;
// Keep track of whether depth functionality is enabled
mDepthEnabled = true;
}
else
{
invalidatedState = Invalidated;
// Keep track of whether depth functionality is enabled
mDepthEnabled = false;
}
// Update the access for optimizing this render pass's loadOp // Update the access for optimizing this render pass's loadOp
UpdateAccess(&mDepthStartAccess, access); UpdateAccess(&mDepthStartAccess, access);
ASSERT((mRenderPassDesc.getDepthStencilAccess() != ResourceAccess::ReadOnly) || ASSERT((mRenderPassDesc.getDepthStencilAccess() != ResourceAccess::ReadOnly) ||
mDepthStartAccess != ResourceAccess::Write); mDepthStartAccess != ResourceAccess::Write);
// Update the invalidate state for optimizing this render pass's storeOp // Update the invalidate state for optimizing this render pass's storeOp
UpdateInvalidatedState(&mDepthInvalidatedState, invalidatedState); return onDepthStencilAccess(access, &mDepthCmdSizeInvalidated, &mDepthCmdSizeDisabled);
} }
void CommandBufferHelper::onStencilAccess(ResourceAccess access) bool CommandBufferHelper::onStencilAccess(ResourceAccess access)
{ {
// TODO(ianelliott): Rework the handling of invalidated attachments in a follow-up CL, using // Update the access for optimizing this render pass's loadOp
// the count of commands in the SecondaryCommandBuffer. UpdateAccess(&mStencilStartAccess, access);
// See https://issuetracker.google.com/issues/163854287
InvalidatedState invalidatedState;
// Update the invalidate state for optimizing this render pass's stencilStoreOp
return onDepthStencilAccess(access, &mStencilCmdSizeInvalidated, &mStencilCmdSizeDisabled);
}
bool CommandBufferHelper::onDepthStencilAccess(ResourceAccess access,
uint32_t *cmdCountInvalidated,
uint32_t *cmdCountDisabled)
{
if (*cmdCountInvalidated == kInfiniteCmdSize)
{
// If never invalidated or no longer invalidated, return early.
return false;
}
if (access == vk::ResourceAccess::Write) if (access == vk::ResourceAccess::Write)
{ {
// This handles various scenarios that an app/test can do with valid GLES usage. For // Drawing to this attachment is being enabled. Assume that drawing will immediately occur
// example, consider an app that invalidates, doesn't disable the functionality, and draws // after this attachment is enabled, and that means that the attachment will no longer be
// again. In that case, the drawing that occurs after the invalidate means that there is // invalidated.
// once again valid content in the attachment (i.e. that should not be discarded). Since *cmdCountInvalidated = kInfiniteCmdSize;
// we don't track draws, we must be conservative and assume that a draw may have occured *cmdCountDisabled = kInfiniteCmdSize;
// since invalidation unless the functionality has also been disabled and the re-enabled. // Return true to indicate that the store op should remain STORE and that mContentDefined
invalidatedState = (!mStencilEnabled) ? NoLongerInvalidated : Invalidated; // should be set to true;
// Keep track of whether stencil functionality is enabled return true;
mStencilEnabled = true;
} }
else else
{ {
invalidatedState = Invalidated; // Drawing to this attachment is being disabled.
// Keep track of whether stencil functionality is enabled if (isNoLongerInvalidated(*cmdCountInvalidated, *cmdCountDisabled))
mStencilEnabled = false; {
// The attachment was previously drawn while enabled, and so is no longer invalidated.
*cmdCountInvalidated = kInfiniteCmdSize;
*cmdCountDisabled = kInfiniteCmdSize;
// Return true to indicate that the store op should remain STORE and that
// mContentDefined should be set to true;
return true;
}
else
{
// Get the latest CmdSize at the start of being disabled. At the end of the render
// pass, cmdCountDisabled is <= the actual command buffer size, and so it's compared
// with cmdCountInvalidated. If the same, the attachment is still invalidated.
*cmdCountDisabled = mCommandBuffer.getCommandBufferSize();
return false;
}
} }
// Update the access for optimizing this render pass's loadOp
UpdateAccess(&mStencilStartAccess, access);
// Update the invalidate state for optimizing this render pass's stencilStoreOp
UpdateInvalidatedState(&mStencilInvalidatedState, invalidatedState);
} }
void CommandBufferHelper::executeBarriers(ContextVk *contextVk, PrimaryCommandBuffer *primary) void CommandBufferHelper::executeBarriers(ContextVk *contextVk, PrimaryCommandBuffer *primary)
...@@ -863,19 +860,20 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -863,19 +860,20 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex]; PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
// Address invalidated depth/stencil attachments // Depth/Stencil buffer optimizations:
if (mDepthInvalidatedState == Invalidated) //
// First, if the attachment is invalidated, skip the store op.
if (isInvalidated(mDepthCmdSizeInvalidated, mDepthCmdSizeDisabled))
{ {
dsOps.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; dsOps.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
} }
if (mStencilInvalidatedState == Invalidated) if (isInvalidated(mStencilCmdSizeInvalidated, mStencilCmdSizeDisabled))
{ {
dsOps.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; dsOps.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
} }
// Depth/Stencil buffer optimization: if we are loading or clearing the buffer, but the // Second, if we are loading or clearing the attachment, but the attachment has not been used,
// buffer has not been used, and the data has also not been stored back into buffer, then // and the data has also not been stored back into attachment, then just skip the load/clear op.
// just skip the load/clear op.
if (mDepthStartAccess == ResourceAccess::Unused && if (mDepthStartAccess == ResourceAccess::Unused &&
dsOps.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE) dsOps.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)
{ {
...@@ -1099,10 +1097,10 @@ void CommandBufferHelper::reset() ...@@ -1099,10 +1097,10 @@ void CommandBufferHelper::reset()
mRebindTransformFeedbackBuffers = false; mRebindTransformFeedbackBuffers = false;
mDepthStartAccess = ResourceAccess::Unused; mDepthStartAccess = ResourceAccess::Unused;
mStencilStartAccess = ResourceAccess::Unused; mStencilStartAccess = ResourceAccess::Unused;
mDepthInvalidatedState = NeverInvalidated; mDepthCmdSizeInvalidated = kInfiniteCmdSize;
mDepthEnabled = false; mDepthCmdSizeDisabled = kInfiniteCmdSize;
mStencilInvalidatedState = NeverInvalidated; mStencilCmdSizeInvalidated = kInfiniteCmdSize;
mStencilEnabled = false; mStencilCmdSizeDisabled = kInfiniteCmdSize;
mDepthStencilAttachmentIndex = kInvalidAttachmentIndex; mDepthStencilAttachmentIndex = kInvalidAttachmentIndex;
mRenderPassUsedImages.clear(); mRenderPassUsedImages.clear();
} }
......
...@@ -875,26 +875,10 @@ enum class AliasingMode ...@@ -875,26 +875,10 @@ enum class AliasingMode
Disallowed, Disallowed,
}; };
enum InvalidatedState // The following are used to help track the state of an invalidated attachment.
{
// The attachment has been invalidated and is currently still invalid.
Invalidated,
// The attachment was previously invalidated, but has since been used while enabled for
// drawing, meaning that it has valid contents (and therefore this render pass should STORE it,
// and a future render pass should LOAD it).
NoLongerInvalidated,
// The attachment has never been invalidated. Since this is the highest value, it should never
// be given to UpdateInvalidatedState(). Instead, it should only be set starting a render pass.
NeverInvalidated,
};
inline void UpdateInvalidatedState(InvalidatedState *oldState, InvalidatedState newState) // This value indicates an "infinite" CmdSize that is not valid for comparing
{ constexpr uint32_t kInfiniteCmdSize = 0xffffffff;
if (newState > *oldState)
{
*oldState = newState;
}
}
// CommandBufferHelper (CBH) class wraps ANGLE's custom command buffer // CommandBufferHelper (CBH) class wraps ANGLE's custom command buffer
// class, SecondaryCommandBuffer. This provides a way to temporarily // class, SecondaryCommandBuffer. This provides a way to temporarily
...@@ -983,29 +967,42 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -983,29 +967,42 @@ class CommandBufferHelper : angle::NonCopyable
SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE); SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
} }
void invalidateRenderPassDepthAttachment() void invalidateRenderPassDepthAttachment(const gl::DepthStencilState &dsState)
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
mDepthInvalidatedState = Invalidated; // Keep track of the size of commands in the command buffer. If the size grows in the
// future, that implies that drawing occured since invalidated.
mDepthCmdSizeInvalidated = mCommandBuffer.getCommandBufferSize();
// Also track the size if the attachment is currently disabled.
mDepthCmdSizeDisabled =
(dsState.depthTest && dsState.depthMask) ? kInfiniteCmdSize : mDepthCmdSizeInvalidated;
} }
void invalidateRenderPassStencilAttachment() void invalidateRenderPassStencilAttachment(const gl::DepthStencilState &dsState)
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
mStencilInvalidatedState = Invalidated; // Keep track of the size of commands in the command buffer. If the size grows in the
// future, that implies that drawing occured since invalidated.
mStencilCmdSizeInvalidated = mCommandBuffer.getCommandBufferSize();
// Also track the size if the attachment is currently disabled.
mStencilCmdSizeDisabled =
dsState.stencilTest ? kInfiniteCmdSize : mStencilCmdSizeInvalidated;
} }
bool shouldRestoreDepthStencilAttachment() bool isNoLongerInvalidated(uint32_t cmdCountInvalidated, uint32_t cmdCountDisabled)
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
// Return true when both depth and stencil attachments were previously-invalidated, and at return (cmdCountInvalidated != kInfiniteCmdSize &&
// least one of those attachments are no longer invalidated. When invalidated, std::min(cmdCountDisabled, mCommandBuffer.getCommandBufferSize()) !=
// RenderTargetVk::mContentDefined is set to false, which will result in the loadOp and cmdCountInvalidated);
// stencilLoadOp of a future render pass being set to DONT_CARE. ContextVk::syncState() }
// will call this method to determine if RenderTargetVk::mContentDefined should be set back
// to true (i.e. use LOAD). bool isInvalidated(uint32_t cmdCountInvalidated, uint32_t cmdCountDisabled)
return mDepthInvalidatedState == NoLongerInvalidated || {
mStencilInvalidatedState == NoLongerInvalidated; ASSERT(mIsRenderPassCommandBuffer);
return cmdCountInvalidated != kInfiniteCmdSize &&
std::min(cmdCountDisabled, mCommandBuffer.getCommandBufferSize()) ==
cmdCountInvalidated;
} }
void updateRenderPassAttachmentFinalLayout(size_t attachmentIndex, ImageLayout finalLayout) void updateRenderPassAttachmentFinalLayout(size_t attachmentIndex, ImageLayout finalLayout)
...@@ -1049,8 +1046,8 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1049,8 +1046,8 @@ class CommandBufferHelper : angle::NonCopyable
// Dumping the command stream is disabled by default. // Dumping the command stream is disabled by default.
static constexpr bool kEnableCommandStreamDiagnostics = false; static constexpr bool kEnableCommandStreamDiagnostics = false;
void onDepthAccess(ResourceAccess access); bool onDepthAccess(ResourceAccess access);
void onStencilAccess(ResourceAccess access); bool onStencilAccess(ResourceAccess access);
void updateRenderPassForResolve(vk::Framebuffer *newFramebuffer, void updateRenderPassForResolve(vk::Framebuffer *newFramebuffer,
const vk::RenderPassDesc &renderPassDesc); const vk::RenderPassDesc &renderPassDesc);
...@@ -1064,6 +1061,11 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1064,6 +1061,11 @@ class CommandBufferHelper : angle::NonCopyable
private: private:
void addCommandDiagnostics(ContextVk *contextVk); void addCommandDiagnostics(ContextVk *contextVk);
bool onDepthStencilAccess(ResourceAccess access,
uint32_t *cmdCountInvalidated,
uint32_t *cmdCountDisabled);
// Allocator used by this class. Using a pool allocator per CBH to avoid threading issues // Allocator used by this class. Using a pool allocator per CBH to avoid threading issues
// that occur w/ shared allocator between multiple CBHs. // that occur w/ shared allocator between multiple CBHs.
angle::PoolAllocator mAllocator; angle::PoolAllocator mAllocator;
...@@ -1095,10 +1097,10 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1095,10 +1097,10 @@ class CommandBufferHelper : angle::NonCopyable
ResourceAccess mStencilStartAccess; ResourceAccess mStencilStartAccess;
// State tracking for whether to optimize the storeOp to DONT_CARE // State tracking for whether to optimize the storeOp to DONT_CARE
bool mDepthEnabled; uint32_t mDepthCmdSizeInvalidated;
InvalidatedState mDepthInvalidatedState; uint32_t mDepthCmdSizeDisabled;
bool mStencilEnabled; uint32_t mStencilCmdSizeInvalidated;
InvalidatedState mStencilInvalidatedState; uint32_t mStencilCmdSizeDisabled;
// Keep track of the depth/stencil attachment index // Keep track of the depth/stencil attachment index
uint32_t mDepthStencilAttachmentIndex; uint32_t mDepthStencilAttachmentIndex;
......
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