Commit d657e1d7 by Jamie Madill Committed by Commit Bot

Vulkan: Defer framebuffer clears.

This works by storing the deferred clears in the ImageHelper's staging buffers. We apply the deferred clears onto the RenderPass right before we begin to draw. Storing the clears in the ImageHelper solves problems where we clear GL Textures in a Framebuffer and then unbind the Textures and sample from them. Or do other commands like CopyTexImage. Note that because the staging buffer clears only handle full-image clears we need to immediately apply some scissored clears where before we would use the RP. This should be a pretty rare occurrence and it is possible to optimize that in the future. Reduces the RenderPass count in the Manhattan "frame 10" trace from max 22 to max 20. May improve perf slightly on Android or may have effects too small to measure. Should not regress performance. Bug: angleproject:4517 Change-Id: I02150d531022afb903f1058f070937ec6337bd88 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2142711Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 3b0c01f4
...@@ -711,6 +711,8 @@ using ShaderVector = angle::FixedVector<T, static_cast<size_t>(ShaderType::EnumC ...@@ -711,6 +711,8 @@ using ShaderVector = angle::FixedVector<T, static_cast<size_t>(ShaderType::EnumC
template <typename T> template <typename T>
using AttachmentArray = std::array<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>; using AttachmentArray = std::array<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
using AttachmentsMask = angle::BitSet<IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
template <typename T> template <typename T>
using DrawBuffersArray = std::array<T, IMPLEMENTATION_MAX_DRAW_BUFFERS>; using DrawBuffersArray = std::array<T, IMPLEMENTATION_MAX_DRAW_BUFFERS>;
......
...@@ -47,10 +47,6 @@ namespace rx ...@@ -47,10 +47,6 @@ namespace rx
namespace namespace
{ {
// The value to assign an alpha channel that's emulated. The type is unsigned int, though it will
// automatically convert to the actual data type.
constexpr unsigned int kEmulatedAlphaValue = 1;
// For shader uniforms such as gl_DepthRange and the viewport size. // For shader uniforms such as gl_DepthRange and the viewport size.
struct GraphicsDriverUniforms struct GraphicsDriverUniforms
{ {
...@@ -972,7 +968,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, ...@@ -972,7 +968,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
if (!mRenderPassCommandBuffer) if (!mRenderPassCommandBuffer)
{ {
gl::Rectangle scissoredRenderArea = mDrawFramebuffer->getScissoredRenderArea(this); gl::Rectangle scissoredRenderArea = mDrawFramebuffer->getScissoredRenderArea(this);
ANGLE_TRY(startRenderPass(scissoredRenderArea)); ANGLE_TRY(startRenderPass(scissoredRenderArea, nullptr));
} }
// We keep a local copy of the command buffer. It's possible that some state changes could // We keep a local copy of the command buffer. It's possible that some state changes could
...@@ -2298,112 +2294,6 @@ angle::Result ContextVk::drawElementsIndirect(const gl::Context *context, ...@@ -2298,112 +2294,6 @@ angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ContextVk::clearWithRenderPassOp(
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{
// Validate cache variable is in sync.
ASSERT(mDrawFramebuffer == vk::GetImpl(mState.getDrawFramebuffer()));
// Start a new render pass if:
//
// - no render pass has started,
// - there is a render pass started but it contains commands; we cannot modify its ops, so new
// render pass is needed,
// - the current render area doesn't match the clear area. We need the render area to be
// exactly as specified by the scissor for the loadOp to clear only that area. See
// ContextVk::updateScissor for more information.
if (!mRenderPassCommands.started() ||
(mRenderPassCommands.started() && !mRenderPassCommands.empty()) ||
mRenderPassCommands.getRenderArea() != clearArea)
{
ANGLE_TRY(startRenderPass(clearArea));
}
else
{
flushOutsideRenderPassCommands();
}
size_t attachmentIndexVk = 0;
// Go through clearColorBuffers and set the appropriate loadOp and clear values.
for (size_t colorIndexGL : mDrawFramebuffer->getState().getEnabledDrawBuffers())
{
if (clearColorBuffers.test(colorIndexGL))
{
RenderTargetVk *renderTarget = mDrawFramebuffer->getColorDrawRenderTarget(colorIndexGL);
// If the render target doesn't have alpha, but its emulated format has it, clear the
// alpha to 1.
VkClearColorValue value = clearColorValue;
if (mDrawFramebuffer->getEmulatedAlphaAttachmentMask()[colorIndexGL])
{
const vk::Format &format = renderTarget->getImageFormat();
if (format.vkFormatIsInt)
{
if (format.vkFormatIsUnsigned)
{
value.uint32[3] = kEmulatedAlphaValue;
}
else
{
value.int32[3] = kEmulatedAlphaValue;
}
}
else
{
value.float32[3] = kEmulatedAlphaValue;
}
}
mRenderPassCommands.clearRenderPassColorAttachment(attachmentIndexVk, value);
}
++attachmentIndexVk;
}
// Set the appropriate loadOp and clear values for depth and stencil.
RenderTargetVk *depthStencilRenderTarget = mDrawFramebuffer->getDepthStencilRenderTarget();
if (depthStencilRenderTarget)
{
const vk::Format &format = depthStencilRenderTarget->getImageFormat();
if (format.hasEmulatedImageChannels())
{
if (format.intendedFormat().stencilBits == 0)
{
// If the format we picked has stencil but user did not ask for
// it due to hardware limitation, force clear the stencil so
// that no load will happen. Also don't try to store stencil
// value as well. Same logic for depth bits bellow.
mRenderPassCommands.invalidateRenderPassStencilAttachment(attachmentIndexVk);
clearStencil = true;
}
if (format.intendedFormat().depthBits == 0)
{
mRenderPassCommands.invalidateRenderPassDepthAttachment(attachmentIndexVk);
clearDepth = true;
}
}
if (clearDepth)
{
mRenderPassCommands.clearRenderPassDepthAttachment(attachmentIndexVk,
clearDepthStencilValue.depth);
}
if (clearStencil)
{
mRenderPassCommands.clearRenderPassStencilAttachment(attachmentIndexVk,
clearDepthStencilValue.stencil);
}
}
return angle::Result::Continue;
}
void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle) void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
{ {
if (!mRenderPassCommands.started()) if (!mRenderPassCommands.started())
...@@ -4244,7 +4134,7 @@ angle::Result ContextVk::flushAndBeginRenderPass( ...@@ -4244,7 +4134,7 @@ angle::Result ContextVk::flushAndBeginRenderPass(
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const vk::RenderPassDesc &renderPassDesc, const vk::RenderPassDesc &renderPassDesc,
const vk::AttachmentOpsArray &renderPassAttachmentOps, const vk::AttachmentOpsArray &renderPassAttachmentOps,
const std::vector<VkClearValue> &clearValues, const vk::ClearValuesArray &clearValues,
vk::CommandBuffer **commandBufferOut) vk::CommandBuffer **commandBufferOut)
{ {
// Flush any outside renderPass commands first // Flush any outside renderPass commands first
...@@ -4267,7 +4157,8 @@ angle::Result ContextVk::flushAndBeginRenderPass( ...@@ -4267,7 +4157,8 @@ angle::Result ContextVk::flushAndBeginRenderPass(
return angle::Result::Continue; return angle::Result::Continue;
} }
ANGLE_INLINE angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea) angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
vk::CommandBuffer **commandBufferOut)
{ {
mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits; mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer)); ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer));
...@@ -4281,6 +4172,12 @@ ANGLE_INLINE angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea) ...@@ -4281,6 +4172,12 @@ ANGLE_INLINE angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea)
mActiveQueryAnySamplesConservative->getQueryHelper()->beginOcclusionQuery( mActiveQueryAnySamplesConservative->getQueryHelper()->beginOcclusionQuery(
this, mRenderPassCommandBuffer); this, mRenderPassCommandBuffer);
} }
if (commandBufferOut)
{
*commandBufferOut = mRenderPassCommandBuffer;
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4639,7 +4536,7 @@ void RenderPassCommandBuffer::beginRenderPass(const vk::Framebuffer &framebuffer ...@@ -4639,7 +4536,7 @@ void RenderPassCommandBuffer::beginRenderPass(const vk::Framebuffer &framebuffer
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const vk::RenderPassDesc &renderPassDesc, const vk::RenderPassDesc &renderPassDesc,
const vk::AttachmentOpsArray &renderPassAttachmentOps, const vk::AttachmentOpsArray &renderPassAttachmentOps,
const std::vector<VkClearValue> &clearValues, const vk::ClearValuesArray &clearValues,
vk::CommandBuffer **commandBufferOut) vk::CommandBuffer **commandBufferOut)
{ {
ASSERT(empty()); ASSERT(empty());
...@@ -4647,8 +4544,8 @@ void RenderPassCommandBuffer::beginRenderPass(const vk::Framebuffer &framebuffer ...@@ -4647,8 +4544,8 @@ void RenderPassCommandBuffer::beginRenderPass(const vk::Framebuffer &framebuffer
mRenderPassDesc = renderPassDesc; mRenderPassDesc = renderPassDesc;
mAttachmentOps = renderPassAttachmentOps; mAttachmentOps = renderPassAttachmentOps;
mFramebuffer.setHandle(framebuffer.getHandle()); mFramebuffer.setHandle(framebuffer.getHandle());
mRenderArea = renderArea; mRenderArea = renderArea;
std::copy(clearValues.begin(), clearValues.end(), mClearValues.begin()); mClearValues = clearValues;
*commandBufferOut = &mCommandBuffer; *commandBufferOut = &mCommandBuffer;
......
...@@ -180,31 +180,13 @@ class RenderPassCommandBuffer final : public CommandBufferHelper ...@@ -180,31 +180,13 @@ class RenderPassCommandBuffer final : public CommandBufferHelper
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const vk::RenderPassDesc &renderPassDesc, const vk::RenderPassDesc &renderPassDesc,
const vk::AttachmentOpsArray &renderPassAttachmentOps, const vk::AttachmentOpsArray &renderPassAttachmentOps,
const std::vector<VkClearValue> &clearValues, const vk::ClearValuesArray &clearValues,
vk::CommandBuffer **commandBufferOut); vk::CommandBuffer **commandBufferOut);
void beginTransformFeedback(size_t validBufferCount, void beginTransformFeedback(size_t validBufferCount,
const VkBuffer *counterBuffers, const VkBuffer *counterBuffers,
bool rebindBuffer); bool rebindBuffer);
void clearRenderPassColorAttachment(size_t attachmentIndex, const VkClearColorValue &clearValue)
{
SetBitField(mAttachmentOps[attachmentIndex].loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
mClearValues[attachmentIndex].color = clearValue;
}
void clearRenderPassDepthAttachment(size_t attachmentIndex, float depth)
{
SetBitField(mAttachmentOps[attachmentIndex].loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
SetBitField(mClearValues[attachmentIndex].depthStencil.depth, depth);
}
void clearRenderPassStencilAttachment(size_t attachmentIndex, uint32_t stencil)
{
SetBitField(mAttachmentOps[attachmentIndex].stencilLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
SetBitField(mClearValues[attachmentIndex].depthStencil.stencil, stencil);
}
void invalidateRenderPassColorAttachment(size_t attachmentIndex) void invalidateRenderPassColorAttachment(size_t attachmentIndex)
{ {
SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE); SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
...@@ -254,7 +236,7 @@ class RenderPassCommandBuffer final : public CommandBufferHelper ...@@ -254,7 +236,7 @@ class RenderPassCommandBuffer final : public CommandBufferHelper
vk::AttachmentOpsArray mAttachmentOps; vk::AttachmentOpsArray mAttachmentOps;
vk::Framebuffer mFramebuffer; vk::Framebuffer mFramebuffer;
gl::Rectangle mRenderArea; gl::Rectangle mRenderArea;
gl::AttachmentArray<VkClearValue> mClearValues; vk::ClearValuesArray mClearValues;
bool mRenderPassStarted; bool mRenderPassStarted;
// Transform feedback state // Transform feedback state
...@@ -351,12 +333,6 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -351,12 +333,6 @@ class ContextVk : public ContextImpl, public vk::Context
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
gl::DrawElementsType type, gl::DrawElementsType type,
const void *indirect) override; const void *indirect) override;
angle::Result clearWithRenderPassOp(const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
// Device loss // Device loss
gl::GraphicsResetStatus getResetStatus() override; gl::GraphicsResetStatus getResetStatus() override;
...@@ -663,7 +639,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -663,7 +639,7 @@ class ContextVk : public ContextImpl, public vk::Context
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const vk::RenderPassDesc &renderPassDesc, const vk::RenderPassDesc &renderPassDesc,
const vk::AttachmentOpsArray &renderPassAttachmentOps, const vk::AttachmentOpsArray &renderPassAttachmentOps,
const std::vector<VkClearValue> &clearValues, const vk::ClearValuesArray &clearValues,
vk::CommandBuffer **commandBufferOut); vk::CommandBuffer **commandBufferOut);
bool hasStartedRenderPass() const { return !mRenderPassCommands.empty(); } bool hasStartedRenderPass() const { return !mRenderPassCommands.empty(); }
...@@ -675,7 +651,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -675,7 +651,7 @@ class ContextVk : public ContextImpl, public vk::Context
} }
egl::ContextPriority getContextPriority() const override { return mContextPriority; } egl::ContextPriority getContextPriority() const override { return mContextPriority; }
angle::Result startRenderPass(gl::Rectangle renderArea); angle::Result startRenderPass(gl::Rectangle renderArea, vk::CommandBuffer **commandBufferOut);
angle::Result endRenderPass(); angle::Result endRenderPass();
angle::Result syncExternalMemory(); angle::Result syncExternalMemory();
......
...@@ -110,7 +110,7 @@ class FramebufferVk : public FramebufferImpl ...@@ -110,7 +110,7 @@ class FramebufferVk : public FramebufferImpl
RenderTargetVk *getColorDrawRenderTarget(size_t colorIndex) const; RenderTargetVk *getColorDrawRenderTarget(size_t colorIndex) const;
RenderTargetVk *getColorReadRenderTarget() const; RenderTargetVk *getColorReadRenderTarget() const;
angle::Result startNewRenderPass(ContextVk *context, angle::Result startNewRenderPass(ContextVk *contextVk,
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
vk::CommandBuffer **commandBufferOut); vk::CommandBuffer **commandBufferOut);
...@@ -160,22 +160,33 @@ class FramebufferVk : public FramebufferImpl ...@@ -160,22 +160,33 @@ class FramebufferVk : public FramebufferImpl
angle::Result clearWithDraw(ContextVk *contextVk, angle::Result clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea, const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil, bool clearStencil,
VkColorComponentFlags colorMaskFlags, VkColorComponentFlags colorMaskFlags,
uint8_t stencilMask, uint8_t stencilMask,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
uint8_t clearStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
void clearWithRenderPassOp(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, size_t colorIndex); angle::Result updateColorAttachment(const gl::Context *context,
bool deferClears,
uint32_t colorIndex);
angle::Result invalidateImpl(ContextVk *contextVk, size_t count, const GLenum *attachments); angle::Result invalidateImpl(ContextVk *contextVk, size_t count, const GLenum *attachments);
// Release all FramebufferVk objects in the cache and clear cache // Release all FramebufferVk objects in the cache and clear cache
void clearCache(ContextVk *contextVk); void clearCache(ContextVk *contextVk);
angle::Result updateDepthStencilAttachment(const gl::Context *context, bool deferClears);
void updateDepthStencilAttachmentSerial(ContextVk *contextVk); void updateDepthStencilAttachmentSerial(ContextVk *contextVk);
RenderTargetVk *getReadPixelsRenderTarget(GLenum format) const; RenderTargetVk *getReadPixelsRenderTarget(GLenum format) const;
VkImageAspectFlagBits getReadPixelsAspectFlags(GLenum format) const; VkImageAspectFlagBits getReadPixelsAspectFlags(GLenum format) const;
angle::Result flushDeferredClears(ContextVk *contextVk, const gl::Rectangle &renderArea);
WindowSurfaceVk *mBackbuffer; WindowSurfaceVk *mBackbuffer;
vk::RenderPassDesc mRenderPassDesc; vk::RenderPassDesc mRenderPassDesc;
...@@ -197,6 +208,8 @@ class FramebufferVk : public FramebufferImpl ...@@ -197,6 +208,8 @@ class FramebufferVk : public FramebufferImpl
vk::FramebufferDesc mCurrentFramebufferDesc; vk::FramebufferDesc mCurrentFramebufferDesc;
std::unordered_map<vk::FramebufferDesc, vk::FramebufferHelper> mFramebufferCache; std::unordered_map<vk::FramebufferDesc, vk::FramebufferHelper> mFramebufferCache;
bool mSupportDepthStencilFeedbackLoops; bool mSupportDepthStencilFeedbackLoops;
vk::ClearValuesArray mDeferredClears;
}; };
} // namespace rx } // namespace rx
......
...@@ -144,20 +144,47 @@ vk::ImageHelper *RenderTargetVk::getImageForWrite(ContextVk *contextVk) const ...@@ -144,20 +144,47 @@ vk::ImageHelper *RenderTargetVk::getImageForWrite(ContextVk *contextVk) const
return mImage; return mImage;
} }
angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk) angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
vk::ClearValuesArray *deferredClears,
uint32_t deferredClearIndex) const
{ {
// Note that the layer index for 3D textures is always zero according to Vulkan.
uint32_t layerIndex = mLayerIndex;
if (mImage->getType() == VK_IMAGE_TYPE_3D)
{
layerIndex = 0;
}
ASSERT(mImage->valid()); ASSERT(mImage->valid());
if (!mImage->hasStagedUpdates()) if (!mImage->isUpdateStaged(mLevelIndex, layerIndex))
return angle::Result::Continue; return angle::Result::Continue;
vk::CommandBuffer *commandBuffer; vk::CommandBuffer *commandBuffer;
ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer)); ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
return mImage->flushStagedUpdates(contextVk, mLevelIndex, mLevelIndex + 1, mLayerIndex, return mImage->flushSingleSubresourceStagedUpdates(
mLayerIndex + 1, commandBuffer); contextVk, mLevelIndex, layerIndex, commandBuffer, deferredClears, deferredClearIndex);
} }
void RenderTargetVk::retainImageViews(ContextVk *contextVk) const void RenderTargetVk::retainImageViews(ContextVk *contextVk) const
{ {
mImageViews->retain(&contextVk->getResourceUseList()); mImageViews->retain(&contextVk->getResourceUseList());
} }
gl::ImageIndex RenderTargetVk::getImageIndex() const
{
// Determine the GL type from the Vk Image properties.
if (mImage->getType() == VK_IMAGE_TYPE_3D)
{
return gl::ImageIndex::Make3D(mLevelIndex, mLayerIndex);
}
// We don't need to distinguish 2D array and cube.
if (mImage->getLayerCount() > 1)
{
return gl::ImageIndex::Make2DArray(mLevelIndex, mLayerIndex);
}
ASSERT(mLayerIndex == 0);
return gl::ImageIndex::Make2D(mLevelIndex);
}
} // namespace rx } // namespace rx
...@@ -68,11 +68,15 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -68,11 +68,15 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
uint32_t getLevelIndex() const { return mLevelIndex; } uint32_t getLevelIndex() const { return mLevelIndex; }
uint32_t getLayerIndex() const { return mLayerIndex; } uint32_t getLayerIndex() const { return mLayerIndex; }
gl::ImageIndex getImageIndex() const;
// Special mutator for Surface RenderTargets. Allows the Framebuffer to keep a single // Special mutator for Surface RenderTargets. Allows the Framebuffer to keep a single
// RenderTargetVk pointer. // RenderTargetVk pointer.
void updateSwapchainImage(vk::ImageHelper *image, vk::ImageViewHelper *imageViews); void updateSwapchainImage(vk::ImageHelper *image, vk::ImageViewHelper *imageViews);
angle::Result flushStagedUpdates(ContextVk *contextVk); angle::Result flushStagedUpdates(ContextVk *contextVk,
vk::ClearValuesArray *deferredClears,
uint32_t deferredClearIndex) const;
void retainImageViews(ContextVk *contextVk) const; void retainImageViews(ContextVk *contextVk) const;
...@@ -92,7 +96,6 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -92,7 +96,6 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
// A vector of rendertargets // A vector of rendertargets
using RenderTargetVector = std::vector<RenderTargetVk>; using RenderTargetVector = std::vector<RenderTargetVk>;
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_ #endif // LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_
...@@ -158,7 +158,6 @@ angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *conte ...@@ -158,7 +158,6 @@ angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *conte
FramebufferAttachmentRenderTarget **rtOut) FramebufferAttachmentRenderTarget **rtOut)
{ {
ASSERT(mImage && mImage->valid()); ASSERT(mImage && mImage->valid());
ANGLE_TRY(mRenderTarget.flushStagedUpdates(vk::GetImpl(context)));
*rtOut = &mRenderTarget; *rtOut = &mRenderTarget;
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -167,7 +166,7 @@ angle::Result RenderbufferVk::initializeContents(const gl::Context *context, ...@@ -167,7 +166,7 @@ angle::Result RenderbufferVk::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) const gl::ImageIndex &imageIndex)
{ {
// Note: stageSubresourceRobustClear only uses the intended format to count channels. // Note: stageSubresourceRobustClear only uses the intended format to count channels.
mImage->stageSubresourceClear(imageIndex); mImage->stageRobustResourceClear(imageIndex);
return mImage->flushAllStagedUpdates(vk::GetImpl(context)); return mImage->flushAllStagedUpdates(vk::GetImpl(context));
} }
......
...@@ -122,17 +122,13 @@ angle::Result SurfaceVk::getAttachmentRenderTarget(const gl::Context *context, ...@@ -122,17 +122,13 @@ angle::Result SurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
GLsizei samples, GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) FramebufferAttachmentRenderTarget **rtOut)
{ {
ContextVk *contextVk = vk::GetImpl(context);
if (binding == GL_BACK) if (binding == GL_BACK)
{ {
ANGLE_TRY(mColorRenderTarget.flushStagedUpdates(contextVk));
*rtOut = &mColorRenderTarget; *rtOut = &mColorRenderTarget;
} }
else else
{ {
ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL); ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
ANGLE_TRY(mDepthStencilRenderTarget.flushStagedUpdates(contextVk));
*rtOut = &mDepthStencilRenderTarget; *rtOut = &mDepthStencilRenderTarget;
} }
...@@ -365,13 +361,13 @@ angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context, ...@@ -365,13 +361,13 @@ angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context,
if (mColorAttachment.image.valid()) if (mColorAttachment.image.valid())
{ {
mColorAttachment.image.stageSubresourceClear(imageIndex); mColorAttachment.image.stageRobustResourceClear(imageIndex);
ANGLE_TRY(mColorAttachment.image.flushAllStagedUpdates(contextVk)); ANGLE_TRY(mColorAttachment.image.flushAllStagedUpdates(contextVk));
} }
if (mDepthStencilAttachment.image.valid()) if (mDepthStencilAttachment.image.valid())
{ {
mDepthStencilAttachment.image.stageSubresourceClear(imageIndex); mDepthStencilAttachment.image.stageRobustResourceClear(imageIndex);
ANGLE_TRY(mDepthStencilAttachment.image.flushAllStagedUpdates(contextVk)); ANGLE_TRY(mDepthStencilAttachment.image.flushAllStagedUpdates(contextVk));
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1353,6 +1349,12 @@ VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context) ...@@ -1353,6 +1349,12 @@ VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context)
mColorRenderTarget.updateSwapchainImage(&image.image, &image.imageViews); mColorRenderTarget.updateSwapchainImage(&image.image, &image.imageViews);
} }
// Notify the owning framebuffer there may be staged updates.
if (image.image.hasStagedUpdates())
{
onStateChange(angle::SubjectMessage::SubjectChanged);
}
return VK_SUCCESS; return VK_SUCCESS;
} }
...@@ -1574,12 +1576,12 @@ angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context, ...@@ -1574,12 +1576,12 @@ angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,
vk::ImageHelper *image = vk::ImageHelper *image =
isMultiSampled() ? &mColorImageMS : &mSwapchainImages[mCurrentSwapchainImageIndex].image; isMultiSampled() ? &mColorImageMS : &mSwapchainImages[mCurrentSwapchainImageIndex].image;
image->stageSubresourceClear(imageIndex); image->stageRobustResourceClear(imageIndex);
ANGLE_TRY(image->flushAllStagedUpdates(contextVk)); ANGLE_TRY(image->flushAllStagedUpdates(contextVk));
if (mDepthStencilImage.valid()) if (mDepthStencilImage.valid())
{ {
mDepthStencilImage.stageSubresourceClear(gl::ImageIndex::Make2D(0)); mDepthStencilImage.stageRobustResourceClear(gl::ImageIndex::Make2D(0));
ANGLE_TRY(mDepthStencilImage.flushAllStagedUpdates(contextVk)); ANGLE_TRY(mDepthStencilImage.flushAllStagedUpdates(contextVk));
} }
......
...@@ -967,7 +967,9 @@ angle::Result TextureVk::redefineImage(const gl::Context *context, ...@@ -967,7 +967,9 @@ angle::Result TextureVk::redefineImage(const gl::Context *context,
{ {
// If there is any staged changes for this index, we can remove them since we're going to // If there is any staged changes for this index, we can remove them since we're going to
// override them with this call. // override them with this call.
mImage->removeStagedUpdates(contextVk, index); uint32_t levelIndex = index.getLevelIndex();
uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
mImage->removeStagedUpdates(contextVk, levelIndex, layerIndex);
if (mImage->valid()) if (mImage->valid())
{ {
...@@ -1370,7 +1372,19 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context, ...@@ -1370,7 +1372,19 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
ASSERT(imageIndex.getLevelIndex() >= 0); ASSERT(imageIndex.getLevelIndex() >= 0);
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
if (!mImage->valid())
{
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
const gl::Extents &baseLevelExtents = baseLevelDesc.size;
const uint32_t levelCount = getMipLevelCount(ImageMipLevels::EnabledLevels);
const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
ANGLE_TRY(initImage(contextVk, format, baseLevelDesc.format.info->sized, baseLevelExtents,
levelCount));
}
// Don't flush staged updates here. We'll handle that in FramebufferVk so it can defer clears.
GLuint layerIndex = 0, layerCount = 0; GLuint layerIndex = 0, layerCount = 0;
GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerCount, &layerIndex); GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerCount, &layerIndex);
...@@ -1522,10 +1536,9 @@ angle::Result TextureVk::initializeContents(const gl::Context *context, ...@@ -1522,10 +1536,9 @@ angle::Result TextureVk::initializeContents(const gl::Context *context,
contextVk->getRenderer()->getFormat(desc.format.info->sizedInternalFormat); contextVk->getRenderer()->getFormat(desc.format.info->sizedInternalFormat);
ASSERT(mImage); ASSERT(mImage);
// Note that we cannot ensure the image is initialized because we might be calling subImage // Note that we cannot ensure the image is initialized because we might be calling subImage
// on a non-complete cube map. // on a non-complete cube map.
return mImage->stageRobustResourceClear(contextVk, desc.size, imageIndex, format); return mImage->stageRobustResourceClearWithFormat(contextVk, imageIndex, desc.size, format);
} }
void TextureVk::releaseOwnershipOfImage(const gl::Context *context) void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
......
...@@ -1186,8 +1186,8 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk, ...@@ -1186,8 +1186,8 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk,
ANGLE_VK_TRY(contextVk, framebuffer.init(contextVk->getDevice(), framebufferInfo)); ANGLE_VK_TRY(contextVk, framebuffer.init(contextVk->getDevice(), framebufferInfo));
vk::AttachmentOpsArray renderPassAttachmentOps; vk::AttachmentOpsArray renderPassAttachmentOps;
std::vector<VkClearValue> clearValues = {{}}; vk::ClearValuesArray clearValues;
ASSERT(clearValues.size() == 1); clearValues.store(0, VK_IMAGE_ASPECT_COLOR_BIT, {});
renderPassAttachmentOps.initWithLoadStore(0, vk::ImageLayout::ColorAttachment, renderPassAttachmentOps.initWithLoadStore(0, vk::ImageLayout::ColorAttachment,
vk::ImageLayout::ColorAttachment); vk::ImageLayout::ColorAttachment);
...@@ -1210,7 +1210,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -1210,7 +1210,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
const gl::Rectangle &scissoredRenderArea = params.clearArea; const gl::Rectangle &scissoredRenderArea = params.clearArea;
vk::CommandBuffer *commandBuffer; vk::CommandBuffer *commandBuffer;
ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, scissoredRenderArea, &commandBuffer)); ANGLE_TRY(contextVk->startRenderPass(scissoredRenderArea, &commandBuffer));
ImageClearShaderParams shaderParams; ImageClearShaderParams shaderParams;
shaderParams.clearValue = params.colorClearValue; shaderParams.clearValue = params.colorClearValue;
......
...@@ -432,7 +432,7 @@ const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &ima ...@@ -432,7 +432,7 @@ const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &ima
} }
} }
VkClearValue GetClearValue(const vk::Format &format) VkClearValue GetRobustResourceClearValue(const vk::Format &format)
{ {
VkClearValue clearValue; VkClearValue clearValue;
if (format.intendedFormat().hasDepthOrStencilBits()) if (format.intendedFormat().hasDepthOrStencilBits())
...@@ -2646,12 +2646,11 @@ void ImageHelper::resolve(ImageHelper *dest, ...@@ -2646,12 +2646,11 @@ void ImageHelper::resolve(ImageHelper *dest,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region); VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
} }
void ImageHelper::removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index) void ImageHelper::removeStagedUpdates(ContextVk *contextVk,
uint32_t levelIndex,
uint32_t layerIndex)
{ {
// Find any staged updates for this index and removes them from the pending list. // Find any staged updates for this index and removes them from the pending list.
uint32_t levelIndex = index.getLevelIndex();
uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
for (size_t index = 0; index < mSubresourceUpdates.size();) for (size_t index = 0; index < mSubresourceUpdates.size();)
{ {
auto update = mSubresourceUpdates.begin() + index; auto update = mSubresourceUpdates.begin() + index;
...@@ -3139,26 +3138,34 @@ void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image, ...@@ -3139,26 +3138,34 @@ void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image,
appendSubresourceUpdate(SubresourceUpdate(image, copyToImage)); appendSubresourceUpdate(SubresourceUpdate(image, copyToImage));
} }
void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index) void ImageHelper::stageClear(const gl::ImageIndex &index,
VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue)
{
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
}
void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
{ {
const VkImageAspectFlags aspectFlags = getAspectFlags(); const VkImageAspectFlags aspectFlags = getAspectFlags();
ASSERT(mFormat); ASSERT(mFormat);
VkClearValue clearValue = GetClearValue(*mFormat); VkClearValue clearValue = GetRobustResourceClearValue(*mFormat);
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index)); appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
} }
angle::Result ImageHelper::stageRobustResourceClear(ContextVk *contextVk, angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
const gl::Extents &glExtents, const gl::ImageIndex &index,
const gl::ImageIndex &index, const gl::Extents &glExtents,
const vk::Format &format) const vk::Format &format)
{ {
const angle::Format &imageFormat = format.actualImageFormat(); const angle::Format &imageFormat = format.actualImageFormat();
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat); const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
// Robust clears must only be staged if we do not have any prior data for this subresource. // Robust clears must only be staged if we do not have any prior data for this subresource.
ASSERT(!isUpdateStaged(index.getLevelIndex(), index.getLayerIndex())); ASSERT(!isUpdateStaged(index.getLevelIndex(), index.getLayerIndex()));
VkClearValue clearValue = GetClearValue(format);
VkClearValue clearValue = GetRobustResourceClearValue(format);
if (imageFormat.isBlock) if (imageFormat.isBlock)
{ {
...@@ -3240,6 +3247,56 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk, ...@@ -3240,6 +3247,56 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
uint32_t level,
uint32_t layer,
CommandBuffer *commandBuffer,
ClearValuesArray *deferredClears,
uint32_t deferredClearIndex)
{
// Handle deferred clears. Search the updates list for a matching clear index.
if (deferredClears)
{
Optional<size_t> foundClear;
for (size_t updateIndex = 0; updateIndex < mSubresourceUpdates.size(); ++updateIndex)
{
SubresourceUpdate &update = mSubresourceUpdates[updateIndex];
if (update.isUpdateToLayerLevel(layer, level))
{
// On any data update, exit out. We'll need to do a full upload.
if (update.updateSource != UpdateSource::Clear || update.clear.layerCount != 1)
{
foundClear.reset();
break;
}
// Otherwise track the latest clear update index.
foundClear = updateIndex;
}
}
// If we have a valid index we defer the clear using the clear reference.
if (foundClear.valid())
{
size_t foundIndex = foundClear.value();
const ClearUpdate &update = mSubresourceUpdates[foundIndex].clear;
// Note that this set command handles combined or separate depth/stencil clears.
deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
// We process the updates again to erase any clears for this level.
removeStagedUpdates(contextVk, level, layer);
return angle::Result::Continue;
}
// Otherwise we proceed with a normal update.
}
return flushStagedUpdates(contextVk, level, level + 1, layer, layer + 1, commandBuffer);
}
angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk, angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
uint32_t levelStart, uint32_t levelStart,
uint32_t levelEnd, uint32_t levelEnd,
...@@ -3661,6 +3718,8 @@ angle::Result ImageHelper::readPixels(ContextVk *contextVk, ...@@ -3661,6 +3718,8 @@ angle::Result ImageHelper::readPixels(ContextVk *contextVk,
ImageHelper *src = this; ImageHelper *src = this;
ASSERT(!isUpdateStaged(level, layer));
if (isMultisampled) if (isMultisampled)
{ {
ANGLE_TRY(resolvedImage.get().init2DStaging( ANGLE_TRY(resolvedImage.get().init2DStaging(
......
...@@ -873,7 +873,7 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -873,7 +873,7 @@ class ImageHelper final : public Resource, public angle::Subject
void resolve(ImageHelper *dest, const VkImageResolve &region, CommandBuffer *commandBuffer); void resolve(ImageHelper *dest, const VkImageResolve &region, CommandBuffer *commandBuffer);
// Data staging // Data staging
void removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index); void removeStagedUpdates(ContextVk *contextVk, uint32_t levelIndex, uint32_t layerIndex);
angle::Result stageSubresourceUpdateImpl(ContextVk *contextVk, angle::Result stageSubresourceUpdateImpl(ContextVk *contextVk,
const gl::ImageIndex &index, const gl::ImageIndex &index,
...@@ -931,12 +931,17 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -931,12 +931,17 @@ class ImageHelper final : public Resource, public angle::Subject
const gl::Extents &glExtents, const gl::Extents &glExtents,
const VkImageType imageType); const VkImageType imageType);
// Stage a clear to an arbitrary value.
void stageClear(const gl::ImageIndex &index,
VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue);
// Stage a clear based on robust resource init. // Stage a clear based on robust resource init.
angle::Result stageRobustResourceClear(ContextVk *contextVk, angle::Result stageRobustResourceClearWithFormat(ContextVk *contextVk,
const gl::Extents &glExtents, const gl::ImageIndex &index,
const gl::ImageIndex &index, const gl::Extents &glExtents,
const vk::Format &format); const vk::Format &format);
void stageSubresourceClear(const gl::ImageIndex &index); void stageRobustResourceClear(const gl::ImageIndex &index);
// This will use the underlying dynamic buffer to allocate some memory to be used as a src or // This will use the underlying dynamic buffer to allocate some memory to be used as a src or
// dst. // dst.
...@@ -947,6 +952,15 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -947,6 +952,15 @@ class ImageHelper final : public Resource, public angle::Subject
StagingBufferOffsetArray *offsetOut, StagingBufferOffsetArray *offsetOut,
bool *newBufferAllocatedOut); bool *newBufferAllocatedOut);
// Flush staged updates for a single subresource. Can optionally take a parameter to defer
// clears to a subsequent RenderPass load op.
angle::Result flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
uint32_t level,
uint32_t layer,
CommandBuffer *commandBuffer,
ClearValuesArray *deferredClears,
uint32_t deferredClearIndex);
// Flushes staged updates to a range of levels and layers from start to (but not including) end. // Flushes staged updates to a range of levels and layers from start to (but not including) end.
// Due to the nature of updates (done wholly to a VkImageSubresourceLayers), some unsolicited // Due to the nature of updates (done wholly to a VkImageSubresourceLayers), some unsolicited
// layers may also be updated. // layers may also be updated.
...@@ -956,6 +970,7 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -956,6 +970,7 @@ class ImageHelper final : public Resource, public angle::Subject
uint32_t layerStart, uint32_t layerStart,
uint32_t layerEnd, uint32_t layerEnd,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
// Creates a command buffer and flushes all staged updates. This is used for one-time // Creates a command buffer and flushes all staged updates. This is used for one-time
// initialization of resources that we don't expect to accumulate further staged updates, such // initialization of resources that we don't expect to accumulate further staged updates, such
// as with renderbuffers or surface images. // as with renderbuffers or surface images.
......
...@@ -682,6 +682,37 @@ void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT ...@@ -682,6 +682,37 @@ void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT
label->pLabelName = marker; label->pLabelName = marker;
kLabelColors[colorIndex].writeData(label->color); kLabelColors[colorIndex].writeData(label->color);
} }
// ClearValuesArray implementation.
ClearValuesArray::ClearValuesArray() : mValues{}, mEnabled{} {}
ClearValuesArray::~ClearValuesArray() = default;
ClearValuesArray::ClearValuesArray(const ClearValuesArray &other) = default;
ClearValuesArray &ClearValuesArray::operator=(const ClearValuesArray &rhs) = default;
void ClearValuesArray::store(uint32_t index,
VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue)
{
ASSERT(aspectFlags != 0);
// We do this double if to handle the packed depth-stencil case.
if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
{
// Special case for stencil.
ASSERT(index == kClearValueDepthIndex);
mValues[kClearValueStencilIndex] = clearValue;
mEnabled.set(kClearValueStencilIndex);
}
if (aspectFlags != VK_IMAGE_ASPECT_STENCIL_BIT)
{
mValues[index] = clearValue;
mEnabled.set(index);
}
}
} // namespace vk } // namespace vk
#if !defined(ANGLE_SHARED_LIBVULKAN) #if !defined(ANGLE_SHARED_LIBVULKAN)
......
...@@ -624,6 +624,51 @@ template <typename T> ...@@ -624,6 +624,51 @@ template <typename T>
using SpecializationConstantMap = angle::PackedEnumMap<sh::vk::SpecializationConstantId, T>; using SpecializationConstantMap = angle::PackedEnumMap<sh::vk::SpecializationConstantId, T>;
void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label); void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label);
constexpr size_t kClearValueDepthIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
constexpr size_t kClearValueStencilIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
class ClearValuesArray final
{
public:
ClearValuesArray();
~ClearValuesArray();
ClearValuesArray(const ClearValuesArray &other);
ClearValuesArray &operator=(const ClearValuesArray &rhs);
void store(uint32_t index, VkImageAspectFlags aspectFlags, const VkClearValue &clearValue);
void reset(size_t index)
{
mValues[index] = {};
mEnabled.reset(index);
}
bool test(size_t index) const { return mEnabled.test(index); }
bool testDepth() const { return mEnabled.test(kClearValueDepthIndex); }
bool testStencil() const { return mEnabled.test(kClearValueStencilIndex); }
const VkClearValue &operator[](size_t index) const { return mValues[index]; }
float getDepthValue() const { return mValues[kClearValueDepthIndex].depthStencil.depth; }
uint32_t getStencilValue() const
{
return mValues[kClearValueStencilIndex].depthStencil.stencil;
}
const VkClearValue *data() const { return mValues.data(); }
bool empty() const { return mEnabled.none(); }
gl::DrawBufferMask getEnabledColorAttachmentsMask() const
{
return gl::DrawBufferMask(mEnabled.to_ulong());
}
private:
gl::AttachmentArray<VkClearValue> mValues;
gl::AttachmentsMask mEnabled;
};
} // namespace vk } // namespace vk
#if !defined(ANGLE_SHARED_LIBVULKAN) #if !defined(ANGLE_SHARED_LIBVULKAN)
......
...@@ -1500,6 +1500,53 @@ TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert) ...@@ -1500,6 +1500,53 @@ TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Clears many small concentric rectangles using scissor regions.
TEST_P(ClearTest, InceptionScissorClears)
{
angle::RNG rng;
constexpr GLuint kSize = 16;
// Create a square user FBO so we have more control over the dimensions.
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLRenderbuffer rbo;
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glViewport(0, 0, kSize, kSize);
// Draw small concentric squares using scissor.
std::vector<GLColor> expectedColors;
for (GLuint index = 0; index < (kSize - 1) / 2; index++)
{
// Do the first clear without the scissor.
if (index > 0)
{
glEnable(GL_SCISSOR_TEST);
glScissor(index, index, kSize - (index * 2), kSize - (index * 2));
}
GLColor color = RandomColor(&rng);
expectedColors.push_back(color);
Vector4 floatColor = color.toNormalizedVector();
glClearColor(floatColor[0], floatColor[1], floatColor[2], floatColor[3]);
glClear(GL_COLOR_BUFFER_BIT);
}
ASSERT_GL_NO_ERROR();
std::vector<GLColor> actualColors(expectedColors.size());
glReadPixels(0, kSize / 2, actualColors.size(), 1, GL_RGBA, GL_UNSIGNED_BYTE,
actualColors.data());
EXPECT_EQ(expectedColors, actualColors);
}
#ifdef Bool #ifdef Bool
// X11 craziness. // X11 craziness.
# undef Bool # undef Bool
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "gpu_info_util/SystemInfo.h" #include "gpu_info_util/SystemInfo.h"
#include "util/EGLWindow.h" #include "util/EGLWindow.h"
#include "util/OSWindow.h" #include "util/OSWindow.h"
#include "util/random_utils.h"
#include "util/test_utils.h" #include "util/test_utils.h"
#if defined(ANGLE_PLATFORM_WINDOWS) #if defined(ANGLE_PLATFORM_WINDOWS)
...@@ -221,6 +222,12 @@ Vector4 GLColor::toNormalizedVector() const ...@@ -221,6 +222,12 @@ Vector4 GLColor::toNormalizedVector() const
return Vector4(ColorNorm(R), ColorNorm(G), ColorNorm(B), ColorNorm(A)); return Vector4(ColorNorm(R), ColorNorm(G), ColorNorm(B), ColorNorm(A));
} }
GLColor RandomColor(angle::RNG *rng)
{
return GLColor(rng->randomIntBetween(0, 255), rng->randomIntBetween(0, 255),
rng->randomIntBetween(0, 255), rng->randomIntBetween(0, 255));
}
GLColor ReadColor(GLint x, GLint y) GLColor ReadColor(GLint x, GLint y)
{ {
GLColor actual; GLColor actual;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
namespace angle namespace angle
{ {
struct SystemInfo; struct SystemInfo;
class RNG;
} // namespace angle } // namespace angle
#define ASSERT_GL_TRUE(a) ASSERT_EQ(static_cast<GLboolean>(GL_TRUE), (a)) #define ASSERT_GL_TRUE(a) ASSERT_EQ(static_cast<GLboolean>(GL_TRUE), (a))
...@@ -161,6 +162,8 @@ GLColor MakeGLColor(TR r, TG g, TB b, TA a) ...@@ -161,6 +162,8 @@ GLColor MakeGLColor(TR r, TG g, TB b, TA a)
static_cast<GLubyte>(a)); static_cast<GLubyte>(a));
} }
GLColor RandomColor(angle::RNG *rng);
bool operator==(const GLColor &a, const GLColor &b); bool operator==(const GLColor &a, const GLColor &b);
bool operator!=(const GLColor &a, const GLColor &b); bool operator!=(const GLColor &a, const GLColor &b);
std::ostream &operator<<(std::ostream &ostream, const GLColor &color); std::ostream &operator<<(std::ostream &ostream, const GLColor &color);
......
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