From 4aa2b6dd9f5dab46f9a18a7e32ee9e1b02ed6889 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 24 Apr 2023 15:23:46 -0400 Subject: [PATCH 1/3] Support separate depth and stencil attachments during dynamic rendering. - MVKRenderSubpass add separate getDepthFormat() & getStencilFormat(), and isDepthAttachmentUsed() & isStencilAttachmentUsed() and use instead of testing pixel format for depth and stencil components. - Add MVKRenderingAttachmentIterator class to consistently iterate, and take actions, on the attachments in VkRenderingInfo to create synthetic MVKRenderPass and extract image views and clear colors. - Remove mvkCreateRenderPass() and mvkCreateFramebuffer() in favor of additional constructors, and remove mvkGetDepthStencilFormat() in favor of retrieving formats for separate depth and stencil attachments. - MVKRenderpass constructors reorganize order of adding attachments and subpasses, and connecting the two. - Renmame MVKRenderPassAttachment to MVKAttachmentDescription. - MVKPipeline reorganize member variables to minimize gaps in content and remove unnecessary _isRasterizingDepthStencil member var (unrelated). --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 20 +- .../MoltenVK/Commands/MVKCommandBuffer.mm | 20 +- .../Commands/MVKCommandEncoderState.mm | 7 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 4 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 10 + MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h | 11 +- .../MoltenVK/GPUObjects/MVKFramebuffer.mm | 54 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 18 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 27 +- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h | 98 ++- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm | 829 +++++++++--------- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 2 +- 13 files changed, 540 insertions(+), 561 deletions(-) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index f22472d7..7bdc87db 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -21,6 +21,7 @@ Released TBD - Add support for extensions: - `VK_KHR_map_memory2` - Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU). +- Support separate depth and stencil attachments during dynamic rendering. - Fix memory leak when waiting on timeline semaphores. - Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`. - Add `MVK_ENABLE_EXPLICIT_LOD_WORKAROUND` environment variable to selectively diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index d72df15e..0aa57b31 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1446,21 +1446,17 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { // The depth value (including vertex position Z value) is held in the last index. clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; - VkFormat vkAttFmt = subpass->getDepthStencilFormat(); - MTLPixelFormat mtlAttFmt = pixFmts->getMTLPixelFormat(vkAttFmt); - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlAttFmt; - - bool isClearingDepth = _isClearingDepth && pixFmts->isDepthFormat(mtlAttFmt); - bool isClearingStencil = _isClearingStencil && pixFmts->isStencilFormat(mtlAttFmt); - if (!isClearingDepth && !isClearingStencil) { - // If the subpass attachment isn't actually used, don't try to clear it. + bool isClearingDepth = _isClearingDepth && subpass->isDepthAttachmentUsed(); + bool isClearingStencil = _isClearingStencil && subpass->isStencilAttachmentUsed(); + if (isClearingDepth) { + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getDepthFormat()); + } else if (isClearingStencil) { + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getStencilFormat()); + } else { _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); } - if (!_rpsKey.isAnyAttachmentEnabled()) { - // Nothing to do. - return; - } + if ( !_rpsKey.isAnyAttachmentEnabled() ) { return; } // Render the clear colors to the attachments MVKCommandEncodingPool* cmdEncPool = cmdEncoder->getCommandEncodingPool(); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index c4205685..5155a141 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -401,10 +401,17 @@ void MVKCommandEncoder::beginRendering(MVKCommand* rendCmd, const VkRenderingInf ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE); - uint32_t maxAttCnt = (pRenderingInfo->colorAttachmentCount + 1) * 2; - MVKImageView* attachments[maxAttCnt]; + uint32_t maxAttCnt = (pRenderingInfo->colorAttachmentCount + 2) * 2; + MVKImageView* imageViews[maxAttCnt]; VkClearValue clearValues[maxAttCnt]; - uint32_t attCnt = mvkGetAttachments(pRenderingInfo, attachments, clearValues); + + uint32_t attCnt = 0; + MVKRenderingAttachmentIterator attIter(pRenderingInfo); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { + imageViews[attCnt] = (MVKImageView*)(isResolveAttachment ? pAttInfo->resolveImageView : pAttInfo->imageView); + clearValues[attCnt] = pAttInfo->clearValue; + attCnt++; + }); // If we're resuming a suspended renderpass, continue to use the existing renderpass // (with updated rendering flags) and framebuffer. Otherwise, create new transient @@ -419,13 +426,14 @@ void MVKCommandEncoder::beginRendering(MVKCommand* rendCmd, const VkRenderingInf mvkRP->setRenderingFlags(pRenderingInfo->flags); mvkFB = _pEncodingContext->getFramebuffer(); } else { - mvkRP = mvkCreateRenderPass(getDevice(), pRenderingInfo); - mvkFB = mvkCreateFramebuffer(getDevice(), pRenderingInfo, mvkRP); + auto* mvkDev = getDevice(); + mvkRP = mvkDev->createRenderPass(pRenderingInfo, nullptr); + mvkFB = mvkDev->createFramebuffer(pRenderingInfo, nullptr); } beginRenderpass(rendCmd, contents, mvkRP, mvkFB, pRenderingInfo->renderArea, MVKArrayRef(clearValues, attCnt), - MVKArrayRef(attachments, attCnt), + MVKArrayRef(imageViews, attCnt), MVKArrayRef>(), kMVKCommandUseBeginRendering); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index c1f7b4c0..0262d47d 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -328,15 +328,12 @@ void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() { MVKCommandEncoderState::beginMetalRenderPass(); MVKRenderSubpass* mvkSubpass = _cmdEncoder->getSubpass(); - MVKPixelFormats* pixFmts = _cmdEncoder->getPixelFormats(); - MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkSubpass->getDepthStencilFormat()); - bool prevHasDepthAttachment = _hasDepthAttachment; - _hasDepthAttachment = pixFmts->isDepthFormat(mtlDSFormat); + _hasDepthAttachment = mvkSubpass->isDepthAttachmentUsed(); if (_hasDepthAttachment != prevHasDepthAttachment) { markDirty(); } bool prevHasStencilAttachment = _hasStencilAttachment; - _hasStencilAttachment = pixFmts->isStencilFormat(mtlDSFormat); + _hasStencilAttachment = mvkSubpass->isStencilAttachmentUsed(); if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 5eddac11..b02cc778 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -631,6 +631,8 @@ public: MVKFramebuffer* createFramebuffer(const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator); + MVKFramebuffer* createFramebuffer(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator); void destroyFramebuffer(MVKFramebuffer* mvkFB, const VkAllocationCallbacks* pAllocator); @@ -638,6 +640,8 @@ public: const VkAllocationCallbacks* pAllocator); MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator); + MVKRenderPass* createRenderPass(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator); void destroyRenderPass(MVKRenderPass* mvkRP, const VkAllocationCallbacks* pAllocator); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 3251449c..8cdca02b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -3893,6 +3893,11 @@ MVKFramebuffer* MVKDevice::createFramebuffer(const VkFramebufferCreateInfo* pCre return new MVKFramebuffer(this, pCreateInfo); } +MVKFramebuffer* MVKDevice::createFramebuffer(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator) { + return new MVKFramebuffer(this, pRenderingInfo); +} + void MVKDevice::destroyFramebuffer(MVKFramebuffer* mvkFB, const VkAllocationCallbacks* pAllocator) { if (mvkFB) { mvkFB->destroy(); } @@ -3908,6 +3913,11 @@ MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo2* pCreat return new MVKRenderPass(this, pCreateInfo); } +MVKRenderPass* MVKDevice::createRenderPass(const VkRenderingInfo* pRenderingInfo, + const VkAllocationCallbacks* pAllocator) { + return new MVKRenderPass(this, pRenderingInfo); +} + void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP, const VkAllocationCallbacks* pAllocator) { if (mvkRP) { mvkRP->destroy(); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h index ec9b3fdf..d5e9c469 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h @@ -58,6 +58,8 @@ public: MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo); + MVKFramebuffer(MVKDevice* device, const VkRenderingInfo* pRenderingInfo); + ~MVKFramebuffer() override; protected: @@ -69,12 +71,3 @@ protected: VkExtent2D _extent; uint32_t _layerCount; }; - - -#pragma mark - -#pragma mark Support functions - -/** Returns an image-less MVKFramebuffer object created from the rendering info. */ -MVKFramebuffer* mvkCreateFramebuffer(MVKDevice* device, - const VkRenderingInfo* pRenderingInfo, - MVKRenderPass* mvkRenderPass); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm index c6f56bc7..d0c376ad 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm @@ -82,8 +82,8 @@ id MVKFramebuffer::getDummyAttachmentMTLTexture(MVKRenderSubpass* su MVKFramebuffer::MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { - _extent = { .width = pCreateInfo->width, .height = pCreateInfo->height }; _layerCount = pCreateInfo->layers; + _extent = { .width = pCreateInfo->width, .height = pCreateInfo->height }; // If this is not an image-less framebuffer, add the attachments if ( !mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) ) { @@ -94,51 +94,25 @@ MVKFramebuffer::MVKFramebuffer(MVKDevice* device, } } -MVKFramebuffer::~MVKFramebuffer() { - [_mtlDummyTex release]; -} +MVKFramebuffer::MVKFramebuffer(MVKDevice* device, + const VkRenderingInfo* pRenderingInfo) : MVKVulkanAPIDeviceObject(device) { + _layerCount = pRenderingInfo->layerCount; - -#pragma mark - -#pragma mark Support functions - -MVKFramebuffer* mvkCreateFramebuffer(MVKDevice* device, - const VkRenderingInfo* pRenderingInfo, - MVKRenderPass* mvkRenderPass) { - uint32_t attCnt = 0; - VkExtent3D fbExtent = {}; + _extent = {}; for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) { auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx]; if (clrAtt.imageView) { - fbExtent = ((MVKImageView*)clrAtt.imageView)->getExtent3D(); - attCnt++; - if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) { - attCnt++; - } + _extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)clrAtt.imageView)->getExtent3D()); } } - auto* pDSAtt = pRenderingInfo->pDepthAttachment ? pRenderingInfo->pDepthAttachment : pRenderingInfo->pStencilAttachment; - if (pDSAtt) { - if (pDSAtt->imageView) { - fbExtent = ((MVKImageView*)pDSAtt->imageView)->getExtent3D(); - attCnt++; - } - if (pDSAtt->resolveImageView && pDSAtt->resolveMode != VK_RESOLVE_MODE_NONE) { - attCnt++; - } + if (pRenderingInfo->pDepthAttachment && pRenderingInfo->pDepthAttachment->imageView) { + _extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)pRenderingInfo->pDepthAttachment->imageView)->getExtent3D()); + } + if (pRenderingInfo->pStencilAttachment && pRenderingInfo->pStencilAttachment->imageView) { + _extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)pRenderingInfo->pStencilAttachment->imageView)->getExtent3D()); } - - VkFramebufferCreateInfo fbCreateInfo; - fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbCreateInfo.pNext = nullptr; - fbCreateInfo.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT; - fbCreateInfo.renderPass = (VkRenderPass)mvkRenderPass; - fbCreateInfo.attachmentCount = attCnt; - fbCreateInfo.pAttachments = nullptr; - fbCreateInfo.width = fbExtent.width; - fbCreateInfo.height = fbExtent.height; - fbCreateInfo.layers = pRenderingInfo->layerCount; - - return device->createFramebuffer(&fbCreateInfo, nullptr); } +MVKFramebuffer::~MVKFramebuffer() { + [_mtlDummyTex release]; +} diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 8d09b87e..154bcf67 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -346,11 +346,6 @@ protected: void markIfUsingPhysicalStorageBufferAddressesCapability(SPIRVToMSLConversionResultInfo& resultsInfo, MVKShaderStage stage); - const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pTessEvalSS = nullptr; - const VkPipelineShaderStageCreateInfo* _pFragmentSS = nullptr; - VkPipelineTessellationStateCreateInfo _tessInfo; VkPipelineRasterizationStateCreateInfo _rasterInfo; VkPipelineDepthStencilStateCreateInfo _depthStencilInfo; @@ -364,7 +359,12 @@ protected: MVKSmallVector _mtlArgumentEncoders; MVKSmallVector _descriptorBindingUse; MVKSmallVector _stagesUsingPhysicalStorageBufferAddressesCapability; + std::unordered_map> _multiviewMTLPipelineStates; + const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr; + const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr; + const VkPipelineShaderStageCreateInfo* _pTessEvalSS = nullptr; + const VkPipelineShaderStageCreateInfo* _pFragmentSS = nullptr; MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil; id _mtlTessVertexFunctions[3] = {nil, nil, nil}; @@ -373,18 +373,17 @@ protected: id _mtlTessVertexStageIndex32State = nil; id _mtlTessControlStageState = nil; id _mtlPipelineState = nil; - std::unordered_map> _multiviewMTLPipelineStates; + + float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 }; MTLCullMode _mtlCullMode; MTLWinding _mtlFrontWinding; MTLTriangleFillMode _mtlFillMode; MTLDepthClipMode _mtlDepthClipMode; MTLPrimitiveType _mtlPrimitiveType; - - float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 }; - uint32_t _outputControlPointCount; MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount; MVKShaderImplicitRezBinding _viewRangeBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex; + uint32_t _outputControlPointCount; uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0; @@ -408,7 +407,6 @@ protected: bool _needsFragmentViewRangeBuffer = false; bool _isRasterizing = false; bool _isRasterizingColor = false; - bool _isRasterizingDepthStencil = false; bool _isUsingCustomSamplePositions = false; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index e24e24e8..bf5e3f13 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -401,7 +401,6 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); _isRasterizing = !isRasterizationDisabled(pCreateInfo); _isRasterizingColor = _isRasterizing && mvkHasColorAttachments(pRendInfo); - _isRasterizingDepthStencil = _isRasterizing && mvkGetDepthStencilFormat(pRendInfo) != VK_FORMAT_UNDEFINED; // Get the tessellation shaders, if present. Do this now, because we need to extract // reflection data from them that informs everything else. @@ -488,8 +487,9 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, initCustomSamplePositions(pCreateInfo); // Depth stencil content - clearing will disable depth and stencil testing - // Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth attachment - mvkSetOrClear(&_depthStencilInfo, _isRasterizingDepthStencil ? pCreateInfo->pDepthStencilState : nullptr); + // Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth or stencil attachment format + bool isRasterizingDepthStencil = _isRasterizing && (pRendInfo->depthAttachmentFormat || pRendInfo->stencilAttachmentFormat); + mvkSetOrClear(&_depthStencilInfo, isRasterizingDepthStencil ? pCreateInfo->pDepthStencilState : nullptr); // Viewports and scissors - must ignore allowed bad pViewportState pointer if rasterization is disabled auto pVPState = _isRasterizing ? pCreateInfo->pViewportState : nullptr; @@ -1469,16 +1469,15 @@ void MVKGraphicsPipeline::addFragmentOutputToPipeline(MTLRenderPipelineDescripto } } - // Depth & stencil attachments + // Depth & stencil attachment formats MVKPixelFormats* pixFmts = getPixelFormats(); - MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkGetDepthStencilFormat(pRendInfo)); - if (pixFmts->isDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; } - if (pixFmts->isStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; } + plDesc.depthAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat); + plDesc.stencilAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat); - // In Vulkan, it's perfectly valid to render with no attachments. In Metal we need to check for - // support for it. If we have no attachments, then we may have to add a dummy attachment. - if (!caCnt && !pixFmts->isDepthFormat(mtlDSFormat) && !pixFmts->isStencilFormat(mtlDSFormat) && - !getDevice()->_pMetalFeatures->renderWithoutAttachments) { + // In Vulkan, it's perfectly valid to render without any attachments. In Metal, if that + // isn't supported, and we have no attachments, then we have to add a dummy attachment. + if (!getDevice()->_pMetalFeatures->renderWithoutAttachments && + !caCnt && !pRendInfo->depthAttachmentFormat && !pRendInfo->stencilAttachmentFormat) { MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[0]; colorDesc.pixelFormat = MTLPixelFormatR8Unorm; @@ -1553,8 +1552,6 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu _viewRangeBufferIndex = _indirectParamsIndex; const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); - MVKPixelFormats* pixFmts = getPixelFormats(); - MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkGetDepthStencilFormat(pRendInfo)); // Disable any unused color attachments, because Metal validation can complain if the // fragment shader outputs a color value without a corresponding color attachment. @@ -1574,8 +1571,8 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu shaderConfig.options.mslOptions.ios_support_base_vertex_instance = getDevice()->_pMetalFeatures->baseVertexInstanceDrawing; shaderConfig.options.mslOptions.texture_1D_as_2D = mvkConfig().texture1DAs2D; shaderConfig.options.mslOptions.enable_point_size_builtin = isRenderingPoints(pCreateInfo) || reflectData.pointMode; - shaderConfig.options.mslOptions.enable_frag_depth_builtin = pixFmts->isDepthFormat(mtlDSFormat); - shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = pixFmts->isStencilFormat(mtlDSFormat); + shaderConfig.options.mslOptions.enable_frag_depth_builtin = (pRendInfo->depthAttachmentFormat != VK_FORMAT_UNDEFINED); + shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = (pRendInfo->stencilAttachmentFormat != VK_FORMAT_UNDEFINED); shaderConfig.options.shouldFlipVertexY = mvkConfig().shaderConversionFlipVertexY; shaderConfig.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle; shaderConfig.options.mslOptions.tess_domain_origin_lower_left = pTessDomainOriginState && pTessDomainOriginState->domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index 3b88f5b0..7d1bb1b0 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h @@ -54,9 +54,6 @@ public: /** Returns whether this subpass has any color attachments. */ bool hasColorAttachments(); - /** Returns whether this subpass has a depth/stencil attachment. */ - bool hasDepthStencilAttachment() { return _depthStencilAttachment.attachment != VK_ATTACHMENT_UNUSED; } - /** Returns the number of color attachments, which may be zero for depth-only rendering. */ uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); } @@ -69,8 +66,17 @@ public: /** Returns whether or not the color attachment is used as both a color attachment and an input attachment. */ bool isColorAttachmentAlsoInputAttachment(uint32_t colorAttIdx); - /** Returns the format of the depth/stencil attachment. */ - VkFormat getDepthStencilFormat(); + /** Returns whether or not the depth attachment is being used. */ + bool isDepthAttachmentUsed() { return _depthAttachment.attachment != VK_ATTACHMENT_UNUSED; } + + /** Returns whether or not the stencil attachment is being used. */ + bool isStencilAttachmentUsed() { return _stencilAttachment.attachment != VK_ATTACHMENT_UNUSED; } + + /** Return the depth attachment format. */ + VkFormat getDepthFormat(); + + /** Return the stencil attachment format. */ + VkFormat getStencilFormat(); /** Returns the Vulkan sample count of the attachments used in this subpass. */ VkSampleCountFlagBits getSampleCount(); @@ -146,10 +152,11 @@ public: MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription2* pCreateInfo); -private: + MVKRenderSubpass(MVKRenderPass* renderPass, const VkRenderingInfo* pRenderingInfo); +protected: friend class MVKRenderPass; - friend class MVKRenderPassAttachment; + friend class MVKAttachmentDescription; uint32_t getViewMaskGroupForMetalPass(uint32_t passIdx); MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx); @@ -162,8 +169,10 @@ private: MVKSmallVector _preserveAttachments; MVKSmallVector _colorAttachmentFormats; VkPipelineRenderingCreateInfo _pipelineRenderingCreateInfo; - VkAttachmentReference2 _depthStencilAttachment; - VkAttachmentReference2 _depthStencilResolveAttachment; + VkAttachmentReference2 _depthAttachment; + VkAttachmentReference2 _stencilAttachment; + VkAttachmentReference2 _depthResolveAttachment; + VkAttachmentReference2 _stencilResolveAttachment; VkResolveModeFlagBits _depthResolveMode = VK_RESOLVE_MODE_NONE; VkResolveModeFlagBits _stencilResolveMode = VK_RESOLVE_MODE_NONE; VkSampleCountFlagBits _defaultSampleCount = VK_SAMPLE_COUNT_1_BIT; @@ -172,10 +181,10 @@ private: #pragma mark - -#pragma mark MVKRenderPassAttachment +#pragma mark MVKAttachmentDescription /** Represents an attachment within a Vulkan render pass. */ -class MVKRenderPassAttachment : public MVKBaseObject { +class MVKAttachmentDescription : public MVKBaseObject { public: @@ -218,13 +227,20 @@ public: /** Returns whether this attachment should be cleared in the subpass. */ bool shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil); - MVKRenderPassAttachment(MVKRenderPass* renderPass, + MVKAttachmentDescription(MVKRenderPass* renderPass, const VkAttachmentDescription* pCreateInfo); - MVKRenderPassAttachment(MVKRenderPass* renderPass, + MVKAttachmentDescription(MVKRenderPass* renderPass, const VkAttachmentDescription2* pCreateInfo); + MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkRenderingAttachmentInfo* pAttInfo, + bool isResolveAttachment); + protected: + friend class MVKRenderPass; + friend class MVKRenderSubpass; + bool isFirstUseOfAttachment(MVKRenderSubpass* subpass); bool isLastUseOfAttachment(MVKRenderSubpass* subpass); MTLStoreAction getMTLStoreAction(MVKRenderSubpass* subpass, @@ -234,7 +250,7 @@ protected: bool canResolveFormat, bool isStencil, bool storeOverride); - void validateFormat(); + void linkToSubpasses(); VkAttachmentDescription2 _info; MVKRenderPass* _renderPass; @@ -282,13 +298,15 @@ public: MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo2* pCreateInfo); + MVKRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo); + protected: friend class MVKRenderSubpass; - friend class MVKRenderPassAttachment; + friend class MVKAttachmentDescription; void propagateDebugName() override {} - MVKSmallVector _attachments; + MVKSmallVector _attachments; MVKSmallVector _subpasses; MVKSmallVector _subpassDependencies; VkRenderingFlags _renderingFlags = 0; @@ -297,21 +315,44 @@ protected: #pragma mark - -#pragma mark Support functions +#pragma mark MVKRenderingAttachmentIterator -/** Returns a MVKRenderPass object created from the rendering info. */ -MVKRenderPass* mvkCreateRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo); +typedef std::function MVKRenderingAttachmentInfoOperation; /** - * Extracts the usable attachments and their clear values from the rendering info, - * and sets them in the corresponding arrays, which must be large enough to hold - * all of the extracted values, and returns the number of attachments extracted. - * For consistency, the clear value of any resolve attachments are populated, - * even though they are ignored. + * Iterates the attachments in a VkRenderingInfo, and processes an operation + * on each attachment, once for the imageView, and once for the resolveImageView. + * + * Attachments are sequentially processed in this order: + * [color, color-resolve], ..., + * depth, depth-resolve, + * stencil, stencil-resolve + * skipping any attachments that do not have a VkImageView */ -uint32_t mvkGetAttachments(const VkRenderingInfo* pRenderingInfo, - MVKImageView* attachments[], - VkClearValue clearValues[]); +class MVKRenderingAttachmentIterator : public MVKBaseObject { + +public: + + MVKVulkanAPIObject* getVulkanAPIObject() override { return nullptr; } + + /** Iterates the attachments with the specified lambda function. */ + void iterate(MVKRenderingAttachmentInfoOperation attOperation); + + MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo) : _pRenderingInfo(pRenderingInfo) {} + +protected: + void handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, + VkImageAspectFlagBits aspect, + MVKRenderingAttachmentInfoOperation attOperation); + + const VkRenderingInfo* _pRenderingInfo; +}; + + +#pragma mark - +#pragma mark Support functions /** Returns whether the view mask uses multiview. */ static constexpr bool mvkIsMultiview(uint32_t viewMask) { return viewMask != 0; } @@ -322,9 +363,6 @@ bool mvkIsColorAttachmentUsed(const VkPipelineRenderingCreateInfo* pRendInfo, ui /** Returns whether any attachment is being used. */ bool mvkHasColorAttachments(const VkPipelineRenderingCreateInfo* pRendInfo); -/** Extracts and returns the combined depth/stencil format . */ -VkFormat mvkGetDepthStencilFormat(const VkPipelineRenderingCreateInfo* pRendInfo); - /** * Extracts the first view, number of views, and the portion of the mask * to be rendered from the lowest clump of set bits in a view mask. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index 662bf2bb..2c4bf185 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -53,9 +53,7 @@ VkFormat MVKRenderSubpass::getColorAttachmentFormat(uint32_t colorAttIdx) { } bool MVKRenderSubpass::isColorAttachmentUsed(uint32_t colorAttIdx) { - if (colorAttIdx >= _colorAttachments.size()) { - return false; - } + if (colorAttIdx >= _colorAttachments.size()) { return false; } return _colorAttachments[colorAttIdx].attachment != VK_ATTACHMENT_UNUSED; } @@ -72,10 +70,12 @@ bool MVKRenderSubpass::isColorAttachmentAlsoInputAttachment(uint32_t colorAttIdx return false; } -VkFormat MVKRenderSubpass::getDepthStencilFormat() { - uint32_t rpAttIdx = _depthStencilAttachment.attachment; - if (rpAttIdx == VK_ATTACHMENT_UNUSED) { return VK_FORMAT_UNDEFINED; } - return _renderPass->_attachments[rpAttIdx].getFormat(); +VkFormat MVKRenderSubpass::getDepthFormat() { + return isDepthAttachmentUsed() ? _renderPass->_attachments[_depthAttachment.attachment].getFormat() : VK_FORMAT_UNDEFINED; +} + +VkFormat MVKRenderSubpass::getStencilFormat() { + return isStencilAttachmentUsed() ? _renderPass->_attachments[_stencilAttachment.attachment].getFormat() : VK_FORMAT_UNDEFINED; } VkSampleCountFlagBits MVKRenderSubpass::getSampleCount() { @@ -85,11 +85,12 @@ VkSampleCountFlagBits MVKRenderSubpass::getSampleCount() { return _renderPass->_attachments[rpAttIdx].getSampleCount(); } } - uint32_t rpAttIdx = _depthStencilAttachment.attachment; - if (rpAttIdx != VK_ATTACHMENT_UNUSED) { - return _renderPass->_attachments[rpAttIdx].getSampleCount(); + if (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED) { + return _renderPass->_attachments[_depthAttachment.attachment].getSampleCount(); + } + if (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED) { + return _renderPass->_attachments[_stencilAttachment.attachment].getSampleCount(); } - return VK_SAMPLE_COUNT_1_BIT; } @@ -176,7 +177,7 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* } // Configure the color attachment - MVKRenderPassAttachment* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx]; + MVKAttachmentDescription* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx]; if (clrMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc, this, attachments[clrRPAttIdx], isRenderingEntireAttachment, hasResolveAttachment, canResolveFormat, @@ -193,66 +194,75 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* } } - // Populate the Metal depth and stencil attachments - uint32_t dsRPAttIdx = _depthStencilAttachment.attachment; - uint32_t dsRslvRPAttIdx = _depthStencilResolveAttachment.attachment; - if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) { - MVKRenderPassAttachment* dsMVKRPAtt = &_renderPass->_attachments[dsRPAttIdx]; - MVKImageView* dsImage = attachments[dsRPAttIdx]; - MVKImageView* dsRslvImage = nullptr; - MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat(0); + // Populate the Metal depth attachment + uint32_t depthRPAttIdx = _depthAttachment.attachment; + if (depthRPAttIdx != VK_ATTACHMENT_UNUSED) { + MVKAttachmentDescription* depthMVKRPAtt = &_renderPass->_attachments[depthRPAttIdx]; + MVKImageView* depthImage = attachments[depthRPAttIdx]; - if (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED) { - dsRslvImage = attachments[dsRslvRPAttIdx]; + MVKImageView* depthRslvImage = nullptr; + uint32_t depthRslvRPAttIdx = _depthResolveAttachment.attachment; + if (depthRslvRPAttIdx != VK_ATTACHMENT_UNUSED) { + depthRslvImage = attachments[depthRslvRPAttIdx]; } - if (pixFmts->isDepthFormat(mtlDSFormat)) { - MTLRenderPassDepthAttachmentDescriptor* mtlDepthAttDesc = mtlRPDesc.depthAttachment; - bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE); - if (hasResolveAttachment) { - dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlDepthAttDesc); - mtlDepthAttDesc.depthResolveFilterMVK = mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(_depthResolveMode); - if (isMultiview()) { - mtlDepthAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); - } - } - if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, dsImage, - isRenderingEntireAttachment, - hasResolveAttachment, true, - false, loadOverride)) { - mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[dsRPAttIdx]); - } + MTLRenderPassDepthAttachmentDescriptor* mtlDepthAttDesc = mtlRPDesc.depthAttachment; + bool hasDepthResolve = depthRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE; + if (hasDepthResolve) { + depthRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlDepthAttDesc); + mtlDepthAttDesc.depthResolveFilterMVK = mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(_depthResolveMode); if (isMultiview()) { - mtlDepthAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + mtlDepthAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); } } - if (pixFmts->isStencilFormat(mtlDSFormat)) { - MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment; - bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE); - if (hasResolveAttachment) { - dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlStencilAttDesc); + if (depthMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, depthImage, + isRenderingEntireAttachment, + hasDepthResolve, true, + false, loadOverride)) { + mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[depthRPAttIdx]); + } + if (isMultiview()) { + mtlDepthAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + } + } + + // Populate the Metal stencil attachment + uint32_t stencilRPAttIdx = _stencilAttachment.attachment; + if (stencilRPAttIdx != VK_ATTACHMENT_UNUSED) { + MVKAttachmentDescription* stencilMVKRPAtt = &_renderPass->_attachments[stencilRPAttIdx]; + MVKImageView* stencilImage = attachments[stencilRPAttIdx]; + + MVKImageView* stencilRslvImage = nullptr; + uint32_t stencilRslvRPAttIdx = _stencilResolveAttachment.attachment; + if (stencilRslvRPAttIdx != VK_ATTACHMENT_UNUSED) { + stencilRslvImage = attachments[stencilRslvRPAttIdx]; + } + + MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment; + bool hasStencilResolve = (stencilRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE); + if (hasStencilResolve) { + stencilRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlStencilAttDesc); #if MVK_MACOS_OR_IOS - mtlStencilAttDesc.stencilResolveFilterMVK = mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(_stencilResolveMode); + mtlStencilAttDesc.stencilResolveFilterMVK = mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(_stencilResolveMode); #endif - if (isMultiview()) { - mtlStencilAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); - } - } - if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, dsImage, - isRenderingEntireAttachment, - hasResolveAttachment, true, - true, loadOverride)) { - mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[dsRPAttIdx]); - } if (isMultiview()) { - mtlStencilAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + mtlStencilAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx); } } + if (stencilMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, stencilImage, + isRenderingEntireAttachment, + hasStencilResolve, true, + true, loadOverride)) { + mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[stencilRPAttIdx]); + } + if (isMultiview()) { + mtlStencilAttDesc.slice += getFirstViewIndexInMetalPass(passIdx); + } } // Vulkan supports rendering without attachments, but older Metal does not. // If Metal does not support rendering without attachments, create a dummy attachment to pass Metal validation. - if (caUsedCnt == 0 && dsRPAttIdx == VK_ATTACHMENT_UNUSED) { + if (caUsedCnt == 0 && depthRPAttIdx == VK_ATTACHMENT_UNUSED && stencilRPAttIdx == VK_ATTACHMENT_UNUSED) { if (_renderPass->getDevice()->_pMetalFeatures->renderWithoutAttachments) { mtlRPDesc.defaultRasterSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_defaultSampleCount); } else { @@ -285,42 +295,42 @@ void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder, _renderPass->_attachments[clrRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[clrRPAttIdx], isRenderingEntireAttachment, hasResolveAttachment, canResolveFormat, caIdx, false, storeOverride); } } - uint32_t dsRPAttIdx = _depthStencilAttachment.attachment; - if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) { - bool hasResolveAttachment = _depthStencilResolveAttachment.attachment != VK_ATTACHMENT_UNUSED; - bool hasDepthResolveAttachment = hasResolveAttachment && _depthResolveMode != VK_RESOLVE_MODE_NONE; - bool hasStencilResolveAttachment = hasResolveAttachment && _stencilResolveMode != VK_RESOLVE_MODE_NONE; - bool canResolveFormat = true; - _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[dsRPAttIdx], isRenderingEntireAttachment, hasDepthResolveAttachment, canResolveFormat, 0, false, storeOverride); - _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[dsRPAttIdx], isRenderingEntireAttachment, hasStencilResolveAttachment, canResolveFormat, 0, true, storeOverride); - } + if (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED) { + _renderPass->_attachments[_depthAttachment.attachment].encodeStoreAction(cmdEncoder, this, attachments[_depthAttachment.attachment], isRenderingEntireAttachment, + (_depthResolveAttachment.attachment != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE), + true, 0, false, storeOverride); + } + if (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED) { + _renderPass->_attachments[_stencilAttachment.attachment].encodeStoreAction(cmdEncoder, this, attachments[_stencilAttachment.attachment], isRenderingEntireAttachment, + (_stencilResolveAttachment.attachment != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE), + true, 0, true, storeOverride); + } } void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts, const MVKArrayRef clearValues) { - uint32_t attIdx; uint32_t caCnt = getColorAttachmentCount(); for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { - attIdx = _colorAttachments[caIdx].attachment; + uint32_t attIdx = _colorAttachments[caIdx].attachment; 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) { - MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); - 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 depth and stencil both need clearing and are the same attachment, just clear once, otherwise, clear them separately. + bool shouldClearDepth = (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED && + _renderPass->_attachments[_depthAttachment.attachment].shouldClearAttachment(this, false)); + bool shouldClearStencil = (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED && + _renderPass->_attachments[_stencilAttachment.attachment].shouldClearAttachment(this, true)); + + if (shouldClearDepth && shouldClearStencil && _depthAttachment.attachment == _stencilAttachment.attachment) { + clearAtts.push_back( { VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, clearValues[_depthAttachment.attachment] } ); + } else { + if (shouldClearDepth) { + clearAtts.push_back( { VK_IMAGE_ASPECT_DEPTH_BIT, 0, clearValues[_depthAttachment.attachment] } ); } - 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 (shouldClearStencil) { + clearAtts.push_back( { VK_IMAGE_ASPECT_STENCIL_BIT, 0, clearValues[_stencilAttachment.attachment] } ); } } } @@ -328,18 +338,24 @@ void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts, void MVKRenderSubpass::populateMultiviewClearRects(MVKSmallVector& clearRects, MVKCommandEncoder* cmdEncoder, uint32_t caIdx, VkImageAspectFlags aspectMask) { - uint32_t attIdx; - assert(this == cmdEncoder->getSubpass()); - if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - attIdx = _depthStencilAttachment.attachment; - if (attIdx != VK_ATTACHMENT_UNUSED) { - _renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder); + if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)) { + uint32_t clrAttIdx = _colorAttachments[caIdx].attachment; + if (clrAttIdx != VK_ATTACHMENT_UNUSED) { + _renderPass->_attachments[clrAttIdx].populateMultiviewClearRects(clearRects, cmdEncoder); } - return; } - attIdx = _colorAttachments[caIdx].attachment; - if (attIdx != VK_ATTACHMENT_UNUSED) { - _renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder); + + // If depth and stencil are the same attachment, only clear once. + if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT) && + _depthAttachment.attachment != VK_ATTACHMENT_UNUSED) { + + _renderPass->_attachments[_depthAttachment.attachment].populateMultiviewClearRects(clearRects, cmdEncoder); + } + if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT) && + _stencilAttachment.attachment != VK_ATTACHMENT_UNUSED && + _stencilAttachment.attachment != _depthAttachment.attachment) { + + _renderPass->_attachments[_stencilAttachment.attachment].populateMultiviewClearRects(clearRects, cmdEncoder); } } @@ -368,8 +384,12 @@ MVKMTLFmtCaps MVKRenderSubpass::getRequiredFormatCapabilitiesForAttachmentAt(uin break; } } - if (_depthStencilAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); } - if (_depthStencilResolveAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsResolve); } + if (_depthAttachment.attachment == rpAttIdx || _stencilAttachment.attachment == rpAttIdx) { + mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); + } + if (_depthResolveAttachment.attachment == rpAttIdx || _stencilResolveAttachment.attachment == rpAttIdx) { + mvkEnableFlags(caps, kMVKMTLFmtCapsResolve); + } return caps; } @@ -405,9 +425,7 @@ void MVKRenderSubpass::resolveUnresolvableAttachments(MVKCommandEncoder* cmdEnco } } -// Must be called after renderpass has both subpasses and attachments bound void MVKRenderSubpass::populatePipelineRenderingCreateInfo() { - MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); _pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; _pipelineRenderingCreateInfo.pNext = nullptr; @@ -415,78 +433,24 @@ void MVKRenderSubpass::populatePipelineRenderingCreateInfo() { for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { _colorAttachmentFormats.push_back(getColorAttachmentFormat(caIdx)); } - _pipelineRenderingCreateInfo.pColorAttachmentFormats = _colorAttachmentFormats.data(); _pipelineRenderingCreateInfo.colorAttachmentCount = caCnt; - - VkFormat dsFmt = getDepthStencilFormat(); - MTLPixelFormat dsMTLFmt = pixFmts->getMTLPixelFormat(dsFmt); - _pipelineRenderingCreateInfo.depthAttachmentFormat = pixFmts->isDepthFormat(dsMTLFmt) ? dsFmt : VK_FORMAT_UNDEFINED; - _pipelineRenderingCreateInfo.stencilAttachmentFormat = pixFmts->isStencilFormat(dsMTLFmt) ? dsFmt : VK_FORMAT_UNDEFINED; + _pipelineRenderingCreateInfo.pColorAttachmentFormats = _colorAttachmentFormats.data(); + _pipelineRenderingCreateInfo.depthAttachmentFormat = getDepthFormat(); + _pipelineRenderingCreateInfo.stencilAttachmentFormat = getStencilFormat(); } -MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, - const VkSubpassDescription* pCreateInfo, - const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects, - uint32_t viewMask) { - _renderPass = renderPass; - _subpassIndex = (uint32_t)_renderPass->_subpasses.size(); - _pipelineRenderingCreateInfo.viewMask = viewMask; +static const VkAttachmentReference2 _unusedAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED, 0}; - // Add attachments - _inputAttachments.reserve(pCreateInfo->inputAttachmentCount); - for (uint32_t i = 0; i < pCreateInfo->inputAttachmentCount; i++) { - const VkAttachmentReference& att = pCreateInfo->pInputAttachments[i]; - _inputAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0}); - } - if (pInputAspects && pInputAspects->aspectReferenceCount) { - for (uint32_t i = 0; i < pInputAspects->aspectReferenceCount; i++) { - const VkInputAttachmentAspectReference& aspectRef = pInputAspects->pAspectReferences[i]; - if (aspectRef.subpass == _subpassIndex) { - _inputAttachments[aspectRef.inputAttachmentIndex].aspectMask = aspectRef.aspectMask; - } - } - } - - _colorAttachments.reserve(pCreateInfo->colorAttachmentCount); - for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { - const VkAttachmentReference& att = pCreateInfo->pColorAttachments[i]; - _colorAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0}); - } - - if (pCreateInfo->pResolveAttachments) { - _resolveAttachments.reserve(pCreateInfo->colorAttachmentCount); - for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { - const VkAttachmentReference& att = pCreateInfo->pResolveAttachments[i]; - _resolveAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0}); - } - } - - if (pCreateInfo->pDepthStencilAttachment) { - _depthStencilAttachment.attachment = pCreateInfo->pDepthStencilAttachment->attachment; - _depthStencilAttachment.layout = pCreateInfo->pDepthStencilAttachment->layout; - } else { - _depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED; - } - - _depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED; - - _preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount); - for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) { - _preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]); - } -} - -MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, - const VkSubpassDescription2* pCreateInfo) { +MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription2* pCreateInfo) { VkSubpassDescriptionDepthStencilResolve* pDSResolveInfo = nullptr; for (auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { switch (next->sType) { - case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: - pDSResolveInfo = (VkSubpassDescriptionDepthStencilResolve*)next; - break; - default: - break; + case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: + pDSResolveInfo = (VkSubpassDescriptionDepthStencilResolve*)next; + break; + default: + break; } } @@ -512,44 +476,177 @@ MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, } } - if (pCreateInfo->pDepthStencilAttachment) { - _depthStencilAttachment = *pCreateInfo->pDepthStencilAttachment; - } else { - _depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED; + MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); + + _depthAttachment = _unusedAttachment; + _stencilAttachment = _unusedAttachment; + const auto* pDSAtt = pCreateInfo->pDepthStencilAttachment; + if (pDSAtt && pDSAtt->attachment != VK_ATTACHMENT_UNUSED) { + MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[pDSAtt->attachment].getFormat()); + if (pixFmts->isDepthFormat(mtlDSFormat)) { + _depthAttachment = *pCreateInfo->pDepthStencilAttachment; + } + if (pixFmts->isStencilFormat(mtlDSFormat)) { + _stencilAttachment = *pCreateInfo->pDepthStencilAttachment; + } } - if (pDSResolveInfo && pDSResolveInfo->pDepthStencilResolveAttachment) { - _depthStencilResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment; - _depthResolveMode = pDSResolveInfo->depthResolveMode; - _stencilResolveMode = pDSResolveInfo->stencilResolveMode; - } else { - _depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED; + _depthResolveAttachment = _unusedAttachment; + _stencilResolveAttachment = _unusedAttachment; + const auto* pDSRslvAtt = pDSResolveInfo ? pDSResolveInfo->pDepthStencilResolveAttachment : nullptr; + if (pDSRslvAtt && pDSRslvAtt->attachment != VK_ATTACHMENT_UNUSED) { + MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[pDSRslvAtt->attachment].getFormat()); + if (pixFmts->isDepthFormat(mtlDSFormat)) { + _depthResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment; + _depthResolveMode = pDSResolveInfo->depthResolveMode; + } + if (pixFmts->isStencilFormat(mtlDSFormat)) { + _stencilResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment; + _stencilResolveMode = pDSResolveInfo->stencilResolveMode; + } } _preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount); for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) { _preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]); } + + populatePipelineRenderingCreateInfo(); +} + +MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, + const VkSubpassDescription* pCreateInfo, + const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects, + uint32_t viewMask) { + _renderPass = renderPass; + _subpassIndex = (uint32_t)_renderPass->_subpasses.size(); + _pipelineRenderingCreateInfo.viewMask = viewMask; + + // Add attachments + _inputAttachments.reserve(pCreateInfo->inputAttachmentCount); + for (uint32_t i = 0; i < pCreateInfo->inputAttachmentCount; i++) { + const VkAttachmentReference& att = pCreateInfo->pInputAttachments[i]; + _inputAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT}); + } + if (pInputAspects && pInputAspects->aspectReferenceCount) { + for (uint32_t i = 0; i < pInputAspects->aspectReferenceCount; i++) { + const VkInputAttachmentAspectReference& aspectRef = pInputAspects->pAspectReferences[i]; + if (aspectRef.subpass == _subpassIndex) { + _inputAttachments[aspectRef.inputAttachmentIndex].aspectMask = aspectRef.aspectMask; + } + } + } + + _colorAttachments.reserve(pCreateInfo->colorAttachmentCount); + for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { + const VkAttachmentReference& att = pCreateInfo->pColorAttachments[i]; + _colorAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT}); + } + + if (pCreateInfo->pResolveAttachments) { + _resolveAttachments.reserve(pCreateInfo->colorAttachmentCount); + for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) { + const VkAttachmentReference& att = pCreateInfo->pResolveAttachments[i]; + _resolveAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT}); + } + } + + _depthAttachment = _unusedAttachment; + _stencilAttachment = _unusedAttachment; + if (pCreateInfo->pDepthStencilAttachment) { + auto* dsAtt = pCreateInfo->pDepthStencilAttachment; + uint32_t dsAttIdx = dsAtt->attachment; + if (dsAttIdx != VK_ATTACHMENT_UNUSED) { + MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); + MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[dsAttIdx].getFormat()); + if (pixFmts->isDepthFormat(mtlDSFormat)) { + _depthAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, dsAtt->attachment, dsAtt->layout, VK_IMAGE_ASPECT_DEPTH_BIT}; + } + if (pixFmts->isStencilFormat(mtlDSFormat)) { + _stencilAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, dsAtt->attachment, dsAtt->layout, VK_IMAGE_ASPECT_STENCIL_BIT}; + } + } + } + + _depthResolveAttachment = _unusedAttachment; + _stencilResolveAttachment = _unusedAttachment; + + _preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount); + for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) { + _preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]); + } + + populatePipelineRenderingCreateInfo(); + +} + +MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, const VkRenderingInfo* pRenderingInfo) { + + _renderPass = renderPass; + _subpassIndex = (uint32_t)_renderPass->_subpasses.size(); + _pipelineRenderingCreateInfo.viewMask = pRenderingInfo->viewMask; + + _depthAttachment = _unusedAttachment; + _depthResolveAttachment = _unusedAttachment; + _stencilAttachment = _unusedAttachment; + _stencilResolveAttachment = _unusedAttachment; + + uint32_t attIdx = 0; + MVKRenderingAttachmentIterator attIter(pRenderingInfo); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { + VkAttachmentReference2 attRef = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, attIdx++, pAttInfo->imageLayout, aspect}; + switch (aspect) { + case VK_IMAGE_ASPECT_COLOR_BIT: + if (isResolveAttachment) { + _resolveAttachments.push_back(attRef); + } else { + _colorAttachments.push_back(attRef); + } + break; + + case VK_IMAGE_ASPECT_DEPTH_BIT: + if (isResolveAttachment) { + _depthResolveAttachment = attRef; + _depthResolveMode = pAttInfo->resolveMode; + } else { + _depthAttachment = attRef; + } + break; + case VK_IMAGE_ASPECT_STENCIL_BIT: + if (isResolveAttachment) { + _stencilResolveAttachment = attRef; + _stencilResolveMode = pAttInfo->resolveMode; + } else { + _stencilAttachment = attRef; + } + break; + + default: + break; + } + }); + + populatePipelineRenderingCreateInfo(); } #pragma mark - -#pragma mark MVKRenderPassAttachment +#pragma mark MVKAttachmentDescription -MVKVulkanAPIObject* MVKRenderPassAttachment::getVulkanAPIObject() { return _renderPass->getVulkanAPIObject(); }; +MVKVulkanAPIObject* MVKAttachmentDescription::getVulkanAPIObject() { return _renderPass->getVulkanAPIObject(); }; -VkFormat MVKRenderPassAttachment::getFormat() { return _info.format; } +VkFormat MVKAttachmentDescription::getFormat() { return _info.format; } -VkSampleCountFlagBits MVKRenderPassAttachment::getSampleCount() { return _info.samples; } +VkSampleCountFlagBits MVKAttachmentDescription::getSampleCount() { return _info.samples; } -bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc, - MVKRenderSubpass* subpass, - MVKImageView* attachment, - bool isRenderingEntireAttachment, - bool hasResolveAttachment, - bool canResolveFormat, - bool isStencil, - bool loadOverride) { +bool MVKAttachmentDescription::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc, + MVKRenderSubpass* subpass, + MVKImageView* attachment, + bool isRenderingEntireAttachment, + bool hasResolveAttachment, + bool canResolveFormat, + bool isStencil, + bool loadOverride) { // Populate from the attachment image view attachment->populateMTLRenderPassAttachmentDescriptor(mtlAttDesc); @@ -597,15 +694,15 @@ bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRende return (mtlLA == MTLLoadActionClear); } -void MVKRenderPassAttachment::encodeStoreAction(MVKCommandEncoder* cmdEncoder, - MVKRenderSubpass* subpass, - MVKImageView* attachment, - bool isRenderingEntireAttachment, - bool hasResolveAttachment, - bool canResolveFormat, - uint32_t caIdx, - bool isStencil, - bool storeOverride) { +void MVKAttachmentDescription::encodeStoreAction(MVKCommandEncoder* cmdEncoder, + MVKRenderSubpass* subpass, + MVKImageView* attachment, + bool isRenderingEntireAttachment, + bool hasResolveAttachment, + bool canResolveFormat, + uint32_t caIdx, + bool isStencil, + bool storeOverride) { // For a combined depth-stencil format in an attachment with VK_IMAGE_ASPECT_STENCIL_BIT, // the attachment format may have been swizzled to a stencil-only format. In this case, // we want to guard against an attempt to store the non-existent depth component. @@ -630,7 +727,7 @@ void MVKRenderPassAttachment::encodeStoreAction(MVKCommandEncoder* cmdEncoder, } } -void MVKRenderPassAttachment::populateMultiviewClearRects(MVKSmallVector& clearRects, MVKCommandEncoder* cmdEncoder) { +void MVKAttachmentDescription::populateMultiviewClearRects(MVKSmallVector& clearRects, MVKCommandEncoder* cmdEncoder) { MVKRenderSubpass* subpass = cmdEncoder->getSubpass(); uint32_t clearMask = subpass->getViewMaskGroupForMetalPass(cmdEncoder->getMultiviewPassIndex()) & _firstUseViewMasks[subpass->_subpassIndex]; @@ -643,7 +740,7 @@ void MVKRenderPassAttachment::populateMultiviewClearRects(MVKSmallVectorisMultiview() ) { return _firstUseViewMasks[subpass->_subpassIndex] == subpass->_pipelineRenderingCreateInfo.viewMask; } else { @@ -651,7 +748,7 @@ bool MVKRenderPassAttachment::isFirstUseOfAttachment(MVKRenderSubpass* subpass) } } -bool MVKRenderPassAttachment::isLastUseOfAttachment(MVKRenderSubpass* subpass) { +bool MVKAttachmentDescription::isLastUseOfAttachment(MVKRenderSubpass* subpass) { if ( subpass->isMultiview() ) { return _lastUseViewMasks[subpass->_subpassIndex] == subpass->_pipelineRenderingCreateInfo.viewMask; } else { @@ -659,13 +756,13 @@ bool MVKRenderPassAttachment::isLastUseOfAttachment(MVKRenderSubpass* subpass) { } } -MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subpass, - bool isRenderingEntireAttachment, - bool isMemorylessAttachment, - bool hasResolveAttachment, - bool canResolveFormat, - bool isStencil, - bool storeOverride) { +MTLStoreAction MVKAttachmentDescription::getMTLStoreAction(MVKRenderSubpass* subpass, + bool isRenderingEntireAttachment, + bool isMemorylessAttachment, + bool hasResolveAttachment, + bool canResolveFormat, + bool isStencil, + bool storeOverride) { // If the renderpass is going to be suspended, and resumed later, store the contents to preserve them until then. if (mvkIsAnyFlagEnabled(_renderPass->getRenderingFlags(), VK_RENDERING_SUSPENDING_BIT)) { @@ -690,7 +787,7 @@ MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subp return mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment, canResolveFormat); } -bool MVKRenderPassAttachment::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) { +bool MVKAttachmentDescription::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) { // If the renderpass is being resumed after being suspended, don't clear this attachment. if (mvkIsAnyFlagEnabled(_renderPass->getRenderingFlags(), VK_RENDERING_RESUMING_BIT_KHR)) { return false; } @@ -705,7 +802,8 @@ bool MVKRenderPassAttachment::shouldClearAttachment(MVKRenderSubpass* subpass, b return loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR; } -void MVKRenderPassAttachment::validateFormat() { +// Must be called after renderpass has both subpasses and attachments bound +void MVKAttachmentDescription::linkToSubpasses() { // Validate pixel format is supported MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); if ( !pixFmts->isSupportedOrSubstitutable(_info.format) ) { @@ -715,7 +813,7 @@ void MVKRenderPassAttachment::validateFormat() { // Determine the indices of the first and last render subpasses to use this attachment. _firstUseSubpassIdx = kMVKUndefinedLargeUInt32; _lastUseSubpassIdx = 0; - if ( _renderPass->isMultiview() ) { + if (_renderPass->_subpasses[0].isMultiview()) { _firstUseViewMasks.reserve(_renderPass->_subpasses.size()); _lastUseViewMasks.reserve(_renderPass->_subpasses.size()); } @@ -746,8 +844,8 @@ void MVKRenderPassAttachment::validateFormat() { } } -MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass, - const VkAttachmentDescription* pCreateInfo) { +MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkAttachmentDescription* pCreateInfo) { _info.flags = pCreateInfo->flags; _info.format = pCreateInfo->format; _info.samples = pCreateInfo->samples; @@ -759,17 +857,41 @@ MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass, _info.finalLayout = pCreateInfo->finalLayout; _renderPass = renderPass; _attachmentIndex = uint32_t(_renderPass->_attachments.size()); - - validateFormat(); } -MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass, - const VkAttachmentDescription2* pCreateInfo) { +MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkAttachmentDescription2* pCreateInfo) { _info = *pCreateInfo; _renderPass = renderPass; _attachmentIndex = uint32_t(_renderPass->_attachments.size()); +} - validateFormat(); +MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass, + const VkRenderingAttachmentInfo* pAttInfo, + bool isResolveAttachment) { + if (isResolveAttachment) { + _info.flags = 0; + _info.format = ((MVKImageView*)pAttInfo->resolveImageView)->getVkFormat(); + _info.samples = VK_SAMPLE_COUNT_1_BIT; + _info.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + _info.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + _info.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + _info.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + _info.initialLayout = pAttInfo->resolveImageLayout; + _info.finalLayout = pAttInfo->resolveImageLayout; + } else { + _info.flags = 0; + _info.format = ((MVKImageView*)pAttInfo->imageView)->getVkFormat(); + _info.samples = ((MVKImageView*)pAttInfo->imageView)->getSampleCount(); + _info.loadOp = pAttInfo->loadOp; + _info.storeOp = pAttInfo->storeOp; + _info.stencilLoadOp = pAttInfo->loadOp; + _info.stencilStoreOp = pAttInfo->storeOp; + _info.initialLayout = pAttInfo->imageLayout; + _info.finalLayout = pAttInfo->imageLayout; + } + _renderPass = renderPass; + _attachmentIndex = uint32_t(_renderPass->_attachments.size()); } @@ -786,8 +908,6 @@ VkExtent2D MVKRenderPass::getRenderAreaGranularity() { return { 1, 1 }; } -bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); } - MVKRenderPass::MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { @@ -815,7 +935,13 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device, viewOffsets = pMultiviewCreateInfo->pViewOffsets; } - // Add subpasses and dependencies first + // Add attachments first so subpasses can access them during creation + _attachments.reserve(pCreateInfo->attachmentCount); + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]); + } + + // Add subpasses and dependencies _subpasses.reserve(pCreateInfo->subpassCount); for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { _subpasses.emplace_back(this, &pCreateInfo->pSubpasses[i], pInputAspectCreateInfo, viewMasks ? viewMasks[i] : 0); @@ -837,23 +963,22 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device, _subpassDependencies.push_back(dependency); } - // Add attachments after subpasses, so each attachment can link to subpasses + // Link attachments to subpasses + for (auto& att : _attachments) { + att.linkToSubpasses(); + } +} + +MVKRenderPass::MVKRenderPass(MVKDevice* device, + const VkRenderPassCreateInfo2* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { + + // Add attachments first so subpasses can access them during creation _attachments.reserve(pCreateInfo->attachmentCount); for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]); } - // Populate additional subpass info after attachments added. - for (auto& mvkSP : _subpasses) { - mvkSP.populatePipelineRenderingCreateInfo(); - } -} - - -MVKRenderPass::MVKRenderPass(MVKDevice* device, - const VkRenderPassCreateInfo2* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { - - // Add subpasses and dependencies first + // Add subpasses and dependencies _subpasses.reserve(pCreateInfo->subpassCount); for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { _subpasses.emplace_back(this, &pCreateInfo->pSubpasses[i]); @@ -863,15 +988,54 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device, _subpassDependencies.push_back(pCreateInfo->pDependencies[i]); } - // Add attachments after subpasses, so each attachment can link to subpasses - _attachments.reserve(pCreateInfo->attachmentCount); - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { - _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]); + // Link attachments to subpasses + for (auto& att : _attachments) { + att.linkToSubpasses(); } +} - // Populate additional subpass info after attachments added. - for (auto& mvkSP : _subpasses) { - mvkSP.populatePipelineRenderingCreateInfo(); +MVKRenderPass::MVKRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo) : MVKVulkanAPIDeviceObject(device) { + + _renderingFlags = pRenderingInfo->flags; + + // Add attachments first so subpasses can access them during creation + uint32_t attCnt = 0; + MVKRenderingAttachmentIterator attIter(pRenderingInfo); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { attCnt++; }); + _attachments.reserve(attCnt); + attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { + _attachments.emplace_back(this, pAttInfo, isResolveAttachment); + }); + + // Add subpass + _subpasses.emplace_back(this, pRenderingInfo); + + // Link attachments to subpasses + for (auto& att : _attachments) { + att.linkToSubpasses(); + } +} + + +#pragma mark - +#pragma mark MVKRenderingAttachmentIterator + +void MVKRenderingAttachmentIterator::iterate(MVKRenderingAttachmentInfoOperation attOperation) { + for (uint32_t caIdx = 0; caIdx < _pRenderingInfo->colorAttachmentCount; caIdx++) { + handleAttachment(&_pRenderingInfo->pColorAttachments[caIdx], VK_IMAGE_ASPECT_COLOR_BIT, attOperation); + } + handleAttachment(_pRenderingInfo->pDepthAttachment, VK_IMAGE_ASPECT_DEPTH_BIT, attOperation); + handleAttachment(_pRenderingInfo->pStencilAttachment, VK_IMAGE_ASPECT_STENCIL_BIT, attOperation); +} + +void MVKRenderingAttachmentIterator::handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, + VkImageAspectFlagBits aspect, + MVKRenderingAttachmentInfoOperation attOperation) { + if (pAttInfo && pAttInfo->imageView) { + attOperation(pAttInfo, aspect, false); + if (pAttInfo->resolveImageView && pAttInfo->resolveMode != VK_RESOLVE_MODE_NONE) { + attOperation(pAttInfo, aspect, true); + } } } @@ -879,199 +1043,6 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device, #pragma mark - #pragma mark Support functions -// Adds the rendering attachment info to the array of attachment descriptors at the index, -// and increments the index, for both the base view and the resolve view, if it is present. -static void mvkAddAttachmentDescriptor(const VkRenderingAttachmentInfo* pAttInfo, - const VkRenderingAttachmentInfo* pStencilAttInfo, - VkAttachmentDescription2 attachmentDescriptors[], - uint32_t& attDescIdx) { - VkAttachmentDescription2 attDesc; - attDesc.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - attDesc.pNext = nullptr; - attDesc.flags = 0; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - - // Handle stencil-only possibility. - if ( !pAttInfo ) { pAttInfo = pStencilAttInfo; } - - if (pAttInfo && pAttInfo->imageView) { - MVKImageView* mvkImgView = (MVKImageView*)pAttInfo->imageView; - attDesc.format = mvkImgView->getVkFormat(); - attDesc.samples = mvkImgView->getSampleCount(); - attDesc.loadOp = pAttInfo->loadOp; - attDesc.storeOp = pAttInfo->storeOp; - attDesc.stencilLoadOp = pStencilAttInfo ? pStencilAttInfo->loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = pStencilAttInfo ? pStencilAttInfo->storeOp : VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = pAttInfo->imageLayout; - attDesc.finalLayout = pAttInfo->imageLayout; - attachmentDescriptors[attDescIdx++] = attDesc; - - if (pAttInfo->resolveImageView && pAttInfo->resolveMode != VK_RESOLVE_MODE_NONE) { - attDesc.samples = VK_SAMPLE_COUNT_1_BIT; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = pStencilAttInfo ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = pAttInfo->resolveImageLayout; - attDesc.finalLayout = pAttInfo->resolveImageLayout; - attachmentDescriptors[attDescIdx++] = attDesc; - } - } -} - -MVKRenderPass* mvkCreateRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo) { - - // Renderpass attachments are sequentially indexed in this order: - // [color, color-resolve], ..., ds, ds-resolve - // skipping any attachments that do not have a VkImageView - uint32_t maxAttDescCnt = (pRenderingInfo->colorAttachmentCount + 1) * 2; - VkAttachmentDescription2 attachmentDescriptors[maxAttDescCnt]; - VkAttachmentReference2 colorAttachmentRefs[pRenderingInfo->colorAttachmentCount]; - VkAttachmentReference2 resolveAttachmentRefs[pRenderingInfo->colorAttachmentCount]; - - VkAttachmentReference2 attRef; - attRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2; - attRef.pNext = nullptr; - attRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - uint32_t attDescIdx = 0; - uint32_t caRefIdx = 0; - bool hasClrRslvAtt = false; - for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) { - auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx]; - if (clrAtt.imageView) { - attRef.layout = clrAtt.imageLayout; - attRef.attachment = attDescIdx; - colorAttachmentRefs[caRefIdx] = attRef; - - if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) { - attRef.layout = clrAtt.resolveImageLayout; - attRef.attachment = attDescIdx + 1; - resolveAttachmentRefs[caRefIdx] = attRef; - hasClrRslvAtt = true; - } - caRefIdx++; - } - mvkAddAttachmentDescriptor(&clrAtt, nullptr, attachmentDescriptors, attDescIdx); - } - - // Combine depth and stencil attachments into one depth-stencil attachment. - // If both depth and stencil are present, their views and layouts must match. - VkAttachmentReference2 dsAttRef; - VkAttachmentReference2 dsRslvAttRef; - VkResolveModeFlagBits depthResolveMode = VK_RESOLVE_MODE_NONE; - VkResolveModeFlagBits stencilResolveMode = VK_RESOLVE_MODE_NONE; - - attRef.aspectMask = 0; - attRef.layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkImageLayout rslvLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - if (pRenderingInfo->pDepthAttachment && pRenderingInfo->pDepthAttachment->imageView) { - attRef.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - depthResolveMode = pRenderingInfo->pDepthAttachment->resolveMode; - attRef.layout = pRenderingInfo->pDepthAttachment->imageLayout; - rslvLayout = pRenderingInfo->pDepthAttachment->resolveImageLayout; - } - if (pRenderingInfo->pStencilAttachment && pRenderingInfo->pStencilAttachment->imageView) { - attRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - stencilResolveMode = pRenderingInfo->pStencilAttachment->resolveMode; - attRef.layout = pRenderingInfo->pStencilAttachment->imageLayout; - rslvLayout = pRenderingInfo->pStencilAttachment->resolveImageLayout; - } - - attRef.attachment = attRef.aspectMask ? attDescIdx : VK_ATTACHMENT_UNUSED; - dsAttRef = attRef; - - attRef.layout = rslvLayout; - attRef.attachment = attDescIdx + 1; - dsRslvAttRef = attRef; - - mvkAddAttachmentDescriptor(pRenderingInfo->pDepthAttachment, - pRenderingInfo->pStencilAttachment, - attachmentDescriptors, attDescIdx); - - // Depth/stencil resolve handled via VkSubpassDescription2 pNext - VkSubpassDescriptionDepthStencilResolve dsRslv; - dsRslv.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE; - dsRslv.pNext = nullptr; - dsRslv.depthResolveMode = depthResolveMode; - dsRslv.stencilResolveMode = stencilResolveMode; - dsRslv.pDepthStencilResolveAttachment = &dsRslvAttRef; - bool hasDSRslvAtt = depthResolveMode != VK_RESOLVE_MODE_NONE || stencilResolveMode != VK_RESOLVE_MODE_NONE; - - // Define the subpass - VkSubpassDescription2 spDesc; - spDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2; - spDesc.pNext = hasDSRslvAtt ? &dsRslv : nullptr; - spDesc.flags = 0; - spDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - spDesc.viewMask = pRenderingInfo->viewMask; - spDesc.inputAttachmentCount = 0; - spDesc.pInputAttachments = nullptr; - spDesc.colorAttachmentCount = caRefIdx; - spDesc.pColorAttachments = colorAttachmentRefs; - spDesc.pResolveAttachments = hasClrRslvAtt ? resolveAttachmentRefs : nullptr;; - spDesc.pDepthStencilAttachment = &dsAttRef; - spDesc.preserveAttachmentCount = 0; - spDesc.pPreserveAttachments = nullptr; - - // Define the renderpass - VkRenderPassCreateInfo2 rpCreateInfo; - rpCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; - rpCreateInfo.pNext = nullptr; - rpCreateInfo.flags = 0; - rpCreateInfo.attachmentCount = attDescIdx; - rpCreateInfo.pAttachments = attachmentDescriptors; - rpCreateInfo.subpassCount = 1; - rpCreateInfo.pSubpasses = &spDesc; - rpCreateInfo.dependencyCount = 0; - rpCreateInfo.pDependencies = nullptr; - rpCreateInfo.correlatedViewMaskCount = 0; - rpCreateInfo.pCorrelatedViewMasks = nullptr; - - auto* mvkRP = device->createRenderPass(&rpCreateInfo, nullptr); - mvkRP->setRenderingFlags(pRenderingInfo->flags); - return mvkRP; -} - -uint32_t mvkGetAttachments(const VkRenderingInfo* pRenderingInfo, - MVKImageView* attachments[], - VkClearValue clearValues[]) { - - // Renderpass attachments are sequentially indexed in this order: - // [color, color-resolve], ..., ds, ds-resolve - // skipping any attachments that do not have a VkImageView - // For consistency, we populate the clear value of any resolve attachments, even though they are ignored. - uint32_t attIdx = 0; - for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) { - auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx]; - if (clrAtt.imageView) { - clearValues[attIdx] = clrAtt.clearValue; - attachments[attIdx++] = (MVKImageView*)clrAtt.imageView; - if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) { - clearValues[attIdx] = clrAtt.clearValue; - attachments[attIdx++] = (MVKImageView*)clrAtt.resolveImageView; - } - } - } - - // We need to combine the DS attachments into one - auto* pDSAtt = pRenderingInfo->pDepthAttachment ? pRenderingInfo->pDepthAttachment : pRenderingInfo->pStencilAttachment; - if (pDSAtt) { - if (pDSAtt->imageView) { - clearValues[attIdx] = pDSAtt->clearValue; - attachments[attIdx++] = (MVKImageView*)pDSAtt->imageView; - } - if (pDSAtt->resolveImageView && pDSAtt->resolveMode != VK_RESOLVE_MODE_NONE) { - clearValues[attIdx] = pDSAtt->clearValue; - attachments[attIdx++] = (MVKImageView*)pDSAtt->resolveImageView; - } - } - - return attIdx; -} - bool mvkIsColorAttachmentUsed(const VkPipelineRenderingCreateInfo* pRendInfo, uint32_t colorAttIdx) { return pRendInfo && pRendInfo->pColorAttachmentFormats[colorAttIdx]; } @@ -1085,14 +1056,6 @@ bool mvkHasColorAttachments(const VkPipelineRenderingCreateInfo* pRendInfo) { return false; } -VkFormat mvkGetDepthStencilFormat(const VkPipelineRenderingCreateInfo* pRendInfo) { - return (pRendInfo - ? (pRendInfo->depthAttachmentFormat - ? pRendInfo->depthAttachmentFormat - : pRendInfo->stencilAttachmentFormat) - : VK_FORMAT_UNDEFINED); -} - uint32_t mvkGetNextViewMaskGroup(uint32_t viewMask, uint32_t* startView, uint32_t* viewCount, uint32_t *groupMask) { // First, find the first set bit. This is the start of the next clump of views to be rendered. // n.b. ffs(3) returns a 1-based index. This actually bit me during development of this feature. diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index ce68d29f..60bafd8f 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -70,7 +70,7 @@ MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0) -MVK_EXTENSION(KHR_map_memory2, KHR_MAP_MEMORY_2, DEVICE, 10.11, 8.0) +MVK_EXTENSION(KHR_map_memory2, KHR_MAP_MEMORY_2, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE, 10.11, 8.0) MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE, 10.11, 8.0) From abb12a5288f5faa9abe80fea3334a4be51160ac2 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 26 Apr 2023 06:29:07 -0400 Subject: [PATCH 2/3] Fix Metal validation errors with dynamic rendering. - MVKPipeline validate depth & stencil formats before setting frag shader depth and stencil builtins, and before setting formats in MTLRenderPipelineDescriptor. - MVKCmdClearAttachments always set depth/stencil format if subpass includes a depth or stencil attachment, even if they are not being cleared. - MVKRenderingAttachmentIterator add synthetic attachment if depth or stencil attachment is not provided, but image format supports both depth and stencil. --- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 16 +++++---- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 3 ++ MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 13 +++++--- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h | 7 ++-- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm | 33 ++++++++++++++++--- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 0aa57b31..7cee3bc0 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1446,15 +1446,17 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { // The depth value (including vertex position Z value) is held in the last index. clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; + MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(subpass->isStencilAttachmentUsed() + ? subpass->getStencilFormat() + : subpass->getDepthFormat()); + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlDSFmt; + + // If neither the depth or stencil attachments are being cleared, nor being used, don't try to clear them. bool isClearingDepth = _isClearingDepth && subpass->isDepthAttachmentUsed(); bool isClearingStencil = _isClearingStencil && subpass->isStencilAttachmentUsed(); - if (isClearingDepth) { - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getDepthFormat()); - } else if (isClearingStencil) { - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getStencilFormat()); - } else { - _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); - } + if ( !isClearingDepth && !isClearingStencil ) { + _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); + } if ( !_rpsKey.isAnyAttachmentEnabled() ) { return; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index c2a03ee5..fadc2504 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -560,6 +560,9 @@ public: /** Returns the 3D extent of this image at the specified mipmap level. */ VkExtent3D getExtent3D(uint8_t planeIndex = 0, uint32_t mipLevel = 0) { return _image->getExtent3D(planeIndex, mipLevel); } + /** Return the underlying image. */ + MVKImage* getImage() { return _image; } + #pragma mark Metal /** Returns the Metal texture underlying this image view. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index bf5e3f13..19d0d06c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -1471,8 +1471,12 @@ void MVKGraphicsPipeline::addFragmentOutputToPipeline(MTLRenderPipelineDescripto // Depth & stencil attachment formats MVKPixelFormats* pixFmts = getPixelFormats(); - plDesc.depthAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat); - plDesc.stencilAttachmentPixelFormat = pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat); + + MTLPixelFormat mtlDepthPixFmt = pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat); + if (pixFmts->isDepthFormat(mtlDepthPixFmt)) { plDesc.depthAttachmentPixelFormat = mtlDepthPixFmt; } + + MTLPixelFormat mtlStencilPixFmt = pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat); + if (pixFmts->isStencilFormat(mtlStencilPixFmt)) { plDesc.stencilAttachmentPixelFormat = mtlStencilPixFmt; } // In Vulkan, it's perfectly valid to render without any attachments. In Metal, if that // isn't supported, and we have no attachments, then we have to add a dummy attachment. @@ -1552,6 +1556,7 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu _viewRangeBufferIndex = _indirectParamsIndex; const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); + MVKPixelFormats* pixFmts = getPixelFormats(); // Disable any unused color attachments, because Metal validation can complain if the // fragment shader outputs a color value without a corresponding color attachment. @@ -1571,8 +1576,8 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu shaderConfig.options.mslOptions.ios_support_base_vertex_instance = getDevice()->_pMetalFeatures->baseVertexInstanceDrawing; shaderConfig.options.mslOptions.texture_1D_as_2D = mvkConfig().texture1DAs2D; shaderConfig.options.mslOptions.enable_point_size_builtin = isRenderingPoints(pCreateInfo) || reflectData.pointMode; - shaderConfig.options.mslOptions.enable_frag_depth_builtin = (pRendInfo->depthAttachmentFormat != VK_FORMAT_UNDEFINED); - shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = (pRendInfo->stencilAttachmentFormat != VK_FORMAT_UNDEFINED); + shaderConfig.options.mslOptions.enable_frag_depth_builtin = pixFmts->isDepthFormat(pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat)); + shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = pixFmts->isStencilFormat(pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat)); shaderConfig.options.shouldFlipVertexY = mvkConfig().shaderConversionFlipVertexY; shaderConfig.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle; shaderConfig.options.mslOptions.tess_domain_origin_lower_left = pTessDomainOriginState && pTessDomainOriginState->domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index 7d1bb1b0..534ec018 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h @@ -340,14 +340,17 @@ public: /** Iterates the attachments with the specified lambda function. */ void iterate(MVKRenderingAttachmentInfoOperation attOperation); - MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo) : _pRenderingInfo(pRenderingInfo) {} + MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo); protected: void handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, MVKRenderingAttachmentInfoOperation attOperation); + const VkRenderingAttachmentInfo* getAttachmentInfo(const VkRenderingAttachmentInfo* pAtt, + const VkRenderingAttachmentInfo* pAltAtt, + bool isStencil); - const VkRenderingInfo* _pRenderingInfo; + VkRenderingInfo _renderingInfo; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index 2c4bf185..af06d9b0 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -1021,11 +1021,11 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderin #pragma mark MVKRenderingAttachmentIterator void MVKRenderingAttachmentIterator::iterate(MVKRenderingAttachmentInfoOperation attOperation) { - for (uint32_t caIdx = 0; caIdx < _pRenderingInfo->colorAttachmentCount; caIdx++) { - handleAttachment(&_pRenderingInfo->pColorAttachments[caIdx], VK_IMAGE_ASPECT_COLOR_BIT, attOperation); + for (uint32_t caIdx = 0; caIdx < _renderingInfo.colorAttachmentCount; caIdx++) { + handleAttachment(&_renderingInfo.pColorAttachments[caIdx], VK_IMAGE_ASPECT_COLOR_BIT, attOperation); } - handleAttachment(_pRenderingInfo->pDepthAttachment, VK_IMAGE_ASPECT_DEPTH_BIT, attOperation); - handleAttachment(_pRenderingInfo->pStencilAttachment, VK_IMAGE_ASPECT_STENCIL_BIT, attOperation); + handleAttachment(_renderingInfo.pDepthAttachment, VK_IMAGE_ASPECT_DEPTH_BIT, attOperation); + handleAttachment(_renderingInfo.pStencilAttachment, VK_IMAGE_ASPECT_STENCIL_BIT, attOperation); } void MVKRenderingAttachmentIterator::handleAttachment(const VkRenderingAttachmentInfo* pAttInfo, @@ -1039,6 +1039,31 @@ void MVKRenderingAttachmentIterator::handleAttachment(const VkRenderingAttachmen } } +MVKRenderingAttachmentIterator::MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo) { + _renderingInfo = *pRenderingInfo; + _renderingInfo.pDepthAttachment = getAttachmentInfo(pRenderingInfo->pDepthAttachment, pRenderingInfo->pStencilAttachment, false); + _renderingInfo.pStencilAttachment = getAttachmentInfo(pRenderingInfo->pStencilAttachment, pRenderingInfo->pDepthAttachment, true); +} + +// If the depth/stencil attachment is not in use, but the alternate stencil/depth attachment is, +// and the MTLPixelFormat is usable by both attachments, force the use of the alternate attachment +// for both attachments, to avoid Metal validation errors when a pipeline expects both depth and +// stencil, but only one of the attachments has been provided here. +// Check the MTLPixelFormat of the MVKImage underlying the MVKImageView, to bypass possible +// substitution of MTLPixelFormat in the MVKImageView due to swizzling, or stencil-only access. +const VkRenderingAttachmentInfo* MVKRenderingAttachmentIterator::getAttachmentInfo(const VkRenderingAttachmentInfo* pAtt, + const VkRenderingAttachmentInfo* pAltAtt, + bool isStencil) { + bool useAlt = false; + if ( !(pAtt && pAtt->imageView) && (pAltAtt && pAltAtt->imageView) ) { + MVKImage* mvkImg = ((MVKImageView*)pAltAtt->imageView)->getImage(); + useAlt = (isStencil + ? mvkImg->getPixelFormats()->isStencilFormat(mvkImg->getMTLPixelFormat()) + : mvkImg->getPixelFormats()->isDepthFormat(mvkImg->getMTLPixelFormat())); + } + return useAlt ? pAltAtt : pAtt; +} + #pragma mark - #pragma mark Support functions From fd6b97317d542a76b86762a96c11beb3b2ee5d0e Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 27 Apr 2023 13:10:30 -0400 Subject: [PATCH 3/3] Clear attachments support separate depth and stencil attachments. - Also rename kMVKCachedColorAttachmentCount to kMVKMaxColorAttachmentCount and kMVKCachedViewportScissorCount to kMVKMaxViewportScissorCount and (unrelated) --- MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h | 4 +-- .../MoltenVK/Commands/MVKCmdRenderPass.mm | 4 +-- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h | 4 +-- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 29 +++++++------------ .../Commands/MVKCommandEncoderState.h | 4 +-- .../Commands/MVKCommandResourceFactory.h | 8 +++-- .../Commands/MVKCommandResourceFactory.mm | 29 +++++++++++-------- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 4 +-- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 10 +++---- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 4 +-- 10 files changed, 48 insertions(+), 52 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h index 4d661475..66c7c304 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h @@ -262,7 +262,7 @@ protected: // Concrete template class implementations. typedef MVKCmdSetViewport<1> MVKCmdSetViewport1; -typedef MVKCmdSetViewport MVKCmdSetViewportMulti; +typedef MVKCmdSetViewport MVKCmdSetViewportMulti; #pragma mark - @@ -292,7 +292,7 @@ protected: // Concrete template class implementations. typedef MVKCmdSetScissor<1> MVKCmdSetScissor1; -typedef MVKCmdSetScissor MVKCmdSetScissorMulti; +typedef MVKCmdSetScissor MVKCmdSetScissorMulti; #pragma mark - diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm index 829264d3..08bbe851 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm @@ -282,7 +282,7 @@ void MVKCmdSetViewport::encode(MVKCommandEncoder* cmdEncoder) { } template class MVKCmdSetViewport<1>; -template class MVKCmdSetViewport; +template class MVKCmdSetViewport; #pragma mark - @@ -309,7 +309,7 @@ void MVKCmdSetScissor::encode(MVKCommandEncoder* cmdEncoder) { } template class MVKCmdSetScissor<1>; -template class MVKCmdSetScissor; +template class MVKCmdSetScissor; #pragma mark - diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h index ce0af39f..e25158b6 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h @@ -284,8 +284,6 @@ protected: float _mtlDepthVal; uint32_t _mtlStencilValue; MVKCommandUse _commandUse; - bool _isClearingDepth; - bool _isClearingStencil; }; @@ -326,7 +324,7 @@ protected: VkClearValue& getClearValue(uint32_t attIdx) override { return _vkClearValues[attIdx]; } void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) override { _vkClearValues[attIdx] = clearValue; } - VkClearValue _vkClearValues[kMVKCachedColorAttachmentCount]; + VkClearValue _vkClearValues[kMVKMaxColorAttachmentCount]; }; typedef MVKCmdClearMultiAttachments<1> MVKCmdClearMultiAttachments1; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 7cee3bc0..88e0b562 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1260,8 +1260,6 @@ VkResult MVKCmdClearAttachments::setContent(MVKCommandBuffer* cmdBuff, _commandUse = cmdUse; _mtlDepthVal = 0.0; _mtlStencilValue = 0; - _isClearingDepth = false; - _isClearingStencil = false; MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats(); // For each attachment to be cleared, mark it so in the render pipeline state @@ -1279,14 +1277,12 @@ VkResult MVKCmdClearAttachments::setContent(MVKCommandBuffer* cmdBuff, } if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT)) { - _isClearingDepth = true; - _rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex); + _rpsKey.enableAttachment(kMVKClearAttachmentDepthIndex); _mtlDepthVal = pixFmts->getMTLClearDepthValue(clrAtt.clearValue); } if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT)) { - _isClearingStencil = true; - _rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex); + _rpsKey.enableAttachment(kMVKClearAttachmentStencilIndex); _mtlStencilValue = pixFmts->getMTLClearStencilValue(clrAtt.clearValue); } } @@ -1443,20 +1439,14 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { clearColors[caIdx] = { (float)mtlCC.red, (float)mtlCC.green, (float)mtlCC.blue, (float)mtlCC.alpha}; } - // The depth value (including vertex position Z value) is held in the last index. - clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; + // The depth value is the vertex position Z value. + clearColors[kMVKClearAttachmentDepthIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal }; - MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(subpass->isStencilAttachmentUsed() - ? subpass->getStencilFormat() - : subpass->getDepthFormat()); - _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlDSFmt; + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthIndex] = pixFmts->getMTLPixelFormat(subpass->getDepthFormat()); + if ( !subpass->isDepthAttachmentUsed() ) { _rpsKey.disableAttachment(kMVKClearAttachmentDepthIndex); } - // If neither the depth or stencil attachments are being cleared, nor being used, don't try to clear them. - bool isClearingDepth = _isClearingDepth && subpass->isDepthAttachmentUsed(); - bool isClearingStencil = _isClearingStencil && subpass->isStencilAttachmentUsed(); - if ( !isClearingDepth && !isClearingStencil ) { - _rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex); - } + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getStencilFormat()); + if ( !subpass->isStencilAttachmentUsed() ) { _rpsKey.disableAttachment(kMVKClearAttachmentStencilIndex); } if ( !_rpsKey.isAnyAttachmentEnabled() ) { return; } @@ -1465,7 +1455,8 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { id mtlRendEnc = cmdEncoder->_mtlRenderEncoder; [mtlRendEnc pushDebugGroup: getMTLDebugGroupLabel()]; [mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdClearMTLRenderPipelineState(_rpsKey)]; - [mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(isClearingDepth, isClearingStencil)]; + [mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(_rpsKey.isAttachmentUsed(kMVKClearAttachmentDepthIndex), + _rpsKey.isAttachmentUsed(kMVKClearAttachmentStencilIndex))]; [mtlRendEnc setStencilReferenceValue: _mtlStencilValue]; [mtlRendEnc setCullMode: MTLCullModeNone]; [mtlRendEnc setTriangleFillMode: MTLTriangleFillModeFill]; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 9caca16c..b47cc22e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -152,7 +152,7 @@ public: protected: void encodeImpl(uint32_t stage) override; - MVKSmallVector _viewports, _dynamicViewports; + MVKSmallVector _viewports, _dynamicViewports; }; @@ -180,7 +180,7 @@ public: protected: void encodeImpl(uint32_t stage) override; - MVKSmallVector _scissors, _dynamicScissors; + MVKSmallVector _scissors, _dynamicScissors; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index bd30da20..1e37844f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -107,9 +107,11 @@ namespace std { #pragma mark - #pragma mark MVKRPSKeyClearAtt -#define kMVKClearAttachmentCount (kMVKCachedColorAttachmentCount + 1) -#define kMVKClearAttachmentDepthStencilIndex (kMVKClearAttachmentCount - 1) -#define kMVKClearAttachmentLayeredRenderingBitIndex kMVKClearAttachmentCount +const static uint32_t kMVKClearColorAttachmentCount = kMVKMaxColorAttachmentCount; +const static uint32_t kMVKClearAttachmentDepthIndex = kMVKClearColorAttachmentCount; +const static uint32_t kMVKClearAttachmentStencilIndex = kMVKClearAttachmentDepthIndex + 1; +const static uint32_t kMVKClearAttachmentCount = kMVKClearAttachmentStencilIndex + 1; +const static uint32_t kMVKClearAttachmentLayeredRenderingBitIndex = kMVKClearAttachmentStencilIndex + 1; /** * Key to use for looking up cached MTLRenderPipelineState instances. diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index d6c6efb6..36fb03b7 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -113,6 +113,8 @@ id MVKCommandResourceFactory::newCmdBlitImageMTLSamplerState(MT id MVKCommandResourceFactory::newCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey, MVKVulkanAPIDeviceObject* owner) { + MVKPixelFormats* pixFmts = getPixelFormats(); + id vtxFunc = newClearVertFunction(attKey); // temp retain id fragFunc = newClearFragFunction(attKey); // temp retain MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // temp retain @@ -122,15 +124,17 @@ id MVKCommandResourceFactory::newCmdClearMTLRenderPipeli plDesc.sampleCount = attKey.mtlSampleCount; plDesc.inputPrimitiveTopologyMVK = MTLPrimitiveTopologyClassTriangle; - for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) { MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[caIdx]; colorDesc.pixelFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]; colorDesc.writeMask = attKey.isAttachmentEnabled(caIdx) ? MTLColorWriteMaskAll : MTLColorWriteMaskNone; } - MVKPixelFormats* pixFmts = getPixelFormats(); - MTLPixelFormat mtlDSFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex]; - if (pixFmts->isDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; } - if (pixFmts->isStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; } + + MTLPixelFormat mtlDepthFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthIndex]; + if (pixFmts->isDepthFormat(mtlDepthFormat)) { plDesc.depthAttachmentPixelFormat = mtlDepthFormat; } + + MTLPixelFormat mtlStencilFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentStencilIndex]; + if (pixFmts->isStencilFormat(mtlStencilFormat)) { plDesc.stencilAttachmentPixelFormat = mtlStencilFormat; } MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor; @@ -273,7 +277,7 @@ id MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg& [msl appendLineMVK: @" return out;"]; [msl appendLineMVK: @"}"]; -// MVKLogDebug("\n%s", msl.UTF8String); +// MVKLogInfo("\n%s", msl.UTF8String); return newMTLFunction(msl, funcName); } @@ -300,15 +304,16 @@ id MVKCommandResourceFactory::newClearVertFunction(MVKRPSKeyClearAt [msl appendLineMVK]; NSString* funcName = @"vertClear"; - [msl appendFormat: @"vertex VaryingsPos %@(AttributesPos attributes [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName]; + [msl appendFormat: @"vertex VaryingsPos %@(AttributesPos attributes [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName]; [msl appendLineMVK]; [msl appendLineMVK: @" VaryingsPos varyings;"]; - [msl appendLineMVK: @" varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[8].r, 1.0);"]; + [msl appendFormat: @" varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[%d].r, 1.0);", kMVKClearAttachmentDepthIndex]; + [msl appendLineMVK]; [msl appendLineMVK: @" varyings.layer = uint(attributes.a_position.w);"]; [msl appendLineMVK: @" return varyings;"]; [msl appendLineMVK: @"}"]; -// MVKLogDebug("\n%s", msl.UTF8String); +// MVKLogInfo("\n%s", msl.UTF8String); return newMTLFunction(msl, funcName); } @@ -329,7 +334,7 @@ id MVKCommandResourceFactory::newClearFragFunction(MVKRPSKeyClearAt [msl appendLineMVK: @"} ClearColorsIn;"]; [msl appendLineMVK]; [msl appendLineMVK: @"typedef struct {"]; - for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) { if (attKey.isAttachmentUsed(caIdx)) { NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]); [msl appendFormat: @" %@4 color%u [[color(%u)]];", typeStr, caIdx, caIdx]; @@ -343,7 +348,7 @@ id MVKCommandResourceFactory::newClearFragFunction(MVKRPSKeyClearAt [msl appendFormat: @"fragment ClearColorsOut %@(VaryingsPos varyings [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName]; [msl appendLineMVK]; [msl appendLineMVK: @" ClearColorsOut ccOut;"]; - for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) { if (attKey.isAttachmentUsed(caIdx)) { NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]); [msl appendFormat: @" ccOut.color%u = %@4(ccIn.colors[%u]);", caIdx, typeStr, caIdx]; @@ -353,7 +358,7 @@ id MVKCommandResourceFactory::newClearFragFunction(MVKRPSKeyClearAt [msl appendLineMVK: @" return ccOut;"]; [msl appendLineMVK: @"}"]; -// MVKLogDebug("\n%s", msl.UTF8String); +// MVKLogInfo("\n%s", msl.UTF8String); return newMTLFunction(msl, funcName); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index b02cc778..42921801 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -80,8 +80,8 @@ const static uint32_t kMVKQueueFamilyCount = 4; const static uint32_t kMVKQueueCountPerQueueFamily = 1; // Must be 1. See comments in MVKPhysicalDevice::getQueueFamilies() const static uint32_t kMVKMinSwapchainImageCount = 2; const static uint32_t kMVKMaxSwapchainImageCount = 3; -const static uint32_t kMVKCachedViewportScissorCount = 16; -const static uint32_t kMVKCachedColorAttachmentCount = 8; +const static uint32_t kMVKMaxColorAttachmentCount = 8; +const static uint32_t kMVKMaxViewportScissorCount = 16; const static uint32_t kMVKMaxDescriptorSetCount = SPIRV_CROSS_NAMESPACE::kMaxArgumentBuffers; #if !MVK_XCODE_12 diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 8cdca02b..8937b90a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2269,17 +2269,17 @@ void MVKPhysicalDevice::initFeatures() { void MVKPhysicalDevice::initLimits() { #if MVK_TVOS - _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; + _properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount; #endif #if MVK_IOS if (supportsMTLFeatureSet(iOS_GPUFamily2_v1)) { - _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; + _properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount; } else { - _properties.limits.maxColorAttachments = 4; // < kMVKCachedColorAttachmentCount + _properties.limits.maxColorAttachments = 4; // < kMVKMaxColorAttachmentCount } #endif #if MVK_MACOS - _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; + _properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount; #endif _properties.limits.maxFragmentOutputAttachments = _properties.limits.maxColorAttachments; @@ -2309,7 +2309,7 @@ void MVKPhysicalDevice::initLimits() { float maxVPDim = max(_properties.limits.maxViewportDimensions[0], _properties.limits.maxViewportDimensions[1]); _properties.limits.viewportBoundsRange[0] = (-2.0 * maxVPDim); _properties.limits.viewportBoundsRange[1] = (2.0 * maxVPDim) - 1; - _properties.limits.maxViewports = _features.multiViewport ? kMVKCachedViewportScissorCount : 1; + _properties.limits.maxViewports = _features.multiViewport ? kMVKMaxViewportScissorCount : 1; _properties.limits.maxImageDimension3D = _metalFeatures.maxTextureLayers; _properties.limits.maxImageArrayLayers = _metalFeatures.maxTextureLayers; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 154bcf67..efb7c492 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -350,8 +350,8 @@ protected: VkPipelineRasterizationStateCreateInfo _rasterInfo; VkPipelineDepthStencilStateCreateInfo _depthStencilInfo; - MVKSmallVector _viewports; - MVKSmallVector _scissors; + MVKSmallVector _viewports; + MVKSmallVector _scissors; MVKSmallVector _dynamicState; MVKSmallVector _customSamplePositions; MVKSmallVector _translatedVertexBindings;