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