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).
This commit is contained in:
Bill Hollings 2023-10-05 17:33:01 -04:00
parent a06827c6fb
commit 3c75e114dd
24 changed files with 1095 additions and 772 deletions

View File

@ -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, - `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 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)* 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_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_host_query_reset`

View File

@ -378,10 +378,13 @@ MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkRe
#endif #endif
/** Returns the Metal MTLViewport corresponding to the specified Vulkan VkViewport. */ /** 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. */ /** 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, */ /** Returns the Metal MTLCompareFunction corresponding to the specified Vulkan VkCompareOp, */
MTLCompareFunction mvkMTLCompareFunctionFromVkCompareOp(VkCompareOp vkOp); MTLCompareFunction mvkMTLCompareFunctionFromVkCompareOp(VkCompareOp vkOp);

View File

@ -151,6 +151,7 @@ typedef struct {
MTLArgumentBuffersTier argumentBuffersTier; /**< The argument buffer tier available on this device, as a Metal enumeration. */ 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. */ 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. */ 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; } MVKPhysicalDeviceMetalFeatures;
/** /**

View File

@ -37,10 +37,12 @@ class MVKCmdBindVertexBuffers : public MVKCommand {
public: public:
VkResult setContent(MVKCommandBuffer* cmdBuff, VkResult setContent(MVKCommandBuffer* cmdBuff,
uint32_t startBinding, uint32_t firstBinding,
uint32_t bindingCount, uint32_t bindingCount,
const VkBuffer* pBuffers, const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets); const VkDeviceSize* pOffsets,
const VkDeviceSize* pSizes,
const VkDeviceSize* pStrides);
void encode(MVKCommandEncoder* cmdEncoder) override; void encode(MVKCommandEncoder* cmdEncoder) override;

View File

@ -30,20 +30,23 @@
template <size_t N> template <size_t N>
VkResult MVKCmdBindVertexBuffers<N>::setContent(MVKCommandBuffer* cmdBuff, VkResult MVKCmdBindVertexBuffers<N>::setContent(MVKCommandBuffer* cmdBuff,
uint32_t startBinding, uint32_t firstBinding,
uint32_t bindingCount, uint32_t bindingCount,
const VkBuffer* pBuffers, const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets) { const VkDeviceSize* pOffsets,
const VkDeviceSize* pSizes,
const VkDeviceSize* pStrides) {
MVKDevice* mvkDvc = cmdBuff->getDevice(); MVKDevice* mvkDvc = cmdBuff->getDevice();
_bindings.clear(); // Clear for reuse _bindings.clear(); // Clear for reuse
_bindings.reserve(bindingCount); _bindings.reserve(bindingCount);
MVKMTLBufferBinding b; MVKMTLBufferBinding b;
for (uint32_t bindIdx = 0; bindIdx < bindingCount; bindIdx++) { for (uint32_t bindIdx = 0; bindIdx < bindingCount; bindIdx++) {
MVKBuffer* mvkBuffer = (MVKBuffer*)pBuffers[bindIdx]; MVKBuffer* mvkBuffer = (MVKBuffer*)pBuffers[bindIdx];
b.index = mvkDvc->getMetalBufferIndexForVertexAttributeBinding(startBinding + bindIdx); b.index = mvkDvc->getMetalBufferIndexForVertexAttributeBinding(firstBinding + bindIdx);
b.mtlBuffer = mvkBuffer->getMTLBuffer(); b.mtlBuffer = mvkBuffer->getMTLBuffer();
b.offset = mvkBuffer->getMTLBufferOffset() + pOffsets[bindIdx]; 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); _bindings.push_back(b);
} }
@ -296,13 +299,13 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {
uint32_t instanceCount = _instanceCount * viewCount; uint32_t instanceCount = _instanceCount * viewCount;
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance); cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) { if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType()
vertexStart: _firstVertex vertexStart: _firstVertex
vertexCount: _vertexCount vertexCount: _vertexCount
instanceCount: instanceCount instanceCount: instanceCount
baseInstance: _firstInstance]; baseInstance: _firstInstance];
} else { } else {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType()
vertexStart: _firstVertex vertexStart: _firstVertex
vertexCount: _vertexCount vertexCount: _vertexCount
instanceCount: instanceCount]; instanceCount: instanceCount];
@ -530,7 +533,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
uint32_t instanceCount = _instanceCount * viewCount; uint32_t instanceCount = _instanceCount * viewCount;
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance); cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) { if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType()
indexCount: _indexCount indexCount: _indexCount
indexType: (MTLIndexType)ibb.mtlIndexType indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer indexBuffer: ibb.mtlBuffer
@ -539,7 +542,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
baseVertex: _vertexOffset baseVertex: _vertexOffset
baseInstance: _firstInstance]; baseInstance: _firstInstance];
} else { } else {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType()
indexCount: _indexCount indexCount: _indexCount
indexType: (MTLIndexType)ibb.mtlIndexType indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer indexBuffer: ibb.mtlBuffer
@ -925,7 +928,7 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass();
} else { } else {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType()
indirectBuffer: mtlIndBuff indirectBuffer: mtlIndBuff
indirectBufferOffset: mtlIndBuffOfst]; indirectBufferOffset: mtlIndBuffOfst];
mtlIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawPrimitivesIndirectArguments) : _mtlIndirectBufferStride; mtlIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawPrimitivesIndirectArguments) : _mtlIndirectBufferStride;
@ -1312,7 +1315,7 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder, const MVKI
cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass();
} else { } else {
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _directCmdFirstInstance); cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _directCmdFirstInstance);
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_rasterizingState.getPrimitiveType()
indexType: (MTLIndexType)ibb.mtlIndexType indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer indexBuffer: ibb.mtlBuffer
indexBufferOffset: ibb.offset indexBufferOffset: ibb.offset

View File

@ -352,10 +352,64 @@ public:
protected: protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override; MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
float _red; float _blendConstants[4] = {};
float _green; };
float _blue;
float _alpha;
#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<MVKCommand>* 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<MVKCommand>* 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<MVKCommand>* 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<MVKCommand>* 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<MVKCommand>* 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<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
VkStencilFaceFlags _faceMask;
VkStencilOp _failOp;
VkStencilOp _passOp;
VkStencilOp _depthFailOp;
VkCompareOp _compareOp;
};
#pragma mark - #pragma mark -
#pragma mark MVKCmdSetStencilCompareMask #pragma mark MVKCmdSetStencilCompareMask
@ -446,10 +565,7 @@ protected:
#pragma mark - #pragma mark -
#pragma mark MVKCmdSetCullMode #pragma mark MVKCmdSetCullMode
/** /** Vulkan command to dynamically set the cull mode. */
* 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 { class MVKCmdSetCullMode : public MVKCommand {
public: public:
@ -461,17 +577,14 @@ public:
protected: protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override; MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
MTLCullMode _cullMode; VkCullModeFlags _cullMode;
}; };
#pragma mark - #pragma mark -
#pragma mark MVKCmdSetFrontFace #pragma mark MVKCmdSetFrontFace
/** /** Vulkan command to dynamically set the front facing winding order. */
* 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 { class MVKCmdSetFrontFace : public MVKCommand {
public: public:
@ -483,6 +596,25 @@ public:
protected: protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override; MVKCommandTypePool<MVKCommand>* 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<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
VkPrimitiveTopology _primitiveTopology;
}; };

View File

