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(
// 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