Commit 16102e8b by Tim Van Patten Committed by Commit Bot

Reland "Vulkan: Fold deferred clears into current clears"

This reverts commit 37c40014. Reason for revert: Need to clear the package cache when bisecting. Original change's description: > Revert "Vulkan: Fold deferred clears into current clears" > > This reverts commit e416c92a. > > Reason for revert: Reverted parent: > https://chromium-review.googlesource.com/c/angle/angle/+/2481612 > > Original change's description: > > Vulkan: Fold deferred clears into current clears > > > > If there are clears prior to a glClear() call, those clears were > > flushed (starting a new render pass) and then the clear call's clears > > would be applied (essentially modifying the loadOps of said render > > pass). > > > > The main downside of the above is that the current glClear() clears > > don't get a chance to be deferred. This was observed in Chrome which > > clears an attachment with an emulated format, then switches > > framebuffers. > > > > Additionally, if the render pass had already been started, the deferred > > clears could have become inlined instead of breaking the render pass. > > Although, it's unlikely for there to be deferred clears when the render > > pass is already open. > > > > This change first identifies which clears need to go through the draw > > path (scissored, masked or as workaround for driver bug). It merges the > > rest of the clears (that don't need the draw path) with the deferred > > clears. It then checks deferred clears and applies them by either: > > > > - vkCmdClearAttachments if mid RP > > - Start a new render pass and use loadOps, if any draw-based clear needs > > to follow. > > - Modify current RP loadOps / defer the clear > > > > Afterwards, the draw-based clears are applied. > > > > Bug: angleproject:4836 > > Change-Id: Id4992c78983b199734508c9d4bb18ed3195c91ec > > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2455167 > > Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> > > Reviewed-by: Jamie Madill <jmadill@chromium.org> > > Reviewed-by: Charlie Lao <cclao@google.com> > > TBR=syoussefi@chromium.org,jmadill@chromium.org,cclao@google.com > > Change-Id: I85733b3594409df9b96e3d5b34933522c97c42cf > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: angleproject:4836 > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2481613 > Reviewed-by: Tim Van Patten <timvp@google.com> > Commit-Queue: Tim Van Patten <timvp@google.com> TBR=timvp@google.com,syoussefi@chromium.org,jmadill@chromium.org,cclao@google.com # Not skipping CQ checks because this is a reland. Bug: angleproject:4836 Change-Id: I702cd510f39ee46feab27d4efbf61ae5da10d4e2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2481856Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Tim Van Patten <timvp@google.com>
parent d3e7ed93
......@@ -4690,6 +4690,8 @@ angle::Result ContextVk::beginNewRenderPass(
// Restart at subpass 0.
mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
mPerfCounters.renderPasses++;
return angle::Result::Continue;
}
......@@ -4715,8 +4717,6 @@ angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
*commandBufferOut = mRenderPassCommandBuffer;
}
mPerfCounters.renderPasses++;
return angle::Result::Continue;
}
......
......@@ -422,12 +422,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
return angle::Result::Continue;
}
// We can sometimes get to a clear operation with other pending clears (e.g. for emulated
// formats). Ensure the prior clears happen before the new clear. Note that we do not defer
// clears for scissored operations. Note that some clears may be redundant with the current
// clear. Due to complexity we haven't implemented de-duplication here.
ANGLE_TRY(flushDeferredClears(contextVk, scissoredRenderArea));
// This function assumes that only enabled attachments are asked to be cleared.
ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
......@@ -445,7 +439,7 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
clearStencil = clearStencil && stencilAttachment;
ASSERT(!clearStencil || stencilAttachment->isAttached());
uint8_t stencilMask =
const uint8_t stencilMask =
static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask);
// The front-end should ensure we don't attempt to clear color if all channels are masked.
......@@ -455,105 +449,127 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
// The front-end should ensure we don't attempt to clear stencil if all bits are masked.
ASSERT(!clearStencil || stencilMask != 0);
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)
{
return angle::Result::Continue;
// 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 can use render pass load ops if clearing depth, unmasked color or unmasked stencil. If
// there's a depth mask, depth clearing is already disabled.
bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) !=
mActiveColorComponentMasksForClear;
bool maskedClearStencil = clearStencil && stencilMask != 0xFF;
bool clearColorWithRenderPassLoadOp = clearColor && !maskedClearColor && !scissoredClear;
bool clearDepthWithRenderPassLoadOp = clearDepth && !scissoredClear;
bool clearStencilWithRenderPassLoadOp = clearStencil && !maskedClearStencil && !scissoredClear;
// 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) !=
mActiveColorComponentMasksForClear;
const bool maskedClearStencil = clearStencil && stencilMask != 0xFF;
// At least one of color, depth or stencil should be clearable with render pass loadOp for us
// to use this clear path.
bool clearAnyWithRenderPassLoadOp = clearColorWithRenderPassLoadOp ||
clearDepthWithRenderPassLoadOp ||
clearStencilWithRenderPassLoadOp;
bool clearColorWithDraw = clearColor && (maskedClearColor || scissoredClear);
bool clearDepthWithDraw = clearDepth && scissoredClear;
bool clearStencilWithDraw = clearStencil && (maskedClearStencil || scissoredClear);
if (clearAnyWithRenderPassLoadOp)
vk::Framebuffer *currentFramebuffer = nullptr;
ANGLE_TRY(getFramebuffer(contextVk, &currentFramebuffer, nullptr));
const bool isMidRenderPassClear =
contextVk->hasStartedRenderPassWithCommands() &&
contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer);
const bool preferDrawOverClearAttachments =
contextVk->getRenderer()->getFeatures().preferDrawClearOverVkCmdClearAttachments.enabled;
// Merge current clears with the deferred clears, then proceed with only processing deferred
// clears. This simplifies the clear paths such that they don't need to consider both the
// current and deferred clears. Additionally, it avoids needing to undo an unresolve
// operation; say attachment A is deferred cleared and multisampled-render-to-texture
// attachment B is currently cleared. Assuming a render pass needs to start (because for
// example attachment C needs to clear with a draw path), starting one with only deferred
// clears and then applying the current clears won't work as attachment B is unresolved, and
// there are no facilities to undo that.
if (preferDrawOverClearAttachments && isMidRenderPassClear)
{
// On buggy hardware, prefer to clear with a draw call instead of vkCmdClearAttachments.
// In this case, flush deferred clears and don't merge current clears (so they take the draw
// path). Note that this path could be optimized by a clearWithDraw-like call that operates
// on mDeferredClears. However, having deferred clears mid-render-pass is rare (if at all
// possible).
ANGLE_TRY(flushDeferredClears(contextVk, scissoredRenderArea));
clearColorWithDraw = clearColor;
clearDepthWithDraw = clearDepth;
clearStencilWithDraw = clearStencil;
}
else
{
vk::Framebuffer *currentFramebuffer = nullptr;
ANGLE_TRY(getFramebuffer(contextVk, &currentFramebuffer, nullptr));
gl::DrawBufferMask clearColorDrawBuffersMask;
if (clearColorWithRenderPassLoadOp)
if (clearColor && !clearColorWithDraw)
{
clearColorDrawBuffersMask = clearColorBuffers;
}
mergeClearsWithDeferredClears(clearColorDrawBuffersMask, clearDepth && !clearDepthWithDraw,
clearStencil && !clearStencilWithDraw, clearColorValue,
clearDepthStencilValue);
}
// If any deferred clears, we can further defer them, modify the current render pass' loadOps,
// or clear them with vkCmdClearAttachments.
if (mDeferredClears.any())
{
const bool clearAnyWithDraw =
clearColorWithDraw || clearDepthWithDraw || clearStencilWithDraw;
// If we are in an active renderpass that has recorded commands and the framebuffer hasn't
// changed, inline the clear
if (contextVk->hasStartedRenderPassWithCommands() &&
contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer))
if (isMidRenderPassClear)
{
ANGLE_PERF_WARNING(
contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW,
"Clear effectively discarding previous draw call results. Suggest earlier Clear "
"followed by masked color or depth/stencil draw calls instead");
RendererVk *renderer = contextVk->getRenderer();
bool clearAnyWithCommand = clearAnyWithRenderPassLoadOp;
ASSERT(!preferDrawOverClearAttachments);
// On buggy hardware, prefer to clear with a draw call instead of vkCmdClearAttachments.
if (renderer->getFeatures().preferDrawClearOverVkCmdClearAttachments.enabled)
// clearWithCommand will operate on deferred clears.
ANGLE_TRY(clearWithCommand(contextVk, &contextVk->getStartedRenderPassCommands(),
scissoredRenderArea));
}
else
{
// This path will defer the current clears along with deferred clears. This won't work
// if any attachment needs to be subsequently cleared with a draw call. In that case,
// flush deferred clears, which will start a render pass with deferred clear values.
// The subsequent draw call will then operate on the cleared attachments.
if (!contextVk->hasStartedRenderPass() && clearAnyWithDraw)
{
clearColorWithRenderPassLoadOp = false;
clearDepthWithRenderPassLoadOp = false;
clearStencilWithRenderPassLoadOp = false;
clearAnyWithCommand = false;
ANGLE_TRY(flushDeferredClears(contextVk, scissoredRenderArea));
}
if (clearAnyWithCommand)
else
{
ANGLE_TRY(clearWithCommand(
contextVk, &contextVk->getStartedRenderPassCommands(), scissoredRenderArea,
clearColorDrawBuffersMask, clearDepthWithRenderPassLoadOp,
clearStencilWithRenderPassLoadOp, clearColorValue, clearDepthStencilValue));
// clearWithLoadOp will operate on deferred clears. Either these will affect the
// currently open render pass' loadOps, or will be re-staged. The latter will
// further defer these clears.
ANGLE_TRY(clearWithLoadOp(contextVk));
}
}
else
{
ANGLE_TRY(clearWithLoadOp(
contextVk, clearColorDrawBuffersMask, clearDepthWithRenderPassLoadOp,
clearStencilWithRenderPassLoadOp, clearColorValue, clearDepthStencilValue));
}
// Fallback to other methods for whatever isn't cleared here.
if (clearColorWithRenderPassLoadOp)
{
clearColorBuffers.reset();
clearColor = false;
}
if (clearDepthWithRenderPassLoadOp)
{
clearDepth = false;
}
if (clearStencilWithRenderPassLoadOp)
{
clearStencil = false;
}
// If nothing left to clear, early out.
if (!clearColor && !clearDepth && !clearStencil)
if (!clearAnyWithDraw)
{
ASSERT(mDeferredClears.empty());
return angle::Result::Continue;
}
}
if (!clearColorWithDraw)
{
clearColorBuffers.reset();
}
// The most costly clear mode is when we need to mask out specific color channels or stencil
// bits. This can only be done with a draw call.
return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepth,
clearStencil, colorMasks, stencilMask, clearColorValue,
return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepthWithDraw,
clearStencilWithDraw, colorMasks, stencilMask, clearColorValue,
clearDepthStencilValue);
}
......@@ -1968,6 +1984,43 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
return angle::Result::Continue;
}
void FramebufferVk::mergeClearsWithDeferredClears(
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{
// Apply clears to mDeferredClears. Note that clears override deferred clears.
// Color clears.
for (size_t colorIndexGL : clearColorBuffers)
{
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
mDeferredClears.store(static_cast<uint32_t>(colorIndexGL), VK_IMAGE_ASPECT_COLOR_BIT,
clearValue);
}
// Depth and stencil clears.
VkImageAspectFlags dsAspectFlags = 0;
VkClearValue dsClearValue;
dsClearValue.depthStencil = clearDepthStencilValue;
if (clearDepth)
{
dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (clearStencil)
{
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (dsAspectFlags != 0)
{
mDeferredClears.store(vk::kUnpackedDepthIndex, dsAspectFlags, dsClearValue);
}
}
angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
......@@ -1978,6 +2031,9 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{
// All deferred clears should be handled already.
ASSERT(mDeferredClears.empty());
UtilsVk::ClearFramebufferParameters params = {};
params.clearArea = clearArea;
params.colorClearValue = clearColorValue;
......@@ -2055,62 +2111,64 @@ VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL,
return clearValue;
}
angle::Result FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
angle::Result FramebufferVk::clearWithLoadOp(ContextVk *contextVk)
{
// Set the appropriate loadOp and clear values for depth and stencil.
VkImageAspectFlags dsAspectFlags = 0;
if (clearDepth)
VkClearValue dsClearValue;
dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue();
dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
if (mDeferredClears.testDepth())
{
dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
mDeferredClears.reset(vk::kUnpackedDepthIndex);
}
if (clearStencil)
if (mDeferredClears.testStencil())
{
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
mDeferredClears.reset(vk::kUnpackedStencilIndex);
}
// If the render pass has started, modify its ops directly. Note that the render pass should
// otherwise not have any commands in it.
if (contextVk->hasStartedRenderPass())
{
vk::CommandBufferHelper &commands = contextVk->getStartedRenderPassCommands();
ASSERT(commands.getCommandBuffer().empty());
// Go through deferred clears and update render pass loadOp and clear colors.
vk::PackedAttachmentIndex colorIndexVk(0);
for (size_t colorIndexGL : mState.getColorAttachmentsMask())
for (size_t colorIndexGL : mDeferredClears.getColorMask())
{
if (mState.getEnabledDrawBuffers()[colorIndexGL] && clearColorBuffers[colorIndexGL])
{
VkClearValue clearValue =
getCorrectedColorClearValue(colorIndexGL, clearColorValue);
commands.updateRenderPassColorClear(colorIndexVk, clearValue);
}
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
commands.updateRenderPassColorClear(colorIndexVk, mDeferredClears[colorIndexGL]);
mDeferredClears.reset(colorIndexGL);
++colorIndexVk;
}
if (dsAspectFlags)
{
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
commands.updateRenderPassDepthStencilClear(dsAspectFlags, clearValue);
commands.updateRenderPassDepthStencilClear(dsAspectFlags, dsClearValue);
// If we were in depth read only mode, we must change to write mode
updateRenderPassReadOnlyDepthMode(contextVk, &commands);
}
}
else
{
for (size_t colorIndexGL : clearColorBuffers)
// Go through deferred clears and stage the clears for future.
for (size_t colorIndexGL : mDeferredClears.getColorMask())
{
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, VK_IMAGE_ASPECT_COLOR_BIT,
clearValue);
mDeferredClears[colorIndexGL]);
mDeferredClears.reset(colorIndexGL);
}
if (dsAspectFlags)
......@@ -2118,55 +2176,50 @@ angle::Result FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
RenderTargetVk *renderTarget = getDepthStencilRenderTarget();
ASSERT(renderTarget);
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, clearValue);
renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, dsClearValue);
}
}
return angle::Result::Continue;
}
angle::Result FramebufferVk::clearWithCommand(
ContextVk *contextVk,
vk::CommandBufferHelper *renderpassCommands,
const gl::Rectangle &scissoredRenderArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
angle::Result FramebufferVk::clearWithCommand(ContextVk *contextVk,
vk::CommandBufferHelper *renderpassCommands,
const gl::Rectangle &scissoredRenderArea)
{
gl::AttachmentVector<VkClearAttachment> attachments;
// Go through clearColorBuffers and add them to the list of attachments to clear.
for (size_t colorIndexGL : clearColorBuffers)
// Go through deferred clears and add them to the list of attachments to clear.
for (size_t colorIndexGL : mDeferredClears.getColorMask())
{
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
attachments.emplace_back(VkClearAttachment{
VK_IMAGE_ASPECT_COLOR_BIT, static_cast<uint32_t>(colorIndexGL), clearValue});
ASSERT(getColorDrawRenderTarget(colorIndexGL)->hasDefinedContent());
attachments.emplace_back(VkClearAttachment{VK_IMAGE_ASPECT_COLOR_BIT,
static_cast<uint32_t>(colorIndexGL),
mDeferredClears[colorIndexGL]});
mDeferredClears.reset(colorIndexGL);
}
// Add depth and stencil to list of attachments as needed.
VkImageAspectFlags dsAspectFlags = 0;
VkClearValue dsClearValue = {};
if (clearDepth)
VkClearValue dsClearValue;
dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue();
dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
if (mDeferredClears.testDepth())
{
dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
dsClearValue.depthStencil = clearDepthStencilValue;
// Explicitly mark a depth write because we are clearing the depth buffer.
renderpassCommands->onDepthAccess(vk::ResourceAccess::Write);
mDeferredClears.reset(vk::kUnpackedDepthIndex);
}
if (clearStencil)
if (mDeferredClears.testStencil())
{
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
dsClearValue.depthStencil = clearDepthStencilValue;
// Explicitly mark a stencil write because we are clearing the stencil buffer.
renderpassCommands->onStencilAccess(vk::ResourceAccess::Write);
mDeferredClears.reset(vk::kUnpackedStencilIndex);
}
if (dsAspectFlags != 0)
......
......@@ -172,6 +172,11 @@ class FramebufferVk : public FramebufferImpl
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
void mergeClearsWithDeferredClears(gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
......@@ -181,20 +186,10 @@ class FramebufferVk : public FramebufferImpl
uint8_t stencilMask,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithLoadOp(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithLoadOp(ContextVk *contextVk);
angle::Result clearWithCommand(ContextVk *contextVk,
vk::CommandBufferHelper *renderpassCommands,
const gl::Rectangle &scissoredRenderArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
const gl::Rectangle &scissoredRenderArea);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a);
void updateRenderPassDesc();
angle::Result updateColorAttachment(const gl::Context *context,
......
......@@ -1081,7 +1081,7 @@ class UniformsAndXfbDesc
// In the FramebufferDesc object:
// - Depth/stencil serial is at index 0
// - Color serials are at indices [1:gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]
// - Color serials are at indices [1, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]
// - Depth/stencil resolve attachment is at index gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+1
// - Resolve attachments are at indices [gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+2,
// gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2+1]
......
......@@ -757,6 +757,13 @@ void ClearValuesArray::storeNoDepthStencil(uint32_t index, const VkClearValue &c
mEnabled.set(index);
}
gl::DrawBufferMask ClearValuesArray::getColorMask() const
{
constexpr uint32_t kColorBuffersMask =
angle::Bit<uint32_t>(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS) - 1;
return gl::DrawBufferMask(mEnabled.bits() & kColorBuffersMask);
}
// ResourceSerialFactory implementation.
ResourceSerialFactory::ResourceSerialFactory() : mCurrentUniqueSerial(1) {}
......
......@@ -711,6 +711,7 @@ class ClearValuesArray final
bool test(size_t index) const { return mEnabled.test(index); }
bool testDepth() const { return mEnabled.test(kUnpackedDepthIndex); }
bool testStencil() const { return mEnabled.test(kUnpackedStencilIndex); }
gl::DrawBufferMask getColorMask() const;
const VkClearValue &operator[](size_t index) const { return mValues[index]; }
......
......@@ -1897,6 +1897,81 @@ TEST_P(ClearTestES3, ClearMaxAttachmentsAfterDraw)
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green);
}
// Test that mixed masked clear works after clear.
TEST_P(ClearTestES3, ClearThenMixedMaskedClear)
{
constexpr GLsizei kSize = 16;
GLint maxDrawBuffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
ASSERT_GE(maxDrawBuffers, 4);
// Setup framebuffer.
GLRenderbuffer color;
glBindRenderbuffer(GL_RENDERBUFFER, color);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize);
GLRenderbuffer depthStencil;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize);
GLFramebuffer fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
EXPECT_GL_NO_ERROR();
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear color and depth/stencil
glClearColor(0.1f, 1.0f, 0.0f, 0.7f);
glClearDepthf(0.0f);
glClearStencil(0x55);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Clear again, but with color and stencil masked
glClearColor(1.0f, 0.2f, 0.6f, 1.0f);
glClearDepthf(1.0f);
glClearStencil(0x3C);
glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
glStencilMask(0xF0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Issue a draw call to verify color, depth and stencil.
// If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not cleared to 0x35, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x35, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
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);
// Blend half-transparent blue into the color buffer.
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 0.5f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
// Verify that the color buffer is now gray
const GLColor kExpected(127, 127, 127, 191);
EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
}
#ifdef Bool
// X11 craziness.
# undef Bool
......
......@@ -2366,6 +2366,154 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
EXPECT_EQ(expectedReadOnlyDepthStencilCount, actualReadOnlyDepthStencilCount);
}
// Ensures repeated clears of various kind (all attachments, some attachments, scissored, masked
// etc) don't break the render pass.
TEST_P(VulkanPerformanceCounterTest, ClearAfterClearDoesNotBreakRenderPass)
{
const rx::vk::PerfCounters &counters = hackANGLE();
uint32_t expectedRenderPassCount = counters.renderPasses + 1;
GLFramebuffer FBO;
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
constexpr GLsizei kSize = 6;
// Create a framebuffer to clear with both color and depth/stencil attachments.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLTexture depth;
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, kSize, kSize, 0, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8_OES, nullptr);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
ASSERT_GL_NO_ERROR();
// Clear color and depth, but not stencil.
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepthf(0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Clear color and stencil, but not depth.
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClearStencil(0x11);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Clear depth and stencil, but not color.
glClearDepthf(0.1f);
glClearStencil(0x22);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Clear masked color, and unmasked depth.
glClearDepthf(0.2f);
glClearColor(0.1f, 1.0f, 0.0f, 1.0f);
glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Clear unmasked color, and masked stencil.
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearStencil(0x33);
glStencilMask(0xF0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Clear unmasked depth and stencil.
glClearDepthf(0.3f);
glClearStencil(0x44);
glStencilMask(0xFF);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Clear with scissor.
glEnable(GL_SCISSOR_TEST);
glScissor(kSize / 3, kSize / 3, kSize / 3, kSize / 3);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClearDepthf(1.0f);
glClearStencil(0x55);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Verify render pass count.
EXPECT_EQ(counters.renderPasses, expectedRenderPassCount);
// Make sure the result is correct. The border of the image should be blue with depth 0.3f and
// stencil 0x44. The center is red with depth 1.0f and stencil 0x55.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, kSize / 3, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3 - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, 2 * kSize / 3 - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::red);
glViewport(0, 0, kSize, kSize);
glDisable(GL_SCISSOR_TEST);
// Center: If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Center: If stencil is not clear to 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
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 green
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
// Verify that only the center has changed
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, kSize / 3, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3 - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, 2 * kSize / 3 - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::green);
// Border: If depth is not cleared to 0.3f, rendering would fail.
glDepthFunc(GL_LESS);
// Center: If stencil is not clear to 0x44, rendering would fail.
glStencilFunc(GL_EQUAL, 0x44, 0xFF);
// Draw yellow
glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), -0.5f);
ASSERT_GL_NO_ERROR();
// Verify that only the border has changed
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, kSize / 3, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3 - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, 2 * kSize / 3 - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::green);
}
ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest, ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest_ES31, ES31_VULKAN());
......
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