Commit 2197dc52 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Implement masked depth & stencil clear

This commit also adds tests for clearing depth and stencil with mask/scissor. Bug: angleproject:2540 Change-Id: I30dd840afd6cdd4e3a38c50fcba4c8623513ceb0 Reviewed-on: https://chromium-review.googlesource.com/c/1307585Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 580baf37
...@@ -178,6 +178,9 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -178,6 +178,9 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
bool clearDepth = (depthAttachment && (mask & GL_DEPTH_BUFFER_BIT) != 0); bool clearDepth = (depthAttachment && (mask & GL_DEPTH_BUFFER_BIT) != 0);
ASSERT(!clearDepth || depthAttachment->isAttached()); ASSERT(!clearDepth || depthAttachment->isAttached());
// If depth write is disabled, pretend that GL_DEPTH_BUFFER_BIT is not specified altogether.
clearDepth = clearDepth && contextVk->getGLState().getDepthStencilState().depthMask;
const gl::FramebufferAttachment *stencilAttachment = mState.getStencilAttachment(); const gl::FramebufferAttachment *stencilAttachment = mState.getStencilAttachment();
bool clearStencil = (stencilAttachment && (mask & GL_STENCIL_BUFFER_BIT) != 0); bool clearStencil = (stencilAttachment && (mask & GL_STENCIL_BUFFER_BIT) != 0);
ASSERT(!clearStencil || stencilAttachment->isAttached()); ASSERT(!clearStencil || stencilAttachment->isAttached());
...@@ -203,8 +206,6 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -203,8 +206,6 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
if (clearDepth || clearStencil) if (clearDepth || clearStencil)
{ {
// Masked stencil clears are currently not implemented.
// TODO(jmadill): Masked stencil clear. http://anglebug.com/2540
ANGLE_TRY(clearWithClearAttachments(contextVk, false, clearDepth, clearStencil)); ANGLE_TRY(clearWithClearAttachments(contextVk, false, clearDepth, clearStencil));
} }
return angle::Result::Continue(); return angle::Result::Continue();
...@@ -222,9 +223,6 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -222,9 +223,6 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
// With scissor test enabled, we clear very differently and we don't need to access // With scissor test enabled, we clear very differently and we don't need to access
// the image inside each attachment we can just use clearCmdAttachments with our // the image inside each attachment we can just use clearCmdAttachments with our
// scissor region instead. // scissor region instead.
// Masked stencil clears are currently not implemented.
// TODO(jmadill): Masked stencil clear. http://anglebug.com/2540
ANGLE_TRY(clearWithClearAttachments(contextVk, clearColor, clearDepth, clearStencil)); ANGLE_TRY(clearWithClearAttachments(contextVk, clearColor, clearDepth, clearStencil));
return angle::Result::Continue(); return angle::Result::Continue();
} }
...@@ -234,9 +232,13 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -234,9 +232,13 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
{ {
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
const VkClearDepthStencilValue &clearDepthStencilValue = VkClearDepthStencilValue clearDepthStencilValue =
contextVk->getClearDepthStencilValue().depthStencil; contextVk->getClearDepthStencilValue().depthStencil;
// Apply the stencil mask to the clear value.
clearDepthStencilValue.stencil &=
contextVk->getGLState().getDepthStencilState().stencilWritemask;
RenderTargetVk *renderTarget = mRenderTargetCache.getDepthStencil(); RenderTargetVk *renderTarget = mRenderTargetCache.getDepthStencil();
const angle::Format &format = renderTarget->getImageFormat().textureFormat(); const angle::Format &format = renderTarget->getImageFormat().textureFormat();
const VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format); const VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format);
...@@ -936,6 +938,16 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk, ...@@ -936,6 +938,16 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk,
} }
} }
VkClearValue depthStencilClearValue = contextVk->getClearDepthStencilValue();
// Apply the stencil mask to the clear value. Stencil mask is generally respected through the
// respective pipeline state, but clear uses its own special function.
if (clearStencil)
{
depthStencilClearValue.depthStencil.stencil &=
contextVk->getGLState().getDepthStencilState().stencilWritemask;
}
if (clearDepth && clearStencil && mState.getDepthStencilAttachment() != nullptr) if (clearDepth && clearStencil && mState.getDepthStencilAttachment() != nullptr)
{ {
// When we have a packed depth/stencil attachment we can do 1 clear for both when it // When we have a packed depth/stencil attachment we can do 1 clear for both when it
...@@ -943,7 +955,7 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk, ...@@ -943,7 +955,7 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk,
VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex]; VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
clearAttachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; clearAttachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
clearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED; clearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED;
clearAttachment.clearValue = contextVk->getClearDepthStencilValue(); clearAttachment.clearValue = depthStencilClearValue;
++clearAttachmentIndex; ++clearAttachmentIndex;
} }
else else
...@@ -953,7 +965,7 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk, ...@@ -953,7 +965,7 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk,
VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex]; VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
clearAttachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; clearAttachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
clearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED; clearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED;
clearAttachment.clearValue = contextVk->getClearDepthStencilValue(); clearAttachment.clearValue = depthStencilClearValue;
++clearAttachmentIndex; ++clearAttachmentIndex;
} }
...@@ -962,7 +974,7 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk, ...@@ -962,7 +974,7 @@ angle::Result FramebufferVk::clearWithClearAttachments(ContextVk *contextVk,
VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex]; VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
clearAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; clearAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
clearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED; clearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED;
clearAttachment.clearValue = contextVk->getClearDepthStencilValue(); clearAttachment.clearValue = depthStencilClearValue;
++clearAttachmentIndex; ++clearAttachmentIndex;
} }
} }
......
...@@ -46,6 +46,7 @@ class ClearTestBase : public ANGLETest ...@@ -46,6 +46,7 @@ class ClearTestBase : public ANGLETest
setConfigBlueBits(8); setConfigBlueBits(8);
setConfigAlphaBits(8); setConfigAlphaBits(8);
setConfigDepthBits(24); setConfigDepthBits(24);
setConfigStencilBits(8);
} }
void SetUp() override void SetUp() override
...@@ -79,7 +80,13 @@ class ClearTestBase : public ANGLETest ...@@ -79,7 +80,13 @@ class ClearTestBase : public ANGLETest
class ClearTest : public ClearTestBase class ClearTest : public ClearTestBase
{ {
protected:
void MaskedScissoredColorDepthStencilClear(bool mask,
bool scissor,
bool clearDepth,
bool clearStencil);
}; };
class ClearTestES3 : public ClearTestBase class ClearTestES3 : public ClearTestBase
{ {
}; };
...@@ -97,6 +104,10 @@ class ClearTestRGB : public ANGLETest ...@@ -97,6 +104,10 @@ class ClearTestRGB : public ANGLETest
} }
}; };
class ScissoredClearTest : public ClearTest
{
};
// Test clearing the default framebuffer // Test clearing the default framebuffer
TEST_P(ClearTest, DefaultFramebuffer) TEST_P(ClearTest, DefaultFramebuffer)
{ {
...@@ -521,135 +532,181 @@ TEST_P(ClearTestES3, RepeatedClear) ...@@ -521,135 +532,181 @@ TEST_P(ClearTestES3, RepeatedClear)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
class ScissoredClearTest : public ANGLETest void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
{ bool scissor,
public: bool clearDepth,
ScissoredClearTest() bool clearStencil)
{
setWindowWidth(64);
setWindowHeight(64);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setConfigDepthBits(24);
setConfigStencilBits(8);
}
};
// Simple scissored clear.
TEST_P(ScissoredClearTest, BasicScissoredColorClear)
{ {
const int w = getWindowWidth(); // Flaky on Android Nexus 5x, possible driver bug.
const int h = getWindowHeight(); // TODO(jmadill): Re-enable when possible. http://anglebug.com/2548
const int whalf = w >> 1; ANGLE_SKIP_TEST_IF(IsOpenGLES() && IsAndroid());
const int hhalf = h >> 1;
// Clear whole region to red.
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// Enable scissor and clear to green.
glEnable(GL_SCISSOR_TEST);
glScissor(whalf / 2, hhalf / 2, whalf, whalf);
glClearColor(0.0, 1.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Check the four corners for the original clear color, and the middle for the scissored clear
// color.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(w - 1, 0, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(0, h - 1, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(w - 1, h - 1, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(whalf, hhalf, GLColor::green) << "in-scissor area should be green";
}
// Tests combined scissored color+depth clear.
TEST_P(ScissoredClearTest, ScissoredColorAndDepthClear)
{
const int w = getWindowWidth(); const int w = getWindowWidth();
const int h = getWindowHeight(); const int h = getWindowHeight();
const int whalf = w >> 1; const int whalf = w >> 1;
const int hhalf = h >> 1; const int hhalf = h >> 1;
// Clear whole region to red/1.0f. // Clear to a random color, 1.0 depth and 0x00 stencil
glClearColor(1.0, 0.0, 0.0, 1.0);
glClearDepthf(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Enable scissor and clear to green/0.5f.
glEnable(GL_SCISSOR_TEST);
glScissor(whalf / 2, hhalf / 2, whalf, whalf);
glClearColor(0.0, 1.0, 0.0, 1.0);
glClearDepthf(0.5f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Check the four corners for the original clear color, and the middle for the scissored clear
// color.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(w - 1, 0, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(0, h - 1, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(w - 1, h - 1, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(whalf, hhalf, GLColor::green) << "in-scissor area should be green";
// Draw blue with depth 0.5f and depth test enabled - verify only the middle changes.
glDisable(GL_SCISSOR_TEST);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_EQUAL);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue());
// OpenGL uses a depth range of [-1,1] so pass in a z value of 0 to get 0.5 depth.
drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(w - 1, 0, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(0, h - 1, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(w - 1, h - 1, GLColor::red) << "out-of-scissor area should be red";
EXPECT_PIXEL_COLOR_EQ(whalf, hhalf, GLColor::blue) << "in-scissor area should be blue";
}
// Tests combined color+depth clear.
TEST_P(ClearTest, MaskedColorAndDepthClear)
{
// Flaky on Android Nexus 5x, possible driver bug.
// TODO(jmadill): Re-enable when possible. http://anglebug.com/2548
ANGLE_SKIP_TEST_IF(IsOpenGLES() && IsAndroid());
// Clear to a random color and 1.0 depth.
Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f); Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f);
GLColor color1RGB(color1); GLColor color1RGB(color1);
glClearColor(color1[0], color1[1], color1[2], color1[3]); glClearColor(color1[0], color1[1], color1[2], color1[3]);
glClearDepthf(1.0f); glClearDepthf(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearStencil(0x00);
glClear(GL_COLOR_BUFFER_BIT | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) |
(clearStencil ? GL_STENCIL_BUFFER_BIT : 0));
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Verify color and was cleared correctly. // Verify color was cleared correctly.
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1);
// Use a color mask to clear to a second color and 0.5 depth. if (scissor)
{
glEnable(GL_SCISSOR_TEST);
glScissor(whalf / 2, hhalf / 2, whalf, hhalf);
}
// Use color and stencil masks to clear to a second color, 0.5 depth and 0x59 stencil.
Vector4 color2(0.2f, 0.4f, 0.6f, 0.8f); Vector4 color2(0.2f, 0.4f, 0.6f, 0.8f);
GLColor color2RGB(color2); GLColor color2RGB(color2);
glClearColor(color2[0], color2[1], color2[2], color2[3]); glClearColor(color2[0], color2[1], color2[2], color2[3]);
glClearDepthf(0.5f); glClearDepthf(0.5f);
glClearStencil(0xFF);
if (mask)
{
glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE); glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDepthMask(GL_FALSE);
glStencilMask(0x59);
}
glClear(GL_COLOR_BUFFER_BIT | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) |
(clearStencil ? GL_STENCIL_BUFFER_BIT : 0));
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glStencilMask(0xFF);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Verify second clear mask worked as expected. // Verify second clear mask worked as expected.
GLColor color2Masked(color2RGB[0], color1RGB[1], color2RGB[2], color1RGB[3]); GLColor color2MaskedRGB(color2RGB[0], color1RGB[1], color2RGB[2], color1RGB[3]);
EXPECT_PIXEL_COLOR_EQ(0, 0, color2Masked); GLColor expectedColorRGB = mask ? color2MaskedRGB : color2RGB;
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedColorRGB, 1);
if (scissor)
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 1);
}
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST);
if (clearDepth)
{
// We use a small shader to verify depth. // We use a small shader to verify depth.
ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Blue());
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_EQUAL); glDepthFunc(GL_EQUAL);
drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), 0.0f); drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), 0.0f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); glDisable(GL_DEPTH_TEST);
ASSERT_GL_NO_ERROR();
expectedColorRGB = mask ? expectedColorRGB : GLColor::blue;
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedColorRGB, 1);
if (scissor)
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 1);
}
}
if (clearStencil)
{
// And another small shader to verify stencil.
ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Green());
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, mask ? 0x59 : 0xFF, 0xFF);
drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f);
glDisable(GL_STENCIL_TEST);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, GLColor::green, 1);
if (scissor)
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color1RGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color1RGB, 1);
}
}
}
// Tests combined color+depth+stencil clears.
TEST_P(ClearTest, MaskedColorAndDepthClear)
{
MaskedScissoredColorDepthStencilClear(true, false, true, false);
}
TEST_P(ClearTest, MaskedColorAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, false, false, true);
}
TEST_P(ClearTest, MaskedColorAndDepthAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, false, true, true);
}
// Simple scissored clear.
TEST_P(ScissoredClearTest, BasicScissoredColorClear)
{
MaskedScissoredColorDepthStencilClear(false, true, false, false);
}
// Simple scissored masked clear.
TEST_P(ScissoredClearTest, MaskedScissoredColorClear)
{
MaskedScissoredColorDepthStencilClear(true, true, false, false);
}
// Tests combined color+depth+stencil scissored clears.
TEST_P(ScissoredClearTest, ScissoredColorAndDepthClear)
{
MaskedScissoredColorDepthStencilClear(false, true, true, false);
}
TEST_P(ScissoredClearTest, ScissoredColorAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(false, true, false, true);
}
TEST_P(ScissoredClearTest, ScissoredColorAndDepthAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(false, true, true, true);
}
// Tests combined color+depth+stencil scissored masked clears.
TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthClear)
{
MaskedScissoredColorDepthStencilClear(true, true, true, false);
}
TEST_P(ScissoredClearTest, MaskedScissoredColorAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, true, false, true);
}
TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, true, true, true);
} }
// Test that just clearing a nonexistent drawbuffer of the default framebuffer doesn't cause an // Test that just clearing a nonexistent drawbuffer of the default framebuffer doesn't cause an
......
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