From 3c75e114dd04636628cc212e947e420ed5415fca Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 5 Oct 2023 17:33:01 -0400 Subject: [PATCH] Add support for VK_EXT_extended_dynamic_state extension. - Add MVKRasterizingCommandEncoderState to consolidate handling of static and dynamic rasterizing states in a consistent manner. - Rework MVKDepthStencilCommandEncoderState to consolidate handling of static and dynamic depth states in a consistent manner. - MVKMTLDepthStencilDescriptorData clean up content setting, and struct layout. - Add MVKRenderStateType to enumerate render state types. - Add MVKRenderStateFlags to track binary info about states (enabled, dirty, etc). - Add MVKMTLBufferBinding::stride. - Add MVKPhysicalDeviceMetalFeatures::dynamicVertexStride. - Set MVKPhysicalDeviceMetalFeatures::vertexStrideAlignment to 1 for Apple5+ GPUs (unrelated). - Set VkPhysicalDeviceLimits::maxVertexInputBindingStride to unlimited for Apple2+ GPUs (unrelated). - Add mvkVkRect2DFromMTLScissorRect() and simplify mvkMTLViewportFromVkViewport() and mvkMTLScissorRectFromVkRect2D(). - MVKFoundation: - Add mvkEnableAllFlags() and mvkDisableAllFlags(). - Improve performance of mvkClear(), mvkCopy() & mvkAreEqual() when content is a single simple primitive type (unrelated). - Declare more functions as static constexpr (unrelated). --- Docs/MoltenVK_Runtime_UserGuide.md | 1 + MoltenVK/MoltenVK/API/mvk_datatypes.h | 7 +- MoltenVK/MoltenVK/API/mvk_private_api.h | 1 + MoltenVK/MoltenVK/Commands/MVKCmdDraw.h | 6 +- MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm | 23 +- MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h | 160 ++++- .../MoltenVK/Commands/MVKCmdRenderPass.mm | 162 +++-- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 5 +- MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h | 38 +- .../MoltenVK/Commands/MVKCommandBuffer.mm | 115 ++-- .../Commands/MVKCommandEncoderState.h | 249 ++++--- .../Commands/MVKCommandEncoderState.mm | 626 ++++++++++-------- .../Commands/MVKCommandResourceFactory.h | 51 +- .../Commands/MVKCommandResourceFactory.mm | 15 +- .../MoltenVK/Commands/MVKCommandTypePools.def | 7 + .../Commands/MVKMTLResourceBindings.h | 7 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 12 +- .../GPUObjects/MVKDeviceFeatureStructs.def | 1 + MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 6 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 54 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 161 +++-- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 101 +-- MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 41 +- MoltenVK/MoltenVK/Vulkan/vulkan.mm | 18 +- 24 files changed, 1095 insertions(+), 772 deletions(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 57773c27..27ed0c2e 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -363,6 +363,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_descriptor_indexing` *(initial release limited to Metal Tier 1: 96/128 textures, 16 samplers, except macOS 11.0 (Big Sur) or later, or on older versions of macOS using an Intel GPU, and if Metal argument buffers enabled in config)* +- `VK_EXT_extended_dynamic_state` *(requires Metal 3.1)* - `VK_EXT_external_memory_host` - `VK_EXT_fragment_shader_interlock` *(requires Metal 2.0 and Raster Order Groups)* - `VK_EXT_host_query_reset` diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h index 8e5670c9..4bbed323 100644 --- a/MoltenVK/MoltenVK/API/mvk_datatypes.h +++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h @@ -378,10 +378,13 @@ MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkRe #endif /** Returns the Metal MTLViewport corresponding to the specified Vulkan VkViewport. */ -MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport); +MTLViewport mvkMTLViewportFromVkViewport(const VkViewport vkViewport); /** Returns the Metal MTLScissorRect corresponding to the specified Vulkan VkRect2D. */ -MTLScissorRect mvkMTLScissorRectFromVkRect2D(VkRect2D vkRect); +MTLScissorRect mvkMTLScissorRectFromVkRect2D(const VkRect2D vkRect); + +/** Returns the Vulkan VkRect2D corresponding to the specified Metal MTLScissorRect. */ +VkRect2D mvkVkRect2DFromMTLScissorRect(const MTLScissorRect mtlScissorRect); /** Returns the Metal MTLCompareFunction corresponding to the specified Vulkan VkCompareOp, */ MTLCompareFunction mvkMTLCompareFunctionFromVkCompareOp(VkCompareOp vkOp); diff --git a/MoltenVK/MoltenVK/API/mvk_private_api.h b/MoltenVK/MoltenVK/API/mvk_private_api.h index 8ed5b754..af6c3ffc 100644 --- a/MoltenVK/MoltenVK/API/mvk_private_api.h +++ b/MoltenVK/MoltenVK/API/mvk_private_api.h @@ -151,6 +151,7 @@ typedef struct { MTLArgumentBuffersTier argumentBuffersTier; /**< The argument buffer tier available on this device, as a Metal enumeration. */ VkBool32 needsSampleDrefLodArrayWorkaround; /**< If true, sampling from arrayed depth images with explicit LoD is broken and needs a workaround. */ VkDeviceSize hostMemoryPageSize; /**< The size of a page of host memory on this platform. */ + VkBool32 dynamicVertexStride; /**< If true, VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE is supported. */ } MVKPhysicalDeviceMetalFeatures; /** diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h index c1e4a693..2b9696ab 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h @@ -37,10 +37,12 @@ class MVKCmdBindVertexBuffers : public MVKCommand { public: VkResult setContent(MVKCommandBuffer* cmdBuff, - uint32_t startBinding, + uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets); + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides); void encode(MVKCommandEncoder* cmdEncoder) override; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm index 20d27815..a1b71512 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm @@ -30,20 +30,23 @@ template VkResult MVKCmdBindVertexBuffers::setContent(MVKCommandBuffer* cmdBuff, - uint32_t startBinding, + uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets) { - + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides) { MVKDevice* mvkDvc = cmdBuff->getDevice(); _bindings.clear(); // Clear for reuse _bindings.reserve(bindingCount); MVKMTLBufferBinding b; for (uint32_t bindIdx = 0; bindIdx < bindingCount; bindIdx++) { MVKBuffer* mvkBuffer = (MVKBuffer*)pBuffers[bindIdx]; - b.index = mvkDvc->getMetalBufferIndexForVertexAttributeBinding(startBinding + bindIdx); + b.index = mvkDvc->getMetalBufferIndexForVertexAttributeBinding(firstBinding + bindIdx); b.mtlBuffer = mvkBuffer->getMTLBuffer(); b.offset = mvkBuffer->getMTLBufferOffset() + pOffsets[bindIdx]; + b.size = pSizes ? (uint32_t)pSizes[bindIdx] : 0; + b.stride = pStrides ? (uint32_t)pStrides[bindIdx] : 0; _bindings.push_back(b); } @@ -296,13 +299,13 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { uint32_t instanceCount = _instanceCount * viewCount; cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance); if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) { - [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType + [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() vertexStart: _firstVertex vertexCount: _vertexCount instanceCount: instanceCount baseInstance: _firstInstance]; } else { - [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType + [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() vertexStart: _firstVertex vertexCount: _vertexCount instanceCount: instanceCount]; @@ -530,7 +533,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { uint32_t instanceCount = _instanceCount * viewCount; cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance); if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) { - [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType + [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() indexCount: _indexCount indexType: (MTLIndexType)ibb.mtlIndexType indexBuffer: ibb.mtlBuffer @@ -539,7 +542,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { baseVertex: _vertexOffset baseInstance: _firstInstance]; } else { - [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType + [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() indexCount: _indexCount indexType: (MTLIndexType)ibb.mtlIndexType indexBuffer: ibb.mtlBuffer @@ -925,7 +928,7 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); } else { - [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType + [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() indirectBuffer: mtlIndBuff indirectBufferOffset: mtlIndBuffOfst]; mtlIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawPrimitivesIndirectArguments) : _mtlIndirectBufferStride; @@ -1312,7 +1315,7 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder, const MVKI cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); } else { cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _directCmdFirstInstance); - [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType + [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() indexType: (MTLIndexType)ibb.mtlIndexType indexBuffer: ibb.mtlBuffer indexBufferOffset: ibb.offset diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h index a74657b2..1e3bae5c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h @@ -352,10 +352,64 @@ public: protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; - float _red; - float _green; - float _blue; - float _alpha; + float _blendConstants[4] = {}; +}; + + +#pragma mark - +#pragma mark MVKCmdSetDepthTestEnable + +/** Vulkan command to dynamically enable depth testing. */ +class MVKCmdSetDepthTestEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthTestEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkBool32 _depthTestEnable; +}; + + +#pragma mark - +#pragma mark MVKCmdSetDepthWriteEnable + +/** Vulkan command to dynamically enable depth writing. */ +class MVKCmdSetDepthWriteEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthWriteEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkBool32 _depthWriteEnable; +}; + + +#pragma mark - +#pragma mark MVKCmdSetDepthCompareOp + +/** Vulkan command to dynamically set the depth compare operation. */ +class MVKCmdSetDepthCompareOp : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkCompareOp depthCompareOp); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkCompareOp _depthCompareOp; }; @@ -380,6 +434,71 @@ protected: }; +#pragma mark - +#pragma mark MVKCmdSetDepthBoundsTestEnable + +/** Vulkan command to enable depth bounds testing. */ +class MVKCmdSetDepthBoundsTestEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthBoundsTestEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + bool _depthBoundsTestEnable; +}; + + +#pragma mark - +#pragma mark MVKCmdSetStencilTestEnable + +/** Vulkan command to dynamically enable stencil testing. */ +class MVKCmdSetStencilTestEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 stencilTestEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkBool32 _stencilTestEnable; +}; + + +#pragma mark - +#pragma mark MVKCmdSetStencilOp + +/** Vulkan command to dynamically set the stencil operations. */ +class MVKCmdSetStencilOp : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkStencilFaceFlags _faceMask; + VkStencilOp _failOp; + VkStencilOp _passOp; + VkStencilOp _depthFailOp; + VkCompareOp _compareOp; +}; + + #pragma mark - #pragma mark MVKCmdSetStencilCompareMask @@ -446,10 +565,7 @@ protected: #pragma mark - #pragma mark MVKCmdSetCullMode -/** - * Vulkan command to dynamically set the cull mode. Originally from VK_EXT_extended_dynamic_state, - * but also part of Vulkan 1.3. - */ +/** Vulkan command to dynamically set the cull mode. */ class MVKCmdSetCullMode : public MVKCommand { public: @@ -461,17 +577,14 @@ public: protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; - MTLCullMode _cullMode; + VkCullModeFlags _cullMode; }; #pragma mark - #pragma mark MVKCmdSetFrontFace -/** - * Vulkan command to dynamically set the front facing winding order. Originally from - * VK_EXT_extended_dynamic_state, but also part of Vulkan 1.3. - */ +/** Vulkan command to dynamically set the front facing winding order. */ class MVKCmdSetFrontFace : public MVKCommand { public: @@ -483,6 +596,25 @@ public: protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; - MTLWinding _frontFace; + VkFrontFace _frontFace; +}; + + +#pragma mark - +#pragma mark MVKCmdSetPrimitiveTopology + +/** Vulkan command to dynamically set the primitive topology. */ +class MVKCmdSetPrimitiveTopology : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkPrimitiveTopology primitiveTopology); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkPrimitiveTopology _primitiveTopology; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm index fbb3292c..b5befc3a 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm @@ -278,7 +278,7 @@ VkResult MVKCmdSetViewport::setContent(MVKCommandBuffer* cmdBuff, template void MVKCmdSetViewport::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_viewportState.setViewports(_viewports.contents(), _firstViewport, true); + cmdEncoder->_rasterizingState.setViewports(_viewports.contents(), _firstViewport, true); } template class MVKCmdSetViewport<1>; @@ -305,7 +305,7 @@ VkResult MVKCmdSetScissor::setContent(MVKCommandBuffer* cmdBuff, template void MVKCmdSetScissor::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_scissorState.setScissors(_scissors.contents(), _firstScissor, true); + cmdEncoder->_rasterizingState.setScissors(_scissors.contents(), _firstScissor, true); } template class MVKCmdSetScissor<1>; @@ -345,9 +345,9 @@ VkResult MVKCmdSetDepthBias::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetDepthBias::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_depthBiasState.setDepthBias(_depthBiasConstantFactor, - _depthBiasSlopeFactor, - _depthBiasClamp); + cmdEncoder->_rasterizingState.setDepthBias(_depthBiasConstantFactor, + _depthBiasSlopeFactor, + _depthBiasClamp); } @@ -356,16 +356,54 @@ void MVKCmdSetDepthBias::encode(MVKCommandEncoder* cmdEncoder) { VkResult MVKCmdSetBlendConstants::setContent(MVKCommandBuffer* cmdBuff, const float blendConst[4]) { - _red = blendConst[0]; - _green = blendConst[1]; - _blue = blendConst[2]; - _alpha = blendConst[3]; - + mvkCopy(_blendConstants, blendConst, 4); return VK_SUCCESS; } void MVKCmdSetBlendConstants::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_blendColorState.setBlendColor(_red, _green, _blue, _alpha, true); + cmdEncoder->_rasterizingState.setBlendConstants(_blendConstants, true); +} + + +#pragma mark - +#pragma mark MVKCmdSetDepthTestEnable + +VkResult MVKCmdSetDepthTestEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthTestEnable) { + _depthTestEnable = depthTestEnable; + return VK_SUCCESS; +} + +void MVKCmdSetDepthTestEnable::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_depthStencilState.setDepthTestEnable(_depthTestEnable); +} + + +#pragma mark - +#pragma mark MVKCmdSetDepthWriteEnable + +VkResult MVKCmdSetDepthWriteEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthWriteEnable) { + _depthWriteEnable = depthWriteEnable; + return VK_SUCCESS; +} + +void MVKCmdSetDepthWriteEnable::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_depthStencilState.setDepthWriteEnable(_depthWriteEnable); +} + + +#pragma mark - +#pragma mark MVKCmdSetDepthCompareOp + +VkResult MVKCmdSetDepthCompareOp::setContent(MVKCommandBuffer* cmdBuff, + VkCompareOp depthCompareOp) { + _depthCompareOp = depthCompareOp; + return VK_SUCCESS; +} + +void MVKCmdSetDepthCompareOp::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_depthStencilState.setDepthCompareOp(_depthCompareOp); } @@ -389,6 +427,60 @@ VkResult MVKCmdSetDepthBounds::setContent(MVKCommandBuffer* cmdBuff, void MVKCmdSetDepthBounds::encode(MVKCommandEncoder* cmdEncoder) {} +#pragma mark - +#pragma mark MVKCmdSetDepthBoundsTestEnable + +VkResult MVKCmdSetDepthBoundsTestEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthBoundsTestEnable) { + _depthBoundsTestEnable = static_cast(depthBoundsTestEnable); + + // Validate + if (cmdBuff->getDevice()->_enabledFeatures.depthBounds) { + return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdSetDepthBoundsTestEnable(): The current device does not support testing depth bounds."); + } + + return VK_SUCCESS; +} + +void MVKCmdSetDepthBoundsTestEnable::encode(MVKCommandEncoder* cmdEncoder) {} + + +#pragma mark - +#pragma mark MVKCmdSetStencilTestEnable + +VkResult MVKCmdSetStencilTestEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 stencilTestEnable) { + _stencilTestEnable = stencilTestEnable; + return VK_SUCCESS; +} + +void MVKCmdSetStencilTestEnable::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_depthStencilState.setStencilTestEnable(_stencilTestEnable); +} + + +#pragma mark - +#pragma mark MVKCmdSetStencilOp + +VkResult MVKCmdSetStencilOp::setContent(MVKCommandBuffer* cmdBuff, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp) { + _faceMask = faceMask; + _failOp = failOp; + _passOp = passOp; + _depthFailOp = depthFailOp; + _compareOp = compareOp; + return VK_SUCCESS; +} + +void MVKCmdSetStencilOp::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_depthStencilState.setStencilOp(_faceMask, _failOp, _passOp, _depthFailOp, _compareOp); +} + + #pragma mark - #pragma mark MVKCmdSetStencilCompareMask @@ -436,7 +528,7 @@ VkResult MVKCmdSetStencilReference::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetStencilReference::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_stencilReferenceValueState.setReferenceValues(_faceMask, _stencilReference); + cmdEncoder->_rasterizingState.setStencilReferenceValues(_faceMask, _stencilReference); } @@ -445,29 +537,12 @@ void MVKCmdSetStencilReference::encode(MVKCommandEncoder* cmdEncoder) { VkResult MVKCmdSetCullMode::setContent(MVKCommandBuffer* cmdBuff, VkCullModeFlags cullMode) { - switch (cullMode) { - case VK_CULL_MODE_NONE: { - _cullMode = MTLCullModeNone; - break; - } - case VK_CULL_MODE_FRONT_BIT: { - _cullMode = MTLCullModeFront; - break; - } - case VK_CULL_MODE_BACK_BIT: { - _cullMode = MTLCullModeBack; - break; - } - case VK_CULL_MODE_FRONT_AND_BACK: { - // Metal doesn't have a equivalent to this... - } - } - - return VK_SUCCESS; + _cullMode = cullMode; + return VK_SUCCESS; } void MVKCmdSetCullMode::encode(MVKCommandEncoder* cmdEncoder) { - [((id)cmdEncoder->getMTLEncoder()) setCullMode:_cullMode]; + cmdEncoder->_rasterizingState.setCullMode(_cullMode, true); } @@ -476,14 +551,25 @@ void MVKCmdSetCullMode::encode(MVKCommandEncoder* cmdEncoder) { VkResult MVKCmdSetFrontFace::setContent(MVKCommandBuffer* cmdBuff, VkFrontFace frontFace) { - _frontFace = frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE - ? MTLWindingClockwise - : MTLWindingCounterClockwise; - - return VK_SUCCESS; + _frontFace = frontFace; + return VK_SUCCESS; } void MVKCmdSetFrontFace::encode(MVKCommandEncoder* cmdEncoder) { - [((id)cmdEncoder->getMTLEncoder()) setFrontFacingWinding:_frontFace]; + cmdEncoder->_rasterizingState.setFrontFace(_frontFace, true); +} + + +#pragma mark - +#pragma mark MVKCmdSetPrimitiveTopology + +VkResult MVKCmdSetPrimitiveTopology::setContent(MVKCommandBuffer* cmdBuff, + VkPrimitiveTopology primitiveTopology) { + _primitiveTopology = primitiveTopology; + return VK_SUCCESS; +} + +void MVKCmdSetPrimitiveTopology::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_rasterizingState.setPrimitiveTopology(_primitiveTopology, true); } diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 1c38d15a..5ae4fee3 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1507,10 +1507,7 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { // Return to the previous rendering state on the next render activity cmdEncoder->_graphicsPipelineState.markDirty(); cmdEncoder->_depthStencilState.markDirty(); - cmdEncoder->_stencilReferenceValueState.markDirty(); - cmdEncoder->_depthBiasState.markDirty(); - cmdEncoder->_viewportState.markDirty(); - cmdEncoder->_scissorState.markDirty(); + cmdEncoder->_rasterizingState.markDirty(); } template diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 07b4c202..cc1d7539 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -300,14 +300,11 @@ public: /** Encodes an operation to signal an event to a status. */ void signalEvent(MVKEvent* mvkEvent, bool status); - /** - * If a pipeline is currently bound, returns whether the current pipeline permits dynamic - * setting of the specified state. If no pipeline is currently bound, returns true. - */ - bool supportsDynamicState(VkDynamicState state); + /** Clips the rect to ensure it fits inside the render area. */ + VkRect2D clipToRenderArea(VkRect2D rect); /** Clips the scissor to ensure it fits inside the render area. */ - VkRect2D clipToRenderArea(VkRect2D scissor); + MTLScissorRect clipToRenderArea(MTLScissorRect scissor); /** Called by each graphics draw command to establish any outstanding state just prior to performing the draw. */ void finalizeDrawState(MVKGraphicsStage stage); @@ -437,35 +434,20 @@ public: /** Tracks the current graphics pipeline bound to the encoder. */ MVKPipelineCommandEncoderState _graphicsPipelineState; + /** Tracks the current graphics resources state of the encoder. */ + MVKGraphicsResourcesCommandEncoderState _graphicsResourcesState; + /** Tracks the current compute pipeline bound to the encoder. */ MVKPipelineCommandEncoderState _computePipelineState; - /** Tracks the current viewport state of the encoder. */ - MVKViewportCommandEncoderState _viewportState; - - /** Tracks the current scissor state of the encoder. */ - MVKScissorCommandEncoderState _scissorState; - - /** Tracks the current depth bias state of the encoder. */ - MVKDepthBiasCommandEncoderState _depthBiasState; - - /** Tracks the current blend color state of the encoder. */ - MVKBlendColorCommandEncoderState _blendColorState; + /** Tracks the current compute resources state of the encoder. */ + MVKComputeResourcesCommandEncoderState _computeResourcesState; /** Tracks the current depth stencil state of the encoder. */ MVKDepthStencilCommandEncoderState _depthStencilState; - /** Tracks the current stencil reference value state of the encoder. */ - MVKStencilReferenceValueCommandEncoderState _stencilReferenceValueState; - - /** Tracks the current graphics resources state of the encoder. */ - MVKGraphicsResourcesCommandEncoderState _graphicsResourcesState; - - /** Tracks the current compute resources state of the encoder. */ - MVKComputeResourcesCommandEncoderState _computeResourcesState; - - /** The type of primitive that will be rendered. */ - MTLPrimitiveType _mtlPrimitiveType; + /** Tracks the current rasterizing states of the encoder. */ + MVKRasterizingCommandEncoderState _rasterizingState; /** The size of the threadgroup for the compute shader. */ MTLSize _mtlThreadgroupSize; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 5f32996e..d640730c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -607,16 +607,12 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) { _graphicsPipelineState.beginMetalRenderPass(); _graphicsResourcesState.beginMetalRenderPass(); - _viewportState.beginMetalRenderPass(); - _scissorState.beginMetalRenderPass(); - _depthBiasState.beginMetalRenderPass(); - _blendColorState.beginMetalRenderPass(); + _depthStencilState.beginMetalRenderPass(); + _rasterizingState.beginMetalRenderPass(); _vertexPushConstants.beginMetalRenderPass(); _tessCtlPushConstants.beginMetalRenderPass(); _tessEvalPushConstants.beginMetalRenderPass(); _fragmentPushConstants.beginMetalRenderPass(); - _depthStencilState.beginMetalRenderPass(); - _stencilReferenceValueState.beginMetalRenderPass(); _occlusionQueryState.beginMetalRenderPass(); } @@ -706,24 +702,23 @@ void MVKCommandEncoder::signalEvent(MVKEvent* mvkEvent, bool status) { mvkEvent->encodeSignal(_mtlCmdBuffer, status); } -bool MVKCommandEncoder::supportsDynamicState(VkDynamicState state) { - MVKGraphicsPipeline* gpl = (MVKGraphicsPipeline*)_graphicsPipelineState.getPipeline(); - return !gpl || gpl->supportsDynamicState(state); +VkRect2D MVKCommandEncoder::clipToRenderArea(VkRect2D rect) { + + uint32_t raLeft = max(_renderArea.offset.x, 0); + uint32_t raRight = raLeft + _renderArea.extent.width; + uint32_t raBottom = max(_renderArea.offset.y, 0); + uint32_t raTop = raBottom + _renderArea.extent.height; + + rect.offset.x = mvkClamp(rect.offset.x, raLeft, max(raRight - 1, raLeft)); + rect.offset.y = mvkClamp(rect.offset.y, raBottom, max(raTop - 1, raBottom)); + rect.extent.width = min(rect.extent.width, raRight - rect.offset.x); + rect.extent.height = min(rect.extent.height, raTop - rect.offset.y); + + return rect; } -VkRect2D MVKCommandEncoder::clipToRenderArea(VkRect2D scissor) { - - int32_t raLeft = _renderArea.offset.x; - int32_t raRight = raLeft + _renderArea.extent.width; - int32_t raBottom = _renderArea.offset.y; - int32_t raTop = raBottom + _renderArea.extent.height; - - scissor.offset.x = mvkClamp(scissor.offset.x, raLeft, max(raRight - 1, raLeft)); - scissor.offset.y = mvkClamp(scissor.offset.y, raBottom, max(raTop - 1, raBottom)); - scissor.extent.width = min(scissor.extent.width, raRight - scissor.offset.x); - scissor.extent.height = min(scissor.extent.height, raTop - scissor.offset.y); - - return scissor; +MTLScissorRect MVKCommandEncoder::clipToRenderArea(MTLScissorRect scissor) { + return mvkMTLScissorRectFromVkRect2D(clipToRenderArea(mvkVkRect2DFromMTLScissorRect(scissor))); } void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) { @@ -733,16 +728,12 @@ void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) { } _graphicsPipelineState.encode(stage); // Must do first..it sets others _graphicsResourcesState.encode(stage); // Before push constants, to allow them to override. - _viewportState.encode(stage); - _scissorState.encode(stage); - _depthBiasState.encode(stage); - _blendColorState.encode(stage); + _depthStencilState.encode(stage); + _rasterizingState.encode(stage); _vertexPushConstants.encode(stage); _tessCtlPushConstants.encode(stage); _tessEvalPushConstants.encode(stage); _fragmentPushConstants.encode(stage); - _depthStencilState.encode(stage); - _stencilReferenceValueState.encode(stage); _occlusionQueryState.encode(stage); } @@ -831,16 +822,12 @@ void MVKCommandEncoder::endMetalRenderEncoding() { _graphicsPipelineState.endMetalRenderPass(); _graphicsResourcesState.endMetalRenderPass(); - _viewportState.endMetalRenderPass(); - _scissorState.endMetalRenderPass(); - _depthBiasState.endMetalRenderPass(); - _blendColorState.endMetalRenderPass(); + _depthStencilState.endMetalRenderPass(); + _rasterizingState.endMetalRenderPass(); _vertexPushConstants.endMetalRenderPass(); _tessCtlPushConstants.endMetalRenderPass(); _tessEvalPushConstants.endMetalRenderPass(); _fragmentPushConstants.endMetalRenderPass(); - _depthStencilState.endMetalRenderPass(); - _stencilReferenceValueState.endMetalRenderPass(); _occlusionQueryState.endMetalRenderPass(); } @@ -1131,39 +1118,35 @@ void MVKCommandEncoder::finishQueries() { MVKCommandEncoder::MVKCommandEncoder(MVKCommandBuffer* cmdBuffer, MVKPrefillMetalCommandBuffersStyle prefillStyle) : MVKBaseDeviceObject(cmdBuffer->getDevice()), - _cmdBuffer(cmdBuffer), - _graphicsPipelineState(this), - _computePipelineState(this), - _viewportState(this), - _scissorState(this), - _depthBiasState(this), - _blendColorState(this), - _depthStencilState(this), - _stencilReferenceValueState(this), - _graphicsResourcesState(this), - _computeResourcesState(this), - _vertexPushConstants(this, VK_SHADER_STAGE_VERTEX_BIT), - _tessCtlPushConstants(this, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), - _tessEvalPushConstants(this, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), - _fragmentPushConstants(this, VK_SHADER_STAGE_FRAGMENT_BIT), - _computePushConstants(this, VK_SHADER_STAGE_COMPUTE_BIT), - _occlusionQueryState(this), - _prefillStyle(prefillStyle){ + _cmdBuffer(cmdBuffer), + _graphicsPipelineState(this), + _graphicsResourcesState(this), + _computePipelineState(this), + _computeResourcesState(this), + _depthStencilState(this), + _rasterizingState(this), + _vertexPushConstants(this, VK_SHADER_STAGE_VERTEX_BIT), + _tessCtlPushConstants(this, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), + _tessEvalPushConstants(this, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), + _fragmentPushConstants(this, VK_SHADER_STAGE_FRAGMENT_BIT), + _computePushConstants(this, VK_SHADER_STAGE_COMPUTE_BIT), + _occlusionQueryState(this), + _prefillStyle(prefillStyle){ - _pDeviceFeatures = &_device->_enabledFeatures; - _pDeviceMetalFeatures = _device->_pMetalFeatures; - _pDeviceProperties = _device->_pProperties; - _pDeviceMemoryProperties = _device->_pMemoryProperties; - _pActivatedQueries = nullptr; - _mtlCmdBuffer = nil; - _mtlRenderEncoder = nil; - _mtlComputeEncoder = nil; - _mtlComputeEncoderUse = kMVKCommandUseNone; - _mtlBlitEncoder = nil; - _mtlBlitEncoderUse = kMVKCommandUseNone; - _pEncodingContext = nullptr; - _stageCountersMTLFence = nil; - _flushCount = 0; + _pDeviceFeatures = &_device->_enabledFeatures; + _pDeviceMetalFeatures = _device->_pMetalFeatures; + _pDeviceProperties = _device->_pProperties; + _pDeviceMemoryProperties = _device->_pMemoryProperties; + _pActivatedQueries = nullptr; + _mtlCmdBuffer = nil; + _mtlRenderEncoder = nil; + _mtlComputeEncoder = nil; + _mtlComputeEncoderUse = kMVKCommandUseNone; + _mtlBlitEncoder = nil; + _mtlBlitEncoderUse = kMVKCommandUseNone; + _pEncodingContext = nullptr; + _stageCountersMTLFence = nil; + _flushCount = 0; } MVKCommandEncoder::~MVKCommandEncoder() { diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 6dbeb647..c8919538 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -21,6 +21,7 @@ #include "MVKMTLResourceBindings.h" #include "MVKCommandResourceFactory.h" #include "MVKDevice.h" +#include "MVKPipeline.h" #include "MVKDescriptor.h" #include "MVKSmallVector.h" #include "MVKBitArray.h" @@ -81,7 +82,7 @@ public: /** * If the content of this instance is dirty, marks this instance as no longer dirty * and calls the encodeImpl() function to encode the content onto the Metal encoder. - * Marking dirty is done in advance so that subclass encodeImpl() implementations + * Marking clean is done in advance so that subclass encodeImpl() implementations * can override to leave this instance in a dirty state. * Subclasses must override the encodeImpl() function to do the actual work. */ @@ -96,8 +97,18 @@ public: MVKCommandEncoderState(MVKCommandEncoder* cmdEncoder) : _cmdEncoder(cmdEncoder) {} protected: - virtual void encodeImpl(uint32_t stage) = 0; + enum StateScope { + Static = 0, + Dynamic, + Count + }; + + virtual void encodeImpl(uint32_t stage) = 0; MVKDevice* getDevice(); + bool isDynamicState(MVKRenderStateType state); + template T& getContent(T* iVarAry, MVKRenderStateType state) { + return iVarAry[isDynamicState(state) ? StateScope::Dynamic : StateScope::Static]; + } MVKCommandEncoder* _cmdEncoder; bool _isDirty = false; @@ -130,62 +141,6 @@ protected: }; -#pragma mark - -#pragma mark MVKViewportCommandEncoderState - -/** Holds encoder state established by viewport commands. */ -class MVKViewportCommandEncoderState : public MVKCommandEncoderState { - -public: - - /** - * Sets one or more of the viewports, starting at the first index. - * The isSettingDynamically indicates that the scissor is being changed dynamically, - * which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR. - */ - void setViewports(MVKArrayRef viewports, - uint32_t firstViewport, - bool isSettingDynamically); - - /** Constructs this instance for the specified command encoder. */ - MVKViewportCommandEncoderState(MVKCommandEncoder* cmdEncoder) - : MVKCommandEncoderState(cmdEncoder) {} - -protected: - void encodeImpl(uint32_t stage) override; - - MVKSmallVector _viewports, _dynamicViewports; -}; - - -#pragma mark - -#pragma mark MVKScissorCommandEncoderState - -/** Holds encoder state established by viewport commands. */ -class MVKScissorCommandEncoderState : public MVKCommandEncoderState { - -public: - - /** - * Sets one or more of the scissors, starting at the first index. - * The isSettingDynamically indicates that the scissor is being changed dynamically, - * which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR. - */ - void setScissors(MVKArrayRef scissors, - uint32_t firstScissor, - bool isSettingDynamically); - - /** Constructs this instance for the specified command encoder. */ - MVKScissorCommandEncoderState(MVKCommandEncoder* cmdEncoder) - : MVKCommandEncoderState(cmdEncoder) {} - -protected: - void encodeImpl(uint32_t stage) override; - - MVKSmallVector _scissors, _dynamicScissors; -}; - - #pragma mark - #pragma mark MVKPushConstantsCommandEncoderState @@ -226,16 +181,29 @@ public: /** Sets the depth stencil state during pipeline binding. */ void setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo); - /** - * Sets the stencil compare mask value of the indicated faces - * to the specified value, from explicit dynamic command. - */ + /** Enables or disables depth testing, from explicit dynamic command. */ + void setDepthTestEnable(VkBool32 depthTestEnable); + + /** Enables or disables depth writing, from explicit dynamic command. */ + void setDepthWriteEnable(VkBool32 depthWriteEnable); + + /** Sets the depth compare operation, from explicit dynamic command. */ + void setDepthCompareOp(VkCompareOp depthCompareOp); + + /** Enables or disables stencil testing, from explicit dynamic command. */ + void setStencilTestEnable(VkBool32 stencilTestEnable); + + /** Sets the stencil operations of the indicated faces from explicit dynamic command. */ + void setStencilOp(VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); + + /** Sets the stencil compare mask value of the indicated faces from explicit dynamic command. */ void setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t stencilCompareMask); - /** - * Sets the stencil write mask value of the indicated faces - * to the specified value, from explicit dynamic command. - */ + /** Sets the stencil write mask value of the indicated faces from explicit dynamic command. */ void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t stencilWriteMask); void beginMetalRenderPass() override; @@ -246,96 +214,105 @@ public: protected: void encodeImpl(uint32_t stage) override; - void setStencilState(MVKMTLStencilDescriptorData& stencilInfo, - const VkStencilOpState& vkStencil, - bool enabled); + MVKMTLDepthStencilDescriptorData& getData(MVKRenderStateType state) { return getContent(_depthStencilData, state); } + template void setContent(T& content, T value) { + if (content != value) { + content = value; + markDirty(); + } + } + void setStencilState(MVKMTLStencilDescriptorData& sData, const VkStencilOpState& vkStencil); + void setStencilOp(MVKMTLStencilDescriptorData& sData, VkStencilOp failOp, + VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); - MVKMTLDepthStencilDescriptorData _depthStencilData = kMVKMTLDepthStencilDescriptorDataDefault; + MVKMTLDepthStencilDescriptorData _depthStencilData[StateScope::Count]; + bool _depthTestEnabled[StateScope::Count]; bool _hasDepthAttachment = false; bool _hasStencilAttachment = false; }; #pragma mark - -#pragma mark MVKStencilReferenceValueCommandEncoderState +#pragma mark MVKRasterizingCommandEncoderState -/** Holds encoder state established by stencil reference values commands. */ -class MVKStencilReferenceValueCommandEncoderState : public MVKCommandEncoderState { - -public: - - /** Sets the stencil references during pipeline binding. */ - void setReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo); - - /** Sets the stencil state from explicit dynamic command. */ - void setReferenceValues(VkStencilFaceFlags faceMask, uint32_t stencilReference); - - /** Constructs this instance for the specified command encoder. */ - MVKStencilReferenceValueCommandEncoderState(MVKCommandEncoder* cmdEncoder) - : MVKCommandEncoderState(cmdEncoder) {} - -protected: - void encodeImpl(uint32_t stage) override; - - uint32_t _frontFaceValue = 0; - uint32_t _backFaceValue = 0; +struct MVKDepthBias { + float depthBiasConstantFactor; + float depthBiasSlopeFactor; + float depthBiasClamp; }; - -#pragma mark - -#pragma mark MVKDepthBiasCommandEncoderState - -/** Holds encoder state established by depth bias commands. */ -class MVKDepthBiasCommandEncoderState : public MVKCommandEncoderState { - -public: - - /** Sets the depth bias during pipeline binding. */ - void setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo); - - /** Sets the depth bias dynamically. */ - void setDepthBias(float depthBiasConstantFactor, - float depthBiasSlopeFactor, - float depthBiasClamp); - - /** Constructs this instance for the specified command encoder. */ - MVKDepthBiasCommandEncoderState(MVKCommandEncoder* cmdEncoder) - : MVKCommandEncoderState(cmdEncoder) {} - -protected: - void encodeImpl(uint32_t stage) override; - - float _depthBiasConstantFactor = 0; - float _depthBiasClamp = 0; - float _depthBiasSlopeFactor = 0; - bool _isEnabled = false; +struct MVKStencilReference { + uint32_t frontFaceValue; + uint32_t backFaceValue; }; +struct MVKMTLViewports { + MTLViewport viewports[kMVKMaxViewportScissorCount]; + uint32_t viewportCount; +}; -#pragma mark - -#pragma mark MVKBlendColorCommandEncoderState - -/** Holds encoder state established by blend color commands. */ -class MVKBlendColorCommandEncoderState : public MVKCommandEncoderState { +struct MVKMTLScissors { + MTLScissorRect scissors[kMVKMaxViewportScissorCount]; + uint32_t scissorCount; +}; +/** Holds encoder state established by various state commands. */ +class MVKRasterizingCommandEncoderState : public MVKCommandEncoderState { public: + void setCullMode(VkCullModeFlags cullMode, bool isDynamic); - /** Sets the blend color, either as part of pipeline binding, or dynamically. */ - void setBlendColor(float red, float green, - float blue, float alpha, - bool isDynamic); + void setFrontFace(VkFrontFace frontFace, bool isDynamic); - /** Constructs this instance for the specified command encoder. */ - MVKBlendColorCommandEncoderState(MVKCommandEncoder* cmdEncoder) - : MVKCommandEncoderState(cmdEncoder) {} + void setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic); + MTLPrimitiveType getPrimitiveType(); + + void setPolygonMode(VkPolygonMode polygonMode, bool isDynamic); + + void setBlendConstants(float blendConstants[4], bool isDynamic); + + void setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo); + void setDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor, float depthBiasClamp); + void setDepthBiasEnable(VkBool32 depthBiasEnable); + void setDepthClipEnable(bool depthClip, bool isDynamic); + + void setStencilReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo); + void setStencilReferenceValues(VkStencilFaceFlags faceMask, uint32_t stencilReference); + + void setViewports(const MVKArrayRef viewports, uint32_t firstViewport, bool isDynamic); + void setScissors(const MVKArrayRef scissors, uint32_t firstScissor, bool isDynamic); + + void beginMetalRenderPass() override; + + MVKRasterizingCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {} protected: - void encodeImpl(uint32_t stage) override; + void encodeImpl(uint32_t stage) override; + bool isDirty(MVKRenderStateType state); + bool isDrawingTriangles(); + template void setContent(T* iVarAry, T* pVal, MVKRenderStateType state, bool isDynamic) { + auto* pIVar = &iVarAry[isDynamic ? StateScope::Dynamic : StateScope::Static]; + if( !mvkAreEqual(pVal, pIVar) ) { + *pIVar = *pVal; + _dirtyStates.enable(state); + _modifiedStates.enable(state); + markDirty(); + } + } - float _red = 0; - float _green = 0; - float _blue = 0; - float _alpha = 0; + MVKMTLViewports _mtlViewports[StateScope::Count] = {}; + MVKMTLScissors _mtlScissors[StateScope::Count] = {}; + MVKColor32 _mtlBlendConstants[StateScope::Count] = {}; + MVKDepthBias _mtlDepthBias[StateScope::Count] = {}; + MVKStencilReference _mtlStencilReference[StateScope::Count] = {}; + MTLCullMode _mtlCullMode[StateScope::Count] = { MTLCullModeNone, MTLCullModeNone }; + MTLWinding _mtlFrontFace[StateScope::Count] = { MTLWindingClockwise, MTLWindingClockwise }; + MTLPrimitiveType _mtlPrimitiveTopology[StateScope::Count] = { MTLPrimitiveTypePoint, MTLPrimitiveTypePoint }; + MTLDepthClipMode _mtlDepthClipEnable[StateScope::Count] = { MTLDepthClipModeClip, MTLDepthClipModeClip }; + MTLTriangleFillMode _mtlPolygonMode[StateScope::Count] = { MTLTriangleFillModeFill, MTLTriangleFillModeFill }; + MVKRenderStateFlags _dirtyStates; + MVKRenderStateFlags _modifiedStates; + bool _mtlDepthBiasEnable[StateScope::Count] = {}; + bool _cullBothFaces[StateScope::Count] = {}; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 37f0194f..828d7c09 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -25,13 +25,21 @@ using namespace std; +#define shouldUpdateFace(face) mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_##face##_BIT) + #pragma mark - #pragma mark MVKCommandEncoderState MVKVulkanAPIObject* MVKCommandEncoderState::getVulkanAPIObject() { return _cmdEncoder->getVulkanAPIObject(); }; + MVKDevice* MVKCommandEncoderState::getDevice() { return _cmdEncoder->getDevice(); } +bool MVKCommandEncoderState::isDynamicState(MVKRenderStateType state) { + auto* gpl = (MVKGraphicsPipeline*)_cmdEncoder->_graphicsPipelineState.getPipeline(); + return !gpl || gpl->isDynamicState(state); +} + #pragma mark - #pragma mark MVKPipelineCommandEncoderState @@ -51,112 +59,6 @@ void MVKPipelineCommandEncoderState::encodeImpl(uint32_t stage) { } -#pragma mark - -#pragma mark MVKViewportCommandEncoderState - -void MVKViewportCommandEncoderState::setViewports(MVKArrayRef viewports, - uint32_t firstViewport, - bool isSettingDynamically) { - - size_t vpCnt = viewports.size(); - uint32_t maxViewports = getDevice()->_pProperties->limits.maxViewports; - if ((firstViewport + vpCnt > maxViewports) || - (firstViewport >= maxViewports) || - (isSettingDynamically && vpCnt == 0)) - return; - - auto& usingViewports = isSettingDynamically ? _dynamicViewports : _viewports; - - if (firstViewport + vpCnt > usingViewports.size()) { - usingViewports.resize(firstViewport + vpCnt); - } - - bool dirty; - bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT); - if (isSettingDynamically || (!mustSetDynamically && vpCnt > 0)) { - dirty = memcmp(&usingViewports[firstViewport], &viewports[0], vpCnt * sizeof(VkViewport)) != 0; - std::copy(viewports.begin(), viewports.end(), usingViewports.begin() + firstViewport); - } else { - dirty = !usingViewports.empty(); - usingViewports.clear(); - } - - if (dirty) markDirty(); -} - -void MVKViewportCommandEncoderState::encodeImpl(uint32_t stage) { - if (stage != kMVKGraphicsStageRasterization) { return; } - auto& usingViewports = _viewports.size() > 0 ? _viewports : _dynamicViewports; - if (usingViewports.empty()) { return; } - - if (_cmdEncoder->_pDeviceFeatures->multiViewport) { - size_t vpCnt = usingViewports.size(); - MTLViewport mtlViewports[vpCnt]; - for (uint32_t vpIdx = 0; vpIdx < vpCnt; vpIdx++) { - mtlViewports[vpIdx] = mvkMTLViewportFromVkViewport(usingViewports[vpIdx]); - } -#if MVK_MACOS_OR_IOS - [_cmdEncoder->_mtlRenderEncoder setViewports: mtlViewports count: vpCnt]; -#endif - } else { - [_cmdEncoder->_mtlRenderEncoder setViewport: mvkMTLViewportFromVkViewport(usingViewports[0])]; - } -} - - -#pragma mark - -#pragma mark MVKScissorCommandEncoderState - -void MVKScissorCommandEncoderState::setScissors(MVKArrayRef scissors, - uint32_t firstScissor, - bool isSettingDynamically) { - - size_t sCnt = scissors.size(); - uint32_t maxScissors = getDevice()->_pProperties->limits.maxViewports; - if ((firstScissor + sCnt > maxScissors) || - (firstScissor >= maxScissors) || - (isSettingDynamically && sCnt == 0)) - return; - - auto& usingScissors = isSettingDynamically ? _dynamicScissors : _scissors; - - if (firstScissor + sCnt > usingScissors.size()) { - usingScissors.resize(firstScissor + sCnt); - } - - bool dirty; - bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR); - if (isSettingDynamically || (!mustSetDynamically && sCnt > 0)) { - dirty = memcmp(&usingScissors[firstScissor], &scissors[0], sCnt * sizeof(VkRect2D)) != 0; - std::copy(scissors.begin(), scissors.end(), usingScissors.begin() + firstScissor); - } else { - dirty = !usingScissors.empty(); - usingScissors.clear(); - } - - if (dirty) markDirty(); -} - -void MVKScissorCommandEncoderState::encodeImpl(uint32_t stage) { - if (stage != kMVKGraphicsStageRasterization) { return; } - auto& usingScissors = _scissors.size() > 0 ? _scissors : _dynamicScissors; - if (usingScissors.empty()) { return; } - - if (_cmdEncoder->_pDeviceFeatures->multiViewport) { - size_t sCnt = usingScissors.size(); - MTLScissorRect mtlScissors[sCnt]; - for (uint32_t sIdx = 0; sIdx < sCnt; sIdx++) { - mtlScissors[sIdx] = mvkMTLScissorRectFromVkRect2D(_cmdEncoder->clipToRenderArea(usingScissors[sIdx])); - } -#if MVK_MACOS_OR_IOS - [_cmdEncoder->_mtlRenderEncoder setScissorRects: mtlScissors count: sCnt]; -#endif - } else { - [_cmdEncoder->_mtlRenderEncoder setScissorRect: mvkMTLScissorRectFromVkRect2D(_cmdEncoder->clipToRenderArea(usingScissors[0]))]; - } -} - - #pragma mark - #pragma mark MVKPushConstantsCommandEncoderState @@ -254,74 +156,84 @@ bool MVKPushConstantsCommandEncoderState::isTessellating() { #pragma mark MVKDepthStencilCommandEncoderState void MVKDepthStencilCommandEncoderState:: setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) { - auto oldData = _depthStencilData; + auto& depthEnabled = _depthTestEnabled[StateScope::Static]; + auto oldDepthEnabled = depthEnabled; + depthEnabled = static_cast(vkDepthStencilInfo.depthTestEnable); - if (vkDepthStencilInfo.depthTestEnable) { - _depthStencilData.depthCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkDepthStencilInfo.depthCompareOp); - _depthStencilData.depthWriteEnabled = vkDepthStencilInfo.depthWriteEnable; - } else { - _depthStencilData.depthCompareFunction = kMVKMTLDepthStencilDescriptorDataDefault.depthCompareFunction; - _depthStencilData.depthWriteEnabled = kMVKMTLDepthStencilDescriptorDataDefault.depthWriteEnabled; - } + auto& dsData = _depthStencilData[StateScope::Static]; + auto oldData = dsData; + dsData.depthCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkDepthStencilInfo.depthCompareOp); + dsData.depthWriteEnabled = vkDepthStencilInfo.depthWriteEnable; - setStencilState(_depthStencilData.frontFaceStencilData, vkDepthStencilInfo.front, vkDepthStencilInfo.stencilTestEnable); - setStencilState(_depthStencilData.backFaceStencilData, vkDepthStencilInfo.back, vkDepthStencilInfo.stencilTestEnable); + dsData.stencilTestEnabled = static_cast(vkDepthStencilInfo.stencilTestEnable); + setStencilState(dsData.frontFaceStencilData, vkDepthStencilInfo.front); + setStencilState(dsData.backFaceStencilData, vkDepthStencilInfo.back); - if (!(oldData == _depthStencilData)) markDirty(); + if (depthEnabled != oldDepthEnabled || dsData != oldData) { markDirty(); } } -void MVKDepthStencilCommandEncoderState::setStencilState(MVKMTLStencilDescriptorData& stencilInfo, - const VkStencilOpState& vkStencil, - bool enabled) { - if ( !enabled ) { - stencilInfo = kMVKMTLStencilDescriptorDataDefault; - return; - } - - stencilInfo.enabled = true; - stencilInfo.stencilCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkStencil.compareOp); - stencilInfo.stencilFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.failOp); - stencilInfo.depthFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.depthFailOp); - stencilInfo.depthStencilPassOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.passOp); - - if ( !_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) ) { - stencilInfo.readMask = vkStencil.compareMask; - } - if ( !_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) ) { - stencilInfo.writeMask = vkStencil.writeMask; - } +void MVKDepthStencilCommandEncoderState::setStencilState(MVKMTLStencilDescriptorData& sData, + const VkStencilOpState& vkStencil) { + sData.readMask = vkStencil.compareMask; + sData.writeMask = vkStencil.writeMask; + sData.stencilCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkStencil.compareOp); + sData.stencilFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.failOp); + sData.depthFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.depthFailOp); + sData.depthStencilPassOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.passOp); +} + +void MVKDepthStencilCommandEncoderState::setDepthTestEnable(VkBool32 depthTestEnable) { + setContent(_depthTestEnabled[StateScope::Dynamic], static_cast(depthTestEnable)); +} + +void MVKDepthStencilCommandEncoderState::setDepthWriteEnable(VkBool32 depthWriteEnable) { + setContent(_depthStencilData[StateScope::Dynamic].depthWriteEnabled, static_cast(depthWriteEnable)); +} + +void MVKDepthStencilCommandEncoderState::setDepthCompareOp(VkCompareOp depthCompareOp) { + setContent(_depthStencilData[StateScope::Dynamic].depthCompareFunction, + (uint8_t)mvkMTLCompareFunctionFromVkCompareOp(depthCompareOp)); +} + +void MVKDepthStencilCommandEncoderState::setStencilTestEnable(VkBool32 stencilTestEnable) { + setContent(_depthStencilData[StateScope::Dynamic].stencilTestEnabled, static_cast(stencilTestEnable)); +} + +void MVKDepthStencilCommandEncoderState::setStencilOp(MVKMTLStencilDescriptorData& sData, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp) { + auto oldData = sData; + sData.stencilCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(compareOp); + sData.stencilFailureOperation = mvkMTLStencilOperationFromVkStencilOp(failOp); + sData.depthFailureOperation = mvkMTLStencilOperationFromVkStencilOp(depthFailOp); + sData.depthStencilPassOperation = mvkMTLStencilOperationFromVkStencilOp(passOp); + if (sData != oldData) { markDirty(); } +} + +void MVKDepthStencilCommandEncoderState::setStencilOp(VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp) { + auto& dsData = _depthStencilData[StateScope::Dynamic]; + if (shouldUpdateFace(FRONT)) { setStencilOp(dsData.frontFaceStencilData, failOp, passOp, depthFailOp, compareOp); } + if (shouldUpdateFace(BACK)) { setStencilOp(dsData.backFaceStencilData, failOp, passOp, depthFailOp, compareOp); } } -// We don't check for dynamic state here, because if this is called before pipeline is set, -// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway. void MVKDepthStencilCommandEncoderState::setStencilCompareMask(VkStencilFaceFlags faceMask, - uint32_t stencilCompareMask) { - auto oldData = _depthStencilData; - - if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) { - _depthStencilData.frontFaceStencilData.readMask = stencilCompareMask; - } - if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_BACK_BIT)) { - _depthStencilData.backFaceStencilData.readMask = stencilCompareMask; - } - - if (!(oldData == _depthStencilData)) markDirty(); + uint32_t stencilCompareMask) { + auto& dsData = _depthStencilData[StateScope::Dynamic]; + if (shouldUpdateFace(FRONT)) { setContent(dsData.frontFaceStencilData.readMask, stencilCompareMask); } + if (shouldUpdateFace(BACK)) { setContent(dsData.backFaceStencilData.readMask, stencilCompareMask); } } -// We don't check for dynamic state here, because if this is called before pipeline is set, -// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway. void MVKDepthStencilCommandEncoderState::setStencilWriteMask(VkStencilFaceFlags faceMask, - uint32_t stencilWriteMask) { - auto oldData = _depthStencilData; - - if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) { - _depthStencilData.frontFaceStencilData.writeMask = stencilWriteMask; - } - if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_BACK_BIT)) { - _depthStencilData.backFaceStencilData.writeMask = stencilWriteMask; - } - - if (!(oldData == _depthStencilData)) markDirty(); + uint32_t stencilWriteMask) { + auto& dsData = _depthStencilData[StateScope::Dynamic]; + if (shouldUpdateFace(FRONT)) { setContent(dsData.frontFaceStencilData.writeMask, stencilWriteMask); } + if (shouldUpdateFace(BACK)) { setContent(dsData.backFaceStencilData.writeMask, stencilWriteMask); } } void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() { @@ -337,130 +249,247 @@ void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() { if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); } } +// Combine static and dynamic depth/stencil data void MVKDepthStencilCommandEncoderState::encodeImpl(uint32_t stage) { - 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; - } - default: // Do nothing on other stages - break; + if (stage != kMVKGraphicsStageRasterization) { return; } + + MVKMTLDepthStencilDescriptorData dsData; + + if (_hasDepthAttachment && getContent(_depthTestEnabled, DepthTestEnable)) { + dsData.depthCompareFunction = getData(DepthCompareOp).depthCompareFunction; + dsData.depthWriteEnabled = getData(DepthWriteEnable).depthWriteEnabled; + } + + if (_hasStencilAttachment && getData(StencilTestEnable).stencilTestEnabled) { + dsData.stencilTestEnabled = true; + + auto& frontFace = dsData.frontFaceStencilData; + auto& backFace = dsData.backFaceStencilData; + + const auto& srcRM = getData(StencilCompareMask); + frontFace.readMask = srcRM.frontFaceStencilData.readMask; + backFace.readMask = srcRM.backFaceStencilData.readMask; + + const auto& srcWM = getData(StencilWriteMask); + frontFace.writeMask = srcWM.frontFaceStencilData.writeMask; + backFace.writeMask = srcWM.backFaceStencilData.writeMask; + + const auto& srcSOp = getData(StencilOp); + frontFace.stencilCompareFunction = srcSOp.frontFaceStencilData.stencilCompareFunction; + frontFace.stencilFailureOperation = srcSOp.frontFaceStencilData.stencilFailureOperation; + frontFace.depthFailureOperation = srcSOp.frontFaceStencilData.depthFailureOperation; + frontFace.depthStencilPassOperation = srcSOp.frontFaceStencilData.depthStencilPassOperation; + + backFace.stencilCompareFunction = srcSOp.backFaceStencilData.stencilCompareFunction; + backFace.stencilFailureOperation = srcSOp.backFaceStencilData.stencilFailureOperation; + backFace.depthFailureOperation = srcSOp.backFaceStencilData.depthFailureOperation; + backFace.depthStencilPassOperation = srcSOp.backFaceStencilData.depthStencilPassOperation; + } + + [_cmdEncoder->_mtlRenderEncoder setDepthStencilState: _cmdEncoder->getCommandEncodingPool()->getMTLDepthStencilState(dsData)]; +} + + +#pragma mark - +#pragma mark MVKRasterizingCommandEncoderState + +#define getContent(state) getContent(_mtl##state, state) +#define setContent(state) setContent(_mtl##state, &mtl##state, state, isDynamic) + +void MVKRasterizingCommandEncoderState::setCullMode(VkCullModeFlags cullMode, bool isDynamic) { + auto mtlCullMode = mvkMTLCullModeFromVkCullModeFlags(cullMode); + setContent(CullMode); + _cullBothFaces[isDynamic ? StateScope::Dynamic : StateScope::Static] = (cullMode == VK_CULL_MODE_FRONT_AND_BACK); +} + +void MVKRasterizingCommandEncoderState::setFrontFace(VkFrontFace frontFace, bool isDynamic) { + auto mtlFrontFace = mvkMTLWindingFromVkFrontFace(frontFace); + setContent(FrontFace); +} + +void MVKRasterizingCommandEncoderState::setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic) { + auto mtlPrimitiveTopology = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(topology); + setContent(PrimitiveTopology); +} + +MTLPrimitiveType MVKRasterizingCommandEncoderState::getPrimitiveType() { + return getContent(PrimitiveTopology); +} + +bool MVKRasterizingCommandEncoderState::isDrawingTriangles() { + switch (getPrimitiveType()) { + case MTLPrimitiveTypeTriangle: return true; + case MTLPrimitiveTypeTriangleStrip: return true; + default: return false; } } - -#pragma mark - -#pragma mark MVKStencilReferenceValueCommandEncoderState - -void MVKStencilReferenceValueCommandEncoderState:: setReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) { - - // If ref values are to be set dynamically, don't set them here. - if (_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE)) { return; } - - if (_frontFaceValue != vkDepthStencilInfo.front.reference || _backFaceValue != vkDepthStencilInfo.back.reference) - markDirty(); - - _frontFaceValue = vkDepthStencilInfo.front.reference; - _backFaceValue = vkDepthStencilInfo.back.reference; +void MVKRasterizingCommandEncoderState::setPolygonMode(VkPolygonMode polygonMode, bool isDynamic) { + auto mtlPolygonMode = mvkMTLTriangleFillModeFromVkPolygonMode(polygonMode); + setContent(PolygonMode); } -// We don't check for dynamic state here, because if this is called before pipeline is set, -// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway. -void MVKStencilReferenceValueCommandEncoderState::setReferenceValues(VkStencilFaceFlags faceMask, - uint32_t stencilReference) { - bool dirty = false; - if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) { - dirty |= (_frontFaceValue != stencilReference); - _frontFaceValue = stencilReference; - } - if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_BACK_BIT)) { - dirty |= (_backFaceValue != stencilReference); - _backFaceValue = stencilReference; - } - if (dirty) markDirty(); +void MVKRasterizingCommandEncoderState::setBlendConstants(float blendConstants[4], bool isDynamic) { + MVKColor32 mtlBlendConstants; + mvkCopy(mtlBlendConstants.float32, blendConstants, 4); + setContent(BlendConstants); } -void MVKStencilReferenceValueCommandEncoderState::encodeImpl(uint32_t stage) { - if (stage != kMVKGraphicsStageRasterization) { return; } - [_cmdEncoder->_mtlRenderEncoder setStencilFrontReferenceValue: _frontFaceValue - backReferenceValue: _backFaceValue]; +void MVKRasterizingCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) { + bool isDynamic = false; + + bool mtlDepthBiasEnable = static_cast(vkRasterInfo.depthBiasEnable); + setContent(DepthBiasEnable); + + MVKDepthBias mtlDepthBias = { + .depthBiasConstantFactor = vkRasterInfo.depthBiasConstantFactor, + .depthBiasSlopeFactor = vkRasterInfo.depthBiasSlopeFactor, + .depthBiasClamp = vkRasterInfo.depthBiasClamp + }; + setContent(DepthBias); } - -#pragma mark - -#pragma mark MVKDepthBiasCommandEncoderState - -void MVKDepthBiasCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) { - - auto wasEnabled = _isEnabled; - _isEnabled = vkRasterInfo.depthBiasEnable; - - // If ref values are to be set dynamically, don't set them here. - if (_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS)) { return; } - - if (_isEnabled != wasEnabled || _depthBiasConstantFactor != vkRasterInfo.depthBiasConstantFactor - || _depthBiasSlopeFactor != vkRasterInfo.depthBiasSlopeFactor || _depthBiasClamp != vkRasterInfo.depthBiasClamp) { - - markDirty(); - _depthBiasConstantFactor = vkRasterInfo.depthBiasConstantFactor; - _depthBiasSlopeFactor = vkRasterInfo.depthBiasSlopeFactor; - _depthBiasClamp = vkRasterInfo.depthBiasClamp; - } +void MVKRasterizingCommandEncoderState::setDepthBias(float depthBiasConstantFactor, + float depthBiasSlopeFactor, + float depthBiasClamp) { + bool isDynamic = true; + MVKDepthBias mtlDepthBias = { + .depthBiasConstantFactor = depthBiasConstantFactor, + .depthBiasSlopeFactor = depthBiasSlopeFactor, + .depthBiasClamp = depthBiasClamp + }; + setContent(DepthBias); } -// We don't check for dynamic state here, because if this is called before pipeline is set, -// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway. -void MVKDepthBiasCommandEncoderState::setDepthBias(float depthBiasConstantFactor, - float depthBiasSlopeFactor, - float depthBiasClamp) { - - if (_depthBiasConstantFactor != depthBiasConstantFactor || _depthBiasSlopeFactor != depthBiasSlopeFactor - || _depthBiasClamp != depthBiasClamp) { - - markDirty(); - _depthBiasConstantFactor = depthBiasConstantFactor; - _depthBiasSlopeFactor = depthBiasSlopeFactor; - _depthBiasClamp = depthBiasClamp; - } +void MVKRasterizingCommandEncoderState::setDepthBiasEnable(VkBool32 depthBiasEnable) { + bool isDynamic = true; + bool mtlDepthBiasEnable = static_cast(depthBiasEnable); + setContent(DepthBiasEnable); } -void MVKDepthBiasCommandEncoderState::encodeImpl(uint32_t stage) { - if (stage != kMVKGraphicsStageRasterization) { return; } - if (_isEnabled) { - [_cmdEncoder->_mtlRenderEncoder setDepthBias: _depthBiasConstantFactor - slopeScale: _depthBiasSlopeFactor - clamp: _depthBiasClamp]; - } else { - [_cmdEncoder->_mtlRenderEncoder setDepthBias: 0 slopeScale: 0 clamp: 0]; - } +void MVKRasterizingCommandEncoderState::setDepthClipEnable(bool depthClip, bool isDynamic) { + auto mtlDepthClipEnable = depthClip ? MTLDepthClipModeClip : MTLDepthClipModeClamp; + setContent(DepthClipEnable); } - -#pragma mark - -#pragma mark MVKBlendColorCommandEncoderState - -void MVKBlendColorCommandEncoderState::setBlendColor(float red, float green, - float blue, float alpha, - bool isDynamic) { - // Abort if we are using dynamic, but call is not dynamic. - if ( !isDynamic && _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS) ) { return; } - - if (_red != red || _green != green || _blue != blue || _alpha != alpha) { - markDirty(); - _red = red; - _green = green; - _blue = blue; - _alpha = alpha; - } +void MVKRasterizingCommandEncoderState::setStencilReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) { + bool isDynamic = false; + MVKStencilReference mtlStencilReference = { + .frontFaceValue = vkDepthStencilInfo.front.reference, + .backFaceValue = vkDepthStencilInfo.back.reference + }; + setContent(StencilReference); } -void MVKBlendColorCommandEncoderState::encodeImpl(uint32_t stage) { - if (stage != kMVKGraphicsStageRasterization) { return; } - [_cmdEncoder->_mtlRenderEncoder setBlendColorRed: _red green: _green blue: _blue alpha: _alpha]; +void MVKRasterizingCommandEncoderState::setStencilReferenceValues(VkStencilFaceFlags faceMask, uint32_t stencilReference) { + bool isDynamic = true; + MVKStencilReference mtlStencilReference = _mtlStencilReference[StateScope::Dynamic]; + if (shouldUpdateFace(FRONT)) { mtlStencilReference.frontFaceValue = stencilReference; } + if (shouldUpdateFace(BACK)) { mtlStencilReference.backFaceValue = stencilReference; } + setContent(StencilReference); +} + +void MVKRasterizingCommandEncoderState::setViewports(const MVKArrayRef viewports, + uint32_t firstViewport, + bool isDynamic) { + uint32_t maxViewports = getDevice()->_pProperties->limits.maxViewports; + if (firstViewport >= maxViewports) { return; } + + MVKMTLViewports mtlViewports = isDynamic ? _mtlViewports[StateScope::Dynamic] : _mtlViewports[StateScope::Static]; + size_t vpCnt = min((uint32_t)viewports.size(), maxViewports - firstViewport); + for (uint32_t vpIdx = 0; vpIdx < vpCnt; vpIdx++) { + mtlViewports.viewports[firstViewport + vpIdx] = mvkMTLViewportFromVkViewport(viewports[vpIdx]); + mtlViewports.viewportCount = max(mtlViewports.viewportCount, vpIdx + 1); + } + setContent(Viewports); +} + +void MVKRasterizingCommandEncoderState::setScissors(const MVKArrayRef scissors, + uint32_t firstScissor, + bool isDynamic) { + uint32_t maxScissors = getDevice()->_pProperties->limits.maxViewports; + if (firstScissor >= maxScissors) { return; } + + MVKMTLScissors mtlScissors = isDynamic ? _mtlScissors[StateScope::Dynamic] : _mtlScissors[StateScope::Static]; + size_t sCnt = min((uint32_t)scissors.size(), maxScissors - firstScissor); + for (uint32_t sIdx = 0; sIdx < sCnt; sIdx++) { + mtlScissors.scissors[firstScissor + sIdx] = mvkMTLScissorRectFromVkRect2D(scissors[sIdx]); + mtlScissors.scissorCount = max(mtlScissors.scissorCount, sIdx + 1); + } + setContent(Scissors); +} + +void MVKRasterizingCommandEncoderState::encodeImpl(uint32_t stage) { + if (stage != kMVKGraphicsStageRasterization) { return; } + + auto& rendEnc = _cmdEncoder->_mtlRenderEncoder; + + if (isDirty(CullMode)) { [rendEnc setCullMode: getContent(CullMode)]; } + if (isDirty(FrontFace)) { [rendEnc setFrontFacingWinding: getContent(FrontFace)]; } + if (isDirty(BlendConstants)) { + auto& bcFlt = getContent(BlendConstants).float32; + [rendEnc setBlendColorRed: bcFlt[0] green: bcFlt[1] blue: bcFlt[2] alpha: bcFlt[3]]; + } + if (isDirty(DepthBiasEnable) || isDirty(DepthBias)) { + if (getContent(DepthBiasEnable)) { + auto& db = getContent(DepthBias); + [rendEnc setDepthBias: db.depthBiasConstantFactor + slopeScale: db.depthBiasSlopeFactor + clamp: db.depthBiasClamp]; + } else { + [rendEnc setDepthBias: 0 slopeScale: 0 clamp: 0]; + } + } + if (isDirty(DepthClipEnable) && getDevice()->_enabledFeatures.depthClamp) { + [rendEnc setDepthClipMode: getContent(DepthClipEnable)]; + } + + if (isDirty(StencilReference)) { + auto& sr = getContent(StencilReference); + [rendEnc setStencilFrontReferenceValue: sr.frontFaceValue backReferenceValue: sr.backFaceValue]; + } + + if (isDirty(Viewports)) { + auto& mtlViewports = getContent(Viewports); + if (_cmdEncoder->_pDeviceFeatures->multiViewport) { +#if MVK_MACOS_OR_IOS + [rendEnc setViewports: mtlViewports.viewports count: mtlViewports.viewportCount]; +#endif + } else { + [rendEnc setViewport: mtlViewports.viewports[0]]; + } + } + + if (isDirty(Scissors)) { + auto mtlScissors = getContent(Scissors); + + // If culling has been dynamically set to front-and-back, emulate this by using zeroed scissor rectangles. + static MTLScissorRect zeroRect = {}; + bool cullBothFaces = isDrawingTriangles() && _cullBothFaces[StateScope::Dynamic] && isDynamicState(CullMode); + for (uint32_t sIdx = 0; sIdx < mtlScissors.scissorCount; sIdx++) { + mtlScissors.scissors[sIdx] = cullBothFaces ? zeroRect : _cmdEncoder->clipToRenderArea(mtlScissors.scissors[sIdx]); + } + + if (_cmdEncoder->_pDeviceFeatures->multiViewport) { +#if MVK_MACOS_OR_IOS + [rendEnc setScissorRects: mtlScissors.scissors count: mtlScissors.scissorCount]; +#endif + } else { + [rendEnc setScissorRect: mtlScissors.scissors[0]]; + } + } +} + +// Return whether state is dirty, and mark it not dirty +bool MVKRasterizingCommandEncoderState::isDirty(MVKRenderStateType state) { + bool rslt = _dirtyStates.isEnabled(state); + _dirtyStates.disable(state); + return rslt; +} + +void MVKRasterizingCommandEncoderState::beginMetalRenderPass() { + MVKCommandEncoderState::beginMetalRenderPass(); + _dirtyStates = _modifiedStates; } @@ -777,6 +806,7 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { MVKGraphicsPipeline* pipeline = (MVKGraphicsPipeline*)getPipeline(); bool fullImageViewSwizzle = pipeline->fullImageViewSwizzle() || getDevice()->_pMetalFeatures->nativeTextureSwizzle; bool forTessellation = pipeline->isTessellationPipeline(); + bool isDynamicVertexStride = pipeline->isDynamicState(VertexStride); if (stage == kMVKGraphicsStageVertex) { encodeBindings(kMVKShaderStageVertex, "vertex", fullImageViewSwizzle, @@ -812,23 +842,32 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { } else if (!forTessellation && stage == kMVKGraphicsStageRasterization) { encodeBindings(kMVKShaderStageVertex, "vertex", fullImageViewSwizzle, - [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { + [pipeline, isDynamicVertexStride](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { // The app may have bound more vertex attribute buffers than used by the pipeline. // We must not bind those extra buffers to the shader because they might overwrite // any implicit buffers used by the pipeline. if (pipeline->isValidVertexBufferIndex(kMVKShaderStageVertex, b.index)) { - if (b.isInline) { - cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, - b.mtlBytes, - b.size, - b.index); + NSUInteger mtlStride = isDynamicVertexStride ? b.stride : MTLAttributeStrideStatic; + if (b.isInline) { + [cmdEncoder->_mtlRenderEncoder setVertexBytes: b.mtlBytes + length: b.size +#if MVK_XCODE_15 + attributeStride: mtlStride +#endif + atIndex: b.index]; } else { - if (b.justOffset) { - [cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: b.offset - atIndex: b.index]; - } else { + if (b.justOffset) { + [cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: b.offset +#if MVK_XCODE_15 + attributeStride: mtlStride +#endif + atIndex: b.index]; + } else { [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer offset: b.offset +#if MVK_XCODE_15 + attributeStride: mtlStride +#endif atIndex: b.index]; } @@ -838,6 +877,9 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { if (b.index == pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.binding)) { [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer offset: b.offset + xltdBind.translationOffset +#if MVK_XCODE_15 + attributeStride: mtlStride +#endif atIndex: pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding)]; } } @@ -898,19 +940,29 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { if (forTessellation && stage == kMVKGraphicsStageRasterization) { encodeBindings(kMVKShaderStageTessEval, "tessellation evaluation", fullImageViewSwizzle, - [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { - if (b.isInline) - cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, - b.mtlBytes, - b.size, - b.index); - else if (b.justOffset) + [isDynamicVertexStride](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { + NSUInteger mtlStride = isDynamicVertexStride ? b.stride : MTLAttributeStrideStatic; + if (b.isInline) { + [cmdEncoder->_mtlRenderEncoder setVertexBytes: b.mtlBytes + length: b.size +#if MVK_XCODE_15 + attributeStride: mtlStride +#endif + atIndex: b.index]; + } else if (b.justOffset) { [cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: b.offset +#if MVK_XCODE_15 + attributeStride: mtlStride +#endif atIndex: b.index]; - else + } else { [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer offset: b.offset +#if MVK_XCODE_15 + attributeStride: mtlStride +#endif atIndex: b.index]; + } }, [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKArrayRef s)->void { cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index 84fa37b6..99fcb384 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -210,27 +210,24 @@ namespace std { * change as early as possible. */ typedef struct MVKMTLStencilDescriptorData { - bool enabled; /**< Indicates whether stencil testing for this face is enabled. */ + uint32_t readMask; /**< The bit-mask to apply when comparing the stencil buffer value to the reference value. */ + uint32_t writeMask; /**< The bit-mask to apply when writing values to the stencil buffer. */ uint8_t stencilCompareFunction; /**< The stencil compare function (interpreted as MTLCompareFunction). */ uint8_t stencilFailureOperation; /**< The operation to take when the stencil test fails (interpreted as MTLStencilOperation). */ uint8_t depthFailureOperation; /**< The operation to take when the stencil test passes, but the depth test fails (interpreted as MTLStencilOperation). */ uint8_t depthStencilPassOperation; /**< The operation to take when both the stencil and depth tests pass (interpreted as MTLStencilOperation). */ - uint32_t readMask; /**< The bit-mask to apply when comparing the stencil buffer value to the reference value. */ - uint32_t writeMask; /**< The bit-mask to apply when writing values to the stencil buffer. */ + + bool operator==(const MVKMTLStencilDescriptorData& rhs) const { return mvkAreEqual(this, &rhs); } + bool operator!=(const MVKMTLStencilDescriptorData& rhs) const { return !(*this == rhs); } MVKMTLStencilDescriptorData() { - - // Start with all zeros to ensure memory comparisons will work, - // even if the structure contains alignment gaps. - mvkClear(this); - - enabled = false; + mvkClear(this); // Clear all memory to ensure memory comparisons will work. + mvkEnableAllFlags(readMask); + mvkEnableAllFlags(writeMask); stencilCompareFunction = MTLCompareFunctionAlways; stencilFailureOperation = MTLStencilOperationKeep; depthFailureOperation = MTLStencilOperationKeep; depthStencilPassOperation = MTLStencilOperationKeep; - readMask = static_cast(~0); - writeMask = static_cast(~0); } } MVKMTLStencilDescriptorData; @@ -247,34 +244,32 @@ const MVKMTLStencilDescriptorData kMVKMTLStencilDescriptorDataDefault; * change as early as possible. */ typedef struct MVKMTLDepthStencilDescriptorData { - uint8_t depthCompareFunction; /**< The depth compare function (interpreted as MTLCompareFunction). */ - bool depthWriteEnabled; /**< Indicates whether depth writing is enabled. */ MVKMTLStencilDescriptorData frontFaceStencilData; MVKMTLStencilDescriptorData backFaceStencilData; + uint8_t depthCompareFunction; /**< The depth compare function (interpreted as MTLCompareFunction). */ + bool depthWriteEnabled; /**< Indicates whether depth writing is enabled. */ + bool stencilTestEnabled; /**< Indicates whether stencil testing is enabled. */ bool operator==(const MVKMTLDepthStencilDescriptorData& rhs) const { return mvkAreEqual(this, &rhs); } + bool operator!=(const MVKMTLDepthStencilDescriptorData& rhs) const { return !(*this == rhs); } std::size_t hash() const { return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_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; - } + void disableDepth() { + depthCompareFunction = MTLCompareFunctionAlways; + depthWriteEnabled = false; + } + void disableStencil() { + stencilTestEnabled = false; + frontFaceStencilData = kMVKMTLStencilDescriptorDataDefault; + backFaceStencilData = kMVKMTLStencilDescriptorDataDefault; } MVKMTLDepthStencilDescriptorData() { - // Start with all zeros to ensure memory comparisons will work, - // even if the structure contains alignment gaps. - mvkClear(this); - disable(true, true); + mvkClear(this); // Clear all memory to ensure memory comparisons will work. + disableDepth(); + disableStencil(); } } __attribute__((aligned(sizeof(uint64_t)))) MVKMTLDepthStencilDescriptorData; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index 33ee4485..1e301734 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -433,9 +433,10 @@ id MVKCommandResourceFactory::newMTLDepthStencilState(bool } id MVKCommandResourceFactory::newMTLDepthStencilState(MVKMTLDepthStencilDescriptorData& dsData) { - MTLStencilDescriptor* fsDesc = newMTLStencilDescriptor(dsData.frontFaceStencilData); // temp retain - MTLStencilDescriptor* bsDesc = newMTLStencilDescriptor(dsData.backFaceStencilData); // temp retain - MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new]; // temp retain + bool testStencil = dsData.stencilTestEnabled; + auto* fsDesc = testStencil ? newMTLStencilDescriptor(dsData.frontFaceStencilData) : nil; // temp retain + auto* bsDesc = testStencil ? newMTLStencilDescriptor(dsData.backFaceStencilData) : nil; // temp retain + auto* dsDesc = [MTLDepthStencilDescriptor new]; // temp retain dsDesc.depthCompareFunction = (MTLCompareFunction)dsData.depthCompareFunction; dsDesc.depthWriteEnabled = dsData.depthWriteEnabled; dsDesc.frontFaceStencil = fsDesc; @@ -443,16 +444,14 @@ id MVKCommandResourceFactory::newMTLDepthStencilState(MVKM id dss = [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc]; - [fsDesc release]; // temp release - [bsDesc release]; // temp release - [dsDesc release]; // temp release + [fsDesc release]; // temp release + [bsDesc release]; // temp release + [dsDesc release]; // temp release return dss; } MTLStencilDescriptor* MVKCommandResourceFactory::newMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData) { - if ( !sData.enabled ) { return nil; } - MTLStencilDescriptor* sDesc = [MTLStencilDescriptor new]; // retained sDesc.stencilCompareFunction = (MTLCompareFunction)sData.stencilCompareFunction; sDesc.stencilFailureOperation = (MTLStencilOperation)sData.stencilFailureOperation; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def index 0ab0ffab..3035677f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def +++ b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def @@ -89,12 +89,19 @@ MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(SetScissor, 1) MVK_CMD_TYPE_POOL(SetLineWidth) MVK_CMD_TYPE_POOL(SetDepthBias) MVK_CMD_TYPE_POOL(SetBlendConstants) +MVK_CMD_TYPE_POOL(SetDepthTestEnable) +MVK_CMD_TYPE_POOL(SetDepthWriteEnable) +MVK_CMD_TYPE_POOL(SetDepthCompareOp) MVK_CMD_TYPE_POOL(SetDepthBounds) +MVK_CMD_TYPE_POOL(SetDepthBoundsTestEnable) +MVK_CMD_TYPE_POOL(SetStencilTestEnable) +MVK_CMD_TYPE_POOL(SetStencilOp) MVK_CMD_TYPE_POOL(SetStencilCompareMask) MVK_CMD_TYPE_POOL(SetStencilWriteMask) MVK_CMD_TYPE_POOL(SetStencilReference) MVK_CMD_TYPE_POOL(SetCullMode) MVK_CMD_TYPE_POOL(SetFrontFace) +MVK_CMD_TYPE_POOL(SetPrimitiveTopology) MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindVertexBuffers, 1, 2) MVK_CMD_TYPE_POOL(BindIndexBuffer) MVK_CMD_TYPE_POOL(Draw) diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h index 3eeb7d42..e0637011 100644 --- a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h +++ b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h @@ -67,6 +67,7 @@ typedef struct MVKMTLBufferBinding { union { id mtlBuffer = nil; id mtlResource; const void* mtlBytes; }; // aliases VkDeviceSize offset = 0; uint32_t size = 0; + uint32_t stride = 0; uint16_t index = 0; bool justOffset = false; bool isDirty = true; @@ -78,14 +79,16 @@ typedef struct MVKMTLBufferBinding { void update(const MVKMTLBufferBinding &other) { if (mtlBuffer != other.mtlBuffer || size != other.size || other.isInline) { mtlBuffer = other.mtlBuffer; + offset = other.offset; size = other.size; + stride = other.stride; isInline = other.isInline; - offset = other.offset; justOffset = false; isOverridden = false; isDirty = true; - } else if (offset != other.offset) { + } else if (offset != other.offset || stride != other.stride) { offset = other.offset; + stride = other.stride; justOffset = !isOverridden && (!isDirty || justOffset); isOverridden = false; isDirty = true; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 20bad33e..c2fe1e86 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -387,6 +387,11 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) { formatFeatures->formatA4B4G4R4 = canSupport4444; break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT: { + auto* extDynState = (VkPhysicalDeviceExtendedDynamicStateFeaturesEXT*)next; + extDynState->extendedDynamicState = true; + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: { auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next; interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups; @@ -1696,10 +1701,11 @@ void MVKPhysicalDevice::initMetalFeatures() { _metalFeatures.minSwapchainImageCount = kMVKMinSwapchainImageCount; _metalFeatures.maxSwapchainImageCount = kMVKMaxSwapchainImageCount; - _metalFeatures.vertexStrideAlignment = 4; - _metalFeatures.maxPerStageStorageTextureCount = 8; + _metalFeatures.vertexStrideAlignment = supportsMTLGPUFamily(Apple5) ? 1 : 4; + _metalFeatures.dynamicVertexStride = mvkOSVersionIsAtLeast(14.0, 17.0, 1.0) && (supportsMTLGPUFamily(Apple4) || supportsMTLGPUFamily(Mac2)); + // GPU-specific features switch (_properties.vendorID) { case kAMDVendorId: @@ -2411,7 +2417,7 @@ void MVKPhysicalDevice::initLimits() { _properties.limits.maxVertexInputAttributes = 31; _properties.limits.maxVertexInputBindings = 31; - _properties.limits.maxVertexInputBindingStride = (2 * KIBI); + _properties.limits.maxVertexInputBindingStride = supportsMTLGPUFamily(Apple2) ? kMVKUndefinedLargeUInt32 : (4 * KIBI); _properties.limits.maxVertexInputAttributeOffset = _properties.limits.maxVertexInputBindingStride - 1; _properties.limits.maxPerStageDescriptorSamplers = _metalFeatures.maxPerStageSamplerCount; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def index 88a3a33f..4e9f3bed 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def @@ -64,6 +64,7 @@ MVK_DEVICE_FEATURE(VulkanMemoryModel, VULKAN_MEMORY_MODEL, MVK_DEVICE_FEATURE_EXTN(FragmentShaderBarycentric, FRAGMENT_SHADER_BARYCENTRIC, KHR, 1) MVK_DEVICE_FEATURE_EXTN(PortabilitySubset, PORTABILITY_SUBSET, KHR, 15) MVK_DEVICE_FEATURE_EXTN(4444Formats, 4444_FORMATS, EXT, 2) +MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, EXT, 1) MVK_DEVICE_FEATURE_EXTN(FragmentShaderInterlock, FRAGMENT_SHADER_INTERLOCK, EXT, 3) MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1) MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index e3c94135..acf6670f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -635,16 +635,16 @@ void MVKInstance::initProcAddrs() { ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdResetEvent2, KHR, KHR_SYNCHRONIZATION_2); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdResolveImage2, KHR, KHR_COPY_COMMANDS_2); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetCullMode, EXT, EXT_EXTENDED_DYNAMIC_STATE); - ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetDepthBiasEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); + ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetDepthBiasEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE_2); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetDepthBoundsTestEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetDepthCompareOp, EXT, EXT_EXTENDED_DYNAMIC_STATE); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetDepthTestEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetDepthWriteEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetEvent2, KHR, KHR_SYNCHRONIZATION_2); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetFrontFace, EXT, EXT_EXTENDED_DYNAMIC_STATE); - ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetPrimitiveRestartEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); + ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetPrimitiveRestartEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE_2); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetPrimitiveTopology, EXT, EXT_EXTENDED_DYNAMIC_STATE); - ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetRasterizerDiscardEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); + ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetRasterizerDiscardEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE_2); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetScissorWithCount, EXT, EXT_EXTENDED_DYNAMIC_STATE); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetStencilOp, EXT, EXT_EXTENDED_DYNAMIC_STATE); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetStencilTestEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 505e894c..c7f67db1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -218,6 +218,44 @@ struct MVKStagedDescriptorBindingUse { MVKBitArray stages[4] = {}; }; +/** Enumeration identifying different state content types. */ +enum MVKRenderStateType { + Unknown = 0, + BlendConstants, + CullMode, + DepthBias, + DepthBiasEnable, + DepthBounds, + DepthBoundsTestEnable, + DepthClipEnable, + DepthCompareOp, + DepthTestEnable, + DepthWriteEnable, + FrontFace, + PolygonMode, + PrimitiveTopology, + SampleLocations, + Scissors, + StencilCompareMask, + StencilOp, + StencilReference, + StencilTestEnable, + StencilWriteMask, + VertexStride, + Viewports, +}; + +/** Boolean tracking of rendering state. */ +struct MVKRenderStateFlags { + void enable(MVKRenderStateType rs) { if (rs) { mvkEnableFlags(_stateFlags, getFlagMask(rs)); } } + void disable(MVKRenderStateType rs) { if (rs) { mvkDisableFlags(_stateFlags, getFlagMask(rs)); } } + bool isEnabled(MVKRenderStateType rs) { return mvkIsAnyFlagEnabled(_stateFlags, getFlagMask(rs)); } +protected: + uint32_t getFlagMask(MVKRenderStateType rs) { return rs ? (1u << (rs - 1u)) : 0; } // Ignore Unknown type + + uint32_t _stateFlags = 0; +}; + /** Represents an Vulkan graphics pipeline. */ class MVKGraphicsPipeline : public MVKPipeline { @@ -229,8 +267,8 @@ public: /** Binds this pipeline to the specified command encoder. */ void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) override; - /** Returns whether this pipeline permits dynamic setting of the specifie state. */ - bool supportsDynamicState(VkDynamicState state); + /** Returns whether this pipeline permits dynamic setting of the state. */ + bool isDynamicState(MVKRenderStateType state) { return _dynamicState.isEnabled(state); } /** Returns whether this pipeline has tessellation shaders. */ bool isTessellationPipeline() { return _tessInfo.patchControlPoints > 0; } @@ -320,6 +358,7 @@ protected: id getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id& plState, const char* compilerType); bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, MVKMTLFunction* pVtxFunctions, VkPipelineCreationFeedback* pVertexFB); bool compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, VkPipelineCreationFeedback* pTessCtlFB); + void initDynamicState(const VkGraphicsPipelineCreateInfo* pCreateInfo); void initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo); void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, VkPipelineCreationFeedback* pPipelineFB, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); @@ -356,10 +395,10 @@ protected: VkPipelineTessellationStateCreateInfo _tessInfo; VkPipelineRasterizationStateCreateInfo _rasterInfo; VkPipelineDepthStencilStateCreateInfo _depthStencilInfo; + MVKRenderStateFlags _dynamicState; MVKSmallVector _viewports; MVKSmallVector _scissors; - MVKSmallVector _dynamicState; MVKSmallVector _customSamplePositions; MVKSmallVector _translatedVertexBindings; MVKSmallVector _zeroDivisorVertexBindings; @@ -374,19 +413,16 @@ protected: id _mtlTessControlStageState = nil; id _mtlPipelineState = nil; - float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 }; - MTLCullMode _mtlCullMode; - MTLWinding _mtlFrontWinding; - MTLTriangleFillMode _mtlFillMode; - MTLDepthClipMode _mtlDepthClipMode; + float _blendConstants[4] = {}; + VkPrimitiveTopology _vkPrimitiveTopology; MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount; MVKShaderImplicitRezBinding _viewRangeBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex; - VkPrimitiveTopology _vkPrimitiveTopology; uint32_t _outputControlPointCount; uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0; + bool _hasRasterInfo = false; bool _needsVertexSwizzleBuffer = false; bool _needsVertexBufferSizeBuffer = false; bool _needsVertexDynamicOffsetBuffer = false; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 779eb75a..f41077c8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -292,24 +292,20 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage) // Depth stencil state - Cleared _depthStencilInfo values will disable depth testing cmdEncoder->_depthStencilState.setDepthStencilState(_depthStencilInfo); - cmdEncoder->_stencilReferenceValueState.setReferenceValues(_depthStencilInfo); // Rasterization - cmdEncoder->_blendColorState.setBlendColor(_blendConstants[0], _blendConstants[1], - _blendConstants[2], _blendConstants[3], false); - cmdEncoder->_depthBiasState.setDepthBias(_rasterInfo); - cmdEncoder->_viewportState.setViewports(_viewports.contents(), 0, false); - cmdEncoder->_scissorState.setScissors(_scissors.contents(), 0, false); - cmdEncoder->_mtlPrimitiveType = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(_vkPrimitiveTopology); - - [mtlCmdEnc setCullMode: _mtlCullMode]; - [mtlCmdEnc setFrontFacingWinding: _mtlFrontWinding]; - [mtlCmdEnc setTriangleFillMode: _mtlFillMode]; - - if (_device->_enabledFeatures.depthClamp) { - [mtlCmdEnc setDepthClipMode: _mtlDepthClipMode]; - } - + cmdEncoder->_rasterizingState.setPrimitiveTopology(_vkPrimitiveTopology, false); + cmdEncoder->_rasterizingState.setBlendConstants(_blendConstants, false); + cmdEncoder->_rasterizingState.setStencilReferenceValues(_depthStencilInfo); + cmdEncoder->_rasterizingState.setViewports(_viewports.contents(), 0, false); + cmdEncoder->_rasterizingState.setScissors(_scissors.contents(), 0, false); + if (_hasRasterInfo) { + cmdEncoder->_rasterizingState.setCullMode(_rasterInfo.cullMode, false); + cmdEncoder->_rasterizingState.setFrontFace(_rasterInfo.frontFace, false); + cmdEncoder->_rasterizingState.setPolygonMode(_rasterInfo.polygonMode, false); + cmdEncoder->_rasterizingState.setDepthBias(_rasterInfo); + cmdEncoder->_rasterizingState.setDepthClipEnable( !_rasterInfo.depthClampEnable, false ); + } break; } @@ -320,21 +316,6 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage) cmdEncoder->_graphicsResourcesState.bindViewRangeBuffer(_viewRangeBufferIndex, _needsVertexViewRangeBuffer, _needsFragmentViewRangeBuffer); } -bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) { - for (auto& ds : _dynamicState) { - if (state == ds) { - // Some dynamic states have other restrictions - switch (state) { - case VK_DYNAMIC_STATE_DEPTH_BIAS: - return _rasterInfo.depthBiasEnable; - default: - return true; - } - } - } - return false; -} - static const char vtxCompilerType[] = "Vertex stage pipeline for tessellation"; bool MVKGraphicsPipeline::compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, @@ -414,6 +395,10 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, const VkGraphicsPipelineCreateInfo* pCreateInfo) : MVKPipeline(device, pipelineCache, (MVKPipelineLayout*)pCreateInfo->layout, pCreateInfo->flags, parent) { + + // Extract dynamic state first, as it can affect many configurations. + initDynamicState(pCreateInfo); + // Determine rasterization early, as various other structs are validated and interpreted in this context. const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); _isRasterizing = !isRasterizationDisabled(pCreateInfo); @@ -509,17 +494,12 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, initMTLRenderPipelineState(pCreateInfo, reflectData, pPipelineFB, pVertexSS, pVertexFB, pTessCtlSS, pTessCtlFB, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB); if ( !_hasValidMTLPipelineStates ) { return; } - // Track dynamic state - const VkPipelineDynamicStateCreateInfo* pDS = pCreateInfo->pDynamicState; - if (pDS) { - for (uint32_t i = 0; i < pDS->dynamicStateCount; i++) { - _dynamicState.push_back(pDS->pDynamicStates[i]); - } - } - // Blending - must ignore allowed bad pColorBlendState pointer if rasterization disabled or no color attachments if (_isRasterizingColor && pCreateInfo->pColorBlendState) { - memcpy(&_blendConstants, &pCreateInfo->pColorBlendState->blendConstants, sizeof(_blendConstants)); + mvkCopy(_blendConstants, pCreateInfo->pColorBlendState->blendConstants, 4); + } else { + float defaultBlendConstants[4] = { 0, 0.0, 0.0, 1.0 }; + mvkCopy(_blendConstants, defaultBlendConstants, 4); } // Topology @@ -528,21 +508,10 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, : VK_PRIMITIVE_TOPOLOGY_POINT_LIST); // Rasterization - _mtlCullMode = MTLCullModeNone; - _mtlFrontWinding = MTLWindingCounterClockwise; - _mtlFillMode = MTLTriangleFillModeFill; - _mtlDepthClipMode = MTLDepthClipModeClip; - bool hasRasterInfo = mvkSetOrClear(&_rasterInfo, pCreateInfo->pRasterizationState); - if (hasRasterInfo) { - _mtlCullMode = mvkMTLCullModeFromVkCullModeFlags(_rasterInfo.cullMode); - _mtlFrontWinding = mvkMTLWindingFromVkFrontFace(_rasterInfo.frontFace); - _mtlFillMode = mvkMTLTriangleFillModeFromVkPolygonMode(_rasterInfo.polygonMode); - if (_rasterInfo.depthClampEnable) { - if (_device->_enabledFeatures.depthClamp) { - _mtlDepthClipMode = MTLDepthClipModeClamp; - } else { - setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "This device does not support depth clamping.")); - } + _hasRasterInfo = mvkSetOrClear(&_rasterInfo, pCreateInfo->pRasterizationState); + if (_hasRasterInfo) { + if (_rasterInfo.depthClampEnable && !_device->_enabledFeatures.depthClamp) { + setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "This device does not support depth clamping.")); } } @@ -557,26 +526,76 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, // Viewports and scissors - must ignore allowed bad pViewportState pointer if rasterization is disabled auto pVPState = _isRasterizing ? pCreateInfo->pViewportState : nullptr; if (pVPState) { - uint32_t vpCnt = pVPState->viewportCount; + + // If viewports are dynamic, ignore them here. + uint32_t vpCnt = (pVPState->pViewports && !isDynamicState(Viewports)) ? pVPState->viewportCount : 0; _viewports.reserve(vpCnt); for (uint32_t vpIdx = 0; vpIdx < vpCnt; vpIdx++) { - // If viewport is dyanamic, we still add a dummy so that the count will be tracked. - VkViewport vp; - if ( !supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT) ) { vp = pVPState->pViewports[vpIdx]; } - _viewports.push_back(vp); + _viewports.push_back(pVPState->pViewports[vpIdx]); } - uint32_t sCnt = pVPState->scissorCount; + // If scissors are dynamic, ignore them here. + uint32_t sCnt = (pVPState->pScissors && !isDynamicState(Scissors)) ? pVPState->scissorCount : 0; _scissors.reserve(sCnt); for (uint32_t sIdx = 0; sIdx < sCnt; sIdx++) { - // If scissor is dyanamic, we still add a dummy so that the count will be tracked. - VkRect2D sc; - if ( !supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR) ) { sc = pVPState->pScissors[sIdx]; } - _scissors.push_back(sc); + _scissors.push_back(pVPState->pScissors[sIdx]); } } } +static MVKRenderStateType getRenderStateType(VkDynamicState vkDynamicState) { + switch (vkDynamicState) { + case VK_DYNAMIC_STATE_BLEND_CONSTANTS: return BlendConstants; + case VK_DYNAMIC_STATE_CULL_MODE: return CullMode; + case VK_DYNAMIC_STATE_DEPTH_BIAS: return DepthBias; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS: return DepthBounds; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE: return DepthBoundsTestEnable; + case VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT: return DepthClipEnable; + case VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT: return DepthClipEnable; + case VK_DYNAMIC_STATE_DEPTH_COMPARE_OP: return DepthCompareOp; + case VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE: return DepthTestEnable; + case VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE: return DepthWriteEnable; + case VK_DYNAMIC_STATE_FRONT_FACE: return FrontFace; + case VK_DYNAMIC_STATE_POLYGON_MODE_EXT: return PolygonMode; + case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY: return PrimitiveTopology; + case VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT: return SampleLocations; + case VK_DYNAMIC_STATE_SCISSOR: return Scissors; + case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT: return Scissors; + case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: return StencilCompareMask; + case VK_DYNAMIC_STATE_STENCIL_OP: return StencilOp; + case VK_DYNAMIC_STATE_STENCIL_REFERENCE: return StencilReference; + case VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE: return StencilTestEnable; + case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: return StencilWriteMask; + case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE: return VertexStride; + case VK_DYNAMIC_STATE_VIEWPORT: return Viewports; + case VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT: return Viewports; + default: return Unknown; + } +} + +// This is executed first during pipeline creation. Do not depend on any internal state here. +void MVKGraphicsPipeline::initDynamicState(const VkGraphicsPipelineCreateInfo* pCreateInfo) { + const auto* pDS = pCreateInfo->pDynamicState; + if ( !pDS ) { return; } + + for (uint32_t i = 0; i < pDS->dynamicStateCount; i++) { + VkDynamicState vkDynState = pDS->pDynamicStates[i]; + bool isDynamic = true; + + // Some dynamic states have other restrictions + switch (vkDynState) { + case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE: + isDynamic = _device->_pMetalFeatures->dynamicVertexStride; + if ( !isDynamic ) { setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "This device and platform does not support VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE (macOS 14.0 or iOS/tvOS 17.0, plus either Apple4 or Mac2 GPU).")); } + break; + default: + break; + } + + if (isDynamic) { _dynamicState.enable(getRenderStateType(vkDynState)); } + } +} + // Either returns an existing pipeline state or compiles a new one. id MVKGraphicsPipeline::getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id& plState) { @@ -613,7 +632,7 @@ void MVKGraphicsPipeline::initCustomSamplePositions(const VkGraphicsPipelineCrea case VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT: { auto* pSampLocnsCreateInfo = (VkPipelineSampleLocationsStateCreateInfoEXT*)next; _isUsingCustomSamplePositions = pSampLocnsCreateInfo->sampleLocationsEnable; - if (_isUsingCustomSamplePositions && !supportsDynamicState(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT)) { + if (_isUsingCustomSamplePositions && !isDynamicState(SampleLocations)) { for (uint32_t slIdx = 0; slIdx < pSampLocnsCreateInfo->sampleLocationsInfo.sampleLocationsCount; slIdx++) { auto& sl = pSampLocnsCreateInfo->sampleLocationsInfo.pSampleLocations[slIdx]; _customSamplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y)); @@ -1328,8 +1347,9 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc, } // Vertex buffer bindings - uint32_t vbCnt = pVI->vertexBindingDescriptionCount; + bool isVtxStrideStatic = !isDynamicState(VertexStride); uint32_t maxBinding = 0; + uint32_t vbCnt = pVI->vertexBindingDescriptionCount; for (uint32_t i = 0; i < vbCnt; i++) { const VkVertexInputBindingDescription* pVKVB = &pVI->pVertexBindingDescriptions[i]; if (shaderConfig.isVertexBufferUsed(pVKVB->binding)) { @@ -1352,7 +1372,7 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc, vbDesc.stepFunction = (decltype(vbDesc.stepFunction))MTLStepFunctionConstant; vbDesc.stepRate = 0; } else { - vbDesc.stride = pVKVB->stride; + vbDesc.stride = isVtxStrideStatic ? pVKVB->stride : MTLBufferLayoutStrideDynamic; vbDesc.stepFunction = (decltype(vbDesc.stepFunction))mvkMTLStepFunctionFromVkVertexInputRate(pVKVB->inputRate, isTessellationPipeline()); vbDesc.stepRate = 1; } @@ -1903,11 +1923,12 @@ bool MVKGraphicsPipeline::isRenderingPoints(const VkGraphicsPipelineCreateInfo* (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->polygonMode == VK_POLYGON_MODE_POINT))); } -// We disable rasterization if either rasterizerDiscard is enabled or the cull mode dictates it. +// We disable rasterization if either rasterizerDiscard is enabled or the static cull mode dictates it. bool MVKGraphicsPipeline::isRasterizationDisabled(const VkGraphicsPipelineCreateInfo* pCreateInfo) { return (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable || - ((pCreateInfo->pRasterizationState->cullMode == VK_CULL_MODE_FRONT_AND_BACK) && pCreateInfo->pInputAssemblyState && + ((pCreateInfo->pRasterizationState->cullMode == VK_CULL_MODE_FRONT_AND_BACK) && !isDynamicState(CullMode) && + pCreateInfo->pInputAssemblyState && (mvkMTLPrimitiveTopologyClassFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology) == MTLPrimitiveTopologyClassTriangle)))); } diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index d26b53a4..8503b917 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -60,6 +60,9 @@ typedef struct { #pragma mark - #pragma mark Vulkan support +/** A generic 32-bit color permitting float, int32, or uint32 values. */ +typedef VkClearColorValue MVKColor32; + /** Tracks the Vulkan command currently being used. */ typedef enum : uint8_t { kMVKCommandUseNone = 0, /**< No use defined. */ @@ -142,7 +145,7 @@ static inline std::string mvkGetMoltenVKVersionString(uint32_t mvkVersion) { /** Returns whether the specified positive value is a power-of-two. */ template static constexpr bool mvkIsPowerOfTwo(T value) { - return value && ((value & (value - 1)) == 0); + return value > 0 && ((value & (value - 1)) == 0); } /** @@ -278,21 +281,21 @@ void mvkFlipVertically(void* rowMajorData, uint32_t rowCount, size_t bytesPerRow * They are ridiculously large numbers, but low enough to be safely used as both * uint and int values without risking overflowing between positive and negative values. */ -static int32_t kMVKUndefinedLargePositiveInt32 = mvkEnsurePowerOfTwo(std::numeric_limits::max() / 2); -static int32_t kMVKUndefinedLargeNegativeInt32 = -kMVKUndefinedLargePositiveInt32; -static uint32_t kMVKUndefinedLargeUInt32 = kMVKUndefinedLargePositiveInt32; -static int64_t kMVKUndefinedLargePositiveInt64 = mvkEnsurePowerOfTwo(std::numeric_limits::max() / 2); -static int64_t kMVKUndefinedLargeNegativeInt64 = -kMVKUndefinedLargePositiveInt64; -static uint64_t kMVKUndefinedLargeUInt64 = kMVKUndefinedLargePositiveInt64; +static constexpr int32_t kMVKUndefinedLargePositiveInt32 = mvkEnsurePowerOfTwo(std::numeric_limits::max() / 2); +static constexpr int32_t kMVKUndefinedLargeNegativeInt32 = -kMVKUndefinedLargePositiveInt32; +static constexpr uint32_t kMVKUndefinedLargeUInt32 = kMVKUndefinedLargePositiveInt32; +static constexpr int64_t kMVKUndefinedLargePositiveInt64 = mvkEnsurePowerOfTwo(std::numeric_limits::max() / 2); +static constexpr int64_t kMVKUndefinedLargeNegativeInt64 = -kMVKUndefinedLargePositiveInt64; +static constexpr uint64_t kMVKUndefinedLargeUInt64 = kMVKUndefinedLargePositiveInt64; #pragma mark Vulkan structure support functions /** Returns a VkExtent2D created from the width and height of a VkExtent3D. */ -static inline VkExtent2D mvkVkExtent2DFromVkExtent3D(VkExtent3D e) { return {e.width, e.height }; } +static constexpr VkExtent2D mvkVkExtent2DFromVkExtent3D(VkExtent3D e) { return {e.width, e.height }; } /** Returns a VkExtent3D, created from a VkExtent2D, and with depth of 1. */ -static inline VkExtent3D mvkVkExtent3DFromVkExtent2D(VkExtent2D e) { return {e.width, e.height, 1U }; } +static constexpr VkExtent3D mvkVkExtent3DFromVkExtent2D(VkExtent2D e) { return {e.width, e.height, 1U }; } /** Returns whether the two Vulkan extents are equal by comparing their respective components. */ static constexpr bool mvkVkExtent2DsAreEqual(VkExtent2D e1, VkExtent2D e2) { @@ -333,13 +336,13 @@ static constexpr uint32_t mvkPackSwizzle(VkComponentMapping components) { } /** Unpacks a single 32-bit word containing four swizzle components. */ -static inline VkComponentMapping mvkUnpackSwizzle(uint32_t packed) { - VkComponentMapping components; - components.r = (VkComponentSwizzle)((packed >> 0) & 0xFF); - components.g = (VkComponentSwizzle)((packed >> 8) & 0xFF); - components.b = (VkComponentSwizzle)((packed >> 16) & 0xFF); - components.a = (VkComponentSwizzle)((packed >> 24) & 0xFF); - return components; +static constexpr VkComponentMapping mvkUnpackSwizzle(uint32_t packed) { + return { + .r = (VkComponentSwizzle)((packed >> 0) & 0xFF), + .g = (VkComponentSwizzle)((packed >> 8) & 0xFF), + .b = (VkComponentSwizzle)((packed >> 16) & 0xFF), + .a = (VkComponentSwizzle)((packed >> 24) & 0xFF), + }; } /** @@ -353,8 +356,8 @@ static inline VkComponentMapping mvkUnpackSwizzle(uint32_t packed) { * and matches any value. */ static constexpr bool mvkVKComponentSwizzlesMatch(VkComponentSwizzle cs1, - VkComponentSwizzle cs2, - VkComponentSwizzle csPos) { + VkComponentSwizzle cs2, + VkComponentSwizzle csPos) { return ((cs1 == cs2) || ((cs1 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs2 == csPos)) || ((cs2 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs1 == csPos)) || @@ -383,25 +386,25 @@ static constexpr bool mvkVkComponentMappingsMatch(VkComponentMapping cm1, VkComp #pragma mark Math /** Rounds the value to nearest integer using half-to-even rounding. */ -static inline double mvkRoundHalfToEven(const double val) { +static constexpr double mvkRoundHalfToEven(const double val) { return val - std::remainder(val, 1.0); // remainder() uses half-to-even rounding, and unfortunately isn't constexpr until C++23. } /** Returns whether the value will fit inside the numeric type. */ template -const bool mvkFits(const Tval& val) { +static constexpr const bool mvkFits(const Tval& val) { return val <= std::numeric_limits::max(); } /** Clamps the value between the lower and upper bounds, inclusive. */ template -const T& mvkClamp(const T& val, const T& lower, const T& upper) { +static constexpr const T& mvkClamp(const T& val, const T& lower, const T& upper) { return std::min(std::max(val, lower), upper); } /** Returns the result of a division, rounded up. */ template -constexpr typename std::common_type::type mvkCeilingDivide(T numerator, U denominator) { +static constexpr typename std::common_type::type mvkCeilingDivide(T numerator, U denominator) { typedef typename std::common_type::type R; // Short circuit very common usecase of dividing by one. return (denominator == 1) ? numerator : (R(numerator) + denominator - 1) / denominator; @@ -427,18 +430,18 @@ struct MVKAbs { /** Returns the absolute value of the difference of two numbers. */ template -constexpr typename std::common_type::type mvkAbsDiff(T x, U y) { +static constexpr typename std::common_type::type mvkAbsDiff(T x, U y) { return x >= y ? x - y : y - x; } /** Returns the greatest common divisor of two numbers. */ template -constexpr T mvkGreatestCommonDivisorImpl(T a, T b) { +static constexpr T mvkGreatestCommonDivisorImpl(T a, T b) { return b == 0 ? a : mvkGreatestCommonDivisorImpl(b, a % b); } template -constexpr typename std::common_type::type mvkGreatestCommonDivisor(T a, U b) { +static constexpr typename std::common_type::type mvkGreatestCommonDivisor(T a, U b) { typedef typename std::common_type::type R; typedef typename std::make_unsigned::type UI; return static_cast(mvkGreatestCommonDivisorImpl(static_cast(MVKAbs::eval(a)), static_cast(MVKAbs::eval(b)))); @@ -446,7 +449,7 @@ constexpr typename std::common_type::type mvkGreatestCommonDivisor(T a, U /** Returns the least common multiple of two numbers. */ template -constexpr typename std::common_type::type mvkLeastCommonMultiple(T a, U b) { +static constexpr typename std::common_type::type mvkLeastCommonMultiple(T a, U b) { typedef typename std::common_type::type R; return (a == 0 && b == 0) ? 0 : MVKAbs::eval(a) / mvkGreatestCommonDivisor(a, b) * MVKAbs::eval(b); } @@ -463,7 +466,7 @@ constexpr typename std::common_type::type mvkLeastCommonMultiple(T a, U b) * value returned by previous calls as the seed in subsequent calls. */ template -std::size_t mvkHash(const N* pVals, std::size_t count = 1, std::size_t seed = 5381) { +static constexpr std::size_t mvkHash(const N* pVals, std::size_t count = 1, std::size_t seed = 5381) { std::size_t hash = seed; for (std::size_t i = 0; i < count; i++) { hash = ((hash << 5) + hash) ^ pVals[i]; } return hash; @@ -497,7 +500,7 @@ protected: /** Ensures the size of the specified container is at least the specified size. */ template -void mvkEnsureSize(C& container, S size) { +static void mvkEnsureSize(C& container, S size) { if (size > container.size()) { container.resize(size); } } @@ -506,7 +509,7 @@ void mvkEnsureSize(C& container, S size) { * each object, including freeing the object memory, and clearing the container. */ template -void mvkDestroyContainerContents(C& container) { +static void mvkDestroyContainerContents(C& container) { for (auto elem : container) { elem->destroy(); } container.clear(); } @@ -517,7 +520,7 @@ void mvkDestroyContainerContents(C& container) { */ #ifdef __OBJC__ template -void mvkReleaseContainerContents(C& container) { +static void mvkReleaseContainerContents(C& container) { for (auto elem : container) { [elem release]; } container.clear(); } @@ -525,14 +528,14 @@ void mvkReleaseContainerContents(C& container) { /** Returns whether the container contains an item equal to the value. */ template -bool mvkContains(C& container, const T& val) { +static constexpr bool mvkContains(C& container, const T& val) { for (const T& cVal : container) { if (cVal == val) { return true; } } return false; } /** Removes the first occurance of the specified value from the specified container. */ template -void mvkRemoveFirstOccurance(C& container, T val) { +static void mvkRemoveFirstOccurance(C& container, T val) { for (auto iter = container.begin(), end = container.end(); iter != end; iter++) { if( *iter == val ) { container.erase(iter); @@ -543,7 +546,7 @@ void mvkRemoveFirstOccurance(C& container, T val) { /** Removes all occurances of the specified value from the specified container. */ template -void mvkRemoveAllOccurances(C& container, T val) { +static void mvkRemoveAllOccurances(C& container, T val) { container.erase(std::remove(container.begin(), container.end(), val), container.end()); } @@ -552,7 +555,7 @@ void mvkRemoveAllOccurances(C& container, T val) { /** Selects and returns one of the values, based on the platform OS. */ template -const T& mvkSelectPlatformValue(const T& macOSVal, const T& iOSVal) { +static constexpr const T& mvkSelectPlatformValue(const T& macOSVal, const T& iOSVal) { #if MVK_IOS_OR_TVOS return iOSVal; #endif @@ -566,22 +569,29 @@ const T& mvkSelectPlatformValue(const T& macOSVal, const T& iOSVal) { * The optional count allows clearing multiple elements in an array. */ template -void mvkClear(T* pVal, size_t count = 1) { if (pVal) { memset(pVal, 0, sizeof(T) * count); } } +static void mvkClear(T* pDst, size_t count = 1) { + if ( !pDst ) { return; } // Bad pointer + if constexpr(std::is_arithmetic_v) { if (count == 1) { *pDst = static_cast(0); } } // Fast clear of a single primitive + memset(pDst, 0, sizeof(T) * count); // Memory clear of complex content or array +} /** * If pVal is not null, overrides the const declaration, and clears the memory occupied by *pVal * by writing zeros to all bytes. The optional count allows clearing multiple elements in an array. */ template -void mvkClear(const T* pVal, size_t count = 1) { mvkClear((T*)pVal, count); } +static void mvkClear(const T* pVal, size_t count = 1) { mvkClear((T*)pVal, count); } /** * If pSrc and pDst are both not null, copies the contents of the source value to the * destination value. The optional count allows copying of multiple elements in an array. */ template -void mvkCopy(T* pDst, const T* pSrc, size_t count = 1) { - if (pSrc && pDst) { memcpy(pDst, pSrc, sizeof(T) * count); } +static void mvkCopy(T* pDst, const T* pSrc, size_t count = 1) { + if ( !pDst || !pSrc ) { return; } // Bad pointers + if (pDst == pSrc) { return; } // Same object + if constexpr(std::is_arithmetic_v) { if (count == 1) { *pDst = *pSrc; } } // Fast copy of a single primitive + memcpy(pDst, pSrc, sizeof(T) * count); // Memory copy of complex content or array } /** @@ -589,8 +599,11 @@ void mvkCopy(T* pDst, const T* pSrc, size_t count = 1) { * otherwise returns false. The optional count allows comparing multiple elements in an array. */ template -bool mvkAreEqual(const T* pV1, const T* pV2, size_t count = 1) { - return (pV1 && pV2) ? (memcmp(pV1, pV2, sizeof(T) * count) == 0) : false; +static constexpr bool mvkAreEqual(const T* pV1, const T* pV2, size_t count = 1) { + if ( !pV2 || !pV2 ) { return false; } // Bad pointers + if (pV1 == pV2) { return true; } // Same object + if constexpr(std::is_arithmetic_v) { if (count == 1) { return *pV1 == *pV2; } } // Fast compare of a single primitive + return memcmp(pV1, pV2, sizeof(T) * count) == 0; // Memory compare of complex content or array } /** @@ -632,10 +645,18 @@ static constexpr bool mvkSetOrClear(T* pDest, const T* pSrc) { template void mvkEnableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value | bitMask); } +/** Enables all the flags (sets bits to 1) within the value parameter. */ +template +void mvkEnableAllFlags(Tv& value) { value = ~static_cast(0); } + /** Disables the flags (sets bits to 0) within the value parameter specified by the bitMask parameter. */ template void mvkDisableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value & ~(Tv)bitMask); } +/** Enables all the flags (sets bits to 1) within the value parameter. */ +template +void mvkDisableAllFlags(Tv& value) { value = static_cast(0); } + /** Returns whether the specified value has ANY of the flags specified in bitMask enabled (set to 1). */ template static constexpr bool mvkIsAnyFlagEnabled(Tv value, const Tm bitMask) { return ((value & bitMask) != 0); } diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index 90cb72e0..ef3cf1ca 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -583,24 +583,33 @@ MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkRe } #endif -MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport) { - MTLViewport mtlViewport; - mtlViewport.originX = vkViewport.x; - mtlViewport.originY = vkViewport.y; - mtlViewport.width = vkViewport.width; - mtlViewport.height = vkViewport.height; - mtlViewport.znear = vkViewport.minDepth; - mtlViewport.zfar = vkViewport.maxDepth; - return mtlViewport; +MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(const VkViewport vkViewport) { + return { + .originX = vkViewport.x, + .originY = vkViewport.y, + .width = vkViewport.width, + .height = vkViewport.height, + .znear = vkViewport.minDepth, + .zfar = vkViewport.maxDepth + }; } -MVK_PUBLIC_SYMBOL MTLScissorRect mvkMTLScissorRectFromVkRect2D(VkRect2D vkRect) { - MTLScissorRect mtlScissor; - mtlScissor.x = vkRect.offset.x; - mtlScissor.y = vkRect.offset.y; - mtlScissor.width = vkRect.extent.width; - mtlScissor.height = vkRect.extent.height; - return mtlScissor; +MVK_PUBLIC_SYMBOL MTLScissorRect mvkMTLScissorRectFromVkRect2D(const VkRect2D vkRect) { + return { + .x = (NSUInteger)max(vkRect.offset.x, 0), + .y = (NSUInteger)max(vkRect.offset.y, 0), + .width = vkRect.extent.width, + .height = vkRect.extent.height + }; +} + +MVK_PUBLIC_SYMBOL VkRect2D mvkVkRect2DFromMTLScissorRect(const MTLScissorRect mtlScissorRect) { + return { + .offset = { .x = (int32_t)mtlScissorRect.x, + .y = (int32_t)mtlScissorRect.y }, + .extent = { .width = (uint32_t)mtlScissorRect.width, + .height = (uint32_t)mtlScissorRect.height } + }; } MVK_PUBLIC_SYMBOL MTLCompareFunction mvkMTLCompareFunctionFromVkCompareOp(VkCompareOp vkOp) { diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 74819d84..cd6d15bf 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -1564,13 +1564,14 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindIndexBuffer( MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindVertexBuffers( VkCommandBuffer commandBuffer, - uint32_t startBinding, + uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) { MVKTraceVulkanCallStart(); - MVKAddCmdFrom2Thresholds(BindVertexBuffers, bindingCount, 1, 2, commandBuffer, startBinding, bindingCount, pBuffers, pOffsets); + MVKAddCmdFrom2Thresholds(BindVertexBuffers, bindingCount, 1, 2, commandBuffer, + firstBinding, bindingCount, pBuffers, pOffsets, nullptr, nullptr); MVKTraceVulkanCallEnd(); } @@ -2536,7 +2537,8 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindVertexBuffers2( const VkDeviceSize* pStrides) { MVKTraceVulkanCallStart(); - + MVKAddCmdFrom2Thresholds(BindVertexBuffers, bindingCount, 1, 2, commandBuffer, + firstBinding, bindingCount, pBuffers, pOffsets, pSizes, pStrides); MVKTraceVulkanCallEnd(); } @@ -2643,7 +2645,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthBoundsTestEnable( VkBool32 depthBoundsTestEnable) { MVKTraceVulkanCallStart(); - + MVKAddCmd(SetDepthBoundsTestEnable, commandBuffer, depthBoundsTestEnable); MVKTraceVulkanCallEnd(); } @@ -2652,7 +2654,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthCompareOp( VkCompareOp depthCompareOp) { MVKTraceVulkanCallStart(); - + MVKAddCmd(SetDepthCompareOp, commandBuffer, depthCompareOp); MVKTraceVulkanCallEnd(); } @@ -2661,7 +2663,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthTestEnable( VkBool32 depthTestEnable) { MVKTraceVulkanCallStart(); - + MVKAddCmd(SetDepthTestEnable, commandBuffer, depthTestEnable); MVKTraceVulkanCallEnd(); } @@ -2670,6 +2672,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthWriteEnable( VkBool32 depthWriteEnable) { MVKTraceVulkanCallStart(); + MVKAddCmd(SetDepthWriteEnable, commandBuffer, depthWriteEnable); MVKTraceVulkanCallEnd(); } @@ -2699,6 +2702,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPrimitiveTopology( VkPrimitiveTopology primitiveTopology) { MVKTraceVulkanCallStart(); + MVKAddCmd(SetPrimitiveTopology, commandBuffer, primitiveTopology); MVKTraceVulkanCallEnd(); } @@ -2723,6 +2727,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetStencilOp( VkCompareOp compareOp) { MVKTraceVulkanCallStart(); + MVKAddCmd(SetStencilOp, commandBuffer, faceMask, failOp, passOp, depthFailOp, compareOp); MVKTraceVulkanCallEnd(); } @@ -2731,6 +2736,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetStencilTestEnable( VkBool32 stencilTestEnable) { MVKTraceVulkanCallStart(); + MVKAddCmd(SetStencilTestEnable, commandBuffer, stencilTestEnable); MVKTraceVulkanCallEnd(); }