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)
}
// 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;
}
// 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;
}
......@@ -3890,8 +3892,8 @@ void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *valu
{
attachment = framebufferObject->getDepthAttachment();
}
if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
else if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
}
......@@ -3942,8 +3944,8 @@ void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values
{
attachment = framebufferObject->getStencilAttachment();
}
if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
else if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
}
......
......@@ -1460,8 +1460,10 @@ angle::Result Framebuffer::clearBufferfi(const Context *context,
GLfloat depth,
GLint stencil)
{
bool clearDepth = context->getState().getDepthStencilState().depthMask;
bool clearStencil = context->getState().getDepthStencilState().stencilWritemask != 0;
const bool clearDepth =
getDepthAttachment() != nullptr && context->getState().getDepthStencilState().depthMask;
const bool clearStencil = getStencilAttachment() != nullptr &&
context->getState().getDepthStencilState().stencilWritemask != 0;
if (clearDepth && clearStencil)
{
......
......@@ -433,20 +433,14 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
// This function assumes that only enabled attachments are asked to be cleared.
ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
// Adjust clear behavior based on whether the respective attachments are present; if asked to
// clear a non-existent attachment, don't attempt to clear it.
ASSERT(!clearDepth || mState.getDepthAttachment() != nullptr);
ASSERT(!clearStencil || mState.getStencilAttachment() != nullptr);
gl::BlendStateExt::ColorMaskStorage::Type colorMasks = contextVk->getClearColorMasks();
bool clearColor = clearColorBuffers.any();
const gl::FramebufferAttachment *depthAttachment = mState.getDepthAttachment();
clearDepth = clearDepth && depthAttachment;
ASSERT(!clearDepth || depthAttachment->isAttached());
const gl::FramebufferAttachment *stencilAttachment = mState.getStencilAttachment();
clearStencil = clearStencil && stencilAttachment;
ASSERT(!clearStencil || stencilAttachment->isAttached());
// When this function is called, there should always be something to clear.
ASSERT(clearColor || clearDepth || clearStencil);
const uint8_t stencilMask =
static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask);
......@@ -460,15 +454,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
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
// clearing is already disabled if there's a depth mask.
const bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) !=
......
......@@ -1744,6 +1744,60 @@ TEST_P(VulkanClearTest, Test)
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
// assert.
TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert)
......@@ -2271,6 +2325,34 @@ TEST_P(ClearTestES3, ClearBufferfiStencilMask)
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
// X11 craziness.
# 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