Commit 5081f89b by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Support invalidate of MSRTT attachments

Invalidate was previously affecting only the storeOp of the color and depth/stencil attachments. With multisampled-render-to-texture attachments, the storeOp of the resolve attachments were not being affected. This change implements the latter, attempting to remove the attachment altogether if possible. With MSRTT depth/stencil buffers, this makes possible the ability to never write depth/stencil data to memory. Bug: angleproject:4836 Change-Id: I53599e2f4ed6c390dfd03bf226274f6f53f438bb Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2437506 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent a3d5a6e3
...@@ -289,8 +289,14 @@ struct PackedAttachmentOpsDesc final ...@@ -289,8 +289,14 @@ struct PackedAttachmentOpsDesc final
uint16_t stencilLoadOp : 2; uint16_t stencilLoadOp : 2;
uint16_t stencilStoreOp : 1; uint16_t stencilStoreOp : 1;
// Reserved for use with multisampled-render-to-texture invalidate. // If a corresponding resolve attachment exists, storeOp may already be DONT_CARE, and it's
uint16_t reserved : 2; // unclear whether the attachment was invalidated or not. This information is passed along here
// so that the resolve attachment's storeOp can be set to DONT_CARE if the attachment is
// invalidated, and if possible removed from the list of resolve attachments altogether. Note
// that the latter may not be possible if the render pass has multiple subpasses due to Vulkan
// render pass compatibility rules.
uint16_t isInvalidated : 1;
uint16_t isStencilInvalidated : 1;
// 4-bits to force pad the structure to exactly 2 bytes. Note that we currently don't support // 4-bits to force pad the structure to exactly 2 bytes. Note that we currently don't support
// any of the extension layouts, whose values start at 1'000'000'000. // any of the extension layouts, whose values start at 1'000'000'000.
......
...@@ -1032,11 +1032,13 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1032,11 +1032,13 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
// First, if the attachment is invalidated, skip the store op. // First, if the attachment is invalidated, skip the store op.
if (isInvalidated(mDepthCmdSizeInvalidated, mDepthCmdSizeDisabled)) if (isInvalidated(mDepthCmdSizeInvalidated, mDepthCmdSizeDisabled))
{ {
dsOps.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; dsOps.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
dsOps.isInvalidated = true;
} }
if (isInvalidated(mStencilCmdSizeInvalidated, mStencilCmdSizeDisabled)) if (isInvalidated(mStencilCmdSizeInvalidated, mStencilCmdSizeDisabled))
{ {
dsOps.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; dsOps.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
dsOps.isStencilInvalidated = true;
} }
// Second, if we are loading or clearing the attachment, but the attachment has not been used, // Second, if we are loading or clearing the attachment, but the attachment has not been used,
......
...@@ -1025,6 +1025,7 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1025,6 +1025,7 @@ class CommandBufferHelper : angle::NonCopyable
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE); SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
mAttachmentOps[attachmentIndex].isInvalidated = true;
} }
void invalidateRenderPassDepthAttachment(const gl::DepthStencilState &dsState) void invalidateRenderPassDepthAttachment(const gl::DepthStencilState &dsState)
......
...@@ -1854,6 +1854,134 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou ...@@ -1854,6 +1854,134 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::yellow);
} }
// Tests counters when multisampled-render-to-texture color/depth/stencil renderbuffers are
// invalidated.
TEST_P(VulkanPerformanceCounterTest, RenderToTextureInvalidate)
{
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
const rx::vk::PerfCounters &counters = hackANGLE();
rx::vk::PerfCounters expected;
// This test creates 4 render passes. In the first render pass, color, depth and stencil are
// cleared. After every render pass, the attachments are invalidated. In the following render
// passes thus they are not loaded (rather unresolved, as the attachments are
// multisampled-render-to-texture). Due to the invalidate call, neither of the 4 render passes
// should resolve the attachments.
// Expect rpCount+4, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+1, Load+0, Stores+0)
setExpectedCountersForInvalidateTest(counters, 4, 1, 0, 0, 1, 0, 0, &expected);
// Additionally, expect no resolve and unresolve.
setExpectedCountersForUnresolveResolveTest(counters, 0, 0, 0, 0, 0, 0, &expected);
GLFramebuffer FBO;
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
constexpr GLsizei kSize = 6;
// Create multisampled framebuffer to draw into, with both color and depth attachments.
GLTexture colorMS;
glBindTexture(GL_TEXTURE_2D, colorMS);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLRenderbuffer depthStencilMS;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
colorMS, 0, 4);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencilMS);
ASSERT_GL_NO_ERROR();
// Set up texture for copy operation that breaks the render pass
GLTexture copyTex;
glBindTexture(GL_TEXTURE_2D, copyTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// Set viewport and clear color, depth and stencil
glViewport(0, 0, kSize, kSize);
glClearColor(0, 0, 0, 1.0f);
glClearDepthf(1);
glClearStencil(0x55);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Output depth/stencil, but disable testing so all draw calls succeed
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilMask(0xFF);
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.75f);
ASSERT_GL_NO_ERROR();
// Invalidate everything
const GLenum discards[] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards);
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Draw green
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Invalidate everything
glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards);
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, 0, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Draw blue
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.25f);
ASSERT_GL_NO_ERROR();
// Invalidate everything
glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards);
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, kSize / 2, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Draw yellow
glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Invalidate everything
glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards);
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, kSize / 2, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Verify the counters
compareLoadCountersForInvalidateTest(counters, expected);
compareCountersForUnresolveResolveTest(counters, expected);
}
// Ensures we use read-only depth layout when there is no write // Ensures we use read-only depth layout when there is no write
TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout) TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
{ {
......
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