From 25acafdb3f0f584c9131041e1cd8328694ba17fe Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 15 Aug 2019 13:39:34 -0400 Subject: [PATCH] Disable depth and/or stencil testing if corresponding attachment is missing. MVKDepthStencilCommandEncoderState track whether depth and stencil attachements exist, and modify testing accordingly. Add MVKMTLDepthStencilDescriptorData::disable() function. MoltenVK_Runtime_UserGuide.md remove VkEvent as known limitation. --- Docs/MoltenVK_Runtime_UserGuide.md | 2 - Docs/Whats_New.md | 1 + .../Commands/MVKCommandEncoderState.h | 8 +++- .../Commands/MVKCommandEncoderState.mm | 47 +++++++++++++------ .../Commands/MVKCommandResourceFactory.h | 33 +++++++------ 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index e7353235..8fc20afb 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -512,8 +512,6 @@ This section documents the known limitations in this version of **MoltenVK**. In order to use Vulkan layers such as the validation layers, use the Vulkan loader and layers from the [LunarG Vulkan SDK](https://vulkan.lunarg.com). -- `VkEvents` are not supported. - - Application-controlled memory allocations using `VkAllocationCallbacks` are ignored. - Pipeline statistics query pool using `VK_QUERY_TYPE_PIPELINE_STATISTICS` is not supported. diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 6440f775..b47e4acf 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -23,6 +23,7 @@ Released TBD - Add support for `VkEvent`, using either native `MTLEvent` or emulation when `MTLEvent` not available. - `vkInvalidateMappedMemoryRanges()` synchronizes managed device memory to CPU. - Revert to supporting host-coherent memory for linear images on macOS. +- Disable depth and/or stencil testing if corresponding attachment is missing. - Ensure Vulkan loader magic number is set every time before returning any dispatchable Vulkan handle. - Fix crash when `VkDeviceCreateInfo` specifies queue families out of numerical order. - Fix crash in `vkDestroyPipelineLayout()`. diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 9af81973..7fd30e8b 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -62,7 +62,7 @@ public: * will be encoded to Metal, otherwise it is marked as clean, so the contents will NOT * be encoded. Default state can be left unencoded on a new Metal encoder. */ - void beginMetalRenderPass() { if (_isModified) { markDirty(); } } + virtual void beginMetalRenderPass() { if (_isModified) { markDirty(); } } /** * If the content of this instance is dirty, marks this instance as no longer dirty @@ -237,6 +237,8 @@ public: */ void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t stencilWriteMask); + void beginMetalRenderPass() override; + /** Constructs this instance for the specified command encoder. */ MVKDepthStencilCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {} @@ -248,7 +250,9 @@ protected: const VkStencilOpState& vkStencil, bool enabled); - MVKMTLDepthStencilDescriptorData _depthStencilData; + MVKMTLDepthStencilDescriptorData _depthStencilData = kMVKMTLDepthStencilDescriptorDataDefault; + bool _hasDepthAttachment = false; + bool _hasStencilAttachment = false; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 641832e6..4d44d4ce 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -312,26 +312,43 @@ void MVKDepthStencilCommandEncoderState::setStencilWriteMask(VkStencilFaceFlags markDirty(); } +void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() { + MVKRenderSubpass* mvkSubpass = _cmdEncoder->getSubpass(); + MTLPixelFormat mtlDSFormat = _cmdEncoder->getMTLPixelFormatFromVkFormat(mvkSubpass->getDepthStencilFormat()); + + bool prevHasDepthAttachment = _hasDepthAttachment; + _hasDepthAttachment = mvkMTLPixelFormatIsDepthFormat(mtlDSFormat); + if (_hasDepthAttachment != prevHasDepthAttachment) { markDirty(); } + + bool prevHasStencilAttachment = _hasStencilAttachment; + _hasStencilAttachment = mvkMTLPixelFormatIsStencilFormat(mtlDSFormat); + if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); } +} + void MVKDepthStencilCommandEncoderState::encodeImpl(uint32_t stage) { - if (stage != kMVKGraphicsStageRasterization && stage != kMVKGraphicsStageVertex) { return; } - MVKRenderSubpass *subpass = _cmdEncoder->getSubpass(); - id mtlDSS = nil; - if (stage != kMVKGraphicsStageVertex && subpass->getDepthStencilFormat() != VK_FORMAT_UNDEFINED) { - mtlDSS = _cmdEncoder->getCommandEncodingPool()->getMTLDepthStencilState(_depthStencilData); - } else { - // If there is no depth attachment but the depth/stencil state contains a non-always depth - // test, Metal Validation will give the following error: - // "validateDepthStencilState:3657: failed assertion `MTLDepthStencilDescriptor sets - // depth test but MTLRenderPassDescriptor has a nil depthAttachment texture'" - // Check the subpass to see if there is a depth/stencil attachment, and if not use - // a depth/stencil state with depth test always, depth write disabled, and no stencil state. - mtlDSS = _cmdEncoder->getCommandEncodingPool()->getMTLDepthStencilState(false, false); - } - [_cmdEncoder->_mtlRenderEncoder setDepthStencilState: mtlDSS]; + auto cmdEncPool = _cmdEncoder->getCommandEncodingPool(); + switch (stage) { + case kMVKGraphicsStageRasterization: { + // If renderpass does not have a depth or a stencil attachment, disable corresponding test + MVKMTLDepthStencilDescriptorData adjustedDSData = _depthStencilData; + adjustedDSData.disable(!_hasDepthAttachment, !_hasStencilAttachment); + [_cmdEncoder->_mtlRenderEncoder setDepthStencilState: cmdEncPool->getMTLDepthStencilState(adjustedDSData)]; + break; + } + case kMVKGraphicsStageVertex: { + // Vertex stage of tessellation pipeline requires depth/stencil testing be disabled + [_cmdEncoder->_mtlRenderEncoder setDepthStencilState: cmdEncPool->getMTLDepthStencilState(false, false)]; + break; + } + default: // Do nothing on other stages + break; + } } void MVKDepthStencilCommandEncoderState::resetImpl() { _depthStencilData = kMVKMTLDepthStencilDescriptorDataDefault; + _hasDepthAttachment = false; + _hasStencilAttachment = false; } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index a14e2deb..46e0fb55 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -207,18 +207,24 @@ typedef struct MVKMTLDepthStencilDescriptorData_t { return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t)); } - MVKMTLDepthStencilDescriptorData_t() { + /** Disable depth and/or stencil testing. */ + void disable(bool disableDepth, bool disableStencil) { + if (disableDepth) { + depthCompareFunction = MTLCompareFunctionAlways; + depthWriteEnabled = false; + } + if (disableStencil) { + frontFaceStencilData = kMVKMTLStencilDescriptorDataDefault; + backFaceStencilData = kMVKMTLStencilDescriptorDataDefault; + } + } - // Start with all zeros to ensure memory comparisons will work, - // even if the structure contains alignment gaps. - memset(this, 0, sizeof(*this)); - - depthCompareFunction = MTLCompareFunctionAlways; - depthWriteEnabled = false; - - frontFaceStencilData = kMVKMTLStencilDescriptorDataDefault; - backFaceStencilData = kMVKMTLStencilDescriptorDataDefault; - } + MVKMTLDepthStencilDescriptorData_t() { + // Start with all zeros to ensure memory comparisons will work, + // even if the structure contains alignment gaps. + memset(this, 0, sizeof(*this)); + disable(true, true); + } } __attribute__((aligned(sizeof(uint64_t)))) MVKMTLDepthStencilDescriptorData; @@ -345,10 +351,7 @@ public: id newCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey, MVKVulkanAPIDeviceObject* owner); - /** - * Returns a new MTLDepthStencilState dedicated to rendering to several - * attachments to support clearing regions of those attachments. - */ + /** Returns a new MTLDepthStencilState that always writes to the depth and/or stencil attachments. */ id newMTLDepthStencilState(bool useDepth, bool useStencil); /**