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.
This commit is contained in:
Bill Hollings 2019-08-15 13:39:34 -04:00
parent e2ce1a6329
commit 25acafdb3f
5 changed files with 57 additions and 34 deletions

View File

@ -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.

View File

@ -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()`.

View File

@ -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;
};

View File

@ -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<MTLDepthStencilState> 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;
}

View File

@ -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<MTLRenderPipelineState> 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<MTLDepthStencilState> newMTLDepthStencilState(bool useDepth, bool useStencil);
/**