Add support for VK_EXT_sample_locations extension.

Supports only setting custom sample locations in subpasses via
vkBeginRenderpass. Does not support setting custom sample locations via
vkCmdBindPipeline or vkCmdSetSampleLocationsEXT, although collects that
info for possible future enhancements.

- MVKPhysicalDevice track platform support and respond to property queries.
- MVKCmdBeginRenderPassBase collect subpass custom sample locations.
- MVKPipeline support dynamic state values beyond 31.
- MVKPipeline collect custom sample locations.
- Add MVKCmdSetSampleLocations to support vkCmdSetSampleLocations
  to collect dynamic custom sample locations.
- MVKCommandEncoder support collecting custom sample positions from subpass
  and dynamic, and set into MTLRenderPassDescriptor for each Metal render pass.
- MVKArrayRef add assignment operator.
- Add MVKPhysicalDeviceMetalFeatures::programmableSamplePositions.
- Update VK_MVK_MOLTENVK_SPEC_VERSION to version 34.
- MVKCommandBuffer.h remove obsolete comment documentation.
- Update Whats_New.md.
This commit is contained in:
Bill Hollings 2022-04-08 14:20:18 -04:00
parent 148823a841
commit 3c0644f36a
18 changed files with 247 additions and 100 deletions

View File

@ -307,6 +307,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
- `VK_EXT_post_depth_coverage` *(iOS and macOS, requires family 4 (A11) or better Apple GPU)* - `VK_EXT_post_depth_coverage` *(iOS and macOS, requires family 4 (A11) or better Apple GPU)*
- `VK_EXT_private_data ` - `VK_EXT_private_data `
- `VK_EXT_robustness2` - `VK_EXT_robustness2`
- `VK_EXT_sample_locations`
- `VK_EXT_scalar_block_layout` - `VK_EXT_scalar_block_layout`
- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)* - `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
- `VK_EXT_shader_viewport_index_layer` - `VK_EXT_shader_viewport_index_layer`

View File

@ -18,6 +18,8 @@ MoltenVK 1.1.9
Released TBD Released TBD
- Add support for extensions:
- `VK_EXT_sample_locations`
- Fixes to pipeline layout compatibility. - Fixes to pipeline layout compatibility.
- Reinstate memory barriers on non-Apple GPUs, which were inadvertently disabled in an earlier update. - Reinstate memory barriers on non-Apple GPUs, which were inadvertently disabled in an earlier update.
- Support base vertex instance support in shader conversion. - Support base vertex instance support in shader conversion.
@ -29,6 +31,7 @@ Released TBD
- Fixes to optimize resource objects retained by descriptors beyond their lifetimes. - Fixes to optimize resource objects retained by descriptors beyond their lifetimes.
- `MoltenVKShaderConverter` tool defaults to the highest MSL version supported on runtime OS. - `MoltenVKShaderConverter` tool defaults to the highest MSL version supported on runtime OS.
- Update *glslang* version, to use `python3` in *glslang* scripts, to replace missing `python` on *macOS 12.3*. - Update *glslang* version, to use `python3` in *glslang* scripts, to replace missing `python` on *macOS 12.3*.
- Update `VK_MVK_MOLTENVK_SPEC_VERSION` to version `34`.
- Update to latest SPIRV-Cross: - Update to latest SPIRV-Cross:
- MSL: Support input/output blocks containing nested struct arrays. - MSL: Support input/output blocks containing nested struct arrays.
- MSL: Use var name instead of var-type name for flattened interface members. - MSL: Use var name instead of var-type name for flattened interface members.

View File

@ -55,7 +55,7 @@ typedef unsigned long MTLLanguageVersion;
#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) #define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH) #define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
#define VK_MVK_MOLTENVK_SPEC_VERSION 33 #define VK_MVK_MOLTENVK_SPEC_VERSION 34
#define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk" #define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk"
/** Identifies the level of logging MoltenVK should be limited to outputting. */ /** Identifies the level of logging MoltenVK should be limited to outputting. */
@ -786,7 +786,7 @@ typedef struct {
* command buffer submission, to a physically removed GPU. In the case where this error does * command buffer submission, to a physically removed GPU. In the case where this error does
* not impact the VkPhysicalDevice, Vulkan requires that the app destroy and re-create a new * not impact the VkPhysicalDevice, Vulkan requires that the app destroy and re-create a new
* VkDevice. However, not all apps (including CTS) respect that requirement, leading to what * VkDevice. However, not all apps (including CTS) respect that requirement, leading to what
* might be a transient command submission failure causing an unexpected catastophic app failure. * might be a transient command submission failure causing an unexpected catastrophic app failure.
* *
* If this setting is enabled, in the case of a VK_ERROR_DEVICE_LOST error that does NOT impact * If this setting is enabled, in the case of a VK_ERROR_DEVICE_LOST error that does NOT impact
* the VkPhysicalDevice, MoltenVK will log the error, but will not mark the VkDevice as lost, * the VkPhysicalDevice, MoltenVK will log the error, but will not mark the VkDevice as lost,
@ -929,6 +929,7 @@ typedef struct {
VkBool32 descriptorSetArgumentBuffers; /**< If true, a Metal argument buffer can be assigned to a descriptor set, and used on any pipeline and pipeline stage. If false, a different Metal argument buffer must be used for each pipeline-stage/descriptor-set combination. */ VkBool32 descriptorSetArgumentBuffers; /**< If true, a Metal argument buffer can be assigned to a descriptor set, and used on any pipeline and pipeline stage. If false, a different Metal argument buffer must be used for each pipeline-stage/descriptor-set combination. */
MVKFloatRounding clearColorFloatRounding; /**< Identifies the type of rounding Metal uses for MTLClearColor float to integer conversions. */ MVKFloatRounding clearColorFloatRounding; /**< Identifies the type of rounding Metal uses for MTLClearColor float to integer conversions. */
MVKCounterSamplingFlags counterSamplingPoints; /**< Identifies the points where pipeline GPU counter sampling may occur. */ MVKCounterSamplingFlags counterSamplingPoints; /**< Identifies the points where pipeline GPU counter sampling may occur. */
VkBool32 programmableSamplePositions; /**< If true, programmable MSAA sample positions are supported. */
} MVKPhysicalDeviceMetalFeatures; } MVKPhysicalDeviceMetalFeatures;
/** MoltenVK performance of a particular type of activity. */ /** MoltenVK performance of a particular type of activity. */

View File

@ -46,6 +46,7 @@ public:
protected: protected:
MVKSmallVector<MVKSmallVector<MTLSamplePosition>> _subpassSamplePositions;
MVKRenderPass* _renderPass; MVKRenderPass* _renderPass;
MVKFramebuffer* _framebuffer; MVKFramebuffer* _framebuffer;
VkRect2D _renderArea; VkRect2D _renderArea;
@ -137,6 +138,25 @@ protected:
}; };
#pragma mark -
#pragma mark MVKCmdSetSampleLocations
/** Vulkan command to dynamically set custom sample locations. */
class MVKCmdSetSampleLocations : public MVKCommand {
public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
const VkSampleLocationsInfoEXT* pSampleLocationsInfo);
void encode(MVKCommandEncoder* cmdEncoder) override;
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
MVKSmallVector<MTLSamplePosition, 8> _samplePositions;
};
#pragma mark - #pragma mark -
#pragma mark MVKCmdExecuteCommands #pragma mark MVKCmdExecuteCommands

View File

@ -36,6 +36,30 @@ VkResult MVKCmdBeginRenderPassBase::setContent(MVKCommandBuffer* cmdBuff,
_renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass; _renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass;
_framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer; _framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
_renderArea = pRenderPassBegin->renderArea; _renderArea = pRenderPassBegin->renderArea;
_subpassSamplePositions.clear();
for (const auto* next = (VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) {
switch (next->sType) {
case VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT: {
// Build an array of arrays, one array of sample positions for each subpass index.
// For subpasses not included in VkRenderPassSampleLocationsBeginInfoEXT, the resulting array of samples will be empty.
_subpassSamplePositions.resize(_renderPass->getSubpassCount());
auto* pRPSampLocnsInfo = (VkRenderPassSampleLocationsBeginInfoEXT*)next;
for (uint32_t spSLIdx = 0; spSLIdx < pRPSampLocnsInfo->postSubpassSampleLocationsCount; spSLIdx++) {
auto& spsl = pRPSampLocnsInfo->pPostSubpassSampleLocations[spSLIdx];
uint32_t spIdx = spsl.subpassIndex;
auto& spSampPosns = _subpassSamplePositions[spIdx];
for (uint32_t slIdx = 0; slIdx < spsl.sampleLocationsInfo.sampleLocationsCount; slIdx++) {
auto& sl = spsl.sampleLocationsInfo.pSampleLocations[slIdx];
spSampPosns.push_back(MTLSamplePositionMake(sl.x, sl.y));
}
}
break;
}
default:
break;
}
}
return VK_SUCCESS; return VK_SUCCESS;
} }
@ -61,13 +85,23 @@ VkResult MVKCmdBeginRenderPass<N_CV, N_A>::setContent(MVKCommandBuffer* cmdBuff,
template <size_t N_CV, size_t N_A> template <size_t N_CV, size_t N_A>
void MVKCmdBeginRenderPass<N_CV, N_A>::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdBeginRenderPass<N_CV, N_A>::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds()); // MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
// Convert the sample position array of arrays to an array of array-references,
// so that it can be passed to the command encoder.
size_t spSPCnt = _subpassSamplePositions.size();
MVKArrayRef<MTLSamplePosition> spSPRefs[spSPCnt];
for (uint32_t spSPIdx = 0; spSPIdx < spSPCnt; spSPIdx++) {
spSPRefs[spSPIdx] = _subpassSamplePositions[spSPIdx].contents();
}
cmdEncoder->beginRenderpass(this, cmdEncoder->beginRenderpass(this,
_contents, _contents,
_renderPass, _renderPass,
_framebuffer, _framebuffer,
_renderArea, _renderArea,
_clearValues.contents(), _clearValues.contents(),
_attachments.contents()); _attachments.contents(),
MVKArrayRef(spSPRefs, spSPCnt));
} }
template class MVKCmdBeginRenderPass<1, 0>; template class MVKCmdBeginRenderPass<1, 0>;
@ -130,6 +164,24 @@ void MVKCmdEndRenderPass::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->endRenderpass(); cmdEncoder->endRenderpass();
} }
#pragma mark -
#pragma mark MVKCmdSetSampleLocations
VkResult MVKCmdSetSampleLocations::setContent(MVKCommandBuffer* cmdBuff,
const VkSampleLocationsInfoEXT* pSampleLocationsInfo) {
for (uint32_t slIdx = 0; slIdx < pSampleLocationsInfo->sampleLocationsCount; slIdx++) {
auto& sl = pSampleLocationsInfo->pSampleLocations[slIdx];
_samplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y));
}
return VK_SUCCESS;
}
void MVKCmdSetSampleLocations::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->setDynamicSamplePositions(_samplePositions.contents());
}
#pragma mark - #pragma mark -
#pragma mark MVKCmdExecuteCommands #pragma mark MVKCmdExecuteCommands

View File

@ -191,74 +191,6 @@ protected:
#pragma mark - #pragma mark -
#pragma mark MVKCommandEncoder #pragma mark MVKCommandEncoder
// The following commands can be issued both inside and outside a renderpass and their state must
// span multiple MTLRenderCommandEncoders, to allow state to be set before a renderpass, and to
// allow more than one MTLRenderCommandEncoder to be used for a single Vulkan renderpass or subpass.
//
// + vkCmdBindPipeline() : _graphicsPipelineState & _computePipelineState
// + vkCmdBindDescriptorSets() : _graphicsResourcesState & _computeResourcesState
// + vkCmdBindVertexBuffers() : _graphicsResourcesState
// + vkCmdBindIndexBuffer() : _graphicsResourcesState
// + vkCmdPushConstants() : _vertexPushConstants & _tessCtlPushConstants & _tessEvalPushConstants & _fragmentPushConstants & _computePushConstants
// + vkCmdSetViewport() : _viewportState
// + vkCmdSetDepthBias() : _depthBiasState
// + vkCmdSetScissor() : _scissorState
// + vkCmdSetStencilCompareMask() : _depthStencilState
// + vkCmdSetStencilWriteMask() : _depthStencilState
// + vkCmdSetStencilReference() : _stencilReferenceValueState
// + vkCmdSetBlendConstants() : _blendColorState
// + vkCmdBeginQuery() : _occlusionQueryState
// + vkCmdEndQuery() : _occlusionQueryState
// + vkCmdPipelineBarrier() : handled via textureBarrier and MTLBlitCommandEncoder
// + vkCmdWriteTimestamp() : doesn't affect MTLCommandEncoders
// + vkCmdExecuteCommands() : state managed by embedded commands
// - vkCmdSetLineWidth() - unsupported by Metal
// - vkCmdSetDepthBounds() - unsupported by Metal
// - vkCmdWaitEvents() - unsupported by Metal
// The above list of Vulkan commands covers the following corresponding MTLRenderCommandEncoder state:
// + setBlendColorRed : _blendColorState
// + setCullMode : _graphicsPipelineState
// + setDepthBias : _depthBiasState
// + setDepthClipMode : _graphicsPipelineState
// + setDepthStencilState : _depthStencilState
// + setFrontFacingWinding : _graphicsPipelineState
// + setRenderPipelineState : _graphicsPipelineState
// + setScissorRect : _scissorState
// + setStencilFrontReferenceValue : _stencilReferenceValueState
// + setStencilReferenceValue (unused) : _stencilReferenceValueState
// + setTriangleFillMode : _graphicsPipelineState
// + setViewport : _viewportState
// + setVisibilityResultMode : _occlusionQueryState
// + setVertexBuffer : _graphicsResourcesState & _vertexPushConstants & _tessEvalPushConstants
// + setVertexBuffers (unused) : _graphicsResourcesState
// + setVertexBytes : _vertexPushConstants & _tessEvalPushConstants
// + setVertexBufferOffset (unused) : _graphicsResourcesState
// + setVertexTexture : _graphicsResourcesState
// + setVertexTextures (unused) : _graphicsResourcesState
// + setVertexSamplerState : _graphicsResourcesState
// + setVertexSamplerStates : (unused) : _graphicsResourcesState
// + setFragmentBuffer : _graphicsResourcesState & _fragmentPushConstants
// + setFragmentBuffers (unused) : _graphicsResourcesState
// + setFragmentBytes : _fragmentPushConstants
// + setFragmentBufferOffset (unused) : _graphicsResourcesState
// + setFragmentTexture : _graphicsResourcesState
// + setFragmentTextures (unused) : _graphicsResourcesState
// + setFragmentSamplerState : _graphicsResourcesState
// + setFragmentSamplerStates : (unused) : _graphicsResourcesState
// The above list of Vulkan commands covers the following corresponding MTLComputeCommandEncoder state:
// + setComputePipelineState : _computePipelineState & _graphicsPipelineState
// + setBuffer : _computeResourcesState & _computePushConstants & _graphicsResourcesState & _tessCtlPushConstants
// + setBuffers (unused) : _computeResourcesState & _graphicsResourcesState
// + setBytes : _computePushConstants & _tessCtlPushConstants
// + setBufferOffset (unused) : _computeResourcesState & _graphicsResourcesState
// + setTexture : _computeResourcesState & _graphicsResourcesState
// + setTextures (unused) : _computeResourcesState & _graphicsResourcesState
// + setSamplerState : _computeResourcesState & _graphicsResourcesState
// + setSamplerStates : (unused) : _computeResourcesState & _graphicsResourcesState
/*** Holds a collection of active queries for each query pool. */ /*** Holds a collection of active queries for each query pool. */
typedef std::unordered_map<MVKQueryPool*, MVKSmallVector<uint32_t, kMVKDefaultQueryCount>> MVKActivatedQueries; typedef std::unordered_map<MVKQueryPool*, MVKSmallVector<uint32_t, kMVKDefaultQueryCount>> MVKActivatedQueries;
@ -293,7 +225,8 @@ public:
MVKFramebuffer* framebuffer, MVKFramebuffer* framebuffer,
VkRect2D& renderArea, VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues, MVKArrayRef<VkClearValue> clearValues,
MVKArrayRef<MVKImageView*> attachments); MVKArrayRef<MVKImageView*> attachments,
MVKArrayRef<MVKArrayRef<MTLSamplePosition>> subpassSamplePositions);
/** Begins the next render subpass. */ /** Begins the next render subpass. */
void beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents renderpassContents); void beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents renderpassContents);
@ -301,6 +234,9 @@ public:
/** Begins the next multiview Metal render pass. */ /** Begins the next multiview Metal render pass. */
void beginNextMultiviewPass(); void beginNextMultiviewPass();
/** Sets the dynamic custom sample positions to use when rendering. */
void setDynamicSamplePositions(MVKArrayRef<MTLSamplePosition> dynamicSamplePositions);
/** Begins a Metal render pass for the current render subpass. */ /** Begins a Metal render pass for the current render subpass. */
void beginMetalRenderPass(MVKCommandUse cmdUse); void beginMetalRenderPass(MVKCommandUse cmdUse);
@ -509,6 +445,7 @@ protected:
void encodeTimestampStageCounterSamples(); void encodeTimestampStageCounterSamples();
bool hasTimestampStageCounterQueries() { return !_timestampStageCounterQueries.empty(); } bool hasTimestampStageCounterQueries() { return !_timestampStageCounterQueries.empty(); }
id<MTLFence> getStageCountersMTLFence(); id<MTLFence> getStageCountersMTLFence();
MVKArrayRef<MTLSamplePosition> getCustomSamplePositions();
typedef struct GPUCounterQuery { typedef struct GPUCounterQuery {
MVKGPUCounterQueryPool* queryPool = nullptr; MVKGPUCounterQueryPool* queryPool = nullptr;
@ -526,6 +463,8 @@ protected:
MVKSmallVector<GPUCounterQuery, 16> _timestampStageCounterQueries; MVKSmallVector<GPUCounterQuery, 16> _timestampStageCounterQueries;
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues; MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
MVKSmallVector<MVKImageView*, kMVKDefaultAttachmentCount> _attachments; MVKSmallVector<MVKImageView*, kMVKDefaultAttachmentCount> _attachments;
MVKSmallVector<MTLSamplePosition> _dynamicSamplePositions;
MVKSmallVector<MVKSmallVector<MTLSamplePosition>> _subpassSamplePositions;
id<MTLComputeCommandEncoder> _mtlComputeEncoder; id<MTLComputeCommandEncoder> _mtlComputeEncoder;
MVKCommandUse _mtlComputeEncoderUse; MVKCommandUse _mtlComputeEncoderUse;
id<MTLBlitCommandEncoder> _mtlBlitEncoder; id<MTLBlitCommandEncoder> _mtlBlitEncoder;

View File

@ -322,7 +322,8 @@ void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
MVKFramebuffer* framebuffer, MVKFramebuffer* framebuffer,
VkRect2D& renderArea, VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues, MVKArrayRef<VkClearValue> clearValues,
MVKArrayRef<MVKImageView*> attachments) { MVKArrayRef<MVKImageView*> attachments,
MVKArrayRef<MVKArrayRef<MTLSamplePosition>> subpassSamplePositions) {
_renderPass = renderPass; _renderPass = renderPass;
_framebuffer = framebuffer; _framebuffer = framebuffer;
_renderArea = renderArea; _renderArea = renderArea;
@ -330,6 +331,14 @@ void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
mvkVkExtent2DsAreEqual(_renderArea.extent, getFramebufferExtent())); mvkVkExtent2DsAreEqual(_renderArea.extent, getFramebufferExtent()));
_clearValues.assign(clearValues.begin(), clearValues.end()); _clearValues.assign(clearValues.begin(), clearValues.end());
_attachments.assign(attachments.begin(), attachments.end()); _attachments.assign(attachments.begin(), attachments.end());
// Copy the sample positions array of arrays, one array of sample positions for each subpass index.
_subpassSamplePositions.resize(subpassSamplePositions.size);
for (uint32_t spSPIdx = 0; spSPIdx < subpassSamplePositions.size; spSPIdx++) {
_subpassSamplePositions[spSPIdx].assign(subpassSamplePositions[spSPIdx].begin(),
subpassSamplePositions[spSPIdx].end());
}
setSubpass(passCmd, subpassContents, 0); setSubpass(passCmd, subpassContents, 0);
} }
@ -365,6 +374,10 @@ void MVKCommandEncoder::beginNextMultiviewPass() {
uint32_t MVKCommandEncoder::getMultiviewPassIndex() { return _multiviewPassIndex; } uint32_t MVKCommandEncoder::getMultiviewPassIndex() { return _multiviewPassIndex; }
void MVKCommandEncoder::setDynamicSamplePositions(MVKArrayRef<MTLSamplePosition> dynamicSamplePositions) {
_dynamicSamplePositions.assign(dynamicSamplePositions.begin(), dynamicSamplePositions.end());
}
// Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder. // Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder.
void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) { void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
@ -416,6 +429,14 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
} }
} }
// If programmable sample positions are supported, set them into the render pass descriptor.
// If no custom sample positions are established, size will be zero,
// and Metal will default to using default sample postions.
if (_pDeviceMetalFeatures->programmableSamplePositions) {
auto cstmSampPosns = getCustomSamplePositions();
[mtlRPDesc setSamplePositions: cstmSampPosns.data count: cstmSampPosns.size];
}
_mtlRenderEncoder = [_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPDesc]; // not retained _mtlRenderEncoder = [_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPDesc]; // not retained
setLabelIfNotNil(_mtlRenderEncoder, getMTLRenderCommandEncoderName(cmdUse)); setLabelIfNotNil(_mtlRenderEncoder, getMTLRenderCommandEncoderName(cmdUse));
@ -439,6 +460,18 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
_occlusionQueryState.beginMetalRenderPass(); _occlusionQueryState.beginMetalRenderPass();
} }
// If custom sample positions have been set, return them, otherwise return an empty array.
// For Metal, VkPhysicalDeviceSampleLocationsPropertiesEXT::variableSampleLocations is false.
// As such, Vulkan requires that sample positions must be established at the beginning of
// a renderpass, and that both pipeline and dynamic sample locations must be the same as those
// set for each subpass. Therefore, the only sample positions of use are those set for each
// subpass when the renderpass begins. The pipeline and dynamic sample positions are ignored.
MVKArrayRef<MTLSamplePosition> MVKCommandEncoder::getCustomSamplePositions() {
return (_renderSubpassIndex < _subpassSamplePositions.size()
? _subpassSamplePositions[_renderSubpassIndex].contents()
: MVKArrayRef<MTLSamplePosition>());
}
void MVKCommandEncoder::encodeStoreActions(bool storeOverride) { void MVKCommandEncoder::encodeStoreActions(bool storeOverride) {
getSubpass()->encodeStoreActions(this, getSubpass()->encodeStoreActions(this,
_isRenderingEntireAttachment, _isRenderingEntireAttachment,

View File

@ -78,6 +78,7 @@ MVK_CMD_TYPE_POOL(BindComputePipeline)
MVK_CMD_TYPE_POOLS_FROM_5_THRESHOLDS(BeginRenderPass, 1, 2, 0, 1, 2) MVK_CMD_TYPE_POOLS_FROM_5_THRESHOLDS(BeginRenderPass, 1, 2, 0, 1, 2)
MVK_CMD_TYPE_POOL(NextSubpass) MVK_CMD_TYPE_POOL(NextSubpass)
MVK_CMD_TYPE_POOL(EndRenderPass) MVK_CMD_TYPE_POOL(EndRenderPass)
MVK_CMD_TYPE_POOL(SetSampleLocations)
MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ExecuteCommands, 1) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ExecuteCommands, 1)
MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindDescriptorSetsStatic, 1, 4) MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindDescriptorSetsStatic, 1, 4)
MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BindDescriptorSetsDynamic, 4) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BindDescriptorSetsDynamic, 4)

View File

@ -128,6 +128,10 @@ public:
/** Populates the specified structure with the format properties of this device. */ /** Populates the specified structure with the format properties of this device. */
void getFormatProperties(VkFormat format, VkFormatProperties2* pFormatProperties); void getFormatProperties(VkFormat format, VkFormatProperties2* pFormatProperties);
/** Populates the specified structure with the multisample properties of this device. */
void getMultisampleProperties(VkSampleCountFlagBits samples,
VkMultisamplePropertiesEXT* pMultisampleProperties);
/** Populates the image format properties supported on this device. */ /** Populates the image format properties supported on this device. */
VkResult getImageFormatProperties(VkFormat format, VkResult getImageFormatProperties(VkFormat format,
VkImageType type, VkImageType type,

View File

@ -75,6 +75,9 @@ static const uint32_t kAMDRadeonRX5500DeviceId = 0x7340;
static const uint32_t kAMDRadeonRX6800DeviceId = 0x73bf; static const uint32_t kAMDRadeonRX6800DeviceId = 0x73bf;
static const uint32_t kAMDRadeonRX6700DeviceId = 0x73df; static const uint32_t kAMDRadeonRX6700DeviceId = 0x73df;
static const VkExtent2D kMetalSamplePositionGridSize = { 1, 1 };
static const VkExtent2D kMetalSamplePositionGridSizeNotSupported = { 0, 0 };
#pragma clang diagnostic pop #pragma clang diagnostic pop
@ -457,6 +460,16 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment; portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
break; break;
} }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT: {
auto* sampLocnProps = (VkPhysicalDeviceSampleLocationsPropertiesEXT*)next;
sampLocnProps->sampleLocationSampleCounts = _metalFeatures.supportedSampleCounts;
sampLocnProps->maxSampleLocationGridSize = kMetalSamplePositionGridSize;
sampLocnProps->sampleLocationCoordinateRange[0] = 0.0;
sampLocnProps->sampleLocationCoordinateRange[1] = (15.0 / 16.0);
sampLocnProps->sampleLocationSubPixelBits = 4;
sampLocnProps->variableSampleLocations = VK_FALSE;
break;
}
default: default:
break; break;
} }
@ -526,6 +539,15 @@ void MVKPhysicalDevice::getFormatProperties(VkFormat format, VkFormatProperties2
getFormatProperties(format, &pFormatProperties->formatProperties); getFormatProperties(format, &pFormatProperties->formatProperties);
} }
void MVKPhysicalDevice::getMultisampleProperties(VkSampleCountFlagBits samples,
VkMultisamplePropertiesEXT* pMultisampleProperties) {
if (pMultisampleProperties) {
pMultisampleProperties->maxSampleLocationGridSize = (mvkIsOnlyAnyFlagEnabled(samples, _metalFeatures.supportedSampleCounts)
? kMetalSamplePositionGridSize
: kMetalSamplePositionGridSizeNotSupported);
}
}
VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format, VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
VkImageType type, VkImageType type,
VkImageTiling tiling, VkImageTiling tiling,
@ -1519,9 +1541,12 @@ void MVKPhysicalDevice::initMetalFeatures() {
#endif #endif
// Note the selector name, which is different from the property name. if ( [_mtlDevice respondsToSelector: @selector(areProgrammableSamplePositionsSupported)] ) {
_metalFeatures.programmableSamplePositions = _mtlDevice.areProgrammableSamplePositionsSupported;
}
if ( [_mtlDevice respondsToSelector: @selector(areRasterOrderGroupsSupported)] ) { if ( [_mtlDevice respondsToSelector: @selector(areRasterOrderGroupsSupported)] ) {
_metalFeatures.rasterOrderGroups = _mtlDevice.rasterOrderGroupsSupported; _metalFeatures.rasterOrderGroups = _mtlDevice.areRasterOrderGroupsSupported;
} }
#if MVK_XCODE_12 #if MVK_XCODE_12
if ( [_mtlDevice respondsToSelector: @selector(supportsPullModelInterpolation)] ) { if ( [_mtlDevice respondsToSelector: @selector(supportsPullModelInterpolation)] ) {
@ -2738,6 +2763,9 @@ void MVKPhysicalDevice::initExtensions() {
if (!_metalFeatures.samplerMirrorClampToEdge) { if (!_metalFeatures.samplerMirrorClampToEdge) {
pWritableExtns->vk_KHR_sampler_mirror_clamp_to_edge.enabled = false; pWritableExtns->vk_KHR_sampler_mirror_clamp_to_edge.enabled = false;
} }
if (!_metalFeatures.programmableSamplePositions) {
pWritableExtns->vk_EXT_sample_locations.enabled = false;
}
if (!_metalFeatures.rasterOrderGroups) { if (!_metalFeatures.rasterOrderGroups) {
pWritableExtns->vk_EXT_fragment_shader_interlock.enabled = false; pWritableExtns->vk_EXT_fragment_shader_interlock.enabled = false;
} }

View File

@ -655,6 +655,8 @@ void MVKInstance::initProcAddrs() {
ADD_DVC_EXT_ENTRY_POINT(vkDestroyPrivateDataSlotEXT, EXT_PRIVATE_DATA); ADD_DVC_EXT_ENTRY_POINT(vkDestroyPrivateDataSlotEXT, EXT_PRIVATE_DATA);
ADD_DVC_EXT_ENTRY_POINT(vkGetPrivateDataEXT, EXT_PRIVATE_DATA); ADD_DVC_EXT_ENTRY_POINT(vkGetPrivateDataEXT, EXT_PRIVATE_DATA);
ADD_DVC_EXT_ENTRY_POINT(vkSetPrivateDataEXT, EXT_PRIVATE_DATA); ADD_DVC_EXT_ENTRY_POINT(vkSetPrivateDataEXT, EXT_PRIVATE_DATA);
ADD_DVC_EXT_ENTRY_POINT(vkGetPhysicalDeviceMultisamplePropertiesEXT, EXT_SAMPLE_LOCATIONS);
ADD_DVC_EXT_ENTRY_POINT(vkCmdSetSampleLocationsEXT, EXT_SAMPLE_LOCATIONS);
ADD_DVC_EXT_ENTRY_POINT(vkGetRefreshCycleDurationGOOGLE, GOOGLE_DISPLAY_TIMING); ADD_DVC_EXT_ENTRY_POINT(vkGetRefreshCycleDurationGOOGLE, GOOGLE_DISPLAY_TIMING);
ADD_DVC_EXT_ENTRY_POINT(vkGetPastPresentationTimingGOOGLE, GOOGLE_DISPLAY_TIMING); ADD_DVC_EXT_ENTRY_POINT(vkGetPastPresentationTimingGOOGLE, GOOGLE_DISPLAY_TIMING);

View File

@ -203,9 +203,6 @@ struct MVKStagedDescriptorBindingUse {
MVKBitArray stages[4] = {}; MVKBitArray stages[4] = {};
}; };
/** The number of dynamic states possible in Vulkan. */
static const uint32_t kMVKVkDynamicStateCount = 32;
/** Represents an Vulkan graphics pipeline. */ /** Represents an Vulkan graphics pipeline. */
class MVKGraphicsPipeline : public MVKPipeline { class MVKGraphicsPipeline : public MVKPipeline {
@ -259,6 +256,12 @@ public:
/** Returns true if the tessellation control shader needs a buffer to store its per-patch output. */ /** Returns true if the tessellation control shader needs a buffer to store its per-patch output. */
bool needsTessCtlPatchOutputBuffer() { return _needsTessCtlPatchOutputBuffer; } bool needsTessCtlPatchOutputBuffer() { return _needsTessCtlPatchOutputBuffer; }
/** Returns whether this pipeline has custom sample positions enabled. */
bool isUsingCustomSamplePositions() { return _isUsingCustomSamplePositions; }
/** Returns the custom samples used by this pipeline. */
MVKArrayRef<MTLSamplePosition> getCustomSamplePositions() { return _customSamplePositions.contents(); }
/** Returns the Metal vertex buffer index to use for the specified vertex attribute binding number. */ /** Returns the Metal vertex buffer index to use for the specified vertex attribute binding number. */
uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding) { return _device->getMetalBufferIndexForVertexAttributeBinding(binding); } uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding) { return _device->getMetalBufferIndexForVertexAttributeBinding(binding); }
@ -287,6 +290,7 @@ protected:
id<MTLRenderPipelineState> getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id<MTLRenderPipelineState>& plState); id<MTLRenderPipelineState> getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id<MTLRenderPipelineState>& plState);
id<MTLComputePipelineState> getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id<MTLComputePipelineState>& plState, const char* compilerType); id<MTLComputePipelineState> getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id<MTLComputePipelineState>& plState, const char* compilerType);
void initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo);
void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
void addVertexInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo); void addVertexInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo);
@ -323,6 +327,8 @@ protected:
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports; MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors; MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
MVKSmallVector<VkDynamicState> _dynamicState;
MVKSmallVector<MTLSamplePosition> _customSamplePositions;
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings; MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings; MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings;
MVKSmallVector<MVKStagedMTLArgumentEncoders> _mtlArgumentEncoders; MVKSmallVector<MVKStagedMTLArgumentEncoders> _mtlArgumentEncoders;
@ -350,7 +356,6 @@ protected:
uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlPatchOutputBufferIndex = 0;
uint32_t _tessCtlLevelBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0;
bool _dynamicStateEnabled[kMVKVkDynamicStateCount];
bool _needsVertexSwizzleBuffer = false; bool _needsVertexSwizzleBuffer = false;
bool _needsVertexBufferSizeBuffer = false; bool _needsVertexBufferSizeBuffer = false;
bool _needsVertexDynamicOffsetBuffer = false; bool _needsVertexDynamicOffsetBuffer = false;
@ -372,6 +377,7 @@ protected:
bool _isRasterizing = false; bool _isRasterizing = false;
bool _isRasterizingColor = false; bool _isRasterizingColor = false;
bool _isRasterizingDepthStencil = false; bool _isRasterizingDepthStencil = false;
bool _isUsingCustomSamplePositions = false;
}; };

View File

@ -309,17 +309,18 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
} }
bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) { bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
for (auto& ds : _dynamicState) {
// First test if this dynamic state is explicitly turned off if (state == ds) {
if ( (state >= kMVKVkDynamicStateCount) || !_dynamicStateEnabled[state] ) { return false; } // Some dynamic states have other restrictions
switch (state) {
// Some dynamic states have other restrictions case VK_DYNAMIC_STATE_DEPTH_BIAS:
switch (state) { return _rasterInfo.depthBiasEnable;
case VK_DYNAMIC_STATE_DEPTH_BIAS: default:
return _rasterInfo.depthBiasEnable; return true;
default: }
return true; }
} }
return false;
} }
static const char vtxCompilerType[] = "Vertex stage pipeline for tessellation"; static const char vtxCompilerType[] = "Vertex stage pipeline for tessellation";
@ -408,13 +409,11 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
} }
} }
// Track dynamic state in _dynamicStateEnabled array // Track dynamic state
mvkClear(_dynamicStateEnabled, kMVKVkDynamicStateCount); // start with all dynamic state disabled
const VkPipelineDynamicStateCreateInfo* pDS = pCreateInfo->pDynamicState; const VkPipelineDynamicStateCreateInfo* pDS = pCreateInfo->pDynamicState;
if (pDS) { if (pDS) {
for (uint32_t i = 0; i < pDS->dynamicStateCount; i++) { for (uint32_t i = 0; i < pDS->dynamicStateCount; i++) {
VkDynamicState ds = pDS->pDynamicStates[i]; _dynamicState.push_back(pDS->pDynamicStates[i]);
_dynamicStateEnabled[ds] = true;
} }
} }
@ -457,6 +456,9 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
} }
} }
// Must run after _isRasterizing and _dynamicState are populated
initCustomSamplePositions(pCreateInfo);
// Render pipeline state // Render pipeline state
initMTLRenderPipelineState(pCreateInfo, reflectData); initMTLRenderPipelineState(pCreateInfo, reflectData);
@ -472,7 +474,7 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
for (uint32_t vpIdx = 0; vpIdx < vpCnt; vpIdx++) { for (uint32_t vpIdx = 0; vpIdx < vpCnt; vpIdx++) {
// If viewport is dyanamic, we still add a dummy so that the count will be tracked. // If viewport is dyanamic, we still add a dummy so that the count will be tracked.
VkViewport vp; VkViewport vp;
if ( !_dynamicStateEnabled[VK_DYNAMIC_STATE_VIEWPORT] ) { vp = pVPState->pViewports[vpIdx]; } if ( !supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT) ) { vp = pVPState->pViewports[vpIdx]; }
_viewports.push_back(vp); _viewports.push_back(vp);
} }
@ -481,7 +483,7 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
for (uint32_t sIdx = 0; sIdx < sCnt; sIdx++) { for (uint32_t sIdx = 0; sIdx < sCnt; sIdx++) {
// If scissor is dyanamic, we still add a dummy so that the count will be tracked. // If scissor is dyanamic, we still add a dummy so that the count will be tracked.
VkRect2D sc; VkRect2D sc;
if ( !_dynamicStateEnabled[VK_DYNAMIC_STATE_SCISSOR] ) { sc = pVPState->pScissors[sIdx]; } if ( !supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR) ) { sc = pVPState->pScissors[sIdx]; }
_scissors.push_back(sc); _scissors.push_back(sc);
} }
} }
@ -512,6 +514,31 @@ id<MTLComputePipelineState> MVKGraphicsPipeline::getOrCompilePipeline(MTLCompute
return plState; return plState;
} }
// Must run after _isRasterizing and _dynamicState are populated
void MVKGraphicsPipeline::initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo) {
// Must ignore allowed bad pMultisampleState pointer if rasterization disabled
if ( !(_isRasterizing && pCreateInfo->pMultisampleState) ) { return; }
for (const auto* next = (VkBaseInStructure*)pCreateInfo->pMultisampleState->pNext; next; next = next->pNext) {
switch (next->sType) {
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)) {
for (uint32_t slIdx = 0; slIdx < pSampLocnsCreateInfo->sampleLocationsInfo.sampleLocationsCount; slIdx++) {
auto& sl = pSampLocnsCreateInfo->sampleLocationsInfo.pSampleLocations[slIdx];
_customSamplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y));
}
}
break;
}
default:
break;
}
}
}
// Constructs the underlying Metal render pipeline. // Constructs the underlying Metal render pipeline.
void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData) { void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData) {
_mtlTessVertexStageState = nil; _mtlTessVertexStageState = nil;

View File

@ -261,8 +261,11 @@ public:
/** Returns the granularity of the render area of this instance. */ /** Returns the granularity of the render area of this instance. */
VkExtent2D getRenderAreaGranularity(); VkExtent2D getRenderAreaGranularity();
/** Returns the format of the color attachment at the specified index. */ /** Returns the number of subpasses. */
MVKRenderSubpass* getSubpass(uint32_t subpassIndex); size_t getSubpassCount() { return _subpasses.size(); }
/** Returns the subpass at the specified index. */
MVKRenderSubpass* getSubpass(uint32_t subpassIndex) { return &_subpasses[subpassIndex]; }
/** Returns whether or not this render pass is a multiview render pass. */ /** Returns whether or not this render pass is a multiview render pass. */
bool isMultiview() const; bool isMultiview() const;

View File

@ -818,8 +818,6 @@ VkExtent2D MVKRenderPass::getRenderAreaGranularity() {
return { 1, 1 }; return { 1, 1 };
} }
MVKRenderSubpass* MVKRenderPass::getSubpass(uint32_t subpassIndex) { return &_subpasses[subpassIndex]; }
bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); } bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); }
MVKRenderPass::MVKRenderPass(MVKDevice* device, MVKRenderPass::MVKRenderPass(MVKDevice* device,

View File

@ -95,6 +95,7 @@ MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE,
MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE, 11.0, 11.0) MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE, 11.0, 11.0)
MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE, 10.11, 8.0)
MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE, 10.11, 8.0)
MVK_EXTENSION(EXT_sample_locations, EXT_SAMPLE_LOCATIONS, DEVICE, 10.13, 11.0)
MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE, 10.11, 8.0)
MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE, 10.14, 12.0) MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE, 10.14, 12.0)
MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE, 10.11, 8.0)

View File

@ -442,6 +442,11 @@ struct MVKArrayRef {
const Type* end() const { return &data[size]; } const Type* end() const { return &data[size]; }
const Type& operator[]( const size_t i ) const { return data[i]; } const Type& operator[]( const size_t i ) const { return data[i]; }
Type& operator[]( const size_t i ) { return data[i]; } Type& operator[]( const size_t i ) { return data[i]; }
MVKArrayRef<Type>& operator=(const MVKArrayRef<Type>& other) {
data = other.data;
*(size_t*)&size = other.size;
return *this;
}
MVKArrayRef() : MVKArrayRef(nullptr, 0) {} MVKArrayRef() : MVKArrayRef(nullptr, 0) {}
MVKArrayRef(Type* d, size_t s) : data(d), size(s) {} MVKArrayRef(Type* d, size_t s) : data(d), size(s) {}
}; };

View File

@ -3098,6 +3098,29 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPastPresentationTimingGOOGLE(
return rslt; return rslt;
} }
#pragma mark -
#pragma mark VK_EXT_sample_locations extension
void vkGetPhysicalDeviceMultisamplePropertiesEXT(
VkPhysicalDevice physicalDevice,
VkSampleCountFlagBits samples,
VkMultisamplePropertiesEXT* pMultisampleProperties) {
MVKTraceVulkanCallStart();
MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
mvkPD->getMultisampleProperties(samples, pMultisampleProperties);
MVKTraceVulkanCallEnd();
}
void vkCmdSetSampleLocationsEXT(
VkCommandBuffer commandBuffer,
const VkSampleLocationsInfoEXT* pSampleLocationsInfo) {
MVKTraceVulkanCallStart();
MVKAddCmd(SetSampleLocations, commandBuffer, pSampleLocationsInfo);
MVKTraceVulkanCallEnd();
}
#pragma mark - #pragma mark -
#pragma mark iOS & macOS surface extensions #pragma mark iOS & macOS surface extensions