@ -278,7 +278,7 @@ VkResult MVKCmdSetViewport<N>::setContent(MVKCommandBuffer* cmdBuff,
template <size_t N> template <size_t N>
void MVKCmdSetViewport<N>::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdSetViewport<N>::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_viewportState.setViewports(_viewports.contents(), _firstViewport, true); cmdEncoder->_rasterizingState.setViewports(_viewports.contents(), _firstViewport, true);
} }
template class MVKCmdSetViewport<1>; template class MVKCmdSetViewport<1>;
@ -305,7 +305,7 @@ VkResult MVKCmdSetScissor<N>::setContent(MVKCommandBuffer* cmdBuff,
template <size_t N> template <size_t N>
void MVKCmdSetScissor<N>::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdSetScissor<N>::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_scissorState.setScissors(_scissors.contents(), _firstScissor, true); cmdEncoder->_rasterizingState.setScissors(_scissors.contents(), _firstScissor, true);
} }
template class MVKCmdSetScissor<1>; template class MVKCmdSetScissor<1>;
@ -345,9 +345,9 @@ VkResult MVKCmdSetDepthBias::setContent(MVKCommandBuffer* cmdBuff,
} }
void MVKCmdSetDepthBias::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdSetDepthBias::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_depthBiasState.setDepthBias(_depthBiasConstantFactor, cmdEncoder->_rasterizingState.setDepthBias(_depthBiasConstantFactor,
_depthBiasSlopeFactor, _depthBiasSlopeFactor,
_depthBiasClamp); _depthBiasClamp);
} }
@ -356,16 +356,54 @@ void MVKCmdSetDepthBias::encode(MVKCommandEncoder* cmdEncoder) {
VkResult MVKCmdSetBlendConstants::setContent(MVKCommandBuffer* cmdBuff, VkResult MVKCmdSetBlendConstants::setContent(MVKCommandBuffer* cmdBuff,
const float blendConst[4]) { const float blendConst[4]) {
_red = blendConst[0]; mvkCopy(_blendConstants, blendConst, 4);
_green = blendConst[1];
_blue = blendConst[2];
_alpha = blendConst[3];
return VK_SUCCESS; return VK_SUCCESS;
} }
void MVKCmdSetBlendConstants::encode(MVKCommandEncoder* cmdEncoder) { 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) {} void MVKCmdSetDepthBounds::encode(MVKCommandEncoder* cmdEncoder) {}
#pragma mark -
#pragma mark MVKCmdSetDepthBoundsTestEnable
VkResult MVKCmdSetDepthBoundsTestEnable::setContent(MVKCommandBuffer* cmdBuff,
VkBool32 depthBoundsTestEnable) {
_depthBoundsTestEnable = static_cast<bool>(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 -
#pragma mark MVKCmdSetStencilCompareMask #pragma mark MVKCmdSetStencilCompareMask
@ -436,7 +528,7 @@ VkResult MVKCmdSetStencilReference::setContent(MVKCommandBuffer* cmdBuff,
} }
void MVKCmdSetStencilReference::encode(MVKCommandEncoder* cmdEncoder) { 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, VkResult MVKCmdSetCullMode::setContent(MVKCommandBuffer* cmdBuff,
VkCullModeFlags cullMode) { VkCullModeFlags cullMode) {
switch (cullMode) { _cullMode = cullMode;
case VK_CULL_MODE_NONE: { return VK_SUCCESS;
_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) { void MVKCmdSetCullMode::encode(MVKCommandEncoder* cmdEncoder) {
[((id<MTLRenderCommandEncoder>)cmdEncoder->getMTLEncoder()) setCullMode:_cullMode]; cmdEncoder->_rasterizingState.setCullMode(_cullMode, true);
} }
@ -476,14 +551,25 @@ void MVKCmdSetCullMode::encode(MVKCommandEncoder* cmdEncoder) {
VkResult MVKCmdSetFrontFace::setContent(MVKCommandBuffer* cmdBuff, VkResult MVKCmdSetFrontFace::setContent(MVKCommandBuffer* cmdBuff,
VkFrontFace frontFace) { VkFrontFace frontFace) {
_frontFace = frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE _frontFace = frontFace;
? MTLWindingClockwise return VK_SUCCESS;
: MTLWindingCounterClockwise;
return VK_SUCCESS;
} }
void MVKCmdSetFrontFace::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdSetFrontFace::encode(MVKCommandEncoder* cmdEncoder) {
[((id<MTLRenderCommandEncoder>)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);
} }

View File

@ -1507,10 +1507,7 @@ void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
// Return to the previous rendering state on the next render activity // Return to the previous rendering state on the next render activity
cmdEncoder->_graphicsPipelineState.markDirty(); cmdEncoder->_graphicsPipelineState.markDirty();
cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->_depthStencilState.markDirty();
cmdEncoder->_stencilReferenceValueState.markDirty(); cmdEncoder->_rasterizingState.markDirty();
cmdEncoder->_depthBiasState.markDirty();
cmdEncoder->_viewportState.markDirty();
cmdEncoder->_scissorState.markDirty();
} }
template <size_t N> template <size_t N>

View File

@ -300,14 +300,11 @@ public:
/** Encodes an operation to signal an event to a status. */ /** Encodes an operation to signal an event to a status. */
void signalEvent(MVKEvent* mvkEvent, bool status); void signalEvent(MVKEvent* mvkEvent, bool status);
/** /** Clips the rect to ensure it fits inside the render area. */
* If a pipeline is currently bound, returns whether the current pipeline permits dynamic VkRect2D clipToRenderArea(VkRect2D rect);
* setting of the specified state. If no pipeline is currently bound, returns true.
*/
bool supportsDynamicState(VkDynamicState state);
/** Clips the scissor to ensure it fits inside the render area. */ /** 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. */ /** Called by each graphics draw command to establish any outstanding state just prior to performing the draw. */
void finalizeDrawState(MVKGraphicsStage stage); void finalizeDrawState(MVKGraphicsStage stage);
@ -437,35 +434,20 @@ public:
/** Tracks the current graphics pipeline bound to the encoder. */ /** Tracks the current graphics pipeline bound to the encoder. */
MVKPipelineCommandEncoderState _graphicsPipelineState; MVKPipelineCommandEncoderState _graphicsPipelineState;
/** Tracks the current graphics resources state of the encoder. */
MVKGraphicsResourcesCommandEncoderState _graphicsResourcesState;
/** Tracks the current compute pipeline bound to the encoder. */ /** Tracks the current compute pipeline bound to the encoder. */
MVKPipelineCommandEncoderState _computePipelineState; MVKPipelineCommandEncoderState _computePipelineState;
/** Tracks the current viewport state of the encoder. */ /** Tracks the current compute resources state of the encoder. */
MVKViewportCommandEncoderState _viewportState; MVKComputeResourcesCommandEncoderState _computeResourcesState;
/** 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 depth stencil state of the encoder. */ /** Tracks the current depth stencil state of the encoder. */
MVKDepthStencilCommandEncoderState _depthStencilState; MVKDepthStencilCommandEncoderState _depthStencilState;
/** Tracks the current stencil reference value state of the encoder. */ /** Tracks the current rasterizing states of the encoder. */
MVKStencilReferenceValueCommandEncoderState _stencilReferenceValueState; MVKRasterizingCommandEncoderState _rasterizingState;
/** 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;
/** The size of the threadgroup for the compute shader. */ /** The size of the threadgroup for the compute shader. */
MTLSize _mtlThreadgroupSize; MTLSize _mtlThreadgroupSize;

View File

@ -607,16 +607,12 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
_graphicsPipelineState.beginMetalRenderPass(); _graphicsPipelineState.beginMetalRenderPass();
_graphicsResourcesState.beginMetalRenderPass(); _graphicsResourcesState.beginMetalRenderPass();
_viewportState.beginMetalRenderPass(); _depthStencilState.beginMetalRenderPass();
_scissorState.beginMetalRenderPass(); _rasterizingState.beginMetalRenderPass();
_depthBiasState.beginMetalRenderPass();
_blendColorState.beginMetalRenderPass();
_vertexPushConstants.beginMetalRenderPass(); _vertexPushConstants.beginMetalRenderPass();
_tessCtlPushConstants.beginMetalRenderPass(); _tessCtlPushConstants.beginMetalRenderPass();
_tessEvalPushConstants.beginMetalRenderPass(); _tessEvalPushConstants.beginMetalRenderPass();
_fragmentPushConstants.beginMetalRenderPass(); _fragmentPushConstants.beginMetalRenderPass();
_depthStencilState.beginMetalRenderPass();
_stencilReferenceValueState.beginMetalRenderPass();
_occlusionQueryState.beginMetalRenderPass(); _occlusionQueryState.beginMetalRenderPass();
} }
@ -706,24 +702,23 @@ void MVKCommandEncoder::signalEvent(MVKEvent* mvkEvent, bool status) {
mvkEvent->encodeSignal(_mtlCmdBuffer, status); mvkEvent->encodeSignal(_mtlCmdBuffer, status);
} }
bool MVKCommandEncoder::supportsDynamicState(VkDynamicState state) { VkRect2D MVKCommandEncoder::clipToRenderArea(VkRect2D rect) {
MVKGraphicsPipeline* gpl = (MVKGraphicsPipeline*)_graphicsPipelineState.getPipeline();
return !gpl || gpl->supportsDynamicState(state); 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<uint32_t>(rect.offset.x, raLeft, max(raRight - 1, raLeft));
rect.offset.y = mvkClamp<uint32_t>(rect.offset.y, raBottom, max(raTop - 1, raBottom));
rect.extent.width = min<uint32_t>(rect.extent.width, raRight - rect.offset.x);
rect.extent.height = min<uint32_t>(rect.extent.height, raTop - rect.offset.y);
return rect;
} }
VkRect2D MVKCommandEncoder::clipToRenderArea(VkRect2D scissor) { MTLScissorRect MVKCommandEncoder::clipToRenderArea(MTLScissorRect scissor) {
return mvkMTLScissorRectFromVkRect2D(clipToRenderArea(mvkVkRect2DFromMTLScissorRect(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<int32_t>(scissor.extent.width, raRight - scissor.offset.x);
scissor.extent.height = min<int32_t>(scissor.extent.height, raTop - scissor.offset.y);
return scissor;
} }
void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) { void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) {
@ -733,16 +728,12 @@ void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) {
} }
_graphicsPipelineState.encode(stage); // Must do first..it sets others _graphicsPipelineState.encode(stage); // Must do first..it sets others
_graphicsResourcesState.encode(stage); // Before push constants, to allow them to override. _graphicsResourcesState.encode(stage); // Before push constants, to allow them to override.
_viewportState.encode(stage); _depthStencilState.encode(stage);
_scissorState.encode(stage); _rasterizingState.encode(stage);
_depthBiasState.encode(stage);
_blendColorState.encode(stage);
_vertexPushConstants.encode(stage); _vertexPushConstants.encode(stage);
_tessCtlPushConstants.encode(stage); _tessCtlPushConstants.encode(stage);
_tessEvalPushConstants.encode(stage); _tessEvalPushConstants.encode(stage);
_fragmentPushConstants.encode(stage); _fragmentPushConstants.encode(stage);
_depthStencilState.encode(stage);
_stencilReferenceValueState.encode(stage);
_occlusionQueryState.encode(stage); _occlusionQueryState.encode(stage);
} }
@ -831,16 +822,12 @@ void MVKCommandEncoder::endMetalRenderEncoding() {
_graphicsPipelineState.endMetalRenderPass(); _graphicsPipelineState.endMetalRenderPass();
_graphicsResourcesState.endMetalRenderPass(); _graphicsResourcesState.endMetalRenderPass();
_viewportState.endMetalRenderPass(); _depthStencilState.endMetalRenderPass();
_scissorState.endMetalRenderPass(); _rasterizingState.endMetalRenderPass();
_depthBiasState.endMetalRenderPass();
_blendColorState.endMetalRenderPass();
_vertexPushConstants.endMetalRenderPass(); _vertexPushConstants.endMetalRenderPass();
_tessCtlPushConstants.endMetalRenderPass(); _tessCtlPushConstants.endMetalRenderPass();
_tessEvalPushConstants.endMetalRenderPass(); _tessEvalPushConstants.endMetalRenderPass();
_fragmentPushConstants.endMetalRenderPass(); _fragmentPushConstants.endMetalRenderPass();
_depthStencilState.endMetalRenderPass();
_stencilReferenceValueState.endMetalRenderPass();
_occlusionQueryState.endMetalRenderPass(); _occlusionQueryState.endMetalRenderPass();
} }
@ -1131,39 +1118,35 @@ void MVKCommandEncoder::finishQueries() {
MVKCommandEncoder::MVKCommandEncoder(MVKCommandBuffer* cmdBuffer, MVKCommandEncoder::MVKCommandEncoder(MVKCommandBuffer* cmdBuffer,
MVKPrefillMetalCommandBuffersStyle prefillStyle) : MVKBaseDeviceObject(cmdBuffer->getDevice()), MVKPrefillMetalCommandBuffersStyle prefillStyle) : MVKBaseDeviceObject(cmdBuffer->getDevice()),
_cmdBuffer(cmdBuffer), _cmdBuffer(cmdBuffer),
_graphicsPipelineState(this), _graphicsPipelineState(this),
_computePipelineState(this), _graphicsResourcesState(this),
_viewportState(this), _computePipelineState(this),
_scissorState(this), _computeResourcesState(this),
_depthBiasState(this), _depthStencilState(this),
_blendColorState(this), _rasterizingState(this),
_depthStencilState(this), _vertexPushConstants(this, VK_SHADER_STAGE_VERTEX_BIT),
_stencilReferenceValueState(this), _tessCtlPushConstants(this, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
_graphicsResourcesState(this), _tessEvalPushConstants(this, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
_computeResourcesState(this), _fragmentPushConstants(this, VK_SHADER_STAGE_FRAGMENT_BIT),
_vertexPushConstants(this, VK_SHADER_STAGE_VERTEX_BIT), _computePushConstants(this, VK_SHADER_STAGE_COMPUTE_BIT),
_tessCtlPushConstants(this, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), _occlusionQueryState(this),
_tessEvalPushConstants(this, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), _prefillStyle(prefillStyle){
_fragmentPushConstants(this, VK_SHADER_STAGE_FRAGMENT_BIT),
_computePushConstants(this, VK_SHADER_STAGE_COMPUTE_BIT),
_occlusionQueryState(this),
_prefillStyle(prefillStyle){
_pDeviceFeatures = &_device->_enabledFeatures; _pDeviceFeatures = &_device->_enabledFeatures;
_pDeviceMetalFeatures = _device->_pMetalFeatures; _pDeviceMetalFeatures = _device->_pMetalFeatures;
_pDeviceProperties = _device->_pProperties; _pDeviceProperties = _device->_pProperties;
_pDeviceMemoryProperties = _device->_pMemoryProperties; _pDeviceMemoryProperties = _device->_pMemoryProperties;
_pActivatedQueries = nullptr; _pActivatedQueries = nullptr;
_mtlCmdBuffer = nil; _mtlCmdBuffer = nil;
_mtlRenderEncoder = nil; _mtlRenderEncoder = nil;
_mtlComputeEncoder = nil; _mtlComputeEncoder = nil;
_mtlComputeEncoderUse = kMVKCommandUseNone; _mtlComputeEncoderUse = kMVKCommandUseNone;
_mtlBlitEncoder = nil; _mtlBlitEncoder = nil;
_mtlBlitEncoderUse = kMVKCommandUseNone; _mtlBlitEncoderUse = kMVKCommandUseNone;
_pEncodingContext = nullptr; _pEncodingContext = nullptr;
_stageCountersMTLFence = nil; _stageCountersMTLFence = nil;
_flushCount = 0; _flushCount = 0;
} }
MVKCommandEncoder::~MVKCommandEncoder() { MVKCommandEncoder::~MVKCommandEncoder() {

View File

@ -21,6 +21,7 @@
#include "MVKMTLResourceBindings.h" #include "MVKMTLResourceBindings.h"
#include "MVKCommandResourceFactory.h" #include "MVKCommandResourceFactory.h"
#include "MVKDevice.h" #include "MVKDevice.h"
#include "MVKPipeline.h"
#include "MVKDescriptor.h" #include "MVKDescriptor.h"
#include "MVKSmallVector.h" #include "MVKSmallVector.h"
#include "MVKBitArray.h" #include "MVKBitArray.h"
@ -81,7 +82,7 @@ public:
/** /**
* If the content of this instance is dirty, marks this instance as no longer dirty * 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. * 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. * can override to leave this instance in a dirty state.
* Subclasses must override the encodeImpl() function to do the actual work. * Subclasses must override the encodeImpl() function to do the actual work.
*/ */
@ -96,8 +97,18 @@ public:
MVKCommandEncoderState(MVKCommandEncoder* cmdEncoder) : _cmdEncoder(cmdEncoder) {} MVKCommandEncoderState(MVKCommandEncoder* cmdEncoder) : _cmdEncoder(cmdEncoder) {}
protected: protected:
virtual void encodeImpl(uint32_t stage) = 0; enum StateScope {
Static = 0,
Dynamic,
Count
};
virtual void encodeImpl(uint32_t stage) = 0;
MVKDevice* getDevice(); MVKDevice* getDevice();
bool isDynamicState(MVKRenderStateType state);
template <typename T> T& getContent(T* iVarAry, MVKRenderStateType state) {
return iVarAry[isDynamicState(state) ? StateScope::Dynamic : StateScope::Static];
}
MVKCommandEncoder* _cmdEncoder; MVKCommandEncoder* _cmdEncoder;
bool _isDirty = false; 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<const VkViewport> 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<VkViewport, kMVKMaxViewportScissorCount> _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<const VkRect2D> 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<VkRect2D, kMVKMaxViewportScissorCount> _scissors, _dynamicScissors;
};
#pragma mark - #pragma mark -
#pragma mark MVKPushConstantsCommandEncoderState #pragma mark MVKPushConstantsCommandEncoderState
@ -226,16 +181,29 @@ public:
/** Sets the depth stencil state during pipeline binding. */ /** Sets the depth stencil state during pipeline binding. */
void setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo); void setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo);
/** /** Enables or disables depth testing, from explicit dynamic command. */
* Sets the stencil compare mask value of the indicated faces void setDepthTestEnable(VkBool32 depthTestEnable);
* to the specified value, from explicit dynamic command.
*/ /** 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); void setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t stencilCompareMask);
/** /** Sets the stencil write mask value of the indicated faces from explicit dynamic command. */
* Sets the stencil write mask value of the indicated faces
* to the specified value, from explicit dynamic command.
*/
void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t stencilWriteMask); void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t stencilWriteMask);
void beginMetalRenderPass() override; void beginMetalRenderPass() override;
@ -246,96 +214,105 @@ public:
protected: protected:
void encodeImpl(uint32_t stage) override; void encodeImpl(uint32_t stage) override;
void setStencilState(MVKMTLStencilDescriptorData& stencilInfo, MVKMTLDepthStencilDescriptorData& getData(MVKRenderStateType state) { return getContent(_depthStencilData, state); }
const VkStencilOpState& vkStencil, template <typename T> void setContent(T& content, T value) {
bool enabled); 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 _hasDepthAttachment = false;
bool _hasStencilAttachment = false; bool _hasStencilAttachment = false;
}; };
#pragma mark - #pragma mark -
#pragma mark MVKStencilReferenceValueCommandEncoderState #pragma mark MVKRasterizingCommandEncoderState
/** Holds encoder state established by stencil reference values commands. */ struct MVKDepthBias {
class MVKStencilReferenceValueCommandEncoderState : public MVKCommandEncoderState { float depthBiasConstantFactor;
float depthBiasSlopeFactor;
public: float depthBiasClamp;
/** 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 MVKStencilReference {
#pragma mark - uint32_t frontFaceValue;
#pragma mark MVKDepthBiasCommandEncoderState uint32_t backFaceValue;
/** 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 MVKMTLViewports {
MTLViewport viewports[kMVKMaxViewportScissorCount];
uint32_t viewportCount;
};
#pragma mark - struct MVKMTLScissors {
#pragma mark MVKBlendColorCommandEncoderState MTLScissorRect scissors[kMVKMaxViewportScissorCount];
uint32_t scissorCount;
/** Holds encoder state established by blend color commands. */ };
class MVKBlendColorCommandEncoderState : public MVKCommandEncoderState {
/** Holds encoder state established by various state commands. */
class MVKRasterizingCommandEncoderState : public MVKCommandEncoderState {
public: public:
void setCullMode(VkCullModeFlags cullMode, bool isDynamic);
/** Sets the blend color, either as part of pipeline binding, or dynamically. */ void setFrontFace(VkFrontFace frontFace, bool isDynamic);
void setBlendColor(float red, float green,
float blue, float alpha,
bool isDynamic);
/** Constructs this instance for the specified command encoder. */ void setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic);
MVKBlendColorCommandEncoderState(MVKCommandEncoder* cmdEncoder) MTLPrimitiveType getPrimitiveType();
: MVKCommandEncoderState(cmdEncoder) {}
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<VkViewport> viewports, uint32_t firstViewport, bool isDynamic);
void setScissors(const MVKArrayRef<VkRect2D> scissors, uint32_t firstScissor, bool isDynamic);
void beginMetalRenderPass() override;
MVKRasterizingCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {}
protected: protected:
void encodeImpl(uint32_t stage) override; void encodeImpl(uint32_t stage) override;
bool isDirty(MVKRenderStateType state);
bool isDrawingTriangles();
template <typename T> 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; MVKMTLViewports _mtlViewports[StateScope::Count] = {};
float _green = 0; MVKMTLScissors _mtlScissors[StateScope::Count] = {};
float _blue = 0; MVKColor32 _mtlBlendConstants[StateScope::Count] = {};
float _alpha = 0; 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] = {};
}; };

