Commit 7dc92430 by Shahbaz Youssefi Committed by Commit Bot

Noop clear of non-existing attachments.

Bug: angleproject:4988 Change-Id: Ib6ff9756ec7ae5aa2b11f4d12932829fe05656d6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2511369 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 42e10d3e
...@@ -3827,13 +3827,15 @@ void Context::clear(GLbitfield mask) ...@@ -3827,13 +3827,15 @@ void Context::clear(GLbitfield mask)
} }
// If depth write is disabled, don't attempt to clear depth. // If depth write is disabled, don't attempt to clear depth.
if (!mState.getDepthStencilState().depthMask) if (mState.getDrawFramebuffer()->getDepthAttachment() == nullptr ||
!mState.getDepthStencilState().depthMask)
{ {
mask &= ~GL_DEPTH_BUFFER_BIT; mask &= ~GL_DEPTH_BUFFER_BIT;
} }
// If all stencil bits are masked, don't attempt to clear stencil. // If all stencil bits are masked, don't attempt to clear stencil.
if (mState.getDepthStencilState().stencilWritemask == 0) if (mState.getDrawFramebuffer()->getStencilAttachment() == nullptr ||
mState.getDepthStencilState().stencilWritemask == 0)
{ {
mask &= ~GL_STENCIL_BUFFER_BIT; mask &= ~GL_STENCIL_BUFFER_BIT;
} }
...@@ -3890,8 +3892,8 @@ void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *valu ...@@ -3890,8 +3892,8 @@ void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *valu
{ {
attachment = framebufferObject->getDepthAttachment(); attachment = framebufferObject->getDepthAttachment();
} }
if (buffer == GL_COLOR && else if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments()) static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{ {
attachment = framebufferObject->getColorAttachment(drawbuffer); attachment = framebufferObject->getColorAttachment(drawbuffer);
} }
...@@ -3942,8 +3944,8 @@ void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values ...@@ -3942,8 +3944,8 @@ void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values
{ {
attachment = framebufferObject->getStencilAttachment(); attachment = framebufferObject->getStencilAttachment();
} }
if (buffer == GL_COLOR && else if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments()) static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{ {
attachment = framebufferObject->getColorAttachment(drawbuffer); attachment = framebufferObject->getColorAttachment(drawbuffer);
} }
......
...@@ -1460,8 +1460,10 @@ angle::Result Framebuffer::clearBufferfi(const Context *context, ...@@ -1460,8 +1460,10 @@ angle::Result Framebuffer::clearBufferfi(const Context *context,
GLfloat depth, GLfloat depth,
GLint stencil) GLint stencil)
{ {
bool clearDepth = context->getState().getDepthStencilState().depthMask; const bool clearDepth =
bool clearStencil = context->getState().getDepthStencilState().stencilWritemask != 0; getDepthAttachment() != nullptr && context->getState().getDepthStencilState().depthMask;
const bool clearStencil = getStencilAttachment() != nullptr &&
context->getState().getDepthStencilState().stencilWritemask != 0;
if (clearDepth && clearStencil) if (clearDepth && clearStencil)
{ {
......
...@@ -433,20 +433,14 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -433,20 +433,14 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
// This function assumes that only enabled attachments are asked to be cleared. // This function assumes that only enabled attachments are asked to be cleared.
ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers); ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
ASSERT(!clearDepth || mState.getDepthAttachment() != nullptr);
// Adjust clear behavior based on whether the respective attachments are present; if asked to ASSERT(!clearStencil || mState.getStencilAttachment() != nullptr);
// clear a non-existent attachment, don't attempt to clear it.
gl::BlendStateExt::ColorMaskStorage::Type colorMasks = contextVk->getClearColorMasks(); gl::BlendStateExt::ColorMaskStorage::Type colorMasks = contextVk->getClearColorMasks();
bool clearColor = clearColorBuffers.any(); bool clearColor = clearColorBuffers.any();
const gl::FramebufferAttachment *depthAttachment = mState.getDepthAttachment(); // When this function is called, there should always be something to clear.
clearDepth = clearDepth && depthAttachment; ASSERT(clearColor || clearDepth || clearStencil);
ASSERT(!clearDepth || depthAttachment->isAttached());
const gl::FramebufferAttachment *stencilAttachment = mState.getStencilAttachment();
clearStencil = clearStencil && stencilAttachment;
ASSERT(!clearStencil || stencilAttachment->isAttached());
const uint8_t stencilMask = const uint8_t stencilMask =
static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask); static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask);
...@@ -460,15 +454,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -460,15 +454,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
const bool scissoredClear = scissoredRenderArea != getRotatedCompleteRenderArea(contextVk); const bool scissoredClear = scissoredRenderArea != getRotatedCompleteRenderArea(contextVk);
// If there is nothing to clear, return right away (for example, if asked to clear depth, but
// there is no depth attachment).
if (!clearColor && !clearDepth && !clearStencil)
{
// We can sometimes get to a clear operation with other pending clears (e.g. for emulated
// formats). Ensure the prior clears happen if new clear is no-op.
return flushDeferredClears(contextVk, scissoredRenderArea);
}
// We use the draw path if scissored clear, or color or stencil are masked. Note that depth // We use the draw path if scissored clear, or color or stencil are masked. Note that depth
// clearing is already disabled if there's a depth mask. // clearing is already disabled if there's a depth mask.
const bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) != const bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) !=
......
...@@ -1744,6 +1744,60 @@ TEST_P(VulkanClearTest, Test) ...@@ -1744,6 +1744,60 @@ TEST_P(VulkanClearTest, Test)
maskedScissoredColorDepthStencilClear(GetParam()); maskedScissoredColorDepthStencilClear(GetParam());
} }
// Tests that clearing a non existing attachment works.
TEST_P(ClearTest, ClearColorThenClearNonExistingDepthStencil)
{
constexpr GLsizei kSize = 16;
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear color.
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Clear depth/stencil.
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Read back color.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
// Tests that clearing a non existing attachment works.
TEST_P(ClearTestES3, ClearDepthStencilThenClearNonExistingColor)
{
constexpr GLsizei kSize = 16;
GLRenderbuffer depth;
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth);
ASSERT_GL_NO_ERROR();
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear depth/stencil.
glClearDepthf(1.0f);
glClearStencil(0xAA);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Clear color.
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
}
// 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
// assert. // assert.
TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert) TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert)
...@@ -2271,6 +2325,34 @@ TEST_P(ClearTestES3, ClearBufferfiStencilMask) ...@@ -2271,6 +2325,34 @@ TEST_P(ClearTestES3, ClearBufferfiStencilMask)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Test that glClearBufferfi works when stencil attachment is not present.
TEST_P(ClearTestES3, ClearBufferfiNoStencilAttachment)
{
constexpr GLsizei kSize = 16;
GLRenderbuffer color;
glBindRenderbuffer(GL_RENDERBUFFER, color);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize);
GLRenderbuffer depth;
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, kSize, kSize);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
EXPECT_GL_NO_ERROR();
// Clear depth/stencil with glClearBufferfi. Note that the stencil attachment doesn't exist.
glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.5f, 0x55);
EXPECT_GL_NO_ERROR();
// Verify depth is cleared correctly.
verifyDepth(0.5f, kSize);
}
#ifdef Bool #ifdef Bool
// X11 craziness. // X11 craziness.
# undef Bool # undef Bool
......
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