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.
This commit is contained in:
Bill Hollings 2021-08-19 17:22:29 -04:00
parent 77c31cd0da
commit ce583f4f3d
3 changed files with 21 additions and 31 deletions

View File

@ -23,6 +23,7 @@ Released TBD
- Set default value of the `MVK_ALLOW_METAL_FENCES` environment variable to `0 (false)`, - Set default value of the `MVK_ALLOW_METAL_FENCES` environment variable to `0 (false)`,
- Vulkan timestamp query pools use Metal GPU counters when available. - Vulkan timestamp query pools use Metal GPU counters when available.
- Support resolving attachments with formats that Metal does not natively resolve. - 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 where swapchain images were acquired out of order under heavy load.
- Fix issue with `vkCmdBlitImage()` from compressed textures. - Fix issue with `vkCmdBlitImage()` from compressed textures.
- Fix incorrect translation of clear color values on Apple Silicon. - Fix incorrect translation of clear color values on Apple Silicon.

View File

@ -208,10 +208,7 @@ public:
void populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects, MVKCommandEncoder* cmdEncoder); void populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects, MVKCommandEncoder* cmdEncoder);
/** Returns whether this attachment should be cleared in the subpass. */ /** Returns whether this attachment should be cleared in the subpass. */
bool shouldUseClearAttachment(MVKRenderSubpass* subpass); bool shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil);
/** If this is a depth attachment, the stencil load op may be different than the depth load op. */
VkAttachmentLoadOp getAttachmentStencilLoadOp() const;
/** Constructs an instance for the specified parent renderpass. */ /** Constructs an instance for the specified parent renderpass. */
MVKRenderPassAttachment(MVKRenderPass* renderPass, MVKRenderPassAttachment(MVKRenderPass* renderPass,

View File

@ -418,34 +418,30 @@ void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder,
void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts, void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts,
const MVKArrayRef<VkClearValue> clearValues) { const MVKArrayRef<VkClearValue> clearValues) {
VkClearAttachment cAtt;
uint32_t attIdx; uint32_t attIdx;
uint32_t caCnt = getColorAttachmentCount(); uint32_t caCnt = getColorAttachmentCount();
for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) {
attIdx = _colorAttachments[caIdx].attachment; attIdx = _colorAttachments[caIdx].attachment;
if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldUseClearAttachment(this)) { if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldClearAttachment(this, false)) {
cAtt.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; clearAtts.push_back( { VK_IMAGE_ASPECT_COLOR_BIT, caIdx, clearValues[attIdx] } );
cAtt.colorAttachment = caIdx;
cAtt.clearValue = clearValues[attIdx];
clearAtts.push_back(cAtt);
} }
} }
attIdx = _depthStencilAttachment.attachment; attIdx = _depthStencilAttachment.attachment;
if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldUseClearAttachment(this)) { if (attIdx != VK_ATTACHMENT_UNUSED) {
cAtt.aspectMask = 0;
cAtt.colorAttachment = 0;
cAtt.clearValue = clearValues[attIdx];
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
MTLPixelFormat mtlDSFmt = _renderPass->getPixelFormats()->getMTLPixelFormat(getDepthStencilFormat()); MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(getDepthStencilFormat());
if (pixFmts->isDepthFormat(mtlDSFmt)) { cAtt.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; } auto& rpAtt = _renderPass->_attachments[attIdx];
if (pixFmts->isStencilFormat(mtlDSFmt) && VkImageAspectFlags aspectMask = 0;
_renderPass->_attachments[attIdx].getAttachmentStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR) { if (rpAtt.shouldClearAttachment(this, false) && pixFmts->isDepthFormat(mtlDSFmt)) {
cAtt.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; 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); 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, otherwise, clear if requested.
// If the subpass is not the first subpass to use this attachment, don't clear this attachment bool MVKRenderPassAttachment::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) {
if (subpass->isMultiview()) { if (subpass->isMultiview()) {
if (_firstUseViewMasks[subpass->_subpassIndex] == 0) { return false; } if (_firstUseViewMasks[subpass->_subpassIndex] == 0) { return false; }
} else { } else {
if (subpass->_subpassIndex != _firstUseSubpassIdx) { return false; } if (subpass->_subpassIndex != _firstUseSubpassIdx) { return false; }
} }
VkAttachmentLoadOp loadOp = isStencil ? _info.stencilLoadOp : _info.loadOp;
return (_info.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR); return loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR;
}
VkAttachmentLoadOp MVKRenderPassAttachment::getAttachmentStencilLoadOp() const {
return _info.stencilLoadOp;
} }
void MVKRenderPassAttachment::validateFormat() { void MVKRenderPassAttachment::validateFormat() {