View File

@ -25,13 +25,21 @@
using namespace std; using namespace std;
#define shouldUpdateFace(face) mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_##face##_BIT)
#pragma mark - #pragma mark -
#pragma mark MVKCommandEncoderState #pragma mark MVKCommandEncoderState
MVKVulkanAPIObject* MVKCommandEncoderState::getVulkanAPIObject() { return _cmdEncoder->getVulkanAPIObject(); }; MVKVulkanAPIObject* MVKCommandEncoderState::getVulkanAPIObject() { return _cmdEncoder->getVulkanAPIObject(); };
MVKDevice* MVKCommandEncoderState::getDevice() { return _cmdEncoder->getDevice(); } 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 -
#pragma mark MVKPipelineCommandEncoderState #pragma mark MVKPipelineCommandEncoderState
@ -51,112 +59,6 @@ void MVKPipelineCommandEncoderState::encodeImpl(uint32_t stage) {
} }
#pragma mark -
#pragma mark MVKViewportCommandEncoderState
void MVKViewportCommandEncoderState::setViewports(MVKArrayRef<const VkViewport> 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<const VkRect2D> 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 -
#pragma mark MVKPushConstantsCommandEncoderState #pragma mark MVKPushConstantsCommandEncoderState
@ -254,74 +156,84 @@ bool MVKPushConstantsCommandEncoderState::isTessellating() {
#pragma mark MVKDepthStencilCommandEncoderState #pragma mark MVKDepthStencilCommandEncoderState
void MVKDepthStencilCommandEncoderState:: setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) { void MVKDepthStencilCommandEncoderState:: setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) {
auto oldData = _depthStencilData; auto& depthEnabled = _depthTestEnabled[StateScope::Static];
auto oldDepthEnabled = depthEnabled;
depthEnabled = static_cast<bool>(vkDepthStencilInfo.depthTestEnable);
if (vkDepthStencilInfo.depthTestEnable) { auto& dsData = _depthStencilData[StateScope::Static];
_depthStencilData.depthCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkDepthStencilInfo.depthCompareOp); auto oldData = dsData;
_depthStencilData.depthWriteEnabled = vkDepthStencilInfo.depthWriteEnable; dsData.depthCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkDepthStencilInfo.depthCompareOp);
} else { dsData.depthWriteEnabled = vkDepthStencilInfo.depthWriteEnable;
_depthStencilData.depthCompareFunction = kMVKMTLDepthStencilDescriptorDataDefault.depthCompareFunction;
_depthStencilData.depthWriteEnabled = kMVKMTLDepthStencilDescriptorDataDefault.depthWriteEnabled;
}
setStencilState(_depthStencilData.frontFaceStencilData, vkDepthStencilInfo.front, vkDepthStencilInfo.stencilTestEnable); dsData.stencilTestEnabled = static_cast<bool>(vkDepthStencilInfo.stencilTestEnable);
setStencilState(_depthStencilData.backFaceStencilData, vkDepthStencilInfo.back, 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, void MVKDepthStencilCommandEncoderState::setStencilState(MVKMTLStencilDescriptorData& sData,
const VkStencilOpState& vkStencil, const VkStencilOpState& vkStencil) {
bool enabled) { sData.readMask = vkStencil.compareMask;
if ( !enabled ) { sData.writeMask = vkStencil.writeMask;
stencilInfo = kMVKMTLStencilDescriptorDataDefault; sData.stencilCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkStencil.compareOp);
return; sData.stencilFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.failOp);
} sData.depthFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.depthFailOp);
sData.depthStencilPassOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.passOp);
stencilInfo.enabled = true; }
stencilInfo.stencilCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkStencil.compareOp);
stencilInfo.stencilFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.failOp); void MVKDepthStencilCommandEncoderState::setDepthTestEnable(VkBool32 depthTestEnable) {
stencilInfo.depthFailureOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.depthFailOp); setContent(_depthTestEnabled[StateScope::Dynamic], static_cast<bool>(depthTestEnable));
stencilInfo.depthStencilPassOperation = mvkMTLStencilOperationFromVkStencilOp(vkStencil.passOp); }
if ( !_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) ) { void MVKDepthStencilCommandEncoderState::setDepthWriteEnable(VkBool32 depthWriteEnable) {
stencilInfo.readMask = vkStencil.compareMask; setContent(_depthStencilData[StateScope::Dynamic].depthWriteEnabled, static_cast<bool>(depthWriteEnable));
} }
if ( !_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) ) {
stencilInfo.writeMask = vkStencil.writeMask; 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<bool>(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, void MVKDepthStencilCommandEncoderState::setStencilCompareMask(VkStencilFaceFlags faceMask,
uint32_t stencilCompareMask) { uint32_t stencilCompareMask) {
auto oldData = _depthStencilData; auto& dsData = _depthStencilData[StateScope::Dynamic];
if (shouldUpdateFace(FRONT)) { setContent(dsData.frontFaceStencilData.readMask, stencilCompareMask); }
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) { if (shouldUpdateFace(BACK)) { setContent(dsData.backFaceStencilData.readMask, stencilCompareMask); }
_depthStencilData.frontFaceStencilData.readMask = stencilCompareMask;
}
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_BACK_BIT)) {
_depthStencilData.backFaceStencilData.readMask = stencilCompareMask;
}
if (!(oldData == _depthStencilData)) markDirty();
} }
// 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, void MVKDepthStencilCommandEncoderState::setStencilWriteMask(VkStencilFaceFlags faceMask,
uint32_t stencilWriteMask) { uint32_t stencilWriteMask) {
auto oldData = _depthStencilData; auto& dsData = _depthStencilData[StateScope::Dynamic];
if (shouldUpdateFace(FRONT)) { setContent(dsData.frontFaceStencilData.writeMask, stencilWriteMask); }
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) { if (shouldUpdateFace(BACK)) { setContent(dsData.backFaceStencilData.writeMask, stencilWriteMask); }
_depthStencilData.frontFaceStencilData.writeMask = stencilWriteMask;
}
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_BACK_BIT)) {
_depthStencilData.backFaceStencilData.writeMask = stencilWriteMask;
}
if (!(oldData == _depthStencilData)) markDirty();
} }
void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() { void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() {
@ -337,130 +249,247 @@ void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() {
if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); } if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); }
} }
// Combine static and dynamic depth/stencil data
void MVKDepthStencilCommandEncoderState::encodeImpl(uint32_t stage) { void MVKDepthStencilCommandEncoderState::encodeImpl(uint32_t stage) {
auto cmdEncPool = _cmdEncoder->getCommandEncodingPool(); if (stage != kMVKGraphicsStageRasterization) { return; }
switch (stage) {
case kMVKGraphicsStageRasterization: { MVKMTLDepthStencilDescriptorData dsData;
// If renderpass does not have a depth or a stencil attachment, disable corresponding test
MVKMTLDepthStencilDescriptorData adjustedDSData = _depthStencilData; if (_hasDepthAttachment && getContent(_depthTestEnabled, DepthTestEnable)) {
adjustedDSData.disable(!_hasDepthAttachment, !_hasStencilAttachment); dsData.depthCompareFunction = getData(DepthCompareOp).depthCompareFunction;
[_cmdEncoder->_mtlRenderEncoder setDepthStencilState: cmdEncPool->getMTLDepthStencilState(adjustedDSData)]; dsData.depthWriteEnabled = getData(DepthWriteEnable).depthWriteEnabled;
break; }
}
default: // Do nothing on other stages if (_hasStencilAttachment && getData(StencilTestEnable).stencilTestEnabled) {
break; 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;
} }
} }
void MVKRasterizingCommandEncoderState::setPolygonMode(VkPolygonMode polygonMode, bool isDynamic) {
#pragma mark - auto mtlPolygonMode = mvkMTLTriangleFillModeFromVkPolygonMode(polygonMode);
#pragma mark MVKStencilReferenceValueCommandEncoderState setContent(PolygonMode);
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;
} }
// We don't check for dynamic state here, because if this is called before pipeline is set, void MVKRasterizingCommandEncoderState::setBlendConstants(float blendConstants[4], bool isDynamic) {
// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway. MVKColor32 mtlBlendConstants;
void MVKStencilReferenceValueCommandEncoderState::setReferenceValues(VkStencilFaceFlags faceMask, mvkCopy(mtlBlendConstants.float32, blendConstants, 4);
uint32_t stencilReference) { setContent(BlendConstants);
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 MVKStencilReferenceValueCommandEncoderState::encodeImpl(uint32_t stage) { void MVKRasterizingCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) {
if (stage != kMVKGraphicsStageRasterization) { return; } bool isDynamic = false;
[_cmdEncoder->_mtlRenderEncoder setStencilFrontReferenceValue: _frontFaceValue
backReferenceValue: _backFaceValue]; bool mtlDepthBiasEnable = static_cast<bool>(vkRasterInfo.depthBiasEnable);
setContent(DepthBiasEnable);
MVKDepthBias mtlDepthBias = {
.depthBiasConstantFactor = vkRasterInfo.depthBiasConstantFactor,
.depthBiasSlopeFactor = vkRasterInfo.depthBiasSlopeFactor,
.depthBiasClamp = vkRasterInfo.depthBiasClamp
};
setContent(DepthBias);
} }
void MVKRasterizingCommandEncoderState::setDepthBias(float depthBiasConstantFactor,
#pragma mark - float depthBiasSlopeFactor,
#pragma mark MVKDepthBiasCommandEncoderState float depthBiasClamp) {
bool isDynamic = true;
void MVKDepthBiasCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) { MVKDepthBias mtlDepthBias = {
.depthBiasConstantFactor = depthBiasConstantFactor,
auto wasEnabled = _isEnabled; .depthBiasSlopeFactor = depthBiasSlopeFactor,
_isEnabled = vkRasterInfo.depthBiasEnable; .depthBiasClamp = depthBiasClamp
};
// If ref values are to be set dynamically, don't set them here. setContent(DepthBias);
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;
}
} }
// We don't check for dynamic state here, because if this is called before pipeline is set, void MVKRasterizingCommandEncoderState::setDepthBiasEnable(VkBool32 depthBiasEnable) {
// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway. bool isDynamic = true;
void MVKDepthBiasCommandEncoderState::setDepthBias(float depthBiasConstantFactor, bool mtlDepthBiasEnable = static_cast<bool>(depthBiasEnable);
float depthBiasSlopeFactor, setContent(DepthBiasEnable);
float depthBiasClamp) {
if (_depthBiasConstantFactor != depthBiasConstantFactor || _depthBiasSlopeFactor != depthBiasSlopeFactor
|| _depthBiasClamp != depthBiasClamp) {
markDirty();
_depthBiasConstantFactor = depthBiasConstantFactor;
_depthBiasSlopeFactor = depthBiasSlopeFactor;
_depthBiasClamp = depthBiasClamp;
}
} }
void MVKDepthBiasCommandEncoderState::encodeImpl(uint32_t stage) { void MVKRasterizingCommandEncoderState::setDepthClipEnable(bool depthClip, bool isDynamic) {
if (stage != kMVKGraphicsStageRasterization) { return; } auto mtlDepthClipEnable = depthClip ? MTLDepthClipModeClip : MTLDepthClipModeClamp;
if (_isEnabled) { setContent(DepthClipEnable);
[_cmdEncoder->_mtlRenderEncoder setDepthBias: _depthBiasConstantFactor
slopeScale: _depthBiasSlopeFactor
clamp: _depthBiasClamp];
} else {
[_cmdEncoder->_mtlRenderEncoder setDepthBias: 0 slopeScale: 0 clamp: 0];
}
} }
void MVKRasterizingCommandEncoderState::setStencilReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) {
#pragma mark - bool isDynamic = false;
#pragma mark MVKBlendColorCommandEncoderState MVKStencilReference mtlStencilReference = {
.frontFaceValue = vkDepthStencilInfo.front.reference,
void MVKBlendColorCommandEncoderState::setBlendColor(float red, float green, .backFaceValue = vkDepthStencilInfo.back.reference
float blue, float alpha, };
bool isDynamic) { setContent(StencilReference);
// 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 MVKBlendColorCommandEncoderState::encodeImpl(uint32_t stage) { void MVKRasterizingCommandEncoderState::setStencilReferenceValues(VkStencilFaceFlags faceMask, uint32_t stencilReference) {
if (stage != kMVKGraphicsStageRasterization) { return; } bool isDynamic = true;
[_cmdEncoder->_mtlRenderEncoder setBlendColorRed: _red green: _green blue: _blue alpha: _alpha]; MVKStencilReference mtlStencilReference = _mtlStencilReference[StateScope::Dynamic];
if (shouldUpdateFace(FRONT)) { mtlStencilReference.frontFaceValue = stencilReference; }
if (shouldUpdateFace(BACK)) { mtlStencilReference.backFaceValue = stencilReference; }
setContent(StencilReference);
}
void MVKRasterizingCommandEncoderState::setViewports(const MVKArrayRef<VkViewport> 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<VkRect2D> 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(); MVKGraphicsPipeline* pipeline = (MVKGraphicsPipeline*)getPipeline();
bool fullImageViewSwizzle = pipeline->fullImageViewSwizzle() || getDevice()->_pMetalFeatures->nativeTextureSwizzle; bool fullImageViewSwizzle = pipeline->fullImageViewSwizzle() || getDevice()->_pMetalFeatures->nativeTextureSwizzle;
bool forTessellation = pipeline->isTessellationPipeline(); bool forTessellation = pipeline->isTessellationPipeline();
bool isDynamicVertexStride = pipeline->isDynamicState(VertexStride);
if (stage == kMVKGraphicsStageVertex) { if (stage == kMVKGraphicsStageVertex) {
encodeBindings(kMVKShaderStageVertex, "vertex", fullImageViewSwizzle, encodeBindings(kMVKShaderStageVertex, "vertex", fullImageViewSwizzle,
@ -812,23 +842,32 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) {
} else if (!forTessellation && stage == kMVKGraphicsStageRasterization) { } else if (!forTessellation && stage == kMVKGraphicsStageRasterization) {
encodeBindings(kMVKShaderStageVertex, "vertex", fullImageViewSwizzle, 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. // 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 // We must not bind those extra buffers to the shader because they might overwrite
// any implicit buffers used by the pipeline. // any implicit buffers used by the pipeline.
if (pipeline->isValidVertexBufferIndex(kMVKShaderStageVertex, b.index)) { if (pipeline->isValidVertexBufferIndex(kMVKShaderStageVertex, b.index)) {
if (b.isInline) { NSUInteger mtlStride = isDynamicVertexStride ? b.stride : MTLAttributeStrideStatic;
cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, if (b.isInline) {
b.mtlBytes, [cmdEncoder->_mtlRenderEncoder setVertexBytes: b.mtlBytes
b.size, length: b.size
b.index); #if MVK_XCODE_15
attributeStride: mtlStride
#endif
atIndex: b.index];
} else { } else {
if (b.justOffset) { if (b.justOffset) {
[cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: b.offset [cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: b.offset
atIndex: b.index]; #if MVK_XCODE_15
} else { attributeStride: mtlStride
#endif
atIndex: b.index];
} else {
[cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
offset: b.offset offset: b.offset
#if MVK_XCODE_15
attributeStride: mtlStride
#endif
atIndex: b.index]; atIndex: b.index];
} }
@ -838,6 +877,9 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) {
if (b.index == pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.binding)) { if (b.index == pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.binding)) {
[cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
offset: b.offset + xltdBind.translationOffset offset: b.offset + xltdBind.translationOffset
#if MVK_XCODE_15
attributeStride: mtlStride
#endif
atIndex: pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding)]; atIndex: pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding)];
} }
} }
@ -898,19 +940,29 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) {
if (forTessellation && stage == kMVKGraphicsStageRasterization) { if (forTessellation && stage == kMVKGraphicsStageRasterization) {
encodeBindings(kMVKShaderStageTessEval, "tessellation evaluation", fullImageViewSwizzle, encodeBindings(kMVKShaderStageTessEval, "tessellation evaluation", fullImageViewSwizzle,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { [isDynamicVertexStride](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
if (b.isInline) NSUInteger mtlStride = isDynamicVertexStride ? b.stride : MTLAttributeStrideStatic;
cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, if (b.isInline) {
b.mtlBytes, [cmdEncoder->_mtlRenderEncoder setVertexBytes: b.mtlBytes
b.size, length: b.size
b.index); #if MVK_XCODE_15
else if (b.justOffset) attributeStride: mtlStride
#endif
atIndex: b.index];
} else if (b.justOffset) {
[cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: b.offset [cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: b.offset
#if MVK_XCODE_15
attributeStride: mtlStride
#endif
atIndex: b.index]; atIndex: b.index];
else } else {
[cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
offset: b.offset offset: b.offset
#if MVK_XCODE_15
attributeStride: mtlStride
#endif
atIndex: b.index]; atIndex: b.index];
}
}, },
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKArrayRef<const uint32_t> s)->void { [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKArrayRef<const uint32_t> s)->void {
cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder, cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder,

View File

@ -210,27 +210,24 @@ namespace std {
* change as early as possible. * change as early as possible.
*/ */
typedef struct MVKMTLStencilDescriptorData { 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 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 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 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). */ 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() { MVKMTLStencilDescriptorData() {
mvkClear(this); // Clear all memory to ensure memory comparisons will work.
// Start with all zeros to ensure memory comparisons will work, mvkEnableAllFlags(readMask);
// even if the structure contains alignment gaps. mvkEnableAllFlags(writeMask);
mvkClear(this);
enabled = false;
stencilCompareFunction = MTLCompareFunctionAlways; stencilCompareFunction = MTLCompareFunctionAlways;
stencilFailureOperation = MTLStencilOperationKeep; stencilFailureOperation = MTLStencilOperationKeep;
depthFailureOperation = MTLStencilOperationKeep; depthFailureOperation = MTLStencilOperationKeep;
depthStencilPassOperation = MTLStencilOperationKeep; depthStencilPassOperation = MTLStencilOperationKeep;
readMask = static_cast<uint32_t>(~0);
writeMask = static_cast<uint32_t>(~0);
} }
} MVKMTLStencilDescriptorData; } MVKMTLStencilDescriptorData;
@ -247,34 +244,32 @@ const MVKMTLStencilDescriptorData kMVKMTLStencilDescriptorDataDefault;
* change as early as possible. * change as early as possible.
*/ */
typedef struct MVKMTLDepthStencilDescriptorData { typedef struct MVKMTLDepthStencilDescriptorData {
uint8_t depthCompareFunction; /**< The depth compare function (interpreted as MTLCompareFunction). */
bool depthWriteEnabled; /**< Indicates whether depth writing is enabled. */
MVKMTLStencilDescriptorData frontFaceStencilData; MVKMTLStencilDescriptorData frontFaceStencilData;
MVKMTLStencilDescriptorData backFaceStencilData; 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 mvkAreEqual(this, &rhs); }
bool operator!=(const MVKMTLDepthStencilDescriptorData& rhs) const { return !(*this == rhs); }
std::size_t hash() const { std::size_t hash() const {
return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t)); return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t));
} }
void disableDepth() {
/** Disable depth and/or stencil testing. */ depthCompareFunction = MTLCompareFunctionAlways;
void disable(bool disableDepth, bool disableStencil) { depthWriteEnabled = false;
if (disableDepth) { }
depthCompareFunction = MTLCompareFunctionAlways; void disableStencil() {
depthWriteEnabled = false; stencilTestEnabled = false;
} frontFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
if (disableStencil) { backFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
frontFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
backFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
}
} }
MVKMTLDepthStencilDescriptorData() { MVKMTLDepthStencilDescriptorData() {
// Start with all zeros to ensure memory comparisons will work, mvkClear(this); // Clear all memory to ensure memory comparisons will work.
// even if the structure contains alignment gaps. disableDepth();
mvkClear(this); disableStencil();
disable(true, true);
} }
} __attribute__((aligned(sizeof(uint64_t)))) MVKMTLDepthStencilDescriptorData; } __attribute__((aligned(sizeof(uint64_t)))) MVKMTLDepthStencilDescriptorData;

