Commit e416c92a by Shahbaz Youssefi Committed by Commit Bot

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: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com>
parent 96a49a48
...@@ -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;
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; 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. // clearWithCommand will operate on deferred clears.
if (renderer->getFeatures().preferDrawClearOverVkCmdClearAttachments.enabled) 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; ANGLE_TRY(flushDeferredClears(contextVk, scissoredRenderArea));
clearDepthWithRenderPassLoadOp = false;
clearStencilWithRenderPassLoadOp = false;
clearAnyWithCommand = false;
} }
else
if (clearAnyWithCommand)
{ {
ANGLE_TRY(clearWithCommand( // clearWithLoadOp will operate on deferred clears. Either these will affect the
contextVk, &contextVk->getStartedRenderPassCommands(), scissoredRenderArea, // currently open render pass' loadOps, or will be re-staged. The latter will
clearColorDrawBuffersMask, clearDepthWithRenderPassLoadOp, // further defer these clears.
clearStencilWithRenderPassLoadOp, clearColorValue, clearDepthStencilValue)); 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 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,6 +172,11 @@ class FramebufferVk : public FramebufferImpl ...@@ -172,6 +172,11 @@ class FramebufferVk : public FramebufferImpl
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
void mergeClearsWithDeferredClears(gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk, angle::Result clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea, const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
...@@ -181,20 +186,10 @@ class FramebufferVk : public FramebufferImpl ...@@ -181,20 +186,10 @@ class FramebufferVk : public FramebufferImpl
uint8_t stencilMask, uint8_t stencilMask,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithLoadOp(ContextVk *contextVk, angle::Result clearWithLoadOp(ContextVk *contextVk);
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
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