Fix tessellation pipeline re-clearing attachments.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm index 6e8a7b5..52f7999 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
@@ -194,7 +194,7 @@ threadsPerThreadgroup: MTLSizeMake(std::max(inControlPointCount, outControlPointCount), 1, 1)]; // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(); + cmdEncoder->beginMetalRenderPass(true); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) { @@ -413,7 +413,7 @@ threadsPerThreadgroup: MTLSizeMake(std::max(inControlPointCount, outControlPointCount), 1, 1)]; // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(); + cmdEncoder->beginMetalRenderPass(true); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) { @@ -663,7 +663,7 @@ mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments); // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(); + cmdEncoder->beginMetalRenderPass(true); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) { @@ -909,7 +909,7 @@ mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments); // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(); + cmdEncoder->beginMetalRenderPass(true); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) {
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 8e4a22b..09e2854 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -246,7 +246,7 @@ void beginNextSubpass(VkSubpassContents renderpassContents); /** Begins a Metal render pass for the current render subpass. */ - void beginMetalRenderPass(); + void beginMetalRenderPass(bool loadOverride = false); /** Returns the render subpass that is currently active. */ MVKRenderSubpass* getSubpass();
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index be4477a..4aabdd2 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -242,12 +242,12 @@ } // Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder. -void MVKCommandEncoder::beginMetalRenderPass() { +void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride) { endCurrentMetalEncoding(); MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor]; - getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues, _isRenderingEntireAttachment); + getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues, _isRenderingEntireAttachment, loadOverride); mtlRPDesc.visibilityResultBuffer = _occlusionQueryState.getVisibilityResultMTLBuffer(); if (_device->_pMetalFeatures->layeredRendering) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index ad591b0..769c9fa 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -58,7 +58,8 @@ void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc, MVKFramebuffer* framebuffer, MVKVector<VkClearValue>& clearValues, - bool isRenderingEntireAttachment); + bool isRenderingEntireAttachment, + bool loadOverride = false); /** * Populates the specified vector with the attachments that need to be cleared @@ -111,7 +112,8 @@ MVKRenderSubpass* subpass, bool isRenderingEntireAttachment, bool hasResolveAttachment, - bool isStencil); + bool isStencil, + bool loadOverride = false); /** Returns whether this attachment should be cleared in the subpass. */ bool shouldUseClearAttachment(MVKRenderSubpass* subpass);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index dc21eb8..67c2980 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -68,7 +68,8 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc, MVKFramebuffer* framebuffer, MVKVector<VkClearValue>& clearValues, - bool isRenderingEntireAttachment) { + bool isRenderingEntireAttachment, + bool loadOverride) { // Populate the Metal color attachments uint32_t caCnt = getColorAttachmentCount(); for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { @@ -89,7 +90,8 @@ framebuffer->getAttachment(clrRPAttIdx)->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc); if (clrMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc, this, isRenderingEntireAttachment, - hasResolveAttachment, false)) { + hasResolveAttachment, false, + loadOverride)) { mtlColorAttDesc.clearColor = mvkMTLClearColorFromVkClearValue(clearValues[clrRPAttIdx], clrMVKRPAtt->getFormat()); } @@ -110,8 +112,9 @@ dsImage->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc); if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, isRenderingEntireAttachment, - false, false)) { - mtlDepthAttDesc.clearDepth = mvkMTLClearDepthFromVkClearValue(clearValues[dsRPAttIdx]); + false, false, + loadOverride)) { + mtlDepthAttDesc.clearDepth = mvkMTLClearDepthFromVkClearValue(clearValues[dsRPAttIdx]); } } if (mvkMTLPixelFormatIsStencilFormat(mtlDSFormat)) { @@ -119,7 +122,8 @@ dsImage->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc); if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, isRenderingEntireAttachment, - false, true)) { + false, true, + loadOverride)) { mtlStencilAttDesc.clearStencil = mvkMTLClearStencilFromVkClearValue(clearValues[dsRPAttIdx]); } } @@ -252,13 +256,16 @@ MVKRenderSubpass* subpass, bool isRenderingEntireAttachment, bool hasResolveAttachment, - bool isStencil) { + bool isStencil, + bool loadOverride) { bool willClear = false; // Assume the attachment won't be cleared // Only allow clearing of entire attachment if we're actually rendering to the entire // attachment AND we're in the first subpass. - if ( isRenderingEntireAttachment && (subpass->_subpassIndex == _firstUseSubpassIdx) ) { + if ( loadOverride ) { + mtlAttDesc.loadAction = MTLLoadActionLoad; + } else if ( isRenderingEntireAttachment && (subpass->_subpassIndex == _firstUseSubpassIdx) ) { VkAttachmentLoadOp loadOp = isStencil ? _info.stencilLoadOp : _info.loadOp; mtlAttDesc.loadAction = mvkMTLLoadActionFromVkAttachmentLoadOp(loadOp); willClear = (_info.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);