Merge pull request #1566 from billhollings/VK_EXT_sample_locations
Add support for VK_EXT_sample_locations extension.
This commit is contained in:
commit
2a565ef8e7
@ -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_private_data `
|
||||
- `VK_EXT_robustness2`
|
||||
- `VK_EXT_sample_locations`
|
||||
- `VK_EXT_scalar_block_layout`
|
||||
- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
|
||||
- `VK_EXT_shader_viewport_index_layer`
|
||||
|
@ -18,6 +18,8 @@ MoltenVK 1.1.9
|
||||
|
||||
Released TBD
|
||||
|
||||
- Add support for extensions:
|
||||
- `VK_EXT_sample_locations`
|
||||
- Fixes to pipeline layout compatibility.
|
||||
- Reinstate memory barriers on non-Apple GPUs, which were inadvertently disabled in an earlier update.
|
||||
- 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.
|
||||
- `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 `VK_MVK_MOLTENVK_SPEC_VERSION` to version `34`.
|
||||
- Update to latest SPIRV-Cross:
|
||||
- MSL: Support input/output blocks containing nested struct arrays.
|
||||
- MSL: Use var name instead of var-type name for flattened interface members.
|
||||
|
@ -55,7 +55,7 @@ typedef unsigned long MTLLanguageVersion;
|
||||
#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 VK_MVK_MOLTENVK_SPEC_VERSION 33
|
||||
#define VK_MVK_MOLTENVK_SPEC_VERSION 34
|
||||
#define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk"
|
||||
|
||||
/** 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
|
||||
* 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
|
||||
* 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
|
||||
* 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. */
|
||||
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. */
|
||||
VkBool32 programmableSamplePositions; /**< If true, programmable MSAA sample positions are supported. */
|
||||
} MVKPhysicalDeviceMetalFeatures;
|
||||
|
||||
/** MoltenVK performance of a particular type of activity. */
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
MVKSmallVector<MVKSmallVector<MTLSamplePosition>> _subpassSamplePositions;
|
||||
MVKRenderPass* _renderPass;
|
||||
MVKFramebuffer* _framebuffer;
|
||||
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 MVKCmdExecuteCommands
|
||||
|
||||
|
@ -36,6 +36,30 @@ VkResult MVKCmdBeginRenderPassBase::setContent(MVKCommandBuffer* cmdBuff,
|
||||
_renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass;
|
||||
_framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
|
||||
_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;
|
||||
}
|
||||
@ -61,13 +85,23 @@ VkResult MVKCmdBeginRenderPass<N_CV, N_A>::setContent(MVKCommandBuffer* cmdBuff,
|
||||
template <size_t N_CV, size_t N_A>
|
||||
void MVKCmdBeginRenderPass<N_CV, N_A>::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
// 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,
|
||||
_contents,
|
||||
_renderPass,
|
||||
_framebuffer,
|
||||
_renderArea,
|
||||
_clearValues.contents(),
|
||||
_attachments.contents());
|
||||
_attachments.contents(),
|
||||
MVKArrayRef(spSPRefs, spSPCnt));
|
||||
}
|
||||
|
||||
template class MVKCmdBeginRenderPass<1, 0>;
|
||||
@ -130,6 +164,24 @@ void MVKCmdEndRenderPass::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
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 MVKCmdExecuteCommands
|
||||
|
@ -191,74 +191,6 @@ protected:
|
||||
#pragma mark -
|
||||
#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. */
|
||||
typedef std::unordered_map<MVKQueryPool*, MVKSmallVector<uint32_t, kMVKDefaultQueryCount>> MVKActivatedQueries;
|
||||
|
||||
@ -293,7 +225,8 @@ public:
|
||||
MVKFramebuffer* framebuffer,
|
||||
VkRect2D& renderArea,
|
||||
MVKArrayRef<VkClearValue> clearValues,
|
||||
MVKArrayRef<MVKImageView*> attachments);
|
||||
MVKArrayRef<MVKImageView*> attachments,
|
||||
MVKArrayRef<MVKArrayRef<MTLSamplePosition>> subpassSamplePositions);
|
||||
|
||||
/** Begins the next render subpass. */
|
||||
void beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents renderpassContents);
|
||||
@ -301,6 +234,9 @@ public:
|
||||
/** Begins the next multiview Metal render pass. */
|
||||
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. */
|
||||
void beginMetalRenderPass(MVKCommandUse cmdUse);
|
||||
|
||||
@ -509,6 +445,7 @@ protected:
|
||||
void encodeTimestampStageCounterSamples();
|
||||
bool hasTimestampStageCounterQueries() { return !_timestampStageCounterQueries.empty(); }
|
||||
id<MTLFence> getStageCountersMTLFence();
|
||||
MVKArrayRef<MTLSamplePosition> getCustomSamplePositions();
|
||||
|
||||
typedef struct GPUCounterQuery {
|
||||
MVKGPUCounterQueryPool* queryPool = nullptr;
|
||||
@ -526,6 +463,8 @@ protected:
|
||||
MVKSmallVector<GPUCounterQuery, 16> _timestampStageCounterQueries;
|
||||
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
|
||||
MVKSmallVector<MVKImageView*, kMVKDefaultAttachmentCount> _attachments;
|
||||
MVKSmallVector<MTLSamplePosition> _dynamicSamplePositions;
|
||||
MVKSmallVector<MVKSmallVector<MTLSamplePosition>> _subpassSamplePositions;
|
||||
id<MTLComputeCommandEncoder> _mtlComputeEncoder;
|
||||
MVKCommandUse _mtlComputeEncoderUse;
|
||||
id<MTLBlitCommandEncoder> _mtlBlitEncoder;
|
||||
|
@ -322,7 +322,8 @@ void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
|
||||
MVKFramebuffer* framebuffer,
|
||||
VkRect2D& renderArea,
|
||||
MVKArrayRef<VkClearValue> clearValues,
|
||||
MVKArrayRef<MVKImageView*> attachments) {
|
||||
MVKArrayRef<MVKImageView*> attachments,
|
||||
MVKArrayRef<MVKArrayRef<MTLSamplePosition>> subpassSamplePositions) {
|
||||
_renderPass = renderPass;
|
||||
_framebuffer = framebuffer;
|
||||
_renderArea = renderArea;
|
||||
@ -330,6 +331,14 @@ void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
|
||||
mvkVkExtent2DsAreEqual(_renderArea.extent, getFramebufferExtent()));
|
||||
_clearValues.assign(clearValues.begin(), clearValues.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);
|
||||
}
|
||||
|
||||
@ -365,6 +374,10 @@ void MVKCommandEncoder::beginNextMultiviewPass() {
|
||||
|
||||
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.
|
||||
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
|
||||
setLabelIfNotNil(_mtlRenderEncoder, getMTLRenderCommandEncoderName(cmdUse));
|
||||
|
||||
@ -439,6 +460,18 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
|
||||
_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) {
|
||||
getSubpass()->encodeStoreActions(this,
|
||||
_isRenderingEntireAttachment,
|
||||
|
@ -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_POOL(NextSubpass)
|
||||
MVK_CMD_TYPE_POOL(EndRenderPass)
|
||||
MVK_CMD_TYPE_POOL(SetSampleLocations)
|
||||
MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ExecuteCommands, 1)
|
||||
MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindDescriptorSetsStatic, 1, 4)
|
||||
MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BindDescriptorSetsDynamic, 4)
|
||||
|
@ -128,6 +128,10 @@ public:
|
||||
/** Populates the specified structure with the format properties of this device. */
|
||||
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. */
|
||||
VkResult getImageFormatProperties(VkFormat format,
|
||||
VkImageType type,
|
||||
|
@ -75,6 +75,9 @@ static const uint32_t kAMDRadeonRX5500DeviceId = 0x7340;
|
||||
static const uint32_t kAMDRadeonRX6800DeviceId = 0x73bf;
|
||||
static const uint32_t kAMDRadeonRX6700DeviceId = 0x73df;
|
||||
|
||||
static const VkExtent2D kMetalSamplePositionGridSize = { 1, 1 };
|
||||
static const VkExtent2D kMetalSamplePositionGridSizeNotSupported = { 0, 0 };
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
@ -457,6 +460,16 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
|
||||
portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
|
||||
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:
|
||||
break;
|
||||
}
|
||||
@ -526,6 +539,15 @@ void MVKPhysicalDevice::getFormatProperties(VkFormat format, VkFormatProperties2
|
||||
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,
|
||||
VkImageType type,
|
||||
VkImageTiling tiling,
|
||||
@ -1519,9 +1541,12 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
||||
|
||||
#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)] ) {
|
||||
_metalFeatures.rasterOrderGroups = _mtlDevice.rasterOrderGroupsSupported;
|
||||
_metalFeatures.rasterOrderGroups = _mtlDevice.areRasterOrderGroupsSupported;
|
||||
}
|
||||
#if MVK_XCODE_12
|
||||
if ( [_mtlDevice respondsToSelector: @selector(supportsPullModelInterpolation)] ) {
|
||||
@ -2738,6 +2763,9 @@ void MVKPhysicalDevice::initExtensions() {
|
||||
if (!_metalFeatures.samplerMirrorClampToEdge) {
|
||||
pWritableExtns->vk_KHR_sampler_mirror_clamp_to_edge.enabled = false;
|
||||
}
|
||||
if (!_metalFeatures.programmableSamplePositions) {
|
||||
pWritableExtns->vk_EXT_sample_locations.enabled = false;
|
||||
}
|
||||
if (!_metalFeatures.rasterOrderGroups) {
|
||||
pWritableExtns->vk_EXT_fragment_shader_interlock.enabled = false;
|
||||
}
|
||||
|
@ -655,6 +655,8 @@ void MVKInstance::initProcAddrs() {
|
||||
ADD_DVC_EXT_ENTRY_POINT(vkDestroyPrivateDataSlotEXT, 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(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(vkGetPastPresentationTimingGOOGLE, GOOGLE_DISPLAY_TIMING);
|
||||
|
||||
|
@ -203,9 +203,6 @@ struct MVKStagedDescriptorBindingUse {
|
||||
MVKBitArray stages[4] = {};
|
||||
};
|
||||
|
||||
/** The number of dynamic states possible in Vulkan. */
|
||||
static const uint32_t kMVKVkDynamicStateCount = 32;
|
||||
|
||||
/** Represents an Vulkan graphics pipeline. */
|
||||
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. */
|
||||
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. */
|
||||
uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding) { return _device->getMetalBufferIndexForVertexAttributeBinding(binding); }
|
||||
|
||||
@ -287,6 +290,7 @@ protected:
|
||||
|
||||
id<MTLRenderPipelineState> getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id<MTLRenderPipelineState>& plState);
|
||||
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 initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
|
||||
void addVertexInputToShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo);
|
||||
@ -323,6 +327,8 @@ protected:
|
||||
|
||||
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
|
||||
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
|
||||
MVKSmallVector<VkDynamicState> _dynamicState;
|
||||
MVKSmallVector<MTLSamplePosition> _customSamplePositions;
|
||||
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
|
||||
MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings;
|
||||
MVKSmallVector<MVKStagedMTLArgumentEncoders> _mtlArgumentEncoders;
|
||||
@ -350,7 +356,6 @@ protected:
|
||||
uint32_t _tessCtlPatchOutputBufferIndex = 0;
|
||||
uint32_t _tessCtlLevelBufferIndex = 0;
|
||||
|
||||
bool _dynamicStateEnabled[kMVKVkDynamicStateCount];
|
||||
bool _needsVertexSwizzleBuffer = false;
|
||||
bool _needsVertexBufferSizeBuffer = false;
|
||||
bool _needsVertexDynamicOffsetBuffer = false;
|
||||
@ -372,6 +377,7 @@ protected:
|
||||
bool _isRasterizing = false;
|
||||
bool _isRasterizingColor = false;
|
||||
bool _isRasterizingDepthStencil = false;
|
||||
bool _isUsingCustomSamplePositions = false;
|
||||
};
|
||||
|
||||
|
||||
|
@ -309,10 +309,8 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
|
||||
}
|
||||
|
||||
bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
|
||||
|
||||
// First test if this dynamic state is explicitly turned off
|
||||
if ( (state >= kMVKVkDynamicStateCount) || !_dynamicStateEnabled[state] ) { return false; }
|
||||
|
||||
for (auto& ds : _dynamicState) {
|
||||
if (state == ds) {
|
||||
// Some dynamic states have other restrictions
|
||||
switch (state) {
|
||||
case VK_DYNAMIC_STATE_DEPTH_BIAS:
|
||||
@ -321,6 +319,9 @@ bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char vtxCompilerType[] = "Vertex stage pipeline for tessellation";
|
||||
|
||||
@ -408,13 +409,11 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
|
||||
}
|
||||
}
|
||||
|
||||
// Track dynamic state in _dynamicStateEnabled array
|
||||
mvkClear(_dynamicStateEnabled, kMVKVkDynamicStateCount); // start with all dynamic state disabled
|
||||
// Track dynamic state
|
||||
const VkPipelineDynamicStateCreateInfo* pDS = pCreateInfo->pDynamicState;
|
||||
if (pDS) {
|
||||
for (uint32_t i = 0; i < pDS->dynamicStateCount; i++) {
|
||||
VkDynamicState ds = pDS->pDynamicStates[i];
|
||||
_dynamicStateEnabled[ds] = true;
|
||||
_dynamicState.push_back(pDS->pDynamicStates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,6 +456,9 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
|
||||
}
|
||||
}
|
||||
|
||||
// Must run after _isRasterizing and _dynamicState are populated
|
||||
initCustomSamplePositions(pCreateInfo);
|
||||
|
||||
// Render pipeline state
|
||||
initMTLRenderPipelineState(pCreateInfo, reflectData);
|
||||
|
||||
@ -472,7 +474,7 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
|
||||
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 ( !_dynamicStateEnabled[VK_DYNAMIC_STATE_VIEWPORT] ) { vp = pVPState->pViewports[vpIdx]; }
|
||||
if ( !supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT) ) { vp = pVPState->pViewports[vpIdx]; }
|
||||
_viewports.push_back(vp);
|
||||
}
|
||||
|
||||
@ -481,7 +483,7 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
|
||||
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 ( !_dynamicStateEnabled[VK_DYNAMIC_STATE_SCISSOR] ) { sc = pVPState->pScissors[sIdx]; }
|
||||
if ( !supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR) ) { sc = pVPState->pScissors[sIdx]; }
|
||||
_scissors.push_back(sc);
|
||||
}
|
||||
}
|
||||
@ -512,6 +514,31 @@ id<MTLComputePipelineState> MVKGraphicsPipeline::getOrCompilePipeline(MTLCompute
|
||||
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.
|
||||
void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData) {
|
||||
_mtlTessVertexStageState = nil;
|
||||
|
@ -261,8 +261,11 @@ public:
|
||||
/** Returns the granularity of the render area of this instance. */
|
||||
VkExtent2D getRenderAreaGranularity();
|
||||
|
||||
/** Returns the format of the color attachment at the specified index. */
|
||||
MVKRenderSubpass* getSubpass(uint32_t subpassIndex);
|
||||
/** Returns the number of subpasses. */
|
||||
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. */
|
||||
bool isMultiview() const;
|
||||
|
@ -818,8 +818,6 @@ VkExtent2D MVKRenderPass::getRenderAreaGranularity() {
|
||||
return { 1, 1 };
|
||||
}
|
||||
|
||||
MVKRenderSubpass* MVKRenderPass::getSubpass(uint32_t subpassIndex) { return &_subpasses[subpassIndex]; }
|
||||
|
||||
bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); }
|
||||
|
||||
MVKRenderPass::MVKRenderPass(MVKDevice* device,
|
||||
|
@ -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_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_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_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)
|
||||
|
@ -442,6 +442,11 @@ struct MVKArrayRef {
|
||||
const Type* end() const { return &data[size]; }
|
||||
const Type& operator[]( const size_t i ) const { 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(Type* d, size_t s) : data(d), size(s) {}
|
||||
};
|
||||
|
@ -3098,6 +3098,29 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPastPresentationTimingGOOGLE(
|
||||
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 iOS & macOS surface extensions
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user