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( ...@@ -4690,6 +4690,8 @@ angle::Result ContextVk::beginNewRenderPass(
// Restart at subpass 0. // Restart at subpass 0.
mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition); mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
mPerfCounters.renderPasses++;
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4715,8 +4717,6 @@ angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea, ...@@ -4715,8 +4717,6 @@ angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
*commandBufferOut = mRenderPassCommandBuffer; *commandBufferOut = mRenderPassCommandBuffer;
} }
mPerfCounters.renderPasses++;
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -422,12 +422,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -422,12 +422,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
return angle::Result::Continue; 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. // This function assumes that only enabled attachments are asked to be cleared.
ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers); ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
...@@ -445,7 +439,7 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -445,7 +439,7 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
clearStencil = clearStencil && stencilAttachment; clearStencil = clearStencil && stencilAttachment;
ASSERT(!clearStencil || stencilAttachment->isAttached()); ASSERT(!clearStencil || stencilAttachment->isAttached());
uint8_t stencilMask = const uint8_t stencilMask =
static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask); 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. // 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, ...@@ -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. // The front-end should ensure we don't attempt to clear stencil if all bits are masked.
ASSERT(!clearStencil || stencilMask != 0); 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 // If there is nothing to clear, return right away (for example, if asked to clear depth, but
// there is no depth attachment). // there is no depth attachment).
if (!clearColor && !clearDepth && !clearStencil) 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 // We use the draw path if scissored clear, or color or stencil are masked. Note that depth
// there's a depth mask, depth clearing is already disabled. // clearing is already disabled if there's a depth mask.
bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) != const bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) !=
mActiveColorComponentMasksForClear; mActiveColorComponentMasksForClear;
bool maskedClearStencil = clearStencil && stencilMask != 0xFF; const bool maskedClearStencil = clearStencil && stencilMask != 0xFF;
bool clearColorWithRenderPassLoadOp = clearColor && !maskedClearColor && !scissoredClear;
bool clearDepthWithRenderPassLoadOp = clearDepth && !scissoredClear;
bool clearStencilWithRenderPassLoadOp = clearStencil && !maskedClearStencil && !scissoredClear;
// At least one of color, depth or stencil should be clearable with render pass loadOp for us bool clearColorWithDraw = clearColor && (maskedClearColor || scissoredClear);
// to use this clear path. bool clearDepthWithDraw = clearDepth && scissoredClear;
bool clearAnyWithRenderPassLoadOp = clearColorWithRenderPassLoadOp || bool clearStencilWithDraw = clearStencil && (maskedClearStencil || scissoredClear);
clearDepthWithRenderPassLoadOp ||
clearStencilWithRenderPassLoadOp;
if (clearAnyWithRenderPassLoadOp)
{
vk::Framebuffer *currentFramebuffer = nullptr; vk::Framebuffer *currentFramebuffer = nullptr;
ANGLE_TRY(getFramebuffer(contextVk, &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
{
gl::DrawBufferMask clearColorDrawBuffersMask; gl::DrawBufferMask clearColorDrawBuffersMask;
if (clearColorWithRenderPassLoadOp) if (clearColor && !clearColorWithDraw)
{ {
clearColorDrawBuffersMask = clearColorBuffers; 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 // If we are in an active renderpass that has recorded commands and the framebuffer hasn't
// changed, inline the clear // changed, inline the clear
if (contextVk->hasStartedRenderPassWithCommands() && if (isMidRenderPassClear)
contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer))
{ {
ANGLE_PERF_WARNING( ANGLE_PERF_WARNING(
contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW, contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW,
"Clear effectively discarding previous draw call results. Suggest earlier Clear " "Clear effectively discarding previous draw call results. Suggest earlier Clear "
"followed by masked color or depth/stencil draw calls instead"); "followed by masked color or depth/stencil draw calls instead");
RendererVk *renderer = contextVk->getRenderer(); ASSERT(!preferDrawOverClearAttachments);
bool clearAnyWithCommand = clearAnyWithRenderPassLoadOp;
// On buggy hardware, prefer to clear with a draw call instead of vkCmdClearAttachments.
if (renderer->getFeatures().preferDrawClearOverVkCmdClearAttachments.enabled)
{
clearColorWithRenderPassLoadOp = false;
clearDepthWithRenderPassLoadOp = false;
clearStencilWithRenderPassLoadOp = false;
clearAnyWithCommand = false;
}
if (clearAnyWithCommand) // clearWithCommand will operate on deferred clears.
{ ANGLE_TRY(clearWithCommand(contextVk, &contextVk->getStartedRenderPassCommands(),
ANGLE_TRY(clearWithCommand( scissoredRenderArea));
contextVk, &contextVk->getStartedRenderPassCommands(), scissoredRenderArea,
clearColorDrawBuffersMask, clearDepthWithRenderPassLoadOp,
clearStencilWithRenderPassLoadOp, clearColorValue, clearDepthStencilValue));
}
} }
else else
{ {
ANGLE_TRY(clearWithLoadOp( // This path will defer the current clears along with deferred clears. This won't work
contextVk, clearColorDrawBuffersMask, clearDepthWithRenderPassLoadOp, // if any attachment needs to be subsequently cleared with a draw call. In that case,
clearStencilWithRenderPassLoadOp, clearColorValue, clearDepthStencilValue)); // 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)
// Fallback to other methods for whatever isn't cleared here.
if (clearColorWithRenderPassLoadOp)
{ {
clearColorBuffers.reset(); ANGLE_TRY(flushDeferredClears(contextVk, scissoredRenderArea));
clearColor = false;
} }
if (clearDepthWithRenderPassLoadOp) else
{ {
clearDepth = false; // 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));
} }
if (clearStencilWithRenderPassLoadOp)
{
clearStencil = false;
} }
// If nothing left to clear, early out. // If nothing left to clear, early out.
if (!clearColor && !clearDepth && !clearStencil) if (!clearAnyWithDraw)
{ {
ASSERT(mDeferredClears.empty());
return angle::Result::Continue; 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 // 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. // bits. This can only be done with a draw call.
return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepth, return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepthWithDraw,
clearStencil, colorMasks, stencilMask, clearColorValue, clearStencilWithDraw, colorMasks, stencilMask, clearColorValue,
clearDepthStencilValue); clearDepthStencilValue);
} }
...@@ -1968,6 +1984,43 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, ...@@ -1968,6 +1984,43 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
return angle::Result::Continue; 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, angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea, const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
...@@ -1978,6 +2031,9 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk, ...@@ -1978,6 +2031,9 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue) const VkClearDepthStencilValue &clearDepthStencilValue)
{ {
// All deferred clears should be handled already.
ASSERT(mDeferredClears.empty());
UtilsVk::ClearFramebufferParameters params = {}; UtilsVk::ClearFramebufferParameters params = {};
params.clearArea = clearArea; params.clearArea = clearArea;
params.colorClearValue = clearColorValue; params.colorClearValue = clearColorValue;
...@@ -2055,62 +2111,64 @@ VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL, ...@@ -2055,62 +2111,64 @@ VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL,
return clearValue; return clearValue;
} }
angle::Result FramebufferVk::clearWithLoadOp(ContextVk *contextVk, angle::Result FramebufferVk::clearWithLoadOp(ContextVk *contextVk)
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{ {
// Set the appropriate loadOp and clear values for depth and stencil. // Set the appropriate loadOp and clear values for depth and stencil.
VkImageAspectFlags dsAspectFlags = 0; 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; dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
mDeferredClears.reset(vk::kUnpackedDepthIndex);
} }
if (clearStencil) if (mDeferredClears.testStencil())
{ {
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; 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()) if (contextVk->hasStartedRenderPass())
{ {
vk::CommandBufferHelper &commands = contextVk->getStartedRenderPassCommands(); vk::CommandBufferHelper &commands = contextVk->getStartedRenderPassCommands();
ASSERT(commands.getCommandBuffer().empty()); ASSERT(commands.getCommandBuffer().empty());
// Go through deferred clears and update render pass loadOp and clear colors.
vk::PackedAttachmentIndex colorIndexVk(0); vk::PackedAttachmentIndex colorIndexVk(0);
for (size_t colorIndexGL : mState.getColorAttachmentsMask()) for (size_t colorIndexGL : mDeferredClears.getColorMask())
{ {
if (mState.getEnabledDrawBuffers()[colorIndexGL] && clearColorBuffers[colorIndexGL]) ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
{
VkClearValue clearValue = commands.updateRenderPassColorClear(colorIndexVk, mDeferredClears[colorIndexGL]);
getCorrectedColorClearValue(colorIndexGL, clearColorValue); mDeferredClears.reset(colorIndexGL);
commands.updateRenderPassColorClear(colorIndexVk, clearValue);
}
++colorIndexVk; ++colorIndexVk;
} }
if (dsAspectFlags) if (dsAspectFlags)
{ {
VkClearValue clearValue; commands.updateRenderPassDepthStencilClear(dsAspectFlags, dsClearValue);
clearValue.depthStencil = clearDepthStencilValue;
commands.updateRenderPassDepthStencilClear(dsAspectFlags, clearValue);
// If we were in depth read only mode, we must change to write mode // If we were in depth read only mode, we must change to write mode
updateRenderPassReadOnlyDepthMode(contextVk, &commands); updateRenderPassReadOnlyDepthMode(contextVk, &commands);
} }
} }
else 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)); ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
RenderTargetVk *renderTarget = getColorDrawRenderTarget(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, renderTarget->getImageForWrite().stageClear(imageIndex, VK_IMAGE_ASPECT_COLOR_BIT,
clearValue); mDeferredClears[colorIndexGL]);
mDeferredClears.reset(colorIndexGL);
} }
if (dsAspectFlags) if (dsAspectFlags)
...@@ -2118,55 +2176,50 @@ angle::Result FramebufferVk::clearWithLoadOp(ContextVk *contextVk, ...@@ -2118,55 +2176,50 @@ angle::Result FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
RenderTargetVk *renderTarget = getDepthStencilRenderTarget(); RenderTargetVk *renderTarget = getDepthStencilRenderTarget();
ASSERT(renderTarget); ASSERT(renderTarget);
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
gl::ImageIndex imageIndex = renderTarget->getImageIndex(); gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, clearValue); renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, dsClearValue);
} }
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result FramebufferVk::clearWithCommand( angle::Result FramebufferVk::clearWithCommand(ContextVk *contextVk,
ContextVk *contextVk,
vk::CommandBufferHelper *renderpassCommands, vk::CommandBufferHelper *renderpassCommands,
const gl::Rectangle &scissoredRenderArea, const gl::Rectangle &scissoredRenderArea)
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{ {
gl::AttachmentVector<VkClearAttachment> attachments; gl::AttachmentVector<VkClearAttachment> attachments;
// Go through clearColorBuffers and add them to the list of attachments to clear. // Go through deferred clears and add them to the list of attachments to clear.
for (size_t colorIndexGL : clearColorBuffers) for (size_t colorIndexGL : mDeferredClears.getColorMask())
{ {
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL)); 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()); 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. // Add depth and stencil to list of attachments as needed.
VkImageAspectFlags dsAspectFlags = 0; VkImageAspectFlags dsAspectFlags = 0;
VkClearValue dsClearValue = {}; VkClearValue dsClearValue;
if (clearDepth) dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue();
dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
if (mDeferredClears.testDepth())
{ {
dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
dsClearValue.depthStencil = clearDepthStencilValue;
// Explicitly mark a depth write because we are clearing the depth buffer. // Explicitly mark a depth write because we are clearing the depth buffer.
renderpassCommands->onDepthAccess(vk::ResourceAccess::Write); renderpassCommands->onDepthAccess(vk::ResourceAccess::Write);
mDeferredClears.reset(vk::kUnpackedDepthIndex);
} }
if (clearStencil) if (mDeferredClears.testStencil())
{ {
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
dsClearValue.depthStencil = clearDepthStencilValue;
// Explicitly mark a stencil write because we are clearing the stencil buffer. // Explicitly mark a stencil write because we are clearing the stencil buffer.
renderpassCommands->onStencilAccess(vk::ResourceAccess::Write); renderpassCommands->onStencilAccess(vk::ResourceAccess::Write);
mDeferredClears.reset(vk::kUnpackedStencilIndex);
} }
if (dsAspectFlags != 0) if (dsAspectFlags != 0)
......
...@@ -172,29 +172,24 @@ class FramebufferVk : public FramebufferImpl ...@@ -172,29 +172,24 @@ class FramebufferVk : public FramebufferImpl
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk, void mergeClearsWithDeferredClears(gl::DrawBufferMask clearColorBuffers,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
bool clearStencil, bool clearStencil,
gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
uint8_t stencilMask,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithLoadOp(ContextVk *contextVk, angle::Result clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
bool clearStencil, bool clearStencil,
gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
uint8_t stencilMask,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithLoadOp(ContextVk *contextVk);
angle::Result clearWithCommand(ContextVk *contextVk, angle::Result clearWithCommand(ContextVk *contextVk,
vk::CommandBufferHelper *renderpassCommands, vk::CommandBufferHelper *renderpassCommands,
const gl::Rectangle &scissoredRenderArea, const gl::Rectangle &scissoredRenderArea);
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a); void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a);
void updateRenderPassDesc(); void updateRenderPassDesc();
angle::Result updateColorAttachment(const gl::Context *context, angle::Result updateColorAttachment(const gl::Context *context,
......
...@@ -1081,7 +1081,7 @@ class UniformsAndXfbDesc ...@@ -1081,7 +1081,7 @@ class UniformsAndXfbDesc
// In the FramebufferDesc object: // In the FramebufferDesc object:
// - Depth/stencil serial is at index 0 // - 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 // - Depth/stencil resolve attachment is at index gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+1
// - Resolve attachments are at indices [gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+2, // - Resolve attachments are at indices [gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+2,
// gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2+1] // gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2+1]
......
...@@ -757,6 +757,13 @@ void ClearValuesArray::storeNoDepthStencil(uint32_t index, const VkClearValue &c ...@@ -757,6 +757,13 @@ void ClearValuesArray::storeNoDepthStencil(uint32_t index, const VkClearValue &c
mEnabled.set(index); 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 implementation.
ResourceSerialFactory::ResourceSerialFactory() : mCurrentUniqueSerial(1) {} ResourceSerialFactory::ResourceSerialFactory() : mCurrentUniqueSerial(1) {}
......
...@@ -711,6 +711,7 @@ class ClearValuesArray final ...@@ -711,6 +711,7 @@ class ClearValuesArray final
bool test(size_t index) const { return mEnabled.test(index); } bool test(size_t index) const { return mEnabled.test(index); }
bool testDepth() const { return mEnabled.test(kUnpackedDepthIndex); } bool testDepth() const { return mEnabled.test(kUnpackedDepthIndex); }
bool testStencil() const { return mEnabled.test(kUnpackedStencilIndex); } bool testStencil() const { return mEnabled.test(kUnpackedStencilIndex); }
gl::DrawBufferMask getColorMask() const;
const VkClearValue &operator[](size_t index) const { return mValues[index]; } const VkClearValue &operator[](size_t index) const { return mValues[index]; }
......
...@@ -1897,6 +1897,81 @@ TEST_P(ClearTestES3, ClearMaxAttachmentsAfterDraw) ...@@ -1897,6 +1897,81 @@ TEST_P(ClearTestES3, ClearMaxAttachmentsAfterDraw)
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green); 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 #ifdef Bool
// X11 craziness. // X11 craziness.
# undef Bool # undef Bool
......
...@@ -2366,6 +2366,154 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout) ...@@ -2366,6 +2366,154 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
EXPECT_EQ(expectedReadOnlyDepthStencilCount, actualReadOnlyDepthStencilCount); 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, ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest_ES31, ES31_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