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)
if (depthStencilRenderTarget)
{
// Change depthstencil attachment storeOp to DONT_CARE
mRenderPassCommands->invalidateRenderPassStencilAttachment();
mRenderPassCommands->invalidateRenderPassDepthAttachment();
const gl::DepthStencilState &dsState = mState.getDepthStencilState();
mRenderPassCommands->invalidateRenderPassStencilAttachment(dsState);
mRenderPassCommands->invalidateRenderPassDepthAttachment(dsState);
// Mark content as invalid so that we will not load them in next renderpass
depthStencilRenderTarget->invalidateEntireContent();
}
......@@ -2908,11 +2909,9 @@ angle::Result ContextVk::syncState(const gl::Context *context,
if (mRenderPassCommands->started())
{
vk::ResourceAccess access = GetStencilAccess(mState.getDepthStencilState());
mRenderPassCommands->onStencilAccess(access);
// Did this depth-state change undo a previous invalidation of the depth-stencil
// attachment?
if (mRenderPassCommands->shouldRestoreDepthStencilAttachment())
if (mRenderPassCommands->onStencilAccess(access))
{
// The attachment is no longer invalidated, so set mContentDefined to true
mDrawFramebuffer->restoreDepthStencilDefinedContents();
}
}
......@@ -4914,11 +4913,9 @@ angle::Result ContextVk::updateRenderPassDepthAccess()
}
else
{
mRenderPassCommands->onDepthAccess(access);
// Did this depth-state change undo a previous invalidation of the depth-stencil
// attachment?
if (mRenderPassCommands->shouldRestoreDepthStencilAttachment())
if (mRenderPassCommands->onDepthAccess(access))
{
// The attachment is no longer invalidated, so set mContentDefined to true
mDrawFramebuffer->restoreDepthStencilDefinedContents();
}
}
......
......@@ -1483,14 +1483,17 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
if (depthStencilRenderTarget)
{
const gl::DepthStencilState &dsState = contextVk->getState().getDepthStencilState();
if (invalidateDepthBuffer)
{
contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment();
contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment(
dsState);
}
if (invalidateStencilBuffer)
{
contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment();
contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment(
dsState);
}
}
if (invalidateColorBuffers.any())
......
......@@ -693,6 +693,14 @@ class SecondaryCommandBuffer final : angle::NonCopyable
static bool CanKnowIfEmpty() { return true; }
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:
void commonDebugUtilsLabel(CommandID cmd, const VkDebugUtilsLabelEXT &label);
......
......@@ -561,10 +561,10 @@ CommandBufferHelper::CommandBufferHelper()
mIsRenderPassCommandBuffer(false),
mDepthStartAccess(ResourceAccess::Unused),
mStencilStartAccess(ResourceAccess::Unused),
mDepthEnabled(false),
mDepthInvalidatedState(NeverInvalidated),
mStencilEnabled(false),
mStencilInvalidatedState(NeverInvalidated),
mDepthCmdSizeInvalidated(kInfiniteCmdSize),
mDepthCmdSizeDisabled(kInfiniteCmdSize),
mStencilCmdSizeInvalidated(kInfiniteCmdSize),
mStencilCmdSizeDisabled(kInfiniteCmdSize),
mDepthStencilAttachmentIndex(kInvalidAttachmentIndex)
{}
......@@ -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
UpdateAccess(&mDepthStartAccess, access);
ASSERT((mRenderPassDesc.getDepthStencilAccess() != ResourceAccess::ReadOnly) ||
mDepthStartAccess != ResourceAccess::Write);
// 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
// the count of commands in the SecondaryCommandBuffer.
// See https://issuetracker.google.com/issues/163854287
InvalidatedState invalidatedState;
// Update the access for optimizing this render pass's loadOp
UpdateAccess(&mStencilStartAccess, access);
// 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)
{
// 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 = (!mStencilEnabled) ? NoLongerInvalidated : Invalidated;
// Keep track of whether stencil functionality is enabled
mStencilEnabled = true;
// Drawing to this attachment is being enabled. Assume that drawing will immediately occur
// after this attachment is enabled, and that means that the attachment will no longer be
// 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
{
invalidatedState = Invalidated;
// Keep track of whether stencil functionality is enabled
mStencilEnabled = false;
// Drawing to this attachment is being disabled.
if (isNoLongerInvalidated(*cmdCountInvalidated, *cmdCountDisabled))
{
// 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)
......@@ -863,19 +860,20 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
// Address invalidated depth/stencil attachments
if (mDepthInvalidatedState == Invalidated)
// Depth/Stencil buffer optimizations:
//
// First, if the attachment is invalidated, skip the store op.
if (isInvalidated(mDepthCmdSizeInvalidated, mDepthCmdSizeDisabled))
{
dsOps.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
if (mStencilInvalidatedState == Invalidated)
if (isInvalidated(mStencilCmdSizeInvalidated, mStencilCmdSizeDisabled))
{
dsOps.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
// Depth/Stencil buffer optimization: if we are loading or clearing the buffer, but the
// buffer has not been used, and the data has also not been stored back into buffer, then
// just skip the load/clear op.
// Second, if we are loading or clearing the attachment, but the attachment has not been used,
// and the data has also not been stored back into attachment, then just skip the load/clear op.
if (mDepthStartAccess == ResourceAccess::Unused &&
dsOps.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)
{
......@@ -1099,10 +1097,10 @@ void CommandBufferHelper::reset()
mRebindTransformFeedbackBuffers = false;
mDepthStartAccess = ResourceAccess::Unused;
mStencilStartAccess = ResourceAccess::Unused;
mDepthInvalidatedState = NeverInvalidated;
mDepthEnabled = false;
mStencilInvalidatedState = NeverInvalidated;
mStencilEnabled = false;
mDepthCmdSizeInvalidated = kInfiniteCmdSize;
mDepthCmdSizeDisabled = kInfiniteCmdSize;
mStencilCmdSizeInvalidated = kInfiniteCmdSize;
mStencilCmdSizeDisabled = kInfiniteCmdSize;
mDepthStencilAttachmentIndex = kInvalidAttachmentIndex;
mRenderPassUsedImages.clear();
}
......
......@@ -875,26 +875,10 @@ enum class AliasingMode
Disallowed,
};
enum InvalidatedState
{
// 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,
};
// The following are used to help track the state of an invalidated attachment.
inline void UpdateInvalidatedState(InvalidatedState *oldState, InvalidatedState newState)
{
if (newState > *oldState)
{
*oldState = newState;
}
}
// This value indicates an "infinite" CmdSize that is not valid for comparing
constexpr uint32_t kInfiniteCmdSize = 0xffffffff;
// CommandBufferHelper (CBH) class wraps ANGLE's custom command buffer
// class, SecondaryCommandBuffer. This provides a way to temporarily
......@@ -983,29 +967,42 @@ class CommandBufferHelper : angle::NonCopyable
SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
}
void invalidateRenderPassDepthAttachment()
void invalidateRenderPassDepthAttachment(const gl::DepthStencilState &dsState)
{
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);
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);
// Return true when both depth and stencil attachments were previously-invalidated, and at
// least one of those attachments are no longer invalidated. When invalidated,
// RenderTargetVk::mContentDefined is set to false, which will result in the loadOp and
// 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).
return mDepthInvalidatedState == NoLongerInvalidated ||
mStencilInvalidatedState == NoLongerInvalidated;
return (cmdCountInvalidated != kInfiniteCmdSize &&
std::min(cmdCountDisabled, mCommandBuffer.getCommandBufferSize()) !=
cmdCountInvalidated);
}
bool isInvalidated(uint32_t cmdCountInvalidated, uint32_t cmdCountDisabled)
{
ASSERT(mIsRenderPassCommandBuffer);
return cmdCountInvalidated != kInfiniteCmdSize &&
std::min(cmdCountDisabled, mCommandBuffer.getCommandBufferSize()) ==
cmdCountInvalidated;
}
void updateRenderPassAttachmentFinalLayout(size_t attachmentIndex, ImageLayout finalLayout)
......@@ -1049,8 +1046,8 @@ class CommandBufferHelper : angle::NonCopyable
// Dumping the command stream is disabled by default.
static constexpr bool kEnableCommandStreamDiagnostics = false;
void onDepthAccess(ResourceAccess access);
void onStencilAccess(ResourceAccess access);
bool onDepthAccess(ResourceAccess access);
bool onStencilAccess(ResourceAccess access);
void updateRenderPassForResolve(vk::Framebuffer *newFramebuffer,
const vk::RenderPassDesc &renderPassDesc);
......@@ -1064,6 +1061,11 @@ class CommandBufferHelper : angle::NonCopyable
private:
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
// that occur w/ shared allocator between multiple CBHs.
angle::PoolAllocator mAllocator;
......@@ -1095,10 +1097,10 @@ class CommandBufferHelper : angle::NonCopyable
ResourceAccess mStencilStartAccess;
// State tracking for whether to optimize the storeOp to DONT_CARE
bool mDepthEnabled;
InvalidatedState mDepthInvalidatedState;
bool mStencilEnabled;
InvalidatedState mStencilInvalidatedState;
uint32_t mDepthCmdSizeInvalidated;
uint32_t mDepthCmdSizeDisabled;
uint32_t mStencilCmdSizeInvalidated;
uint32_t mStencilCmdSizeDisabled;
// Keep track of the depth/stencil attachment index
uint32_t mDepthStencilAttachmentIndex;
......
......@@ -45,6 +45,81 @@ class VulkanPerformanceCounterTest : public ANGLETest
const gl::Context *context = static_cast<const gl::Context *>(getEGLWindow()->getContext());
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
......@@ -416,62 +491,631 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthStencilFeedbackLoopUsesSingleR
ASSERT_GL_NO_ERROR();
}
// Tests that RGB texture should not break renderpass (similar to PUBG MOBILE).
TEST_P(VulkanPerformanceCounterTest, InvalidatingAndUsingDepthDoesNotBreakRenderPass)
// Tests that common PUBG MOBILE case does not break render pass, and that counts are correct:
//
// - Scenario: invalidate, disable, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDraw)
{
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());
glUseProgram(program);
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
// Setup to draw to color and depth
// 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);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
GLFramebuffer framebuffer;
GLTexture texture;
GLRenderbuffer renderbuffer;
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);
setupClearAndDrawForInvalidateTest(&program, &framebuffer, &texture, &renderbuffer);
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();
// First, clear and draw with depth buffer enabled
// 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();
// Enable (shouldn't change result)
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);
// 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);
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};
// Note: PUBG uses glDiscardFramebufferEXT() instead of glInvalidateFramebuffer()
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, discards);
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();
// 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 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);
// Third, re-enable the depth buffer and draw again
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);
// 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);
ASSERT_GL_NO_ERROR();
swapBuffers();
compareLoadCountersForInvalidateTest(counters, expected);
}
uint32_t actualRenderPassCount = counters.renderPasses;
EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount);
// Tests that another case does not break render pass, and that counts are correct:
//
// - 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
// end when the test infrastructure calls eglSwapBuffers(), after the RAII-based GLRenderbuffer
// has been deleted.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
// 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();
// 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.
......
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