View File

@ -433,9 +433,10 @@ id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(bool
} }
id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(MVKMTLDepthStencilDescriptorData& dsData) { id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(MVKMTLDepthStencilDescriptorData& dsData) {
MTLStencilDescriptor* fsDesc = newMTLStencilDescriptor(dsData.frontFaceStencilData); // temp retain bool testStencil = dsData.stencilTestEnabled;
MTLStencilDescriptor* bsDesc = newMTLStencilDescriptor(dsData.backFaceStencilData); // temp retain auto* fsDesc = testStencil ? newMTLStencilDescriptor(dsData.frontFaceStencilData) : nil; // temp retain
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new]; // temp retain auto* bsDesc = testStencil ? newMTLStencilDescriptor(dsData.backFaceStencilData) : nil; // temp retain
auto* dsDesc = [MTLDepthStencilDescriptor new]; // temp retain
dsDesc.depthCompareFunction = (MTLCompareFunction)dsData.depthCompareFunction; dsDesc.depthCompareFunction = (MTLCompareFunction)dsData.depthCompareFunction;
dsDesc.depthWriteEnabled = dsData.depthWriteEnabled; dsDesc.depthWriteEnabled = dsData.depthWriteEnabled;
dsDesc.frontFaceStencil = fsDesc; dsDesc.frontFaceStencil = fsDesc;
@ -443,16 +444,14 @@ id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(MVKM
id<MTLDepthStencilState> dss = [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc]; id<MTLDepthStencilState> dss = [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc];
[fsDesc release]; // temp release [fsDesc release]; // temp release
[bsDesc release]; // temp release [bsDesc release]; // temp release
[dsDesc release]; // temp release [dsDesc release]; // temp release
return dss; return dss;
} }
MTLStencilDescriptor* MVKCommandResourceFactory::newMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData) { MTLStencilDescriptor* MVKCommandResourceFactory::newMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData) {
if ( !sData.enabled ) { return nil; }
MTLStencilDescriptor* sDesc = [MTLStencilDescriptor new]; // retained MTLStencilDescriptor* sDesc = [MTLStencilDescriptor new]; // retained
sDesc.stencilCompareFunction = (MTLCompareFunction)sData.stencilCompareFunction; sDesc.stencilCompareFunction = (MTLCompareFunction)sData.stencilCompareFunction;
sDesc.stencilFailureOperation = (MTLStencilOperation)sData.stencilFailureOperation; sDesc.stencilFailureOperation = (MTLStencilOperation)sData.stencilFailureOperation;

View File

@ -89,12 +89,19 @@ MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(SetScissor, 1)
MVK_CMD_TYPE_POOL(SetLineWidth) MVK_CMD_TYPE_POOL(SetLineWidth)
MVK_CMD_TYPE_POOL(SetDepthBias) MVK_CMD_TYPE_POOL(SetDepthBias)
MVK_CMD_TYPE_POOL(SetBlendConstants) 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(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(SetStencilCompareMask)
MVK_CMD_TYPE_POOL(SetStencilWriteMask) MVK_CMD_TYPE_POOL(SetStencilWriteMask)
MVK_CMD_TYPE_POOL(SetStencilReference) MVK_CMD_TYPE_POOL(SetStencilReference)
MVK_CMD_TYPE_POOL(SetCullMode) MVK_CMD_TYPE_POOL(SetCullMode)
MVK_CMD_TYPE_POOL(SetFrontFace) MVK_CMD_TYPE_POOL(SetFrontFace)
MVK_CMD_TYPE_POOL(SetPrimitiveTopology)
MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindVertexBuffers, 1, 2) MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindVertexBuffers, 1, 2)
MVK_CMD_TYPE_POOL(BindIndexBuffer) MVK_CMD_TYPE_POOL(BindIndexBuffer)
MVK_CMD_TYPE_POOL(Draw) MVK_CMD_TYPE_POOL(Draw)

