From ce583f4f3d8afcf0c4f281866c67fd2d6e332841 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 19 Aug 2021 17:22:29 -0400 Subject: [PATCH] Support stencil-only partial attachment clearing. Rename MVKRenderPassAttachment::shouldUseClearAttachment() to shouldClearAttachment(), pass whether testing for stencil clearing, and check stencil clearing distinct from depth clearing. Refactor MVKRenderSubpass::populateClearAttachments() to work with this. Remove MVKRenderPassAttachment::getAttachmentStencilLoadOp() as obsolete. --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h | 5 +- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm | 46 ++++++++----------- 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 904ff96c..8f9530a1 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -23,6 +23,7 @@ Released TBD - Set default value of the `MVK_ALLOW_METAL_FENCES` environment variable to `0 (false)`, - Vulkan timestamp query pools use Metal GPU counters when available. - Support resolving attachments with formats that Metal does not natively resolve. +- Support stencil-only partial attachment clearing. - Fix issue where swapchain images were acquired out of order under heavy load. - Fix issue with `vkCmdBlitImage()` from compressed textures. - Fix incorrect translation of clear color values on Apple Silicon. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index ff115912..9cb0808f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h @@ -208,10 +208,7 @@ public: void populateMultiviewClearRects(MVKSmallVector& clearRects, MVKCommandEncoder* cmdEncoder); /** Returns whether this attachment should be cleared in the subpass. */ - bool shouldUseClearAttachment(MVKRenderSubpass* subpass); - - /** If this is a depth attachment, the stencil load op may be different than the depth load op. */ - VkAttachmentLoadOp getAttachmentStencilLoadOp() const; + bool shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil); /** Constructs an instance for the specified parent renderpass. */ MVKRenderPassAttachment(MVKRenderPass* renderPass, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index 774b1eb9..ed54e753 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -418,34 +418,30 @@ void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder, void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts, const MVKArrayRef clearValues) { - VkClearAttachment cAtt; - uint32_t attIdx; uint32_t caCnt = getColorAttachmentCount(); for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { attIdx = _colorAttachments[caIdx].attachment; - if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldUseClearAttachment(this)) { - cAtt.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - cAtt.colorAttachment = caIdx; - cAtt.clearValue = clearValues[attIdx]; - clearAtts.push_back(cAtt); + if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldClearAttachment(this, false)) { + clearAtts.push_back( { VK_IMAGE_ASPECT_COLOR_BIT, caIdx, clearValues[attIdx] } ); } } attIdx = _depthStencilAttachment.attachment; - if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldUseClearAttachment(this)) { - cAtt.aspectMask = 0; - cAtt.colorAttachment = 0; - cAtt.clearValue = clearValues[attIdx]; - + if (attIdx != VK_ATTACHMENT_UNUSED) { MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); - MTLPixelFormat mtlDSFmt = _renderPass->getPixelFormats()->getMTLPixelFormat(getDepthStencilFormat()); - if (pixFmts->isDepthFormat(mtlDSFmt)) { cAtt.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; } - if (pixFmts->isStencilFormat(mtlDSFmt) && - _renderPass->_attachments[attIdx].getAttachmentStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR) { - cAtt.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(getDepthStencilFormat()); + auto& rpAtt = _renderPass->_attachments[attIdx]; + VkImageAspectFlags aspectMask = 0; + if (rpAtt.shouldClearAttachment(this, false) && pixFmts->isDepthFormat(mtlDSFmt)) { + mvkEnableFlags(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT); + } + if (rpAtt.shouldClearAttachment(this, true) && pixFmts->isStencilFormat(mtlDSFmt)) { + mvkEnableFlags(aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT); + } + if (aspectMask) { + clearAtts.push_back( { aspectMask, 0, clearValues[attIdx] } ); } - if (cAtt.aspectMask) { clearAtts.push_back(cAtt); } } } @@ -761,20 +757,16 @@ MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subp return mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment, canResolveFormat); } -bool MVKRenderPassAttachment::shouldUseClearAttachment(MVKRenderSubpass* subpass) { - - // If the subpass is not the first subpass to use this attachment, don't clear this attachment +// If the subpass is not the first subpass to use this attachment, +// don't clear this attachment, otherwise, clear if requested. +bool MVKRenderPassAttachment::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) { if (subpass->isMultiview()) { if (_firstUseViewMasks[subpass->_subpassIndex] == 0) { return false; } } else { if (subpass->_subpassIndex != _firstUseSubpassIdx) { return false; } } - - return (_info.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR); -} - -VkAttachmentLoadOp MVKRenderPassAttachment::getAttachmentStencilLoadOp() const { - return _info.stencilLoadOp; + VkAttachmentLoadOp loadOp = isStencil ? _info.stencilLoadOp : _info.loadOp; + return loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR; } void MVKRenderPassAttachment::validateFormat() {