From 259039ed2c9d692a2222452d29b935a17f04e93c Mon Sep 17 00:00:00 2001 From: spnda Date: Tue, 24 May 2022 15:36:11 +0200 Subject: [PATCH 1/5] Add: Support for VK_EXT_extended_dynamic_state --- Docs/Whats_New.md | 1 + MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h | 44 +++++++ .../MoltenVK/Commands/MVKCmdRenderPass.mm | 48 +++++++ .../MoltenVK/Commands/MVKCommandTypePools.def | 2 + MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Vulkan/vulkan.mm | 117 ++++++++++++++++++ 6 files changed, 213 insertions(+) diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 5c05fbd8..2131f429 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -25,6 +25,7 @@ Released TBD - `VK_KHR_dynamic_rendering` - `VK_KHR_separate_depth_stencil_layouts` - `VK_EXT_separate_stencil_usage` + - `VK_EXT_extended_dynamic_state` - Support attachment clearing when some clearing formats are not specified. - Fix error where previously bound push constants can override a descriptor buffer binding used by a subsequent pipeline that does not use push constants. diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h index 9b3c14d0..8af34247 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h @@ -442,3 +442,47 @@ protected: uint32_t _stencilReference; }; + +#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. + */ +class MVKCmdSetCullMode : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkCullModeFlags cullMode); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + MTLCullMode _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. + */ +class MVKCmdSetFrontFace : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkFrontFace frontFace); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + MTLWinding _frontFace; +}; + diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm index 967c905a..82445e1a 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm @@ -439,3 +439,51 @@ void MVKCmdSetStencilReference::encode(MVKCommandEncoder* cmdEncoder) { cmdEncoder->_stencilReferenceValueState.setReferenceValues(_faceMask, _stencilReference); } + +#pragma mark - +#pragma mark MVKCmdSetCullMode + +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; +} + +void MVKCmdSetCullMode::encode(MVKCommandEncoder* cmdEncoder) { + [((id)cmdEncoder->getMTLEncoder()) setCullMode:_cullMode]; +} + + +#pragma mark - +#pragma mark MVKCmdSetFrontFace + +VkResult MVKCmdSetFrontFace::setContent(MVKCommandBuffer* cmdBuff, + VkFrontFace frontFace) { + _frontFace = frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE + ? MTLWindingClockwise + : MTLWindingCounterClockwise; + + return VK_SUCCESS; +} + +void MVKCmdSetFrontFace::encode(MVKCommandEncoder* cmdEncoder) { + [((id)cmdEncoder->getMTLEncoder()) setFrontFacingWinding:_frontFace]; +} + diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def index e8cbae6e..a17e57f4 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def +++ b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def @@ -93,6 +93,8 @@ MVK_CMD_TYPE_POOL(SetDepthBounds) 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_POOLS_FROM_2_THRESHOLDS(BindVertexBuffers, 1, 2) MVK_CMD_TYPE_POOL(BindIndexBuffer) MVK_CMD_TYPE_POOL(Draw) diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 019b23b4..32cb393d 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -87,6 +87,7 @@ MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE, 10.11, 8.0) MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0) MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_extended_dynamic_state, EXT_extended_dynamic_state, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0) MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA) MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index c291e892..4231a525 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -2985,6 +2985,123 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkSubmitDebugUtilsMessageEXT( } +#pragma mark - +#pragma mark VK_EXT_extended_dynamic_state + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindVertexBuffers2EXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides) { + + MVKTraceVulkanCallStart(); + + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetCullModeEXT( + VkCommandBuffer commandBuffer, + VkCullModeFlags cullMode) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetCullMode, commandBuffer, cullMode); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthBoundsTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthBoundsTestEnable) { + + MVKTraceVulkanCallStart(); + + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthCompareOpEXT( + VkCommandBuffer commandBuffer, + VkCompareOp depthCompareOp) { + + MVKTraceVulkanCallStart(); + + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthTestEnable) { + + MVKTraceVulkanCallStart(); + + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthWriteEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthWriteEnable) { + + MVKTraceVulkanCallStart(); + + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetFrontFaceEXT( + VkCommandBuffer commandBuffer, + VkFrontFace frontFace) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetFrontFace, commandBuffer, frontFace); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPrimitiveTopologyEXT( + VkCommandBuffer commandBuffer, + VkPrimitiveTopology primitiveTopology) { + + MVKTraceVulkanCallStart(); + + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetScissorWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t scissorCount, + const VkRect2D* pScissors) { + + MVKTraceVulkanCallStart(); + MVKAddCmdFromThreshold(SetScissor, scissorCount, 1, commandBuffer, 0, scissorCount, pScissors); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetStencilOpEXT( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp) { + +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetStencilTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 stencilTestEnable) { + +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetViewportWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t viewportCount, + const VkViewport* pViewports) { + + MVKTraceVulkanCallStart(); + MVKAddCmdFromThreshold(SetViewport, viewportCount, 1, commandBuffer, 0, viewportCount, pViewports); + MVKTraceVulkanCallEnd(); +} + + #pragma mark - #pragma mark VK_EXT_hdr_metadata extension From 3c75e114dd04636628cc212e947e420ed5415fca Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 5 Oct 2023 17:33:01 -0400 Subject: [PATCH 2/5] 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(); } From f4423428e3b0d1034130451d666ebdf7d63dbaff Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 10 Oct 2023 12:19:15 -0400 Subject: [PATCH 3/5] Add support for VK_EXT_extended_dynamic_state2 extension. - Add MVKPipelineCommandEncoderState subclasses MVKGraphicsPipelineCommandEncoderState & MVKComputePipelineCommandEncoderState, track patch control points in MVKGraphicsPipelineCommandEncoderState, and add getGraphicsPipeline() & getComputePipeline() to simplify casting. - Rename MVKRasterizingCommandEncoderState to MVKRenderingCommandEncoderState, and MVKCommandEncoder::_rasterizingState to _renderingState. - Rename MVKCmdRenderPass.h/mm to MVKCmdRendering.h/mm. - Move MVKCmdExecuteCommands from MVKCmdRenderPass.h/mm to MVKCmdPipeline.h/mm. - While working on vkCmdSetLogicOpEXT(), add support for vkCmdSetLogicOpEnableEXT() from VK_EXT_extended_dynamic_state3. --- Docs/MoltenVK_Runtime_UserGuide.md | 3 +- Docs/Whats_New.md | 3 +- MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 40 ++--- MoltenVK/MoltenVK/Commands/MVKCmdDispatch.mm | 2 +- MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm | 28 ++-- MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h | 28 ++++ MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm | 27 ++++ .../{MVKCmdRenderPass.h => MVKCmdRendering.h} | 138 +++++++++++++---- ...MVKCmdRenderPass.mm => MVKCmdRendering.mm} | 140 +++++++++++++----- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 2 +- MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h | 8 +- .../MoltenVK/Commands/MVKCommandBuffer.mm | 10 +- .../Commands/MVKCommandEncoderState.h | 58 ++++++-- .../Commands/MVKCommandEncoderState.mm | 79 ++++++---- MoltenVK/MoltenVK/Commands/MVKCommandPool.h | 2 +- .../MoltenVK/Commands/MVKCommandTypePools.def | 8 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 7 + .../GPUObjects/MVKDeviceFeatureStructs.def | 1 + MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 3 + MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h | 12 +- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 54 ++++--- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Vulkan/vulkan.mm | 67 ++++++++- 23 files changed, 541 insertions(+), 180 deletions(-) rename MoltenVK/MoltenVK/Commands/{MVKCmdRenderPass.h => MVKCmdRendering.h} (86%) rename MoltenVK/MoltenVK/Commands/{MVKCmdRenderPass.mm => MVKCmdRendering.mm} (82%) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 27ed0c2e..79f3f1a5 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -363,7 +363,8 @@ 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_extended_dynamic_state` *(requires Metal 3.1 for `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`)* +- `VK_EXT_extended_dynamic_state2` - `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/Docs/Whats_New.md b/Docs/Whats_New.md index 6da6eb0c..6ab13f7a 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -20,7 +20,8 @@ Released TBD - Add support for extensions: - `VK_KHR_synchronization2` - - `VK_EXT_extended_dynamic_state` + - `VK_EXT_extended_dynamic_state` *(requires Metal 3.1 for `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`)* + - `VK_EXT_extended_dynamic_state2` - Fix rare case where vertex attribute buffers are not bound to Metal when no other bindings change between pipelines. - Ensure objects retained for life of `MTLCommandBuffer` during `vkCmdBlitImage()` & `vkQueuePresentKHR()`. diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index 1dffab36..46ff50fc 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -46,7 +46,7 @@ 2FEA0A6724902F9F00EEF3AD /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */; }; 2FEA0A6824902F9F00EEF3AD /* MVKWatermark.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149491FB6A3F7005F00B4 /* MVKWatermark.h */; }; 2FEA0A6924902F9F00EEF3AD /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; }; - 2FEA0A6A24902F9F00EEF3AD /* MVKCmdRenderPass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRenderPass.h */; }; + 2FEA0A6A24902F9F00EEF3AD /* MVKCmdRendering.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRendering.h */; }; 2FEA0A6B24902F9F00EEF3AD /* MVKCmdPipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB76E1C7DFB4800632CA3 /* MVKCmdPipeline.h */; }; 2FEA0A6C24902F9F00EEF3AD /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; }; 2FEA0A6D24902F9F00EEF3AD /* MVKPipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB78D1C7DFB4800632CA3 /* MVKPipeline.h */; }; @@ -90,7 +90,7 @@ 2FEA0A9424902F9F00EEF3AD /* MVKCommandPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB77B1C7DFB4800632CA3 /* MVKCommandPool.mm */; }; 2FEA0A9524902F9F00EEF3AD /* MVKCmdDraw.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7751C7DFB4800632CA3 /* MVKCmdDraw.mm */; }; 2FEA0A9624902F9F00EEF3AD /* MVKCommandBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7791C7DFB4800632CA3 /* MVKCommandBuffer.mm */; }; - 2FEA0A9724902F9F00EEF3AD /* MVKCmdRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRenderPass.mm */; }; + 2FEA0A9724902F9F00EEF3AD /* MVKCmdRendering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRendering.mm */; }; 2FEA0A9824902F9F00EEF3AD /* MVKBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7801C7DFB4800632CA3 /* MVKBuffer.mm */; }; 2FEA0A9924902F9F00EEF3AD /* mvk_datatypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A91C7DFB4800632CA3 /* mvk_datatypes.mm */; }; 2FEA0A9A24902F9F00EEF3AD /* MVKExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A909F65E213B190700FCD6BE /* MVKExtensions.mm */; }; @@ -172,10 +172,10 @@ A94FB7C11C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7701C7DFB4800632CA3 /* MVKCmdQueries.h */; }; A94FB7C21C7DFB4800632CA3 /* MVKCmdQueries.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7711C7DFB4800632CA3 /* MVKCmdQueries.mm */; }; A94FB7C31C7DFB4800632CA3 /* MVKCmdQueries.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7711C7DFB4800632CA3 /* MVKCmdQueries.mm */; }; - A94FB7C41C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRenderPass.h */; }; - A94FB7C51C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRenderPass.h */; }; - A94FB7C61C7DFB4800632CA3 /* MVKCmdRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRenderPass.mm */; }; - A94FB7C71C7DFB4800632CA3 /* MVKCmdRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRenderPass.mm */; }; + A94FB7C41C7DFB4800632CA3 /* MVKCmdRendering.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRendering.h */; }; + A94FB7C51C7DFB4800632CA3 /* MVKCmdRendering.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRendering.h */; }; + A94FB7C61C7DFB4800632CA3 /* MVKCmdRendering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRendering.mm */; }; + A94FB7C71C7DFB4800632CA3 /* MVKCmdRendering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRendering.mm */; }; A94FB7C81C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7741C7DFB4800632CA3 /* MVKCmdDraw.h */; }; A94FB7C91C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7741C7DFB4800632CA3 /* MVKCmdDraw.h */; }; A94FB7CA1C7DFB4800632CA3 /* MVKCmdDraw.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7751C7DFB4800632CA3 /* MVKCmdDraw.mm */; }; @@ -420,7 +420,7 @@ DCFD7F0B2A45BC6E007BBBF7 /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */; }; DCFD7F0C2A45BC6E007BBBF7 /* MVKWatermark.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149491FB6A3F7005F00B4 /* MVKWatermark.h */; }; DCFD7F0D2A45BC6E007BBBF7 /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; }; - DCFD7F0E2A45BC6E007BBBF7 /* MVKCmdRenderPass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRenderPass.h */; }; + DCFD7F0E2A45BC6E007BBBF7 /* MVKCmdRendering.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB7721C7DFB4800632CA3 /* MVKCmdRendering.h */; }; DCFD7F0F2A45BC6E007BBBF7 /* MVKCmdPipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB76E1C7DFB4800632CA3 /* MVKCmdPipeline.h */; }; DCFD7F102A45BC6E007BBBF7 /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; }; DCFD7F112A45BC6E007BBBF7 /* MVKPipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = A94FB78D1C7DFB4800632CA3 /* MVKPipeline.h */; }; @@ -466,7 +466,7 @@ DCFD7F3A2A45BC6E007BBBF7 /* MVKCommandPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB77B1C7DFB4800632CA3 /* MVKCommandPool.mm */; }; DCFD7F3B2A45BC6E007BBBF7 /* MVKCmdDraw.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7751C7DFB4800632CA3 /* MVKCmdDraw.mm */; }; DCFD7F3C2A45BC6E007BBBF7 /* MVKCommandBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7791C7DFB4800632CA3 /* MVKCommandBuffer.mm */; }; - DCFD7F3D2A45BC6E007BBBF7 /* MVKCmdRenderPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRenderPass.mm */; }; + DCFD7F3D2A45BC6E007BBBF7 /* MVKCmdRendering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7731C7DFB4800632CA3 /* MVKCmdRendering.mm */; }; DCFD7F3E2A45BC6E007BBBF7 /* MVKBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7801C7DFB4800632CA3 /* MVKBuffer.mm */; }; DCFD7F3F2A45BC6E007BBBF7 /* MVKEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */; }; DCFD7F402A45BC6E007BBBF7 /* mvk_datatypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A91C7DFB4800632CA3 /* mvk_datatypes.mm */; }; @@ -595,8 +595,8 @@ A94FB76F1C7DFB4800632CA3 /* MVKCmdPipeline.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCmdPipeline.mm; sourceTree = ""; }; A94FB7701C7DFB4800632CA3 /* MVKCmdQueries.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCmdQueries.h; sourceTree = ""; }; A94FB7711C7DFB4800632CA3 /* MVKCmdQueries.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCmdQueries.mm; sourceTree = ""; }; - A94FB7721C7DFB4800632CA3 /* MVKCmdRenderPass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCmdRenderPass.h; sourceTree = ""; }; - A94FB7731C7DFB4800632CA3 /* MVKCmdRenderPass.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCmdRenderPass.mm; sourceTree = ""; }; + A94FB7721C7DFB4800632CA3 /* MVKCmdRendering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCmdRendering.h; sourceTree = ""; }; + A94FB7731C7DFB4800632CA3 /* MVKCmdRendering.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCmdRendering.mm; sourceTree = ""; }; A94FB7741C7DFB4800632CA3 /* MVKCmdDraw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCmdDraw.h; sourceTree = ""; }; A94FB7751C7DFB4800632CA3 /* MVKCmdDraw.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCmdDraw.mm; sourceTree = ""; }; A94FB7761C7DFB4800632CA3 /* MVKCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommand.h; sourceTree = ""; }; @@ -744,8 +744,8 @@ A94FB76F1C7DFB4800632CA3 /* MVKCmdPipeline.mm */, A94FB7701C7DFB4800632CA3 /* MVKCmdQueries.h */, A94FB7711C7DFB4800632CA3 /* MVKCmdQueries.mm */, - A94FB7721C7DFB4800632CA3 /* MVKCmdRenderPass.h */, - A94FB7731C7DFB4800632CA3 /* MVKCmdRenderPass.mm */, + A94FB7721C7DFB4800632CA3 /* MVKCmdRendering.h */, + A94FB7731C7DFB4800632CA3 /* MVKCmdRendering.mm */, A94FB76C1C7DFB4800632CA3 /* MVKCmdTransfer.h */, A94FB76D1C7DFB4800632CA3 /* MVKCmdTransfer.mm */, A94FB7761C7DFB4800632CA3 /* MVKCommand.h */, @@ -995,7 +995,7 @@ 2FEA0A6724902F9F00EEF3AD /* MVKCommonEnvironment.h in Headers */, 2FEA0A6824902F9F00EEF3AD /* MVKWatermark.h in Headers */, 2FEA0A6924902F9F00EEF3AD /* MVKOSExtensions.h in Headers */, - 2FEA0A6A24902F9F00EEF3AD /* MVKCmdRenderPass.h in Headers */, + 2FEA0A6A24902F9F00EEF3AD /* MVKCmdRendering.h in Headers */, 2FEA0A6B24902F9F00EEF3AD /* MVKCmdPipeline.h in Headers */, 2FEA0A6C24902F9F00EEF3AD /* MVKSmallVectorAllocator.h in Headers */, 2FEA0A6D24902F9F00EEF3AD /* MVKPipeline.h in Headers */, @@ -1074,7 +1074,7 @@ A9F042A41FB4CF83009FCCB8 /* MVKCommonEnvironment.h in Headers */, A981495D1FB6A3F7005F00B4 /* MVKWatermark.h in Headers */, A9B51BD9225E986A00AC74D2 /* MVKOSExtensions.h in Headers */, - A94FB7C41C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */, + A94FB7C41C7DFB4800632CA3 /* MVKCmdRendering.h in Headers */, A94FB7BC1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */, A9F3D9DC24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */, A9C327562AAFBD390025EE79 /* MVKConfigMembers.def in Headers */, @@ -1151,7 +1151,7 @@ A9F042A51FB4CF83009FCCB8 /* MVKCommonEnvironment.h in Headers */, A981495E1FB6A3F7005F00B4 /* MVKWatermark.h in Headers */, A9B51BDA225E986A00AC74D2 /* MVKOSExtensions.h in Headers */, - A94FB7C51C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */, + A94FB7C51C7DFB4800632CA3 /* MVKCmdRendering.h in Headers */, A94FB7BD1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */, A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */, A94FB7F91C7DFB4800632CA3 /* MVKPipeline.h in Headers */, @@ -1228,7 +1228,7 @@ DCFD7F0B2A45BC6E007BBBF7 /* MVKCommonEnvironment.h in Headers */, DCFD7F0C2A45BC6E007BBBF7 /* MVKWatermark.h in Headers */, DCFD7F0D2A45BC6E007BBBF7 /* MVKOSExtensions.h in Headers */, - DCFD7F0E2A45BC6E007BBBF7 /* MVKCmdRenderPass.h in Headers */, + DCFD7F0E2A45BC6E007BBBF7 /* MVKCmdRendering.h in Headers */, DCFD7F0F2A45BC6E007BBBF7 /* MVKCmdPipeline.h in Headers */, DCFD7F102A45BC6E007BBBF7 /* MVKSmallVectorAllocator.h in Headers */, DCFD7F112A45BC6E007BBBF7 /* MVKPipeline.h in Headers */, @@ -1674,7 +1674,7 @@ 2FEA0A9424902F9F00EEF3AD /* MVKCommandPool.mm in Sources */, 2FEA0A9524902F9F00EEF3AD /* MVKCmdDraw.mm in Sources */, 2FEA0A9624902F9F00EEF3AD /* MVKCommandBuffer.mm in Sources */, - 2FEA0A9724902F9F00EEF3AD /* MVKCmdRenderPass.mm in Sources */, + 2FEA0A9724902F9F00EEF3AD /* MVKCmdRendering.mm in Sources */, 2FEA0A9824902F9F00EEF3AD /* MVKBuffer.mm in Sources */, 2FEA0A9924902F9F00EEF3AD /* mvk_datatypes.mm in Sources */, 2FEA0A9A24902F9F00EEF3AD /* MVKExtensions.mm in Sources */, @@ -1734,7 +1734,7 @@ A94FB7D61C7DFB4800632CA3 /* MVKCommandPool.mm in Sources */, A94FB7CA1C7DFB4800632CA3 /* MVKCmdDraw.mm in Sources */, A94FB7D21C7DFB4800632CA3 /* MVKCommandBuffer.mm in Sources */, - A94FB7C61C7DFB4800632CA3 /* MVKCmdRenderPass.mm in Sources */, + A94FB7C61C7DFB4800632CA3 /* MVKCmdRendering.mm in Sources */, A94FB7DE1C7DFB4800632CA3 /* MVKBuffer.mm in Sources */, A9A5E9C725C0822700E9085E /* MVKEnvironment.cpp in Sources */, A94FB82A1C7DFB4800632CA3 /* mvk_datatypes.mm in Sources */, @@ -1794,7 +1794,7 @@ A94FB7D71C7DFB4800632CA3 /* MVKCommandPool.mm in Sources */, A94FB7CB1C7DFB4800632CA3 /* MVKCmdDraw.mm in Sources */, A94FB7D31C7DFB4800632CA3 /* MVKCommandBuffer.mm in Sources */, - A94FB7C71C7DFB4800632CA3 /* MVKCmdRenderPass.mm in Sources */, + A94FB7C71C7DFB4800632CA3 /* MVKCmdRendering.mm in Sources */, A94FB7DF1C7DFB4800632CA3 /* MVKBuffer.mm in Sources */, A9A5E9C925C0822700E9085E /* MVKEnvironment.cpp in Sources */, A94FB82B1C7DFB4800632CA3 /* mvk_datatypes.mm in Sources */, @@ -1854,7 +1854,7 @@ DCFD7F3A2A45BC6E007BBBF7 /* MVKCommandPool.mm in Sources */, DCFD7F3B2A45BC6E007BBBF7 /* MVKCmdDraw.mm in Sources */, DCFD7F3C2A45BC6E007BBBF7 /* MVKCommandBuffer.mm in Sources */, - DCFD7F3D2A45BC6E007BBBF7 /* MVKCmdRenderPass.mm in Sources */, + DCFD7F3D2A45BC6E007BBBF7 /* MVKCmdRendering.mm in Sources */, DCFD7F3E2A45BC6E007BBBF7 /* MVKBuffer.mm in Sources */, DCFD7F3F2A45BC6E007BBBF7 /* MVKEnvironment.cpp in Sources */, DCFD7F402A45BC6E007BBBF7 /* mvk_datatypes.mm in Sources */, diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.mm index 1125963d..020f04b5 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.mm @@ -46,7 +46,7 @@ void MVKCmdDispatch::encode(MVKCommandEncoder* cmdEncoder) { MTLRegion mtlThreadgroupCount = MTLRegionMake3D(_baseGroupX, _baseGroupY, _baseGroupZ, _groupCountX, _groupCountY, _groupCountZ); cmdEncoder->finalizeDispatchState(); // Ensure all updated state has been submitted to Metal id mtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch); - auto* pipeline = (MVKComputePipeline*)cmdEncoder->_computePipelineState.getPipeline(); + auto* pipeline = cmdEncoder->_computePipelineState.getComputePipeline(); if (pipeline->allowsDispatchBase()) { if ([mtlEncoder respondsToSelector: @selector(setStageInRegion:)]) { // We'll use the stage-input region to pass the base along to the shader. diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm index a1b71512..a7930a47 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm @@ -149,7 +149,7 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { return; } - auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); + auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); // Metal doesn't support triangle fans, so encode it as triangles via an indexed indirect triangles command instead. if (pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { @@ -172,7 +172,7 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { } tessParams; uint32_t outControlPointCount = 0; if (pipeline->isTessellationPipeline()) { - tessParams.inControlPointCount = pipeline->getInputControlPointCount(); + tessParams.inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); tessParams.patchCount = mvkCeilingDivide(_vertexCount, tessParams.inControlPointCount) * _instanceCount; } @@ -299,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->_rasterizingState.getPrimitiveType() + [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_renderingState.getPrimitiveType() vertexStart: _firstVertex vertexCount: _vertexCount instanceCount: instanceCount baseInstance: _firstInstance]; } else { - [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() + [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_renderingState.getPrimitiveType() vertexStart: _firstVertex vertexCount: _vertexCount instanceCount: instanceCount]; @@ -374,7 +374,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { return; } - auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); + auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); // Metal doesn't support triangle fans, so encode it as triangles via an indexed indirect triangles command instead. if (pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { @@ -401,7 +401,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { } tessParams; uint32_t outControlPointCount = 0; if (pipeline->isTessellationPipeline()) { - tessParams.inControlPointCount = pipeline->getInputControlPointCount(); + tessParams.inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); tessParams.patchCount = mvkCeilingDivide(_indexCount, tessParams.inControlPointCount) * _instanceCount; } @@ -533,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->_rasterizingState.getPrimitiveType() + [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_renderingState.getPrimitiveType() indexCount: _indexCount indexType: (MTLIndexType)ibb.mtlIndexType indexBuffer: ibb.mtlBuffer @@ -542,7 +542,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { baseVertex: _vertexOffset baseInstance: _firstInstance]; } else { - [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() + [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_renderingState.getPrimitiveType() indexCount: _indexCount indexType: (MTLIndexType)ibb.mtlIndexType indexBuffer: ibb.mtlBuffer @@ -649,7 +649,7 @@ void MVKCmdDrawIndirect::encodeIndexedIndirect(MVKCommandEncoder* cmdEncoder) { void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { - auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); + auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); // Metal doesn't support triangle fans, so encode it as indexed indirect triangles instead. if (pipeline->getVkPrimitiveTopology() == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) { @@ -686,7 +686,7 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { // encoding and execution. So we don't know how big to make the buffers. // We must assume an arbitrarily large number of vertices may be submitted. // But not too many, or we'll exhaust available VRAM. - inControlPointCount = pipeline->getInputControlPointCount(); + inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); vertexCount = kMVKMaxDrawIndirectVertexCount; patchCount = mvkCeilingDivide(vertexCount, inControlPointCount); @@ -928,7 +928,7 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); } else { - [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType() + [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_renderingState.getPrimitiveType() indirectBuffer: mtlIndBuff indirectBufferOffset: mtlIndBuffOfst]; mtlIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawPrimitivesIndirectArguments) : _mtlIndirectBufferStride; @@ -999,7 +999,7 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder, const MVKI MVKIndexMTLBufferBinding ibb = ibbOrig; MVKIndexMTLBufferBinding ibbTriFan = ibb; - auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); + auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); MVKVertexAdjustments vtxAdjmts; vtxAdjmts.mtlIndexType = ibb.mtlIndexType; @@ -1034,7 +1034,7 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder, const MVKI // encoding and execution. So we don't know how big to make the buffers. // We must assume an arbitrarily large number of vertices may be submitted. // But not too many, or we'll exhaust available VRAM. - inControlPointCount = pipeline->getInputControlPointCount(); + inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); vertexCount = kMVKMaxDrawIndirectVertexCount; patchCount = mvkCeilingDivide(vertexCount, inControlPointCount); @@ -1315,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->_rasterizingState.getPrimitiveType() + [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_renderingState.getPrimitiveType() indexType: (MTLIndexType)ibb.mtlIndexType indexBuffer: ibb.mtlBuffer indexBufferOffset: ibb.offset diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h index aec8800c..84bc923a 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h @@ -30,6 +30,34 @@ class MVKDescriptorSet; class MVKDescriptorUpdateTemplate; +#pragma mark - +#pragma mark MVKCmdExecuteCommands + +/** + * Vulkan command to execute secondary command buffers. + * Template class to balance vector pre-allocations between very common low counts and fewer larger counts. + */ +template +class MVKCmdExecuteCommands : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + uint32_t commandBuffersCount, + const VkCommandBuffer* pCommandBuffers); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + MVKSmallVector _secondaryCommandBuffers; +}; + +// Concrete template class implementations. +typedef MVKCmdExecuteCommands<1> MVKCmdExecuteCommands1; +typedef MVKCmdExecuteCommands<16> MVKCmdExecuteCommandsMulti; + + #pragma mark - #pragma mark MVKCmdPipelineBarrier diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm index 05e578f6..1a30f550 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm @@ -26,6 +26,33 @@ #include "mvk_datatypes.hpp" +#pragma mark - +#pragma mark MVKCmdExecuteCommands + +template +VkResult MVKCmdExecuteCommands::setContent(MVKCommandBuffer* cmdBuff, + uint32_t commandBuffersCount, + const VkCommandBuffer* pCommandBuffers) { + // Add clear values + _secondaryCommandBuffers.clear(); // Clear for reuse + _secondaryCommandBuffers.reserve(commandBuffersCount); + for (uint32_t cbIdx = 0; cbIdx < commandBuffersCount; cbIdx++) { + _secondaryCommandBuffers.push_back(MVKCommandBuffer::getMVKCommandBuffer(pCommandBuffers[cbIdx])); + } + cmdBuff->recordExecuteCommands(_secondaryCommandBuffers.contents()); + + return VK_SUCCESS; +} + +template +void MVKCmdExecuteCommands::encode(MVKCommandEncoder* cmdEncoder) { + for (auto& cb : _secondaryCommandBuffers) { cmdEncoder->encodeSecondary(cb); } +} + +template class MVKCmdExecuteCommands<1>; +template class MVKCmdExecuteCommands<16>; + + #pragma mark - #pragma mark MVKCmdPipelineBarrier diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h similarity index 86% rename from MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h rename to MoltenVK/MoltenVK/Commands/MVKCmdRendering.h index 1e3bae5c..2b11ae8e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h @@ -1,5 +1,5 @@ /* - * MVKCmdRenderPass.h + * MVKCmdRendering.h * * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) * @@ -207,34 +207,6 @@ protected: }; -#pragma mark - -#pragma mark MVKCmdExecuteCommands - -/** - * Vulkan command to execute secondary command buffers. - * Template class to balance vector pre-allocations between very common low counts and fewer larger counts. - */ -template -class MVKCmdExecuteCommands : public MVKCommand { - -public: - VkResult setContent(MVKCommandBuffer* cmdBuff, - uint32_t commandBuffersCount, - const VkCommandBuffer* pCommandBuffers); - - void encode(MVKCommandEncoder* cmdEncoder) override; - -protected: - MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; - - MVKSmallVector _secondaryCommandBuffers; -}; - -// Concrete template class implementations. -typedef MVKCmdExecuteCommands<1> MVKCmdExecuteCommands1; -typedef MVKCmdExecuteCommands<16> MVKCmdExecuteCommandsMulti; - - #pragma mark - #pragma mark MVKCmdSetViewport @@ -337,6 +309,25 @@ protected: }; +#pragma mark - +#pragma mark MVKCmdSetDepthBiasEnable + +/** Vulkan command to dynamically enable or disable depth bias. */ +class MVKCmdSetDepthBiasEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthBiasEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkBool32 _depthBiasEnable; +}; + + #pragma mark - #pragma mark MVKCmdSetBlendConstants @@ -356,6 +347,40 @@ protected: }; +#pragma mark - +#pragma mark MVKCmdSetLogicOp + +/** Vulkan command to dynamically set the blending logic operation. */ +class MVKCmdSetLogicOp : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkLogicOp logicOp); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; +}; + + +#pragma mark - +#pragma mark MVKCmdSetLogicOpEnable + +/** Vulkan command to dynamically enable or disable the blending logic operation. */ +class MVKCmdSetLogicOpEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 logicOpEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; +}; + + #pragma mark - #pragma mark MVKCmdSetDepthTestEnable @@ -600,6 +625,25 @@ protected: }; +#pragma mark - +#pragma mark MVKCmdSetPatchControlPoints + +/** Vulkan command to dynamically set the number of patch control points. */ +class MVKCmdSetPatchControlPoints : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + uint32_t patchControlPoints); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + uint32_t _patchControlPoints; +}; + + #pragma mark - #pragma mark MVKCmdSetPrimitiveTopology @@ -618,3 +662,39 @@ protected: VkPrimitiveTopology _primitiveTopology; }; + +#pragma mark - +#pragma mark MVKCmdSetPrimitiveRestartEnable + +/** Vulkan command to dynamically enable or disable primitive restart functionality. */ +class MVKCmdSetPrimitiveRestartEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 primitiveRestartEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; +}; + + +#pragma mark - +#pragma mark MVKCmdSetRasterizerDiscardEnable + +/** Vulkan command to dynamically enable or disable rasterization. */ +class MVKCmdSetRasterizerDiscardEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 rasterizerDiscardEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkBool32 _rasterizerDiscardEnable; +}; + diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm similarity index 82% rename from MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm rename to MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm index b5befc3a..33078a02 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm @@ -1,5 +1,5 @@ /* - * MVKCmdRenderPass.mm + * MVKCmdRendering.mm * * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) * @@ -16,7 +16,7 @@ * limitations under the License. */ -#include "MVKCmdRenderPass.h" +#include "MVKCmdRendering.h" #include "MVKCommandBuffer.h" #include "MVKCommandPool.h" #include "MVKFramebuffer.h" @@ -231,33 +231,6 @@ void MVKCmdSetSampleLocations::encode(MVKCommandEncoder* cmdEncoder) { } -#pragma mark - -#pragma mark MVKCmdExecuteCommands - -template -VkResult MVKCmdExecuteCommands::setContent(MVKCommandBuffer* cmdBuff, - uint32_t commandBuffersCount, - const VkCommandBuffer* pCommandBuffers) { - // Add clear values - _secondaryCommandBuffers.clear(); // Clear for reuse - _secondaryCommandBuffers.reserve(commandBuffersCount); - for (uint32_t cbIdx = 0; cbIdx < commandBuffersCount; cbIdx++) { - _secondaryCommandBuffers.push_back(MVKCommandBuffer::getMVKCommandBuffer(pCommandBuffers[cbIdx])); - } - cmdBuff->recordExecuteCommands(_secondaryCommandBuffers.contents()); - - return VK_SUCCESS; -} - -template -void MVKCmdExecuteCommands::encode(MVKCommandEncoder* cmdEncoder) { - for (auto& cb : _secondaryCommandBuffers) { cmdEncoder->encodeSecondary(cb); } -} - -template class MVKCmdExecuteCommands<1>; -template class MVKCmdExecuteCommands<16>; - - #pragma mark - #pragma mark MVKCmdSetViewport @@ -278,7 +251,7 @@ VkResult MVKCmdSetViewport::setContent(MVKCommandBuffer* cmdBuff, template void MVKCmdSetViewport::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setViewports(_viewports.contents(), _firstViewport, true); + cmdEncoder->_renderingState.setViewports(_viewports.contents(), _firstViewport, true); } template class MVKCmdSetViewport<1>; @@ -305,7 +278,7 @@ VkResult MVKCmdSetScissor::setContent(MVKCommandBuffer* cmdBuff, template void MVKCmdSetScissor::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setScissors(_scissors.contents(), _firstScissor, true); + cmdEncoder->_renderingState.setScissors(_scissors.contents(), _firstScissor, true); } template class MVKCmdSetScissor<1>; @@ -345,12 +318,26 @@ VkResult MVKCmdSetDepthBias::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetDepthBias::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setDepthBias(_depthBiasConstantFactor, + cmdEncoder->_renderingState.setDepthBias(_depthBiasConstantFactor, _depthBiasSlopeFactor, _depthBiasClamp); } +#pragma mark - +#pragma mark MVKCmdSetDepthBiasEnable + +VkResult MVKCmdSetDepthBiasEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthBiasEnable) { + _depthBiasEnable = depthBiasEnable; + return VK_SUCCESS; +} + +void MVKCmdSetDepthBiasEnable::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_renderingState.setDepthBiasEnable(_depthBiasEnable); +} + + #pragma mark - #pragma mark MVKCmdSetBlendConstants @@ -361,10 +348,42 @@ VkResult MVKCmdSetBlendConstants::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetBlendConstants::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setBlendConstants(_blendConstants, true); + cmdEncoder->_renderingState.setBlendConstants(_blendConstants, true); } +#pragma mark - +#pragma mark MVKCmdSetLogicOp + +VkResult MVKCmdSetLogicOp::setContent(MVKCommandBuffer* cmdBuff, + VkLogicOp logicOp) { + // Validate + if (logicOp != VK_LOGIC_OP_COPY) { + return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support blending using logic operations."); + } + + return VK_SUCCESS; +} + +void MVKCmdSetLogicOp::encode(MVKCommandEncoder* cmdEncoder) {} + + +#pragma mark - +#pragma mark MVKCmdSetLogicOpEnable + +VkResult MVKCmdSetLogicOpEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 logicOpEnable) { + // Validate + if (logicOpEnable) { + return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support blending using logic operations."); + } + + return VK_SUCCESS; +} + +void MVKCmdSetLogicOpEnable::encode(MVKCommandEncoder* cmdEncoder) {} + + #pragma mark - #pragma mark MVKCmdSetDepthTestEnable @@ -528,7 +547,7 @@ VkResult MVKCmdSetStencilReference::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetStencilReference::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setStencilReferenceValues(_faceMask, _stencilReference); + cmdEncoder->_renderingState.setStencilReferenceValues(_faceMask, _stencilReference); } @@ -542,7 +561,7 @@ VkResult MVKCmdSetCullMode::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetCullMode::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setCullMode(_cullMode, true); + cmdEncoder->_renderingState.setCullMode(_cullMode, true); } @@ -556,7 +575,21 @@ VkResult MVKCmdSetFrontFace::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetFrontFace::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setFrontFace(_frontFace, true); + cmdEncoder->_renderingState.setFrontFace(_frontFace, true); +} + + +#pragma mark - +#pragma mark MVKCmdSetPatchControlPoints + +VkResult MVKCmdSetPatchControlPoints::setContent(MVKCommandBuffer* cmdBuff, + uint32_t patchControlPoints) { + _patchControlPoints = patchControlPoints; + return VK_SUCCESS; +} + +void MVKCmdSetPatchControlPoints::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_graphicsPipelineState.setPatchControlPoints(_patchControlPoints); } @@ -570,6 +603,39 @@ VkResult MVKCmdSetPrimitiveTopology::setContent(MVKCommandBuffer* cmdBuff, } void MVKCmdSetPrimitiveTopology::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_rasterizingState.setPrimitiveTopology(_primitiveTopology, true); + cmdEncoder->_renderingState.setPrimitiveTopology(_primitiveTopology, true); } + +#pragma mark - +#pragma mark MVKCmdSetPrimitiveRestartEnable + +VkResult MVKCmdSetPrimitiveRestartEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 primitiveRestartEnable) { + // Validate + // In Metal, primitive restart cannot be disabled. + // Just issue warning here, as it is very likely the app is not actually expecting + // to use primitive restart at all, and is just setting this as a "just-in-case", + // and forcing an error here would be unexpected to the app (including CTS). + if ( !primitiveRestartEnable ) { + reportWarning(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support disabling primitive restart."); + } + + return VK_SUCCESS; +} + +void MVKCmdSetPrimitiveRestartEnable::encode(MVKCommandEncoder* cmdEncoder) {} + + +#pragma mark - +#pragma mark MVKCmdSetRasterizerDiscardEnable + +VkResult MVKCmdSetRasterizerDiscardEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 rasterizerDiscardEnable) { + _rasterizerDiscardEnable = rasterizerDiscardEnable; + return VK_SUCCESS; +} + +void MVKCmdSetRasterizerDiscardEnable::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_renderingState.setRasterizerDiscardEnable(_rasterizerDiscardEnable, true); +} diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 5ae4fee3..124859bd 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1507,7 +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->_rasterizingState.markDirty(); + cmdEncoder->_renderingState.markDirty(); } template diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index cc1d7539..94f4585c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -432,13 +432,13 @@ public: id _mtlRenderEncoder; /** Tracks the current graphics pipeline bound to the encoder. */ - MVKPipelineCommandEncoderState _graphicsPipelineState; + MVKGraphicsPipelineCommandEncoderState _graphicsPipelineState; /** Tracks the current graphics resources state of the encoder. */ MVKGraphicsResourcesCommandEncoderState _graphicsResourcesState; /** Tracks the current compute pipeline bound to the encoder. */ - MVKPipelineCommandEncoderState _computePipelineState; + MVKComputePipelineCommandEncoderState _computePipelineState; /** Tracks the current compute resources state of the encoder. */ MVKComputeResourcesCommandEncoderState _computeResourcesState; @@ -446,8 +446,8 @@ public: /** Tracks the current depth stencil state of the encoder. */ MVKDepthStencilCommandEncoderState _depthStencilState; - /** Tracks the current rasterizing states of the encoder. */ - MVKRasterizingCommandEncoderState _rasterizingState; + /** Tracks the current rendering states of the encoder. */ + MVKRenderingCommandEncoderState _renderingState; /** 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 d640730c..55127489 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -25,7 +25,7 @@ #include "MVKFoundation.h" #include "MTLRenderPassDescriptor+MoltenVK.h" #include "MVKCmdDraw.h" -#include "MVKCmdRenderPass.h" +#include "MVKCmdRendering.h" #include using namespace std; @@ -608,7 +608,7 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) { _graphicsPipelineState.beginMetalRenderPass(); _graphicsResourcesState.beginMetalRenderPass(); _depthStencilState.beginMetalRenderPass(); - _rasterizingState.beginMetalRenderPass(); + _renderingState.beginMetalRenderPass(); _vertexPushConstants.beginMetalRenderPass(); _tessCtlPushConstants.beginMetalRenderPass(); _tessEvalPushConstants.beginMetalRenderPass(); @@ -729,7 +729,7 @@ 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. _depthStencilState.encode(stage); - _rasterizingState.encode(stage); + _renderingState.encode(stage); _vertexPushConstants.encode(stage); _tessCtlPushConstants.encode(stage); _tessEvalPushConstants.encode(stage); @@ -823,7 +823,7 @@ void MVKCommandEncoder::endMetalRenderEncoding() { _graphicsPipelineState.endMetalRenderPass(); _graphicsResourcesState.endMetalRenderPass(); _depthStencilState.endMetalRenderPass(); - _rasterizingState.endMetalRenderPass(); + _renderingState.endMetalRenderPass(); _vertexPushConstants.endMetalRenderPass(); _tessCtlPushConstants.endMetalRenderPass(); _tessEvalPushConstants.endMetalRenderPass(); @@ -1124,7 +1124,7 @@ MVKCommandEncoder::MVKCommandEncoder(MVKCommandBuffer* cmdBuffer, _computePipelineState(this), _computeResourcesState(this), _depthStencilState(this), - _rasterizingState(this), + _renderingState(this), _vertexPushConstants(this, VK_SHADER_STAGE_VERTEX_BIT), _tessCtlPushConstants(this, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), _tessEvalPushConstants(this, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index c8919538..c518c54a 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -119,20 +119,15 @@ protected: #pragma mark - #pragma mark MVKPipelineCommandEncoderState -/** Holds encoder state established by pipeline commands. */ +/** Abstract class to hold encoder state established by pipeline commands. */ class MVKPipelineCommandEncoderState : public MVKCommandEncoderState { public: + virtual void bindPipeline(MVKPipeline* pipeline); - /** Binds the pipeline. */ - void bindPipeline(MVKPipeline* pipeline); - - /** Returns the currently bound pipeline. */ MVKPipeline* getPipeline(); - /** Constructs this instance for the specified command encoder. */ - MVKPipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) - : MVKCommandEncoderState(cmdEncoder) {} + MVKPipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {} protected: void encodeImpl(uint32_t stage) override; @@ -141,6 +136,42 @@ protected: }; +#pragma mark - +#pragma mark MVKGraphicsPipelineCommandEncoderState + +/** Holds encoder state established by graphics pipeline commands. */ +class MVKGraphicsPipelineCommandEncoderState : public MVKPipelineCommandEncoderState { + +public: + void bindPipeline(MVKPipeline* pipeline) override; + + MVKGraphicsPipeline* getGraphicsPipeline() { return (MVKGraphicsPipeline*)getPipeline(); } + + void setPatchControlPoints(uint32_t patchControlPoints); + uint32_t getPatchControlPoints(); + + MVKGraphicsPipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKPipelineCommandEncoderState(cmdEncoder) {} + +protected: + uint32_t _patchControlPoints[StateScope::Count] = {}; +}; + + +#pragma mark - +#pragma mark MVKComputePipelineCommandEncoderState + +/** Holds encoder state established by compute pipeline commands. */ +class MVKComputePipelineCommandEncoderState : public MVKPipelineCommandEncoderState { + +public: + MVKComputePipeline* getComputePipeline() { return (MVKComputePipeline*)getPipeline(); } + + MVKComputePipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKPipelineCommandEncoderState(cmdEncoder) {} + +protected: +}; + + #pragma mark - #pragma mark MVKPushConstantsCommandEncoderState @@ -233,7 +264,7 @@ protected: #pragma mark - -#pragma mark MVKRasterizingCommandEncoderState +#pragma mark MVKRenderingCommandEncoderState struct MVKDepthBias { float depthBiasConstantFactor; @@ -256,8 +287,8 @@ struct MVKMTLScissors { uint32_t scissorCount; }; -/** Holds encoder state established by various state commands. */ -class MVKRasterizingCommandEncoderState : public MVKCommandEncoderState { +/** Holds encoder state established by various rendering state commands. */ +class MVKRenderingCommandEncoderState : public MVKCommandEncoderState { public: void setCullMode(VkCullModeFlags cullMode, bool isDynamic); @@ -281,9 +312,11 @@ public: void setViewports(const MVKArrayRef viewports, uint32_t firstViewport, bool isDynamic); void setScissors(const MVKArrayRef scissors, uint32_t firstScissor, bool isDynamic); + void setRasterizerDiscardEnable(VkBool32 rasterizerDiscardEnable, bool isDynamic); + void beginMetalRenderPass() override; - MVKRasterizingCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {} + MVKRenderingCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {} protected: void encodeImpl(uint32_t stage) override; @@ -312,6 +345,7 @@ protected: MVKRenderStateFlags _dirtyStates; MVKRenderStateFlags _modifiedStates; bool _mtlDepthBiasEnable[StateScope::Count] = {}; + bool _mtlRasterizerDiscardEnable[StateScope::Count] = {}; bool _cullBothFaces[StateScope::Count] = {}; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 828d7c09..72db24d6 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -36,7 +36,7 @@ MVKVulkanAPIObject* MVKCommandEncoderState::getVulkanAPIObject() { return _cmdEn MVKDevice* MVKCommandEncoderState::getDevice() { return _cmdEncoder->getDevice(); } bool MVKCommandEncoderState::isDynamicState(MVKRenderStateType state) { - auto* gpl = (MVKGraphicsPipeline*)_cmdEncoder->_graphicsPipelineState.getPipeline(); + auto* gpl = _cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); return !gpl || gpl->isDynamicState(state); } @@ -59,6 +59,23 @@ void MVKPipelineCommandEncoderState::encodeImpl(uint32_t stage) { } +#pragma mark - +#pragma mark MVKGraphicsPipelineCommandEncoderState + +void MVKGraphicsPipelineCommandEncoderState::bindPipeline(MVKPipeline* pipeline) { + MVKPipelineCommandEncoderState::bindPipeline(pipeline); + _patchControlPoints[StateScope::Static] = getGraphicsPipeline()->_tessInfo.patchControlPoints; +} + +void MVKGraphicsPipelineCommandEncoderState::setPatchControlPoints(uint32_t patchControlPoints) { + _patchControlPoints[StateScope::Dynamic] = patchControlPoints; +} + +uint32_t MVKGraphicsPipelineCommandEncoderState::getPatchControlPoints() { + return getContent(_patchControlPoints, PatchControlPoints); +} + + #pragma mark - #pragma mark MVKPushConstantsCommandEncoderState @@ -147,7 +164,7 @@ void MVKPushConstantsCommandEncoderState::encodeImpl(uint32_t stage) { } bool MVKPushConstantsCommandEncoderState::isTessellating() { - MVKGraphicsPipeline* gp = (MVKGraphicsPipeline*)_cmdEncoder->_graphicsPipelineState.getPipeline(); + auto* gp = _cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); return gp ? gp->isTessellationPipeline() : false; } @@ -291,32 +308,32 @@ void MVKDepthStencilCommandEncoderState::encodeImpl(uint32_t stage) { #pragma mark - -#pragma mark MVKRasterizingCommandEncoderState +#pragma mark MVKRenderingCommandEncoderState #define getContent(state) getContent(_mtl##state, state) #define setContent(state) setContent(_mtl##state, &mtl##state, state, isDynamic) -void MVKRasterizingCommandEncoderState::setCullMode(VkCullModeFlags cullMode, bool isDynamic) { +void MVKRenderingCommandEncoderState::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) { +void MVKRenderingCommandEncoderState::setFrontFace(VkFrontFace frontFace, bool isDynamic) { auto mtlFrontFace = mvkMTLWindingFromVkFrontFace(frontFace); setContent(FrontFace); } -void MVKRasterizingCommandEncoderState::setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic) { +void MVKRenderingCommandEncoderState::setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic) { auto mtlPrimitiveTopology = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(topology); setContent(PrimitiveTopology); } -MTLPrimitiveType MVKRasterizingCommandEncoderState::getPrimitiveType() { +MTLPrimitiveType MVKRenderingCommandEncoderState::getPrimitiveType() { return getContent(PrimitiveTopology); } -bool MVKRasterizingCommandEncoderState::isDrawingTriangles() { +bool MVKRenderingCommandEncoderState::isDrawingTriangles() { switch (getPrimitiveType()) { case MTLPrimitiveTypeTriangle: return true; case MTLPrimitiveTypeTriangleStrip: return true; @@ -324,18 +341,18 @@ bool MVKRasterizingCommandEncoderState::isDrawingTriangles() { } } -void MVKRasterizingCommandEncoderState::setPolygonMode(VkPolygonMode polygonMode, bool isDynamic) { +void MVKRenderingCommandEncoderState::setPolygonMode(VkPolygonMode polygonMode, bool isDynamic) { auto mtlPolygonMode = mvkMTLTriangleFillModeFromVkPolygonMode(polygonMode); setContent(PolygonMode); } -void MVKRasterizingCommandEncoderState::setBlendConstants(float blendConstants[4], bool isDynamic) { +void MVKRenderingCommandEncoderState::setBlendConstants(float blendConstants[4], bool isDynamic) { MVKColor32 mtlBlendConstants; mvkCopy(mtlBlendConstants.float32, blendConstants, 4); setContent(BlendConstants); } -void MVKRasterizingCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) { +void MVKRenderingCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) { bool isDynamic = false; bool mtlDepthBiasEnable = static_cast(vkRasterInfo.depthBiasEnable); @@ -349,7 +366,7 @@ void MVKRasterizingCommandEncoderState::setDepthBias(const VkPipelineRasterizati setContent(DepthBias); } -void MVKRasterizingCommandEncoderState::setDepthBias(float depthBiasConstantFactor, +void MVKRenderingCommandEncoderState::setDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor, float depthBiasClamp) { bool isDynamic = true; @@ -361,18 +378,18 @@ void MVKRasterizingCommandEncoderState::setDepthBias(float depthBiasConstantFact setContent(DepthBias); } -void MVKRasterizingCommandEncoderState::setDepthBiasEnable(VkBool32 depthBiasEnable) { +void MVKRenderingCommandEncoderState::setDepthBiasEnable(VkBool32 depthBiasEnable) { bool isDynamic = true; bool mtlDepthBiasEnable = static_cast(depthBiasEnable); setContent(DepthBiasEnable); } -void MVKRasterizingCommandEncoderState::setDepthClipEnable(bool depthClip, bool isDynamic) { +void MVKRenderingCommandEncoderState::setDepthClipEnable(bool depthClip, bool isDynamic) { auto mtlDepthClipEnable = depthClip ? MTLDepthClipModeClip : MTLDepthClipModeClamp; setContent(DepthClipEnable); } -void MVKRasterizingCommandEncoderState::setStencilReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) { +void MVKRenderingCommandEncoderState::setStencilReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) { bool isDynamic = false; MVKStencilReference mtlStencilReference = { .frontFaceValue = vkDepthStencilInfo.front.reference, @@ -381,7 +398,7 @@ void MVKRasterizingCommandEncoderState::setStencilReferenceValues(const VkPipeli setContent(StencilReference); } -void MVKRasterizingCommandEncoderState::setStencilReferenceValues(VkStencilFaceFlags faceMask, uint32_t stencilReference) { +void MVKRenderingCommandEncoderState::setStencilReferenceValues(VkStencilFaceFlags faceMask, uint32_t stencilReference) { bool isDynamic = true; MVKStencilReference mtlStencilReference = _mtlStencilReference[StateScope::Dynamic]; if (shouldUpdateFace(FRONT)) { mtlStencilReference.frontFaceValue = stencilReference; } @@ -389,7 +406,7 @@ void MVKRasterizingCommandEncoderState::setStencilReferenceValues(VkStencilFaceF setContent(StencilReference); } -void MVKRasterizingCommandEncoderState::setViewports(const MVKArrayRef viewports, +void MVKRenderingCommandEncoderState::setViewports(const MVKArrayRef viewports, uint32_t firstViewport, bool isDynamic) { uint32_t maxViewports = getDevice()->_pProperties->limits.maxViewports; @@ -404,7 +421,7 @@ void MVKRasterizingCommandEncoderState::setViewports(const MVKArrayRef scissors, +void MVKRenderingCommandEncoderState::setScissors(const MVKArrayRef scissors, uint32_t firstScissor, bool isDynamic) { uint32_t maxScissors = getDevice()->_pProperties->limits.maxViewports; @@ -419,7 +436,14 @@ void MVKRasterizingCommandEncoderState::setScissors(const MVKArrayRef setContent(Scissors); } -void MVKRasterizingCommandEncoderState::encodeImpl(uint32_t stage) { +void MVKRenderingCommandEncoderState::setRasterizerDiscardEnable(VkBool32 rasterizerDiscardEnable, bool isDynamic) { + bool mtlRasterizerDiscardEnable = static_cast(rasterizerDiscardEnable); + setContent(RasterizerDiscardEnable); +} + +#pragma mark Encoding + +void MVKRenderingCommandEncoderState::encodeImpl(uint32_t stage) { if (stage != kMVKGraphicsStageRasterization) { return; } auto& rendEnc = _cmdEncoder->_mtlRenderEncoder; @@ -460,14 +484,15 @@ void MVKRasterizingCommandEncoderState::encodeImpl(uint32_t stage) { } } + // If rasterizing discard has been dynamically enabled, or culling has been dynamically + // set to front-and-back, emulate this by using zeroed scissor rectangles. 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); + auto mtlScissors = getContent(Scissors); + bool shouldDiscard = ((_mtlRasterizerDiscardEnable[StateScope::Dynamic] && isDynamicState(RasterizerDiscardEnable)) || + (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]); + mtlScissors.scissors[sIdx] = shouldDiscard ? zeroRect : _cmdEncoder->clipToRenderArea(mtlScissors.scissors[sIdx]); } if (_cmdEncoder->_pDeviceFeatures->multiViewport) { @@ -481,13 +506,13 @@ void MVKRasterizingCommandEncoderState::encodeImpl(uint32_t stage) { } // Return whether state is dirty, and mark it not dirty -bool MVKRasterizingCommandEncoderState::isDirty(MVKRenderStateType state) { +bool MVKRenderingCommandEncoderState::isDirty(MVKRenderStateType state) { bool rslt = _dirtyStates.isEnabled(state); _dirtyStates.disable(state); return rslt; } -void MVKRasterizingCommandEncoderState::beginMetalRenderPass() { +void MVKRenderingCommandEncoderState::beginMetalRenderPass() { MVKCommandEncoderState::beginMetalRenderPass(); _dirtyStates = _modifiedStates; } @@ -803,7 +828,7 @@ void MVKGraphicsResourcesCommandEncoderState::markDirty() { void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { - MVKGraphicsPipeline* pipeline = (MVKGraphicsPipeline*)getPipeline(); + auto* pipeline = _cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); bool fullImageViewSwizzle = pipeline->fullImageViewSwizzle() || getDevice()->_pMetalFeatures->nativeTextureSwizzle; bool forTessellation = pipeline->isTessellationPipeline(); bool isDynamicVertexStride = pipeline->isDynamicState(VertexStride); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h index a6b1a38b..e2325857 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h @@ -23,7 +23,7 @@ #include "MVKCommandEncodingPool.h" #include "MVKCommand.h" #include "MVKCmdPipeline.h" -#include "MVKCmdRenderPass.h" +#include "MVKCmdRendering.h" #include "MVKCmdDispatch.h" #include "MVKCmdDraw.h" #include "MVKCmdTransfer.h" diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def index 3035677f..880f5551 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def +++ b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def @@ -87,8 +87,11 @@ MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BindDescriptorSetsDynamic, 4) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(SetViewport, 1) 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(SetLogicOp) +MVK_CMD_TYPE_POOL(SetLogicOpEnable) +MVK_CMD_TYPE_POOL(SetDepthBias) +MVK_CMD_TYPE_POOL(SetDepthBiasEnable) MVK_CMD_TYPE_POOL(SetDepthTestEnable) MVK_CMD_TYPE_POOL(SetDepthWriteEnable) MVK_CMD_TYPE_POOL(SetDepthCompareOp) @@ -102,6 +105,9 @@ MVK_CMD_TYPE_POOL(SetStencilReference) MVK_CMD_TYPE_POOL(SetCullMode) MVK_CMD_TYPE_POOL(SetFrontFace) MVK_CMD_TYPE_POOL(SetPrimitiveTopology) +MVK_CMD_TYPE_POOL(SetPatchControlPoints) +MVK_CMD_TYPE_POOL(SetPrimitiveRestartEnable) +MVK_CMD_TYPE_POOL(SetRasterizerDiscardEnable) 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/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index c2fe1e86..a660be0a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -392,6 +392,13 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) { extDynState->extendedDynamicState = true; break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT: { + auto* extDynState2 = (VkPhysicalDeviceExtendedDynamicState2FeaturesEXT*)next; + extDynState2->extendedDynamicState2 = true; + extDynState2->extendedDynamicState2LogicOp = false; + extDynState2->extendedDynamicState2PatchControlPoints = true; + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: { auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next; interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def index 4e9f3bed..b9792833 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def @@ -65,6 +65,7 @@ MVK_DEVICE_FEATURE_EXTN(FragmentShaderBarycentric, FRAGMENT_SHADER_BARYCENTRI 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(ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, EXT, 3) 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 acf6670f..b08f6741 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -698,6 +698,9 @@ void MVKInstance::initProcAddrs() { ADD_DVC_EXT_ENTRY_POINT(vkReleaseSwapchainImagesEXT, EXT_SWAPCHAIN_MAINTENANCE_1); ADD_DVC_EXT_ENTRY_POINT(vkGetRefreshCycleDurationGOOGLE, GOOGLE_DISPLAY_TIMING); ADD_DVC_EXT_ENTRY_POINT(vkGetPastPresentationTimingGOOGLE, GOOGLE_DISPLAY_TIMING); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetLogicOpEXT, EXT_EXTENDED_DYNAMIC_STATE_2); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetPatchControlPointsEXT, EXT_EXTENDED_DYNAMIC_STATE_2); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetLogicOpEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); } void MVKInstance::logVersions() { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index c7f67db1..68e10dd8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -232,8 +232,13 @@ enum MVKRenderStateType { DepthTestEnable, DepthWriteEnable, FrontFace, + LogicOp, + LogicOpEnable, + PatchControlPoints, PolygonMode, + PrimitiveRestartEnable, PrimitiveTopology, + RasterizerDiscardEnable, SampleLocations, Scissors, StencilCompareMask, @@ -273,9 +278,6 @@ public: /** Returns whether this pipeline has tessellation shaders. */ bool isTessellationPipeline() { return _tessInfo.patchControlPoints > 0; } - /** Returns the number of input tessellation patch control points. */ - uint32_t getInputControlPointCount() { return _tessInfo.patchControlPoints; } - /** Returns the number of output tessellation patch control points. */ uint32_t getOutputControlPointCount() { return _outputControlPointCount; } @@ -351,6 +353,8 @@ public: ~MVKGraphicsPipeline() override; protected: + friend class MVKGraphicsPipelineCommandEncoderState; + typedef MVKSmallVector SPIRVShaderOutputs; typedef MVKSmallVector SPIRVShaderInputs; @@ -414,10 +418,10 @@ protected: id _mtlPipelineState = nil; float _blendConstants[4] = {}; - VkPrimitiveTopology _vkPrimitiveTopology; MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount; MVKShaderImplicitRezBinding _viewRangeBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex; + VkPrimitiveTopology _vkPrimitiveTopology; uint32_t _outputControlPointCount; uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index f41077c8..e361f1ea 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -294,17 +294,17 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage) cmdEncoder->_depthStencilState.setDepthStencilState(_depthStencilInfo); // Rasterization - 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); + cmdEncoder->_renderingState.setPrimitiveTopology(_vkPrimitiveTopology, false); + cmdEncoder->_renderingState.setBlendConstants(_blendConstants, false); + cmdEncoder->_renderingState.setStencilReferenceValues(_depthStencilInfo); + cmdEncoder->_renderingState.setViewports(_viewports.contents(), 0, false); + cmdEncoder->_renderingState.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 ); + cmdEncoder->_renderingState.setCullMode(_rasterInfo.cullMode, false); + cmdEncoder->_renderingState.setFrontFace(_rasterInfo.frontFace, false); + cmdEncoder->_renderingState.setPolygonMode(_rasterInfo.polygonMode, false); + cmdEncoder->_renderingState.setDepthBias(_rasterInfo); + cmdEncoder->_renderingState.setDepthClipEnable( !_rasterInfo.depthClampEnable, false ); } break; } @@ -497,8 +497,13 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, // Blending - must ignore allowed bad pColorBlendState pointer if rasterization disabled or no color attachments if (_isRasterizingColor && pCreateInfo->pColorBlendState) { mvkCopy(_blendConstants, pCreateInfo->pColorBlendState->blendConstants, 4); + + // Metal does not support blending with logic operations. + if (pCreateInfo->pColorBlendState->logicOpEnable && pCreateInfo->pColorBlendState->logicOp != VK_LOGIC_OP_COPY) { + setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support blending using logic operations.")); + } } else { - float defaultBlendConstants[4] = { 0, 0.0, 0.0, 1.0 }; + static float defaultBlendConstants[4] = { 0, 0.0, 0.0, 1.0 }; mvkCopy(_blendConstants, defaultBlendConstants, 4); } @@ -507,6 +512,14 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, ? pCreateInfo->pInputAssemblyState->topology : VK_PRIMITIVE_TOPOLOGY_POINT_LIST); + // In Metal, primitive restart cannot be disabled. + // Just issue warning here, as it is very likely the app is not actually expecting + // to use primitive restart at all, and is just setting this as a "just-in-case", + // and forcing an error here would be unexpected to the app (including CTS). + if (pCreateInfo->pInputAssemblyState && !pCreateInfo->pInputAssemblyState->primitiveRestartEnable) { + reportWarning(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateGraphicsPipeline(): Metal does not support disabling primitive restart."); + } + // Rasterization _hasRasterInfo = mvkSetOrClear(&_rasterInfo, pCreateInfo->pRasterizationState); if (_hasRasterInfo) { @@ -548,6 +561,7 @@ static MVKRenderStateType getRenderStateType(VkDynamicState 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_BIAS_ENABLE: return DepthBiasEnable; 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; @@ -556,9 +570,13 @@ static MVKRenderStateType getRenderStateType(VkDynamicState vkDynamicState) { 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_LOGIC_OP_EXT: return LogicOp; + case VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT: return LogicOpEnable; + case VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT: return PatchControlPoints; case VK_DYNAMIC_STATE_POLYGON_MODE_EXT: return PolygonMode; + case VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE: return PrimitiveRestartEnable; case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY: return PrimitiveTopology; - case VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT: return SampleLocations; + case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE: return RasterizerDiscardEnable; 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; @@ -579,12 +597,12 @@ void MVKGraphicsPipeline::initDynamicState(const VkGraphicsPipelineCreateInfo* p if ( !pDS ) { return; } for (uint32_t i = 0; i < pDS->dynamicStateCount; i++) { - VkDynamicState vkDynState = pDS->pDynamicStates[i]; + auto dynStateType = getRenderStateType(pDS->pDynamicStates[i]); bool isDynamic = true; // Some dynamic states have other restrictions - switch (vkDynState) { - case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE: + switch (dynStateType) { + case VertexStride: 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; @@ -592,7 +610,7 @@ void MVKGraphicsPipeline::initDynamicState(const VkGraphicsPipelineCreateInfo* p break; } - if (isDynamic) { _dynamicState.enable(getRenderStateType(vkDynState)); } + if (isDynamic) { _dynamicState.enable(dynStateType); } } } @@ -1923,10 +1941,10 @@ bool MVKGraphicsPipeline::isRenderingPoints(const VkGraphicsPipelineCreateInfo* (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->polygonMode == VK_POLYGON_MODE_POINT))); } -// We disable rasterization if either rasterizerDiscard is enabled or the static cull mode dictates it. +// We disable rasterization if either static rasterizerDiscard is enabled or the static cull mode dictates it. bool MVKGraphicsPipeline::isRasterizationDisabled(const VkGraphicsPipelineCreateInfo* pCreateInfo) { return (pCreateInfo->pRasterizationState && - (pCreateInfo->pRasterizationState->rasterizerDiscardEnable || + ((pCreateInfo->pRasterizationState->rasterizerDiscardEnable && !isDynamicState(RasterizerDiscardEnable)) || ((pCreateInfo->pRasterizationState->cullMode == VK_CULL_MODE_FRONT_AND_BACK) && !isDynamicState(CullMode) && pCreateInfo->pInputAssemblyState && (mvkMTLPrimitiveTopologyClassFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology) == MTLPrimitiveTopologyClassTriangle)))); diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 944b81a6..f63ecf98 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -104,6 +104,7 @@ MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_extended_dynamic_state, EXT_EXTENDED_DYNAMIC_STATE, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_extended_dynamic_state2, EXT_EXTENDED_DYNAMIC_STATE_2, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0, 1.0) MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA, MVK_NA) diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index cd6d15bf..642ad040 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -2638,7 +2638,14 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetCullMode( MVKTraceVulkanCallEnd(); } -MVK_PUBLIC_VULKAN_STUB(vkCmdSetDepthBiasEnable, void, VkCommandBuffer, VkBool32) +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthBiasEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthBiasEnable) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetDepthBiasEnable, commandBuffer, depthBiasEnable); + MVKTraceVulkanCallEnd(); +} MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthBoundsTestEnable( VkCommandBuffer commandBuffer, @@ -2695,7 +2702,14 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetFrontFace( MVKTraceVulkanCallEnd(); } -MVK_PUBLIC_VULKAN_STUB(vkCmdSetPrimitiveRestartEnable, void, VkCommandBuffer, VkBool32) +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPrimitiveRestartEnable( + VkCommandBuffer commandBuffer, + VkBool32 primitiveRestartEnable) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetPrimitiveRestartEnable, commandBuffer, primitiveRestartEnable); + MVKTraceVulkanCallEnd(); +} MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPrimitiveTopology( VkCommandBuffer commandBuffer, @@ -2706,7 +2720,14 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPrimitiveTopology( MVKTraceVulkanCallEnd(); } -MVK_PUBLIC_VULKAN_STUB(vkCmdSetRasterizerDiscardEnable, void, VkCommandBuffer, VkBool32) +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetRasterizerDiscardEnable( + VkCommandBuffer commandBuffer, + VkBool32 rasterizerDiscardEnable) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetRasterizerDiscardEnable, commandBuffer, rasterizerDiscardEnable); + MVKTraceVulkanCallEnd(); +} MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetScissorWithCount( VkCommandBuffer commandBuffer, @@ -2842,7 +2863,6 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetPrivateData( } - #pragma mark - #pragma mark VK_KHR_bind_memory2 extension @@ -3607,6 +3627,45 @@ MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdSetStencilTestEnable, EXT); MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdSetViewportWithCount, EXT); +#pragma mark - +#pragma mark VK_EXT_extended_dynamic_state2 +MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdSetDepthBiasEnable, EXT); + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLogicOpEXT( + VkCommandBuffer commandBuffer, + VkLogicOp logicOp) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetLogicOp, commandBuffer, logicOp); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPatchControlPointsEXT( + VkCommandBuffer commandBuffer, + uint32_t patchControlPoints) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetPatchControlPoints, commandBuffer, patchControlPoints); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdSetPrimitiveRestartEnable, EXT); +MVK_PUBLIC_VULKAN_CORE_ALIAS(vkCmdSetRasterizerDiscardEnable, EXT); + + +#pragma mark - +#pragma mark VK_EXT_extended_dynamic_state3 + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLogicOpEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 logicOpEnable) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetLogicOpEnable, commandBuffer, logicOpEnable); + MVKTraceVulkanCallEnd(); +} + + #pragma mark - #pragma mark VK_EXT_external_memory_host extension From 659b1cecd798aac65a9084bab12e6774911dfabc Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 10 Oct 2023 13:58:08 -0400 Subject: [PATCH 4/5] VK_EXT_extended_dynamic_state fix build fail before Xcode 15. --- MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm | 4 ++++ MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 4 ++++ MoltenVK/MoltenVK/Utility/MVKFoundation.h | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 72db24d6..d01dc5ef 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -826,6 +826,10 @@ void MVKGraphicsResourcesCommandEncoderState::markDirty() { } } +#if !MVK_XCODE_15 +static const NSUInteger MTLAttributeStrideStatic = NSUIntegerMax; +#endif + void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { auto* pipeline = _cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index e361f1ea..6660e9b7 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -1348,6 +1348,10 @@ bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescripto return true; } +#if !MVK_XCODE_15 +static const NSUInteger MTLBufferLayoutStrideDynamic = NSUIntegerMax; +#endif + template bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index 8503b917..c729c153 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -386,8 +386,8 @@ static constexpr bool mvkVkComponentMappingsMatch(VkComponentMapping cm1, VkComp #pragma mark Math /** Rounds the value to nearest integer using half-to-even rounding. */ -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. +static inline double mvkRoundHalfToEven(const double val) { + return val - std::remainder(val, 1.0); // remainder() uses half-to-even rounding, but unfortunately isn't constexpr until C++23. } /** Returns whether the value will fit inside the numeric type. */ From eb7cfa1006adaf5d5baf2702c4d5d72af13bba3b Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 11 Oct 2023 11:37:50 -0400 Subject: [PATCH 5/5] Fixes based on VK_EXT_extended_dynamic_state code review. - Fix runtime failure on Metal versions that don't support dynamic attribute stride. - Add MVKCommandEncoder::encodeVertexAttributeBuffer() consolidation function. - Remove unnecessary validations that will be caught by Vulkan validation layers. - To reduce memory, remove command class and pools for rendering commands that are not supported, and perform no validation. - Document extension conformance limitations in MoltenVK_Runtime_UserGuide.md. --- Docs/MoltenVK_Runtime_UserGuide.md | 86 +++++++++++------ MoltenVK/MoltenVK/API/mvk_datatypes.h | 6 +- MoltenVK/MoltenVK/Commands/MVKCmdRendering.h | 93 ------------------- MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm | 88 ------------------ MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h | 3 + .../MoltenVK/Commands/MVKCommandBuffer.mm | 36 +++++++ .../Commands/MVKCommandEncoderState.mm | 64 +++---------- .../MoltenVK/Commands/MVKCommandTypePools.def | 5 - MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 10 -- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 2 +- MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 6 +- MoltenVK/MoltenVK/Vulkan/vulkan.mm | 5 - 12 files changed, 114 insertions(+), 290 deletions(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 79f3f1a5..080b4d0c 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -312,7 +312,8 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_16bit_storage` - `VK_KHR_8bit_storage` - `VK_KHR_bind_memory2` -- `VK_KHR_buffer_device_address` *(requires GPU Tier 2 argument buffers support)* +- `VK_KHR_buffer_device_address` + - *Requires GPU Tier 2 argument buffers support.* - `VK_KHR_copy_commands2` - `VK_KHR_create_renderpass2` - `VK_KHR_dedicated_allocation` @@ -322,7 +323,8 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_device_group_creation` - `VK_KHR_driver_properties` - `VK_KHR_dynamic_rendering` -- `VK_KHR_fragment_shader_barycentric` *(requires Metal 2.2 on Mac or Metal 2.3 on iOS)* +- `VK_KHR_fragment_shader_barycentric` + - *Requires Metal 2.2 on Mac or Metal 2.3 on iOS.* - `VK_KHR_get_memory_requirements2` - `VK_KHR_get_physical_device_properties2` - `VK_KHR_get_surface_capabilities2` @@ -337,14 +339,16 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_portability_subset` - `VK_KHR_push_descriptor` - `VK_KHR_relaxed_block_layout` -- `VK_KHR_sampler_mirror_clamp_to_edge` *(requires a Mac GPU or Apple family 7 GPU)* +- `VK_KHR_sampler_mirror_clamp_to_edge` + - *Requires a Mac GPU or Apple family 7 GPU.* - `VK_KHR_sampler_ycbcr_conversion` - `VK_KHR_separate_depth_stencil_layouts` - `VK_KHR_shader_draw_parameters` - `VK_KHR_shader_float_controls` - `VK_KHR_shader_float16_int8` - `VK_KHR_shader_non_semantic_info` -- `VK_KHR_shader_subgroup_extended_types` *(requires Metal 2.1 on Mac or Metal 2.2 and Apple family 4 on iOS)* +- `VK_KHR_shader_subgroup_extended_types` + - *Requires Metal 2.1 on Mac or Metal 2.2 and Apple family 4 on iOS.* - `VK_KHR_spirv_1_4` - `VK_KHR_storage_buffer_storage_class` - `VK_KHR_surface` @@ -354,55 +358,78 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_KHR_timeline_semaphore` - `VK_KHR_uniform_buffer_standard_layout` - `VK_KHR_variable_pointers` -- `VK_EXT_4444_formats` *(requires 16-bit formats and either native texture swizzling or manual swizzling to be enabled)* -- `VK_EXT_buffer_device_address` *(requires GPU Tier 2 argument buffers support)* -- `VK_EXT_calibrated_timestamps` *(requires Metal 2.2)* +- `VK_EXT_4444_formats` + - *Requires 16-bit formats and either native texture swizzling or manual swizzling to be enabled.* +- `VK_EXT_buffer_device_address` + - *Requires GPU Tier 2 argument buffers support.* +- `VK_EXT_calibrated_timestamps` + - *Requires Metal 2.2.* - `VK_EXT_debug_marker` - `VK_EXT_debug_report` - `VK_EXT_debug_utils` -- `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 for `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`)* +- `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 for `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`.* - `VK_EXT_extended_dynamic_state2` + - *Primitive restart is always enabled, as Metal does not support disabling it (`VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT`).* - `VK_EXT_external_memory_host` -- `VK_EXT_fragment_shader_interlock` *(requires Metal 2.0 and Raster Order Groups)* +- `VK_EXT_fragment_shader_interlock` + - *Requires Metal 2.0 and Raster Order Groups.* - `VK_EXT_host_query_reset` - `VK_EXT_image_robustness` - `VK_EXT_inline_uniform_block` -- `VK_EXT_memory_budget` *(requires Metal 2.0)* +- `VK_EXT_memory_budget` + - *Requires Metal 2.0.* - `VK_EXT_metal_objects` - `VK_EXT_metal_surface` - `VK_EXT_pipeline_creation_cache_control` - `VK_EXT_pipeline_creation_feedback` -- `VK_EXT_post_depth_coverage` *(iOS and macOS, requires family 4 (A11) or better Apple GPU)* +- `VK_EXT_post_depth_coverage` + - *iOS and macOS, requires family 4 (A11) or better Apple GPU.* - `VK_EXT_private_data ` - `VK_EXT_robustness2` - `VK_EXT_sample_locations` - `VK_EXT_scalar_block_layout` - `VK_EXT_separate_stencil_usage` -- `VK_EXT_shader_atomic_float` *(requires Metal 3.0)* -- `VK_EXT_shader_demote_to_helper_invocation` *(requires Metal Shading Language 2.3)* -- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)* -- `VK_EXT_shader_subgroup_ballot` *(requires Mac GPU family 2 or Apple GPU family 4)* -- `VK_EXT_shader_subgroup_vote` *(requires Mac GPU family 2 or Apple GPU family 4)* +- `VK_EXT_shader_atomic_float` + - *Requires Metal 3.0.* +- `VK_EXT_shader_demote_to_helper_invocation` + - *Requires Metal Shading Language 2.3.* +- `VK_EXT_shader_stencil_export` + - *Requires Mac GPU family 2 or iOS GPU family 5.* +- `VK_EXT_shader_subgroup_ballot` + - *Requires Mac GPU family 2 or Apple GPU family 4.* +- `VK_EXT_shader_subgroup_vote` + - *Requires Mac GPU family 2 or Apple GPU family 4.* - `VK_EXT_shader_viewport_index_layer` -- `VK_EXT_subgroup_size_control` *(requires Metal 2.1 on Mac or Metal 2.2 and Apple family 4 on iOS)* +- `VK_EXT_subgroup_size_control` + - *Requires Metal 2.1 on Mac or Metal 2.2 and Apple family 4 on iOS.* - `VK_EXT_surface_maintenance1` - `VK_EXT_swapchain_colorspace` - `VK_EXT_swapchain_maintenance1` - `VK_EXT_vertex_attribute_divisor` -- `VK_EXT_texel_buffer_alignment` *(requires Metal 2.0)* -- `VK_EXT_texture_compression_astc_hdr` *(iOS and macOS, requires family 6 (A13) or better Apple GPU)* -- `VK_MVK_ios_surface` *(iOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)* -- `VK_MVK_macos_surface` *(macOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)* +- `VK_EXT_texel_buffer_alignment` + - *Requires Metal 2.0.* +- `VK_EXT_texture_compression_astc_hdr` + - *iOS and macOS, requires family 6 (A13) or better Apple GPU.* +- `VK_MVK_ios_surface` + - *Obsolete. Use `VK_EXT_metal_surface` instead.* +- `VK_MVK_macos_surface` + - *Obsolete. Use `VK_EXT_metal_surface` instead.* - `VK_AMD_gpu_shader_half_float` - `VK_AMD_negative_viewport_height` -- `VK_AMD_shader_image_load_store_lod` *(requires Apple GPU)* -- `VK_AMD_shader_trinary_minmax` *(requires Metal 2.1)* -- `VK_IMG_format_pvrtc` *(requires Apple GPU)* +- `VK_AMD_shader_image_load_store_lod` + - *Requires Apple GPU.* +- `VK_AMD_shader_trinary_minmax` + - *Requires Metal 2.1.* +- `VK_IMG_format_pvrtc` + - *Requires Apple GPU.* - `VK_INTEL_shader_integer_functions2` -- `VK_NV_fragment_shader_barycentric` *(requires Metal 2.2 on Mac or Metal 2.3 on iOS)* +- `VK_NV_fragment_shader_barycentric` + - *Requires Metal 2.2 on Mac or Metal 2.3 on iOS.* - `VK_NV_glsl_shader` In order to visibly display your content on *macOS*, *iOS*, or *tvOS*, you must enable the @@ -624,6 +651,8 @@ Known **MoltenVK** Limitations ------------------------------ This section documents the known limitations in this version of **MoltenVK**. + +- See [above](#interaction) for known limitations for specific Vulkan extensions. - On *macOS* versions prior to *macOS 10.15.6*, native host-coherent image device memory is not available. Because of this, changes made to `VkImage VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` device memory by the CPU @@ -647,4 +676,3 @@ This section documents the known limitations in this version of **MoltenVK**. use the *Vulkan Loader and Layers* from the *[Vulkan SDK](https://vulkan.lunarg.com/sdk/home)*. Refer to the *Vulkan SDK [Getting Started](https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html)* document for more info. - diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h index 4bbed323..eabb5aa3 100644 --- a/MoltenVK/MoltenVK/API/mvk_datatypes.h +++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h @@ -378,13 +378,13 @@ MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkRe #endif /** Returns the Metal MTLViewport corresponding to the specified Vulkan VkViewport. */ -MTLViewport mvkMTLViewportFromVkViewport(const VkViewport vkViewport); +MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport); /** Returns the Metal MTLScissorRect corresponding to the specified Vulkan VkRect2D. */ -MTLScissorRect mvkMTLScissorRectFromVkRect2D(const VkRect2D vkRect); +MTLScissorRect mvkMTLScissorRectFromVkRect2D(VkRect2D vkRect); /** Returns the Vulkan VkRect2D corresponding to the specified Metal MTLScissorRect. */ -VkRect2D mvkVkRect2DFromMTLScissorRect(const MTLScissorRect mtlScissorRect); +VkRect2D mvkVkRect2DFromMTLScissorRect(MTLScissorRect mtlScissorRect); /** Returns the Metal MTLCompareFunction corresponding to the specified Vulkan VkCompareOp, */ MTLCompareFunction mvkMTLCompareFunctionFromVkCompareOp(VkCompareOp vkOp); diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h index 2b11ae8e..fc67422e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h @@ -267,25 +267,6 @@ typedef MVKCmdSetScissor<1> MVKCmdSetScissor1; typedef MVKCmdSetScissor MVKCmdSetScissorMulti; -#pragma mark - -#pragma mark MVKCmdSetLineWidth - -/** Vulkan command to set the line width. */ -class MVKCmdSetLineWidth : public MVKCommand { - -public: - VkResult setContent(MVKCommandBuffer* cmdBuff, - float lineWidth); - - void encode(MVKCommandEncoder* cmdEncoder) override; - -protected: - MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; - - float _lineWidth; -}; - - #pragma mark - #pragma mark MVKCmdSetDepthBias @@ -347,40 +328,6 @@ protected: }; -#pragma mark - -#pragma mark MVKCmdSetLogicOp - -/** Vulkan command to dynamically set the blending logic operation. */ -class MVKCmdSetLogicOp : public MVKCommand { - -public: - VkResult setContent(MVKCommandBuffer* cmdBuff, - VkLogicOp logicOp); - - void encode(MVKCommandEncoder* cmdEncoder) override; - -protected: - MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; -}; - - -#pragma mark - -#pragma mark MVKCmdSetLogicOpEnable - -/** Vulkan command to dynamically enable or disable the blending logic operation. */ -class MVKCmdSetLogicOpEnable : public MVKCommand { - -public: - VkResult setContent(MVKCommandBuffer* cmdBuff, - VkBool32 logicOpEnable); - - void encode(MVKCommandEncoder* cmdEncoder) override; - -protected: - MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; -}; - - #pragma mark - #pragma mark MVKCmdSetDepthTestEnable @@ -438,46 +385,6 @@ protected: }; -#pragma mark - -#pragma mark MVKCmdSetDepthBounds - -/** Vulkan command to set depth bounds. */ -class MVKCmdSetDepthBounds : public MVKCommand { - -public: - VkResult setContent(MVKCommandBuffer* cmdBuff, - float minDepthBounds, - float maxDepthBounds); - - void encode(MVKCommandEncoder* cmdEncoder) override; - -protected: - MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; - - float _minDepthBounds; - float _maxDepthBounds; -}; - - -#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 diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm index 33078a02..1aa4aa5c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm @@ -285,24 +285,6 @@ template class MVKCmdSetScissor<1>; template class MVKCmdSetScissor; -#pragma mark - -#pragma mark MVKCmdSetLineWidth - -VkResult MVKCmdSetLineWidth::setContent(MVKCommandBuffer* cmdBuff, - float lineWidth) { - _lineWidth = lineWidth; - - // Validate - if (_lineWidth != 1.0 || cmdBuff->getDevice()->_enabledFeatures.wideLines) { - return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdSetLineWidth(): The current device does not support wide lines."); - } - - return VK_SUCCESS; -} - -void MVKCmdSetLineWidth::encode(MVKCommandEncoder* cmdEncoder) {} - - #pragma mark - #pragma mark MVKCmdSetDepthBias @@ -352,38 +334,6 @@ void MVKCmdSetBlendConstants::encode(MVKCommandEncoder* cmdEncoder) { } -#pragma mark - -#pragma mark MVKCmdSetLogicOp - -VkResult MVKCmdSetLogicOp::setContent(MVKCommandBuffer* cmdBuff, - VkLogicOp logicOp) { - // Validate - if (logicOp != VK_LOGIC_OP_COPY) { - return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support blending using logic operations."); - } - - return VK_SUCCESS; -} - -void MVKCmdSetLogicOp::encode(MVKCommandEncoder* cmdEncoder) {} - - -#pragma mark - -#pragma mark MVKCmdSetLogicOpEnable - -VkResult MVKCmdSetLogicOpEnable::setContent(MVKCommandBuffer* cmdBuff, - VkBool32 logicOpEnable) { - // Validate - if (logicOpEnable) { - return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support blending using logic operations."); - } - - return VK_SUCCESS; -} - -void MVKCmdSetLogicOpEnable::encode(MVKCommandEncoder* cmdEncoder) {} - - #pragma mark - #pragma mark MVKCmdSetDepthTestEnable @@ -426,44 +376,6 @@ void MVKCmdSetDepthCompareOp::encode(MVKCommandEncoder* cmdEncoder) { } -#pragma mark - -#pragma mark MVKCmdSetDepthBounds - -VkResult MVKCmdSetDepthBounds::setContent(MVKCommandBuffer* cmdBuff, - float minDepthBounds, - float maxDepthBounds) { - _minDepthBounds = minDepthBounds; - _maxDepthBounds = maxDepthBounds; - - // Validate - if (cmdBuff->getDevice()->_enabledFeatures.depthBounds) { - return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdSetDepthBounds(): The current device does not support setting depth bounds."); - } - - return VK_SUCCESS; -} - -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 diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 94f4585c..39580131 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -358,6 +358,9 @@ public: /** Returns the push constants associated with the specified shader stage. */ MVKPushConstantsCommandEncoderState* getPushConstants(VkShaderStageFlagBits shaderStage); + /** Encode the buffer binding as a vertex attribute buffer. */ + void encodeVertexAttributeBuffer(MVKMTLBufferBinding& b, bool isDynamicStride); + /** * Copy bytes into the Metal encoder at a Metal vertex buffer index, and optionally indicate * that this binding might override a desriptor binding. If so, the descriptor binding will diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 55127489..9575bb76 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -919,6 +919,42 @@ void MVKCommandEncoder::setVertexBytes(id mtlEncoder, } } +void MVKCommandEncoder::encodeVertexAttributeBuffer(MVKMTLBufferBinding& b, bool isDynamicStride) { + if (_device->_pMetalFeatures->dynamicVertexStride) { +#if MVK_XCODE_15 + NSUInteger mtlStride = isDynamicStride ? b.stride : MTLAttributeStrideStatic; + if (b.isInline) { + [_mtlRenderEncoder setVertexBytes: b.mtlBytes + length: b.size + attributeStride: mtlStride + atIndex: b.index]; + } else if (b.justOffset) { + [_mtlRenderEncoder setVertexBufferOffset: b.offset + attributeStride: mtlStride + atIndex: b.index]; + } else { + [_mtlRenderEncoder setVertexBuffer: b.mtlBuffer + offset: b.offset + attributeStride: mtlStride + atIndex: b.index]; + } +#endif + } else { + if (b.isInline) { + [_mtlRenderEncoder setVertexBytes: b.mtlBytes + length: b.size + atIndex: b.index]; + } else if (b.justOffset) { + [_mtlRenderEncoder setVertexBufferOffset: b.offset + atIndex: b.index]; + } else { + [_mtlRenderEncoder setVertexBuffer: b.mtlBuffer + offset: b.offset + atIndex: b.index]; + } + } +} + void MVKCommandEncoder::setFragmentBytes(id mtlEncoder, const void* bytes, NSUInteger length, diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index d01dc5ef..35f0b6e8 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -464,7 +464,7 @@ void MVKRenderingCommandEncoderState::encodeImpl(uint32_t stage) { [rendEnc setDepthBias: 0 slopeScale: 0 clamp: 0]; } } - if (isDirty(DepthClipEnable) && getDevice()->_enabledFeatures.depthClamp) { + if (isDirty(DepthClipEnable) && _cmdEncoder->_pDeviceFeatures->depthClamp) { [rendEnc setDepthClipMode: getContent(DepthClipEnable)]; } @@ -876,40 +876,19 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { // 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)) { - 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 { - [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer - offset: b.offset -#if MVK_XCODE_15 - attributeStride: mtlStride -#endif - atIndex: b.index]; - } + cmdEncoder->encodeVertexAttributeBuffer(b, isDynamicVertexStride); - // Add any translated vertex bindings for this binding + // Add any translated vertex bindings for this binding + if ( !b.isInline ) { auto xltdVtxBindings = pipeline->getTranslatedVertexBindings(); for (auto& xltdBind : xltdVtxBindings) { 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)]; + MVKMTLBufferBinding bx = { + .mtlBuffer = b.mtlBuffer, + .offset = b.offset + xltdBind.translationOffset, + .stride = b.stride, + .index = static_cast(pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding)) }; + cmdEncoder->encodeVertexAttributeBuffer(bx, isDynamicVertexStride); } } } @@ -970,28 +949,7 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) { if (forTessellation && stage == kMVKGraphicsStageRasterization) { encodeBindings(kMVKShaderStageTessEval, "tessellation evaluation", fullImageViewSwizzle, [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 { - [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer - offset: b.offset -#if MVK_XCODE_15 - attributeStride: mtlStride -#endif - atIndex: b.index]; - } + cmdEncoder->encodeVertexAttributeBuffer(b, isDynamicVertexStride); }, [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKArrayRef s)->void { cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def index 880f5551..65683f84 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def +++ b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def @@ -86,17 +86,12 @@ MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindDescriptorSetsStatic, 1, 4) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BindDescriptorSetsDynamic, 4) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(SetViewport, 1) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(SetScissor, 1) -MVK_CMD_TYPE_POOL(SetLineWidth) MVK_CMD_TYPE_POOL(SetBlendConstants) -MVK_CMD_TYPE_POOL(SetLogicOp) -MVK_CMD_TYPE_POOL(SetLogicOpEnable) MVK_CMD_TYPE_POOL(SetDepthBias) MVK_CMD_TYPE_POOL(SetDepthBiasEnable) 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) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 6660e9b7..cb0acac2 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -497,11 +497,6 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, // Blending - must ignore allowed bad pColorBlendState pointer if rasterization disabled or no color attachments if (_isRasterizingColor && pCreateInfo->pColorBlendState) { mvkCopy(_blendConstants, pCreateInfo->pColorBlendState->blendConstants, 4); - - // Metal does not support blending with logic operations. - if (pCreateInfo->pColorBlendState->logicOpEnable && pCreateInfo->pColorBlendState->logicOp != VK_LOGIC_OP_COPY) { - setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support blending using logic operations.")); - } } else { static float defaultBlendConstants[4] = { 0, 0.0, 0.0, 1.0 }; mvkCopy(_blendConstants, defaultBlendConstants, 4); @@ -522,11 +517,6 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, // Rasterization _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.")); - } - } // Must run after _isRasterizing and _dynamicState are populated initCustomSamplePositions(pCreateInfo); diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index c729c153..f5820721 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -392,7 +392,7 @@ static inline double mvkRoundHalfToEven(const double val) { /** Returns whether the value will fit inside the numeric type. */ template -static constexpr const bool mvkFits(const Tval& val) { +static constexpr bool mvkFits(const Tval& val) { return val <= std::numeric_limits::max(); } diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index ef3cf1ca..7644f49c 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -583,7 +583,7 @@ MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkRe } #endif -MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(const VkViewport vkViewport) { +MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport) { return { .originX = vkViewport.x, .originY = vkViewport.y, @@ -594,7 +594,7 @@ MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(const VkViewport vkVi }; } -MVK_PUBLIC_SYMBOL MTLScissorRect mvkMTLScissorRectFromVkRect2D(const VkRect2D vkRect) { +MVK_PUBLIC_SYMBOL MTLScissorRect mvkMTLScissorRectFromVkRect2D(VkRect2D vkRect) { return { .x = (NSUInteger)max(vkRect.offset.x, 0), .y = (NSUInteger)max(vkRect.offset.y, 0), @@ -603,7 +603,7 @@ MVK_PUBLIC_SYMBOL MTLScissorRect mvkMTLScissorRectFromVkRect2D(const VkRect2D vk }; } -MVK_PUBLIC_SYMBOL VkRect2D mvkVkRect2DFromMTLScissorRect(const MTLScissorRect mtlScissorRect) { +MVK_PUBLIC_SYMBOL VkRect2D mvkVkRect2DFromMTLScissorRect(MTLScissorRect mtlScissorRect) { return { .offset = { .x = (int32_t)mtlScissorRect.x, .y = (int32_t)mtlScissorRect.y }, diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 642ad040..d1c6fbbe 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -1466,7 +1466,6 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLineWidth( float lineWidth) { MVKTraceVulkanCallStart(); - MVKAddCmd(SetLineWidth, commandBuffer, lineWidth); MVKTraceVulkanCallEnd(); } @@ -1496,7 +1495,6 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthBounds( float maxDepthBounds) { MVKTraceVulkanCallStart(); - MVKAddCmd(SetDepthBounds, commandBuffer, minDepthBounds, maxDepthBounds); MVKTraceVulkanCallEnd(); } @@ -2652,7 +2650,6 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthBoundsTestEnable( VkBool32 depthBoundsTestEnable) { MVKTraceVulkanCallStart(); - MVKAddCmd(SetDepthBoundsTestEnable, commandBuffer, depthBoundsTestEnable); MVKTraceVulkanCallEnd(); } @@ -3636,7 +3633,6 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLogicOpEXT( VkLogicOp logicOp) { MVKTraceVulkanCallStart(); - MVKAddCmd(SetLogicOp, commandBuffer, logicOp); MVKTraceVulkanCallEnd(); } @@ -3661,7 +3657,6 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLogicOpEnableEXT( VkBool32 logicOpEnable) { MVKTraceVulkanCallStart(); - MVKAddCmd(SetLogicOpEnable, commandBuffer, logicOpEnable); MVKTraceVulkanCallEnd(); }