View File

@ -67,6 +67,7 @@ typedef struct MVKMTLBufferBinding {
union { id<MTLBuffer> mtlBuffer = nil; id<MTLBuffer> mtlResource; const void* mtlBytes; }; // aliases union { id<MTLBuffer> mtlBuffer = nil; id<MTLBuffer> mtlResource; const void* mtlBytes; }; // aliases
VkDeviceSize offset = 0; VkDeviceSize offset = 0;
uint32_t size = 0; uint32_t size = 0;
uint32_t stride = 0;
uint16_t index = 0; uint16_t index = 0;
bool justOffset = false; bool justOffset = false;
bool isDirty = true; bool isDirty = true;
@ -78,14 +79,16 @@ typedef struct MVKMTLBufferBinding {
void update(const MVKMTLBufferBinding &other) { void update(const MVKMTLBufferBinding &other) {
if (mtlBuffer != other.mtlBuffer || size != other.size || other.isInline) { if (mtlBuffer != other.mtlBuffer || size != other.size || other.isInline) {
mtlBuffer = other.mtlBuffer; mtlBuffer = other.mtlBuffer;
offset = other.offset;
size = other.size; size = other.size;
stride = other.stride;
isInline = other.isInline; isInline = other.isInline;
offset = other.offset;
justOffset = false; justOffset = false;
isOverridden = false; isOverridden = false;
isDirty = true; isDirty = true;
} else if (offset != other.offset) { } else if (offset != other.offset || stride != other.stride) {
offset = other.offset; offset = other.offset;
stride = other.stride;
justOffset = !isOverridden && (!isDirty || justOffset); justOffset = !isOverridden && (!isDirty || justOffset);
isOverridden = false; isOverridden = false;
isDirty = true; isDirty = true;

View File

@ -387,6 +387,11 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
formatFeatures->formatA4B4G4R4 = canSupport4444; formatFeatures->formatA4B4G4R4 = canSupport4444;
break; 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: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next; auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups; interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups;
@ -1696,10 +1701,11 @@ void MVKPhysicalDevice::initMetalFeatures() {
_metalFeatures.minSwapchainImageCount = kMVKMinSwapchainImageCount; _metalFeatures.minSwapchainImageCount = kMVKMinSwapchainImageCount;
_metalFeatures.maxSwapchainImageCount = kMVKMaxSwapchainImageCount; _metalFeatures.maxSwapchainImageCount = kMVKMaxSwapchainImageCount;
_metalFeatures.vertexStrideAlignment = 4;
_metalFeatures.maxPerStageStorageTextureCount = 8; _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 // GPU-specific features
switch (_properties.vendorID) { switch (_properties.vendorID) {
case kAMDVendorId: case kAMDVendorId:
@ -2411,7 +2417,7 @@ void MVKPhysicalDevice::initLimits() {
_properties.limits.maxVertexInputAttributes = 31; _properties.limits.maxVertexInputAttributes = 31;
_properties.limits.maxVertexInputBindings = 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.maxVertexInputAttributeOffset = _properties.limits.maxVertexInputBindingStride - 1;
_properties.limits.maxPerStageDescriptorSamplers = _metalFeatures.maxPerStageSamplerCount; _properties.limits.maxPerStageDescriptorSamplers = _metalFeatures.maxPerStageSamplerCount;

View File

@ -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(FragmentShaderBarycentric, FRAGMENT_SHADER_BARYCENTRIC, KHR, 1)
MVK_DEVICE_FEATURE_EXTN(PortabilitySubset, PORTABILITY_SUBSET, KHR, 15) MVK_DEVICE_FEATURE_EXTN(PortabilitySubset, PORTABILITY_SUBSET, KHR, 15)
MVK_DEVICE_FEATURE_EXTN(4444Formats, 4444_FORMATS, EXT, 2) 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(FragmentShaderInterlock, FRAGMENT_SHADER_INTERLOCK, EXT, 3)
MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1) MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1)
MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3) MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3)

View File

@ -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(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(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(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(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(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(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(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(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(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(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(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(vkCmdSetStencilOp, EXT, EXT_EXTENDED_DYNAMIC_STATE);
ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetStencilTestEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE); ADD_DVC_1_3_PROMOTED_ENTRY_POINT(vkCmdSetStencilTestEnable, EXT, EXT_EXTENDED_DYNAMIC_STATE);

View File

@ -218,6 +218,44 @@ struct MVKStagedDescriptorBindingUse {
MVKBitArray stages[4] = {}; 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. */ /** Represents an Vulkan graphics pipeline. */
class MVKGraphicsPipeline : public MVKPipeline { class MVKGraphicsPipeline : public MVKPipeline {
@ -229,8 +267,8 @@ public:
/** Binds this pipeline to the specified command encoder. */ /** Binds this pipeline to the specified command encoder. */
void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) override; void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) override;
/** Returns whether this pipeline permits dynamic setting of the specifie state. */ /** Returns whether this pipeline permits dynamic setting of the state. */
bool supportsDynamicState(VkDynamicState state); bool isDynamicState(MVKRenderStateType state) { return _dynamicState.isEnabled(state); }
/** Returns whether this pipeline has tessellation shaders. */ /** Returns whether this pipeline has tessellation shaders. */
bool isTessellationPipeline() { return _tessInfo.patchControlPoints > 0; } bool isTessellationPipeline() { return _tessInfo.patchControlPoints > 0; }
@ -320,6 +358,7 @@ protected:
id<MTLComputePipelineState> getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id<MTLComputePipelineState>& plState, const char* compilerType); id<MTLComputePipelineState> getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id<MTLComputePipelineState>& plState, const char* compilerType);
bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, MVKMTLFunction* pVtxFunctions, VkPipelineCreationFeedback* pVertexFB); bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, MVKMTLFunction* pVtxFunctions, VkPipelineCreationFeedback* pVertexFB);
bool compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, VkPipelineCreationFeedback* pTessCtlFB); bool compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, VkPipelineCreationFeedback* pTessCtlFB);
void initDynamicState(const VkGraphicsPipelineCreateInfo* pCreateInfo);
void initCustomSamplePositions(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 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); void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
@ -356,10 +395,10 @@ protected:
VkPipelineTessellationStateCreateInfo _tessInfo; VkPipelineTessellationStateCreateInfo _tessInfo;
VkPipelineRasterizationStateCreateInfo _rasterInfo; VkPipelineRasterizationStateCreateInfo _rasterInfo;
VkPipelineDepthStencilStateCreateInfo _depthStencilInfo; VkPipelineDepthStencilStateCreateInfo _depthStencilInfo;
MVKRenderStateFlags _dynamicState;
MVKSmallVector<VkViewport, kMVKMaxViewportScissorCount> _viewports; MVKSmallVector<VkViewport, kMVKMaxViewportScissorCount> _viewports;
MVKSmallVector<VkRect2D, kMVKMaxViewportScissorCount> _scissors; MVKSmallVector<VkRect2D, kMVKMaxViewportScissorCount> _scissors;
MVKSmallVector<VkDynamicState> _dynamicState;
MVKSmallVector<MTLSamplePosition> _customSamplePositions; MVKSmallVector<MTLSamplePosition> _customSamplePositions;
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings; MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings; MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings;
@ -374,19 +413,16 @@ protected:
id<MTLComputePipelineState> _mtlTessControlStageState = nil; id<MTLComputePipelineState> _mtlTessControlStageState = nil;
id<MTLRenderPipelineState> _mtlPipelineState = nil; id<MTLRenderPipelineState> _mtlPipelineState = nil;
float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 }; float _blendConstants[4] = {};
MTLCullMode _mtlCullMode; VkPrimitiveTopology _vkPrimitiveTopology;
MTLWinding _mtlFrontWinding;
MTLTriangleFillMode _mtlFillMode;
MTLDepthClipMode _mtlDepthClipMode;
MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount; MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount;
MVKShaderImplicitRezBinding _viewRangeBufferIndex; MVKShaderImplicitRezBinding _viewRangeBufferIndex;
MVKShaderImplicitRezBinding _outputBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex;
VkPrimitiveTopology _vkPrimitiveTopology;
uint32_t _outputControlPointCount; uint32_t _outputControlPointCount;
uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlPatchOutputBufferIndex = 0;
uint32_t _tessCtlLevelBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0;
bool _hasRasterInfo = false;
bool _needsVertexSwizzleBuffer = false; bool _needsVertexSwizzleBuffer = false;
bool _needsVertexBufferSizeBuffer = false; bool _needsVertexBufferSizeBuffer = false;
bool _needsVertexDynamicOffsetBuffer = false; bool _needsVertexDynamicOffsetBuffer = false;

View File

@ -292,24 +292,20 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
// Depth stencil state - Cleared _depthStencilInfo values will disable depth testing // Depth stencil state - Cleared _depthStencilInfo values will disable depth testing
cmdEncoder->_depthStencilState.setDepthStencilState(_depthStencilInfo); cmdEncoder->_depthStencilState.setDepthStencilState(_depthStencilInfo);
cmdEncoder->_stencilReferenceValueState.setReferenceValues(_depthStencilInfo);
// Rasterization // Rasterization
cmdEncoder->_blendColorState.setBlendColor(_blendConstants[0], _blendConstants[1], cmdEncoder->_rasterizingState.setPrimitiveTopology(_vkPrimitiveTopology, false);
_blendConstants[2], _blendConstants[3], false); cmdEncoder->_rasterizingState.setBlendConstants(_blendConstants, false);
cmdEncoder->_depthBiasState.setDepthBias(_rasterInfo); cmdEncoder->_rasterizingState.setStencilReferenceValues(_depthStencilInfo);
cmdEncoder->_viewportState.setViewports(_viewports.contents(), 0, false); cmdEncoder->_rasterizingState.setViewports(_viewports.contents(), 0, false);
cmdEncoder->_scissorState.setScissors(_scissors.contents(), 0, false); cmdEncoder->_rasterizingState.setScissors(_scissors.contents(), 0, false);
cmdEncoder->_mtlPrimitiveType = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(_vkPrimitiveTopology); if (_hasRasterInfo) {
cmdEncoder->_rasterizingState.setCullMode(_rasterInfo.cullMode, false);
[mtlCmdEnc setCullMode: _mtlCullMode]; cmdEncoder->_rasterizingState.setFrontFace(_rasterInfo.frontFace, false);
[mtlCmdEnc setFrontFacingWinding: _mtlFrontWinding]; cmdEncoder->_rasterizingState.setPolygonMode(_rasterInfo.polygonMode, false);
[mtlCmdEnc setTriangleFillMode: _mtlFillMode]; cmdEncoder->_rasterizingState.setDepthBias(_rasterInfo);
cmdEncoder->_rasterizingState.setDepthClipEnable( !_rasterInfo.depthClampEnable, false );
if (_device->_enabledFeatures.depthClamp) { }
[mtlCmdEnc setDepthClipMode: _mtlDepthClipMode];
}
break; break;
} }
@ -320,21 +316,6 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
cmdEncoder->_graphicsResourcesState.bindViewRangeBuffer(_viewRangeBufferIndex, _needsVertexViewRangeBuffer, _needsFragmentViewRangeBuffer); 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"; static const char vtxCompilerType[] = "Vertex stage pipeline for tessellation";
bool MVKGraphicsPipeline::compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, bool MVKGraphicsPipeline::compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc,
@ -414,6 +395,10 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
const VkGraphicsPipelineCreateInfo* pCreateInfo) : const VkGraphicsPipelineCreateInfo* pCreateInfo) :
MVKPipeline(device, pipelineCache, (MVKPipelineLayout*)pCreateInfo->layout, pCreateInfo->flags, parent) { 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. // Determine rasterization early, as various other structs are validated and interpreted in this context.
const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo); const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo);
_isRasterizing = !isRasterizationDisabled(pCreateInfo); _isRasterizing = !isRasterizationDisabled(pCreateInfo);
@ -509,17 +494,12 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
initMTLRenderPipelineState(pCreateInfo, reflectData, pPipelineFB, pVertexSS, pVertexFB, pTessCtlSS, pTessCtlFB, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB); initMTLRenderPipelineState(pCreateInfo, reflectData, pPipelineFB, pVertexSS, pVertexFB, pTessCtlSS, pTessCtlFB, pTessEvalSS, pTessEvalFB, pFragmentSS, pFragmentFB);
if ( !_hasValidMTLPipelineStates ) { return; } 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 // Blending - must ignore allowed bad pColorBlendState pointer if rasterization disabled or no color attachments
if (_isRasterizingColor && pCreateInfo->pColorBlendState) { 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 // Topology
@ -528,21 +508,10 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
: VK_PRIMITIVE_TOPOLOGY_POINT_LIST); : VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
// Rasterization // Rasterization
_mtlCullMode = MTLCullModeNone; _hasRasterInfo = mvkSetOrClear(&_rasterInfo, pCreateInfo->pRasterizationState);
_mtlFrontWinding = MTLWindingCounterClockwise; if (_hasRasterInfo) {
_mtlFillMode = MTLTriangleFillModeFill; if (_rasterInfo.depthClampEnable && !_device->_enabledFeatures.depthClamp) {
_mtlDepthClipMode = MTLDepthClipModeClip; setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "This device does not support depth clamping."));
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."));
}
} }
} }
@ -557,26 +526,76 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
// Viewports and scissors - must ignore allowed bad pViewportState pointer if rasterization is disabled // Viewports and scissors - must ignore allowed bad pViewportState pointer if rasterization is disabled
auto pVPState = _isRasterizing ? pCreateInfo->pViewportState : nullptr; auto pVPState = _isRasterizing ? pCreateInfo->pViewportState : nullptr;
if (pVPState) { 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); _viewports.reserve(vpCnt);
for (uint32_t vpIdx = 0; vpIdx < vpCnt; vpIdx++) { for (uint32_t vpIdx = 0; vpIdx < vpCnt; vpIdx++) {
// If viewport is dyanamic, we still add a dummy so that the count will be tracked. _viewports.push_back(pVPState->pViewports[vpIdx]);
VkViewport vp;
if ( !supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT) ) { vp = pVPState->pViewports[vpIdx]; }
_viewports.push_back(vp);
} }
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); _scissors.reserve(sCnt);
for (uint32_t sIdx = 0; sIdx < sCnt; sIdx++) { for (uint32_t sIdx = 0; sIdx < sCnt; sIdx++) {
// If scissor is dyanamic, we still add a dummy so that the count will be tracked. _scissors.push_back(pVPState->pScissors[sIdx]);
VkRect2D sc;
if ( !supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR) ) { sc = pVPState->pScissors[sIdx]; }
_scissors.push_back(sc);
} }
} }
} }
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. // Either returns an existing pipeline state or compiles a new one.
id<MTLRenderPipelineState> MVKGraphicsPipeline::getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id<MTLRenderPipelineState> MVKGraphicsPipeline::getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc,
id<MTLRenderPipelineState>& plState) { id<MTLRenderPipelineState>& plState) {
@ -613,7 +632,7 @@ void MVKGraphicsPipeline::initCustomSamplePositions(const VkGraphicsPipelineCrea
case VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT: { case VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT: {
auto* pSampLocnsCreateInfo = (VkPipelineSampleLocationsStateCreateInfoEXT*)next; auto* pSampLocnsCreateInfo = (VkPipelineSampleLocationsStateCreateInfoEXT*)next;
_isUsingCustomSamplePositions = pSampLocnsCreateInfo->sampleLocationsEnable; _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++) { for (uint32_t slIdx = 0; slIdx < pSampLocnsCreateInfo->sampleLocationsInfo.sampleLocationsCount; slIdx++) {
auto& sl = pSampLocnsCreateInfo->sampleLocationsInfo.pSampleLocations[slIdx]; auto& sl = pSampLocnsCreateInfo->sampleLocationsInfo.pSampleLocations[slIdx];
_customSamplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y)); _customSamplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y));
@ -1328,8 +1347,9 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
} }
// Vertex buffer bindings // Vertex buffer bindings
uint32_t vbCnt = pVI->vertexBindingDescriptionCount; bool isVtxStrideStatic = !isDynamicState(VertexStride);
uint32_t maxBinding = 0; uint32_t maxBinding = 0;
uint32_t vbCnt = pVI->vertexBindingDescriptionCount;
for (uint32_t i = 0; i < vbCnt; i++) { for (uint32_t i = 0; i < vbCnt; i++) {
const VkVertexInputBindingDescription* pVKVB = &pVI->pVertexBindingDescriptions[i]; const VkVertexInputBindingDescription* pVKVB = &pVI->pVertexBindingDescriptions[i];
if (shaderConfig.isVertexBufferUsed(pVKVB->binding)) { if (shaderConfig.isVertexBufferUsed(pVKVB->binding)) {
@ -1352,7 +1372,7 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
vbDesc.stepFunction = (decltype(vbDesc.stepFunction))MTLStepFunctionConstant; vbDesc.stepFunction = (decltype(vbDesc.stepFunction))MTLStepFunctionConstant;
vbDesc.stepRate = 0; vbDesc.stepRate = 0;
} else { } else {
vbDesc.stride = pVKVB->stride; vbDesc.stride = isVtxStrideStatic ? pVKVB->stride : MTLBufferLayoutStrideDynamic;
vbDesc.stepFunction = (decltype(vbDesc.stepFunction))mvkMTLStepFunctionFromVkVertexInputRate(pVKVB->inputRate, isTessellationPipeline()); vbDesc.stepFunction = (decltype(vbDesc.stepFunction))mvkMTLStepFunctionFromVkVertexInputRate(pVKVB->inputRate, isTessellationPipeline());
vbDesc.stepRate = 1; vbDesc.stepRate = 1;
} }
@ -1903,11 +1923,12 @@ bool MVKGraphicsPipeline::isRenderingPoints(const VkGraphicsPipelineCreateInfo*
(pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->polygonMode == VK_POLYGON_MODE_POINT))); (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) { bool MVKGraphicsPipeline::isRasterizationDisabled(const VkGraphicsPipelineCreateInfo* pCreateInfo) {
return (pCreateInfo->pRasterizationState && return (pCreateInfo->pRasterizationState &&
(pCreateInfo->pRasterizationState->rasterizerDiscardEnable || (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)))); (mvkMTLPrimitiveTopologyClassFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology) == MTLPrimitiveTopologyClassTriangle))));
} }

