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;
......
...@@ -45,6 +45,81 @@ class VulkanPerformanceCounterTest : public ANGLETest ...@@ -45,6 +45,81 @@ class VulkanPerformanceCounterTest : public ANGLETest
const gl::Context *context = static_cast<const gl::Context *>(getEGLWindow()->getContext()); const gl::Context *context = static_cast<const gl::Context *>(getEGLWindow()->getContext());
return rx::GetImplAs<const rx::ContextVk>(context)->getPerfCounters(); return rx::GetImplAs<const rx::ContextVk>(context)->getPerfCounters();
} }
void setupClearAndDrawForInvalidateTest(GLProgram *program,
GLFramebuffer *framebuffer,
GLTexture *texture,
GLRenderbuffer *renderbuffer)
{
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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0);
glBindRenderbuffer(GL_RENDERBUFFER, *renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 16, 16);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
*renderbuffer);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear and draw with depth and stencil buffer enabled
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_GEQUAL);
glClearDepthf(0.99f);
glEnable(GL_STENCIL_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawQuad(*program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
}
void setExpectedCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
uint32_t incrementalRenderPasses,
uint32_t incrementalDepthClears,
uint32_t incrementalDepthLoads,
uint32_t incrementalDepthStores,
uint32_t incrementalStencilClears,
uint32_t incrementalStencilLoads,
uint32_t incrementalStencilStores,
rx::vk::PerfCounters *expected)
{
expected->renderPasses = counters.renderPasses + incrementalRenderPasses;
expected->depthClears = counters.depthClears + incrementalDepthClears;
expected->depthLoads = counters.depthLoads + incrementalDepthLoads;
expected->depthStores = counters.depthStores + incrementalDepthStores;
expected->stencilClears = counters.stencilClears + incrementalStencilClears;
expected->stencilLoads = counters.stencilLoads + incrementalStencilLoads;
expected->stencilStores = counters.stencilStores + incrementalStencilStores;
}
void setAndIncrementLoadCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
uint32_t incrementalDepthLoads,
uint32_t incrementalStencilLoads,
rx::vk::PerfCounters *expected)
{
expected->depthLoads = counters.depthLoads + incrementalDepthLoads;
expected->stencilLoads = counters.stencilLoads + incrementalStencilLoads;
}
void compareDepthStencilCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
const rx::vk::PerfCounters &expected)
{
EXPECT_EQ(expected.depthClears, counters.depthClears);
EXPECT_EQ(expected.depthLoads, counters.depthLoads);
EXPECT_EQ(expected.depthStores, counters.depthStores);
EXPECT_EQ(expected.stencilClears, counters.stencilClears);
EXPECT_EQ(expected.stencilLoads, counters.stencilLoads);
EXPECT_EQ(expected.stencilStores, counters.stencilStores);
}
void compareLoadCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
const rx::vk::PerfCounters &expected)
{
EXPECT_EQ(expected.depthLoads, counters.depthLoads);
EXPECT_EQ(expected.stencilLoads, counters.stencilLoads);
}
}; };
class VulkanPerformanceCounterTest_ES31 : public VulkanPerformanceCounterTest class VulkanPerformanceCounterTest_ES31 : public VulkanPerformanceCounterTest
...@@ -416,62 +491,631 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthStencilFeedbackLoopUsesSingleR ...@@ -416,62 +491,631 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthStencilFeedbackLoopUsesSingleR
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Tests that RGB texture should not break renderpass (similar to PUBG MOBILE). // Tests that common PUBG MOBILE case does not break render pass, and that counts are correct:
TEST_P(VulkanPerformanceCounterTest, InvalidatingAndUsingDepthDoesNotBreakRenderPass) //
// - Scenario: invalidate, disable, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDraw)
{ {
const rx::vk::PerfCounters &counters = hackANGLE(); const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+1, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 0, 0, 1, 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());
glUseProgram(program); GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
// Execute the scenario that this test is for:
// Invalidate (storeOp = DONT_CARE; mContentDefined = false)
const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards);
ASSERT_GL_NO_ERROR();
// Disable (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Draw (since disabled, shouldn't change result)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 0, 0, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that alternative PUBG MOBILE case does not break render pass, and that counts are correct:
//
// - Scenario: disable, invalidate, draw
TEST_P(VulkanPerformanceCounterTest, DisableInvalidateDraw)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+1, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 0, 0, 1, 0, &expected);
// Setup to draw to color and depth ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer; GLFramebuffer framebuffer;
GLTexture texture; GLTexture texture;
GLRenderbuffer renderbuffer; GLRenderbuffer renderbuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 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);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
renderbuffer);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
uint32_t expectedRenderPassCount = counters.renderPasses + 1; // Execute the scenario that this test is for:
// Disable (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Invalidate (storeOp = DONT_CARE; mContentDefined = false)
const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards);
ASSERT_GL_NO_ERROR();
// Draw (since disabled, shouldn't change result)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 0, 0, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that another case does not break render pass, and that counts are correct:
//
// - Scenario: disable, draw, invalidate, enable
TEST_P(VulkanPerformanceCounterTest, DisableDrawInvalidateEnable)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+1, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 0, 0, 1, 0, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
// Execute the scenario that this test is for:
// Note: setupClearAndDrawForInvalidateTest() did an enable and draw
// Disable (since not invalidated, shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Draw (since not invalidated, shouldn't change result)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// 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();
// First, clear and draw with depth buffer enabled // Enable (shouldn't change result)
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_GEQUAL);
glClearDepthf(0.99f);
glEnable(GL_STENCIL_TEST); glEnable(GL_STENCIL_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Note: The above enable calls will be ignored, since no drawing was done to force the enable
// dirty bit to be processed
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Break the render pass by reading back a pixel.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 0, 0, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that common TRex case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate
TEST_P(VulkanPerformanceCounterTest, Invalidate)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+1, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 0, 0, 1, 0, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
// Execute the scenario that this test is for:
// Invalidate (storeOp = DONT_CARE; mContentDefined = false)
const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 0, 0, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that another case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDraw)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+1, Stores+1)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 1, 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);
// Execute the scenario that this test is for:
// 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();
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// TODO(ianelliott): have mContentDefined set at endRP(), so that it's correct
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 1, 1, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
// TODO(ianelliott): have mContentDefined set at endRP(), so that it's correct; then uncomment:
// compareLoadCountersForInvalidateTest(counters, expected);
//
// TODO(ianelliott): have mContentDefined set at endRP(), so that it's correct; then uncomment:
// TEST_FUTURE_RP_LOADOP(1, 1);
}
// Tests that another case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, draw, disable
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisable)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+1, Stores+1)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 1, 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);
// Execute the scenario that this test is for:
// 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();
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Disable (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Note: this draw is just so that the disable dirty bits will be processed
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 1, 1, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that another case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, disable, draw, enable
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnable)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+1, Stores+0)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 0, 0, 1, 0, &expected);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
// Execute the scenario that this test is for:
// 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 (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Draw (since disabled, shouldn't change result)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Second, invalidate the depth buffer and draw with depth buffer disabled // Enable (shouldn't change result)
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
// Note: The above enable calls will be ignored, since no drawing was done to force the enable
// dirty bit to be processed
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 0, 0, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that another case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, disable, draw, enable, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnableDraw)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+1, Stores+1)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 1, 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);
// Execute the scenario that this test is for:
// Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false)
const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
// Note: PUBG uses glDiscardFramebufferEXT() instead of glInvalidateFramebuffer() glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards);
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, discards);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Disable (shouldn't change result)
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Draw (since disabled, shouldn't change result)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Enable (shouldn't change result)
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 1, 1, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that another case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, draw, disable, enable
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnable)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+1, Stores+1)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 1, 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);
// Third, re-enable the depth buffer and draw again // Execute the scenario that this test is for:
// 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(); ASSERT_GL_NO_ERROR();
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Disable (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Note: this draw is just so that the disable dirty bits will be processed
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Enable (shouldn't change result)
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
// Note: The above enable calls will be ignored, since no drawing was done to force the enable
// dirty bit to be processed
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 1, 1, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
uint32_t actualRenderPassCount = counters.renderPasses; // Tests that another case does not break render pass, and that counts are correct:
EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); //
// - Scenario: invalidate, draw, disable, enable, invalidate
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidate)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Make sure the render pass is ended by reading back a pixel. Otherwise, the render pass will // Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+1, Stores+0)
// end when the test infrastructure calls eglSwapBuffers(), after the RAII-based GLRenderbuffer setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 0, 0, 1, 0, &expected);
// has been deleted.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
// Execute the scenario that this test is for:
// 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();
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Disable (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Note: this draw is just so that the disable dirty bits will be processed
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Enable (shouldn't change result)
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
// Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false)
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 0, 0, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that another case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, draw, disable, enable, invalidate, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidateDraw)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+1, Stores+1)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 1, 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);
// Execute the scenario that this test is for:
// 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();
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Disable (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Note: this draw is just so that the disable dirty bits will be processed
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Enable (shouldn't change result)
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
// Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false)
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards);
ASSERT_GL_NO_ERROR();
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 1, 1, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
// Tests that another common (dEQP) case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, disable, enable, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableEnableDraw)
{
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+1, Stores+1)
setExpectedCountersForInvalidateTest(counters, 1, 1, 0, 1, 0, 1, 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);
// Execute the scenario that this test is for:
// 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 (shouldn't change result)
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Note: this draw is just so that the disable dirty bits will be processed
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Enable (shouldn't change result)
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
// Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true)
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Ensure that the render pass wasn't broken
EXPECT_EQ(expected.renderPasses, counters.renderPasses);
// Use swapBuffers and then check how many loads and stores were actually done
swapBuffers();
compareDepthStencilCountersForInvalidateTest(counters, expected);
// Start and end another render pass, to check that the load ops are as expected
setAndIncrementLoadCountersForInvalidateTest(counters, 1, 1, &expected);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
} }
// Tests that even if the app clears depth, it should be invalidated if there is no read. // Tests that even if the app clears depth, it should be invalidated if there is no read.
......
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