View File

@ -60,6 +60,9 @@ typedef struct {
#pragma mark - #pragma mark -
#pragma mark Vulkan support #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. */ /** Tracks the Vulkan command currently being used. */
typedef enum : uint8_t { typedef enum : uint8_t {
kMVKCommandUseNone = 0, /**< No use defined. */ 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. */ /** Returns whether the specified positive value is a power-of-two. */
template<typename T> template<typename T>
static constexpr bool mvkIsPowerOfTwo(T value) { 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 * 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. * uint and int values without risking overflowing between positive and negative values.
*/ */
static int32_t kMVKUndefinedLargePositiveInt32 = mvkEnsurePowerOfTwo(std::numeric_limits<int32_t>::max() / 2); static constexpr int32_t kMVKUndefinedLargePositiveInt32 = mvkEnsurePowerOfTwo(std::numeric_limits<int32_t>::max() / 2);
static int32_t kMVKUndefinedLargeNegativeInt32 = -kMVKUndefinedLargePositiveInt32; static constexpr int32_t kMVKUndefinedLargeNegativeInt32 = -kMVKUndefinedLargePositiveInt32;
static uint32_t kMVKUndefinedLargeUInt32 = kMVKUndefinedLargePositiveInt32; static constexpr uint32_t kMVKUndefinedLargeUInt32 = kMVKUndefinedLargePositiveInt32;
static int64_t kMVKUndefinedLargePositiveInt64 = mvkEnsurePowerOfTwo(std::numeric_limits<int64_t>::max() / 2); static constexpr int64_t kMVKUndefinedLargePositiveInt64 = mvkEnsurePowerOfTwo(std::numeric_limits<int64_t>::max() / 2);
static int64_t kMVKUndefinedLargeNegativeInt64 = -kMVKUndefinedLargePositiveInt64; static constexpr int64_t kMVKUndefinedLargeNegativeInt64 = -kMVKUndefinedLargePositiveInt64;
static uint64_t kMVKUndefinedLargeUInt64 = kMVKUndefinedLargePositiveInt64; static constexpr uint64_t kMVKUndefinedLargeUInt64 = kMVKUndefinedLargePositiveInt64;
#pragma mark Vulkan structure support functions #pragma mark Vulkan structure support functions
/** Returns a VkExtent2D created from the width and height of a VkExtent3D. */ /** 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. */ /** 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. */ /** Returns whether the two Vulkan extents are equal by comparing their respective components. */
static constexpr bool mvkVkExtent2DsAreEqual(VkExtent2D e1, VkExtent2D e2) { 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. */ /** Unpacks a single 32-bit word containing four swizzle components. */
static inline VkComponentMapping mvkUnpackSwizzle(uint32_t packed) { static constexpr VkComponentMapping mvkUnpackSwizzle(uint32_t packed) {
VkComponentMapping components; return {
components.r = (VkComponentSwizzle)((packed >> 0) & 0xFF); .r = (VkComponentSwizzle)((packed >> 0) & 0xFF),
components.g = (VkComponentSwizzle)((packed >> 8) & 0xFF); .g = (VkComponentSwizzle)((packed >> 8) & 0xFF),
components.b = (VkComponentSwizzle)((packed >> 16) & 0xFF); .b = (VkComponentSwizzle)((packed >> 16) & 0xFF),
components.a = (VkComponentSwizzle)((packed >> 24) & 0xFF); .a = (VkComponentSwizzle)((packed >> 24) & 0xFF),
return components; };
} }
/** /**
@ -353,8 +356,8 @@ static inline VkComponentMapping mvkUnpackSwizzle(uint32_t packed) {
* and matches any value. * and matches any value.
*/ */
static constexpr bool mvkVKComponentSwizzlesMatch(VkComponentSwizzle cs1, static constexpr bool mvkVKComponentSwizzlesMatch(VkComponentSwizzle cs1,
VkComponentSwizzle cs2, VkComponentSwizzle cs2,
VkComponentSwizzle csPos) { VkComponentSwizzle csPos) {
return ((cs1 == cs2) || return ((cs1 == cs2) ||
((cs1 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs2 == csPos)) || ((cs1 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs2 == csPos)) ||
((cs2 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs1 == csPos)) || ((cs2 == VK_COMPONENT_SWIZZLE_IDENTITY) && (cs1 == csPos)) ||
@ -383,25 +386,25 @@ static constexpr bool mvkVkComponentMappingsMatch(VkComponentMapping cm1, VkComp
#pragma mark Math #pragma mark Math
/** Rounds the value to nearest integer using half-to-even rounding. */ /** 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. 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. */ /** Returns whether the value will fit inside the numeric type. */
template<typename T, typename Tval> template<typename T, typename Tval>
const bool mvkFits(const Tval& val) { static constexpr const bool mvkFits(const Tval& val) {
return val <= std::numeric_limits<T>::max(); return val <= std::numeric_limits<T>::max();
} }
/** Clamps the value between the lower and upper bounds, inclusive. */ /** Clamps the value between the lower and upper bounds, inclusive. */
template<typename T> template<typename T>
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); return std::min(std::max(val, lower), upper);
} }
/** Returns the result of a division, rounded up. */ /** Returns the result of a division, rounded up. */
template<typename T, typename U> template<typename T, typename U>
constexpr typename std::common_type<T, U>::type mvkCeilingDivide(T numerator, U denominator) { static constexpr typename std::common_type<T, U>::type mvkCeilingDivide(T numerator, U denominator) {
typedef typename std::common_type<T, U>::type R; typedef typename std::common_type<T, U>::type R;
// Short circuit very common usecase of dividing by one. // Short circuit very common usecase of dividing by one.
return (denominator == 1) ? numerator : (R(numerator) + denominator - 1) / denominator; return (denominator == 1) ? numerator : (R(numerator) + denominator - 1) / denominator;
@ -427,18 +430,18 @@ struct MVKAbs<R, T, false> {
/** Returns the absolute value of the difference of two numbers. */ /** Returns the absolute value of the difference of two numbers. */
template<typename T, typename U> template<typename T, typename U>
constexpr typename std::common_type<T, U>::type mvkAbsDiff(T x, U y) { static constexpr typename std::common_type<T, U>::type mvkAbsDiff(T x, U y) {
return x >= y ? x - y : y - x; return x >= y ? x - y : y - x;
} }
/** Returns the greatest common divisor of two numbers. */ /** Returns the greatest common divisor of two numbers. */
template<typename T> template<typename T>
constexpr T mvkGreatestCommonDivisorImpl(T a, T b) { static constexpr T mvkGreatestCommonDivisorImpl(T a, T b) {
return b == 0 ? a : mvkGreatestCommonDivisorImpl(b, a % b); return b == 0 ? a : mvkGreatestCommonDivisorImpl(b, a % b);
} }
template<typename T, typename U> template<typename T, typename U>
constexpr typename std::common_type<T, U>::type mvkGreatestCommonDivisor(T a, U b) { static constexpr typename std::common_type<T, U>::type mvkGreatestCommonDivisor(T a, U b) {
typedef typename std::common_type<T, U>::type R; typedef typename std::common_type<T, U>::type R;
typedef typename std::make_unsigned<R>::type UI; typedef typename std::make_unsigned<R>::type UI;
return static_cast<R>(mvkGreatestCommonDivisorImpl(static_cast<UI>(MVKAbs<R, T>::eval(a)), static_cast<UI>(MVKAbs<R, U>::eval(b)))); return static_cast<R>(mvkGreatestCommonDivisorImpl(static_cast<UI>(MVKAbs<R, T>::eval(a)), static_cast<UI>(MVKAbs<R, U>::eval(b))));
@ -446,7 +449,7 @@ constexpr typename std::common_type<T, U>::type mvkGreatestCommonDivisor(T a, U
/** Returns the least common multiple of two numbers. */ /** Returns the least common multiple of two numbers. */
template<typename T, typename U> template<typename T, typename U>
constexpr typename std::common_type<T, U>::type mvkLeastCommonMultiple(T a, U b) { static constexpr typename std::common_type<T, U>::type mvkLeastCommonMultiple(T a, U b) {
typedef typename std::common_type<T, U>::type R; typedef typename std::common_type<T, U>::type R;
return (a == 0 && b == 0) ? 0 : MVKAbs<R, T>::eval(a) / mvkGreatestCommonDivisor(a, b) * MVKAbs<R, U>::eval(b); return (a == 0 && b == 0) ? 0 : MVKAbs<R, T>::eval(a) / mvkGreatestCommonDivisor(a, b) * MVKAbs<R, U>::eval(b);
} }
@ -463,7 +466,7 @@ constexpr typename std::common_type<T, U>::type mvkLeastCommonMultiple(T a, U b)
* value returned by previous calls as the seed in subsequent calls. * value returned by previous calls as the seed in subsequent calls.
*/ */
template<class N> template<class N>
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; std::size_t hash = seed;
for (std::size_t i = 0; i < count; i++) { hash = ((hash << 5) + hash) ^ pVals[i]; } for (std::size_t i = 0; i < count; i++) { hash = ((hash << 5) + hash) ^ pVals[i]; }
return hash; return hash;
@ -497,7 +500,7 @@ protected:
/** Ensures the size of the specified container is at least the specified size. */ /** Ensures the size of the specified container is at least the specified size. */
template<typename C, typename S> template<typename C, typename S>
void mvkEnsureSize(C& container, S size) { static void mvkEnsureSize(C& container, S size) {
if (size > container.size()) { container.resize(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. * each object, including freeing the object memory, and clearing the container.
*/ */
template<typename C> template<typename C>
void mvkDestroyContainerContents(C& container) { static void mvkDestroyContainerContents(C& container) {
for (auto elem : container) { elem->destroy(); } for (auto elem : container) { elem->destroy(); }
container.clear(); container.clear();
} }
@ -517,7 +520,7 @@ void mvkDestroyContainerContents(C& container) {
*/ */
#ifdef __OBJC__ #ifdef __OBJC__
template<typename C> template<typename C>
void mvkReleaseContainerContents(C& container) { static void mvkReleaseContainerContents(C& container) {
for (auto elem : container) { [elem release]; } for (auto elem : container) { [elem release]; }
container.clear(); container.clear();
} }
@ -525,14 +528,14 @@ void mvkReleaseContainerContents(C& container) {
/** Returns whether the container contains an item equal to the value. */ /** Returns whether the container contains an item equal to the value. */
template<class C, class T> template<class C, class T>
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; } } for (const T& cVal : container) { if (cVal == val) { return true; } }
return false; return false;
} }
/** Removes the first occurance of the specified value from the specified container. */ /** Removes the first occurance of the specified value from the specified container. */
template<class C, class T> template<class C, class T>
void mvkRemoveFirstOccurance(C& container, T val) { static void mvkRemoveFirstOccurance(C& container, T val) {
for (auto iter = container.begin(), end = container.end(); iter != end; iter++) { for (auto iter = container.begin(), end = container.end(); iter != end; iter++) {
if( *iter == val ) { if( *iter == val ) {
container.erase(iter); container.erase(iter);
@ -543,7 +546,7 @@ void mvkRemoveFirstOccurance(C& container, T val) {
/** Removes all occurances of the specified value from the specified container. */ /** Removes all occurances of the specified value from the specified container. */
template<class C, class T> template<class C, class T>
void mvkRemoveAllOccurances(C& container, T val) { static void mvkRemoveAllOccurances(C& container, T val) {
container.erase(std::remove(container.begin(), container.end(), val), container.end()); 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. */ /** Selects and returns one of the values, based on the platform OS. */
template<typename T> template<typename T>
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 #if MVK_IOS_OR_TVOS
return iOSVal; return iOSVal;
#endif #endif
@ -566,22 +569,29 @@ const T& mvkSelectPlatformValue(const T& macOSVal, const T& iOSVal) {
* The optional count allows clearing multiple elements in an array. * The optional count allows clearing multiple elements in an array.
*/ */
template<typename T> template<typename T>
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<T>) { if (count == 1) { *pDst = static_cast<T>(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 * 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. * by writing zeros to all bytes. The optional count allows clearing multiple elements in an array.
*/ */
template<typename T> template<typename T>
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 * 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. * destination value. The optional count allows copying of multiple elements in an array.
*/ */
template<typename T> template<typename T>
void mvkCopy(T* pDst, const T* pSrc, size_t count = 1) { static void mvkCopy(T* pDst, const T* pSrc, size_t count = 1) {
if (pSrc && pDst) { memcpy(pDst, pSrc, sizeof(T) * count); } if ( !pDst || !pSrc ) { return; } // Bad pointers
if (pDst == pSrc) { return; } // Same object
if constexpr(std::is_arithmetic_v<T>) { 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. * otherwise returns false. The optional count allows comparing multiple elements in an array.
*/ */
template<typename T> template<typename T>
bool mvkAreEqual(const T* pV1, const T* pV2, size_t count = 1) { static constexpr bool mvkAreEqual(const T* pV1, const T* pV2, size_t count = 1) {
return (pV1 && pV2) ? (memcmp(pV1, pV2, sizeof(T) * count) == 0) : false; if ( !pV2 || !pV2 ) { return false; } // Bad pointers
if (pV1 == pV2) { return true; } // Same object
if constexpr(std::is_arithmetic_v<T>) { 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<typename Tv, typename Tm> template<typename Tv, typename Tm>
void mvkEnableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value | bitMask); } void mvkEnableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value | bitMask); }
/** Enables all the flags (sets bits to 1) within the value parameter. */
template<typename Tv>
void mvkEnableAllFlags(Tv& value) { value = ~static_cast<Tv>(0); }
/** Disables the flags (sets bits to 0) within the value parameter specified by the bitMask parameter. */ /** Disables the flags (sets bits to 0) within the value parameter specified by the bitMask parameter. */
template<typename Tv, typename Tm> template<typename Tv, typename Tm>
void mvkDisableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value & ~(Tv)bitMask); } 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<typename Tv>
void mvkDisableAllFlags(Tv& value) { value = static_cast<Tv>(0); }
/** Returns whether the specified value has ANY of the flags specified in bitMask enabled (set to 1). */ /** Returns whether the specified value has ANY of the flags specified in bitMask enabled (set to 1). */
template<typename Tv, typename Tm> template<typename Tv, typename Tm>
static constexpr bool mvkIsAnyFlagEnabled(Tv value, const Tm bitMask) { return ((value & bitMask) != 0); } static constexpr bool mvkIsAnyFlagEnabled(Tv value, const Tm bitMask) { return ((value & bitMask) != 0); }

View File

@ -583,24 +583,33 @@ MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkRe
} }
#endif #endif
MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport) { MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(const VkViewport vkViewport) {
MTLViewport mtlViewport; return {
mtlViewport.originX = vkViewport.x; .originX = vkViewport.x,
mtlViewport.originY = vkViewport.y; .originY = vkViewport.y,
mtlViewport.width = vkViewport.width; .width = vkViewport.width,
mtlViewport.height = vkViewport.height; .height = vkViewport.height,
mtlViewport.znear = vkViewport.minDepth; .znear = vkViewport.minDepth,
mtlViewport.zfar = vkViewport.maxDepth; .zfar = vkViewport.maxDepth
return mtlViewport; };
} }
MVK_PUBLIC_SYMBOL MTLScissorRect mvkMTLScissorRectFromVkRect2D(VkRect2D vkRect) { MVK_PUBLIC_SYMBOL MTLScissorRect mvkMTLScissorRectFromVkRect2D(const VkRect2D vkRect) {
MTLScissorRect mtlScissor; return {
mtlScissor.x = vkRect.offset.x; .x = (NSUInteger)max(vkRect.offset.x, 0),
mtlScissor.y = vkRect.offset.y; .y = (NSUInteger)max(vkRect.offset.y, 0),
mtlScissor.width = vkRect.extent.width; .width = vkRect.extent.width,
mtlScissor.height = vkRect.extent.height; .height = vkRect.extent.height
return mtlScissor; };
}
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) { MVK_PUBLIC_SYMBOL MTLCompareFunction mvkMTLCompareFunctionFromVkCompareOp(VkCompareOp vkOp) {

View File

@ -1564,13 +1564,14 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindIndexBuffer(
MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindVertexBuffers( MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindVertexBuffers(
VkCommandBuffer commandBuffer, VkCommandBuffer commandBuffer,
uint32_t startBinding, uint32_t firstBinding,
uint32_t bindingCount, uint32_t bindingCount,
const VkBuffer* pBuffers, const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets) { const VkDeviceSize* pOffsets) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmdFrom2Thresholds(BindVertexBuffers, bindingCount, 1, 2, commandBuffer, startBinding, bindingCount, pBuffers, pOffsets); MVKAddCmdFrom2Thresholds(BindVertexBuffers, bindingCount, 1, 2, commandBuffer,
firstBinding, bindingCount, pBuffers, pOffsets, nullptr, nullptr);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2536,7 +2537,8 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdBindVertexBuffers2(
const VkDeviceSize* pStrides) { const VkDeviceSize* pStrides) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmdFrom2Thresholds(BindVertexBuffers, bindingCount, 1, 2, commandBuffer,
firstBinding, bindingCount, pBuffers, pOffsets, pSizes, pStrides);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2643,7 +2645,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthBoundsTestEnable(
VkBool32 depthBoundsTestEnable) { VkBool32 depthBoundsTestEnable) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmd(SetDepthBoundsTestEnable, commandBuffer, depthBoundsTestEnable);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2652,7 +2654,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthCompareOp(
VkCompareOp depthCompareOp) { VkCompareOp depthCompareOp) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmd(SetDepthCompareOp, commandBuffer, depthCompareOp);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2661,7 +2663,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthTestEnable(
VkBool32 depthTestEnable) { VkBool32 depthTestEnable) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmd(SetDepthTestEnable, commandBuffer, depthTestEnable);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2670,6 +2672,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthWriteEnable(
VkBool32 depthWriteEnable) { VkBool32 depthWriteEnable) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmd(SetDepthWriteEnable, commandBuffer, depthWriteEnable);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2699,6 +2702,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPrimitiveTopology(
VkPrimitiveTopology primitiveTopology) { VkPrimitiveTopology primitiveTopology) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmd(SetPrimitiveTopology, commandBuffer, primitiveTopology);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2723,6 +2727,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetStencilOp(
VkCompareOp compareOp) { VkCompareOp compareOp) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmd(SetStencilOp, commandBuffer, faceMask, failOp, passOp, depthFailOp, compareOp);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
@ -2731,6 +2736,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetStencilTestEnable(
VkBool32 stencilTestEnable) { VkBool32 stencilTestEnable) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKAddCmd(SetStencilTestEnable, commandBuffer, stencilTestEnable);
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }