Merge pull request #1131 from billhollings/VK_EXT_descriptor_indexing
Initial support for the VK_EXT_descriptor_indexing extension
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 2a0fcd5..c4b6da0 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -303,6 +303,7 @@
- `VK_EXT_debug_marker`
- `VK_EXT_debug_report`
- `VK_EXT_debug_utils`
+- `VK_EXT_descriptor_indexing`
- `VK_EXT_fragment_shader_interlock` *(requires Metal 2.0 and Raster Order Groups)*
- `VK_EXT_host_query_reset`
- `VK_EXT_image_robustness`
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index a3c9c45..bb11f8a 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -19,6 +19,7 @@
Released TBD
- Add support for extensions:
+ - `VK_EXT_descriptor_indexing` (initial release limited to Metal Tier 1: 96/128 textures, 16 samplers)
- `VK_EXT_private_data`
- `VK_IMG_format_pvrtc` (macOS)
- Use `VK_KHR_image_format_list` to disable `MTLTextureUsagePixelFormatView`
@@ -27,7 +28,10 @@
- Move *Metal* drawable presentation from `MTLCommandBuffer` to `MTLDrawable`
to improve performance and reduce blocking.
- Allow binding descriptor set using layout different than it was created with.
+- Report `VkPhysicalDeviceLimits::maxPerStageDescriptorStorageImages` as Metal limit of `8`.
+- Increase per-stage texture count to `96` for A11 SoC's and above.
- Clarify documentation on mapping limitations for host-coherent image memory on *macOS*.
+- Update `VK_MVK_MOLTENVK_SPEC_VERSION` to `29`.
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index e938194..00be046 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-0db1569e970b0b1b9bfcaec691e2bfb2f26a73db
+fc644b50e631ccd88c324793823ade040a80caf5
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index cfb2663..fbe42f9 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -55,7 +55,7 @@
#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 28
+#define VK_MVK_MOLTENVK_SPEC_VERSION 29
#define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk"
/**
@@ -271,11 +271,16 @@
* command buffer. Depending on the number of command buffers that you use, you may also need to
* change the value of the maxActiveMetalCommandBuffersPerQueue setting.
*
- * In addition, if this feature is enabled, be aware that if you have recorded commands to a
- * Vulkan command buffer, and then choose to reset that command buffer instead of submitting it,
- * the corresponding prefilled Metal command buffer will still be submitted. This is because Metal
- * command buffers do not support the concept of being reset after being filled. Depending on when
- * and how often you do this, it may cause unexpected visual artifacts and unnecessary GPU load.
+ * If this feature is enabled, be aware that if you have recorded commands to a Vulkan command buffer,
+ * and then choose to reset that command buffer instead of submitting it, the corresponding prefilled
+ * Metal command buffer will still be submitted. This is because Metal command buffers do not support
+ * the concept of being reset after being filled. Depending on when and how often you do this,
+ * it may cause unexpected visual artifacts and unnecessary GPU load.
+ *
+ * This feature is incompatible with updating descriptors after binding. If any of the
+ * *UpdateAfterBind feature flags of VkPhysicalDeviceDescriptorIndexingFeaturesEXT or
+ * VkPhysicalDeviceInlineUniformBlockFeaturesEXT have been enabled, the value of this
+ * setting will be ignored and treated as if it is false.
*
* The value of this parameter may be changed at any time during application runtime,
* and the changed value will immediately effect subsequent MoltenVK behaviour.
@@ -621,6 +626,7 @@
VkBool32 depthResolve; /**< If true, resolving depth textures with filters other than Sample0 is supported. */
VkBool32 stencilResolve; /**< If true, resolving stencil textures with filters other than Sample0 is supported. */
uint32_t maxPerStageDynamicMTLBufferCount; /**< The maximum number of inline buffers that can be set on a command buffer. */
+ uint32_t maxPerStageStorageTextureCount; /**< The total number of per-stage Metal textures with read-write access available for writing to from a shader. */
} MVKPhysicalDeviceMetalFeatures;
/** MoltenVK performance of a particular type of activity. */
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 7d619b5..5c0efd2 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -161,7 +161,7 @@
}
bool MVKCommandBuffer::canPrefill() {
- bool wantPrefill = _device->_pMVKConfig->prefillMetalCommandBuffers;
+ bool wantPrefill = _device->shouldPrefillMTLCommandBuffers();
return wantPrefill && !(_isSecondary || _supportsConcurrentExecution);
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
index d88c1f8..0ce732e 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
@@ -70,8 +70,20 @@
/** Returns the binding number of this layout. */
inline uint32_t getBinding() { return _info.binding; }
- /** Returns the number of descriptors in this layout. */
- inline uint32_t getDescriptorCount() { return (_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) ? 1 : _info.descriptorCount; }
+ /** Returns whether this binding has a variable descriptor count. */
+ inline bool hasVariableDescriptorCount() {
+ return mvkIsAnyFlagEnabled(_flags, VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT);
+ }
+
+ /**
+ * Returns the number of descriptors in this layout.
+ *
+ * If this is an inline block data descriptor, always returns 1. If this descriptor
+ * has a variable descriptor count, and descSet is not null, the variable descriptor
+ * count provided to that descriptor set is returned. Otherwise returns the value
+ * defined in VkDescriptorSetLayoutBinding::descriptorCount.
+ */
+ uint32_t getDescriptorCount(MVKDescriptorSet* descSet);
/** Returns the descriptor type of this layout. */
inline VkDescriptorType getDescriptorType() { return _info.descriptorType; }
@@ -86,12 +98,15 @@
/** Returns the immutable sampler at the index, or nullptr if immutable samplers are not used. */
MVKSampler* getImmutableSampler(uint32_t index);
- /** Encodes the descriptors in the descriptor set that are specified by this layout, */
- void bind(MVKCommandEncoder* cmdEncoder,
- MVKDescriptorSet* descSet,
- MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKArrayRef<uint32_t> dynamicOffsets,
- uint32_t baseDynamicOffsetIndex);
+ /**
+ * Encodes the descriptors in the descriptor set that are specified by this layout,
+ * Returns the number of dynamic offsets consumed.
+ */
+ uint32_t bind(MVKCommandEncoder* cmdEncoder,
+ MVKDescriptorSet* descSet,
+ MVKShaderResourceBinding& dslMTLRezIdxOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
+ uint32_t descSetDynamicOffsetIndex);
/** Encodes this binding layout and the specified descriptor on the specified command encoder immediately. */
void push(MVKCommandEncoder* cmdEncoder,
@@ -110,7 +125,8 @@
MVKDescriptorSetLayoutBinding(MVKDevice* device,
MVKDescriptorSetLayout* layout,
- const VkDescriptorSetLayoutBinding* pBinding);
+ const VkDescriptorSetLayoutBinding* pBinding,
+ VkDescriptorBindingFlagsEXT bindingFlags);
MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding);
@@ -125,6 +141,7 @@
MVKDescriptorSetLayout* _layout;
VkDescriptorSetLayoutBinding _info;
+ VkDescriptorBindingFlagsEXT _flags;
MVKSmallVector<MVKSampler*> _immutableSamplers;
MVKShaderResourceBinding _mtlResourceIndexOffsets;
bool _applyToStage[kMVKShaderStageMax];
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
index 74ce403..e70a769 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
@@ -74,26 +74,48 @@
MVKVulkanAPIObject* MVKDescriptorSetLayoutBinding::getVulkanAPIObject() { return _layout; };
+uint32_t MVKDescriptorSetLayoutBinding::getDescriptorCount(MVKDescriptorSet* descSet) {
+
+ if (_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+ return 1;
+ }
+
+ if (descSet && hasVariableDescriptorCount()) {
+ return descSet->_variableDescriptorCount;
+ }
+
+ return _info.descriptorCount;
+}
+
MVKSampler* MVKDescriptorSetLayoutBinding::getImmutableSampler(uint32_t index) {
return (index < _immutableSamplers.size()) ? _immutableSamplers[index] : nullptr;
}
// A null cmdEncoder can be passed to perform a validation pass
-void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
- MVKDescriptorSet* descSet,
- MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKArrayRef<uint32_t> dynamicOffsets,
- uint32_t baseDynamicOffsetIndex) {
+uint32_t MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
+ MVKDescriptorSet* descSet,
+ MVKShaderResourceBinding& dslMTLRezIdxOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
+ uint32_t descSetDynamicOffsetIndex) {
// Establish the resource indices to use, by combining the offsets of the DSL and this DSL binding.
MVKShaderResourceBinding mtlIdxs = _mtlResourceIndexOffsets + dslMTLRezIdxOffsets;
- uint32_t descCnt = getDescriptorCount();
+ VkDescriptorType descType = getDescriptorType();
+ uint32_t descCnt = getDescriptorCount(descSet);
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
MVKDescriptor* mvkDesc = descSet->getDescriptor(getBinding(), descIdx);
- mvkDesc->bind(cmdEncoder, _info.descriptorType, descIdx, _applyToStage, mtlIdxs,
- dynamicOffsets, baseDynamicOffsetIndex + _dynamicOffsetIndex + descIdx);
+ mvkDesc->bind(cmdEncoder, descType, descIdx, _applyToStage, mtlIdxs,
+ dynamicOffsets, descSetDynamicOffsetIndex + _dynamicOffsetIndex + descIdx);
}
+
+ switch (descType) {
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ return descCnt;
+ default:
+ return 0;
+ }
}
template<typename T>
@@ -352,6 +374,7 @@
models[i],
dslIndex,
_info.binding,
+ getDescriptorCount(nullptr),
mvkSamp);
}
}
@@ -359,8 +382,15 @@
MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(MVKDevice* device,
MVKDescriptorSetLayout* layout,
- const VkDescriptorSetLayoutBinding* pBinding) : MVKBaseDeviceObject(device), _layout(layout),
- _dynamicOffsetIndex(0) {
+ const VkDescriptorSetLayoutBinding* pBinding,
+ VkDescriptorBindingFlagsEXT bindingFlags) :
+ MVKBaseDeviceObject(device),
+ _layout(layout),
+ _info(*pBinding),
+ _flags(bindingFlags),
+ _dynamicOffsetIndex(0) {
+
+ _info.pImmutableSamplers = nullptr; // Remove dangling pointer
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
// Determine if this binding is used by this shader stage
@@ -383,13 +413,14 @@
}
}
- _info = *pBinding;
- _info.pImmutableSamplers = nullptr; // Remove dangling pointer
}
MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding) :
- MVKBaseDeviceObject(binding._device), _layout(binding._layout),
- _info(binding._info), _immutableSamplers(binding._immutableSamplers),
+ MVKBaseDeviceObject(binding._device),
+ _layout(binding._layout),
+ _info(binding._info),
+ _flags(binding._flags),
+ _immutableSamplers(binding._immutableSamplers),
_mtlResourceIndexOffsets(binding._mtlResourceIndexOffsets),
_dynamicOffsetIndex(0) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 1f2ce42..c31ef35 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -43,15 +43,15 @@
/** Returns the debug report object type of this object. */
VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT; }
- inline uint32_t getDynamicDescriptorCount() { return _dynamicDescriptorCount; }
-
- /** Encodes this descriptor set layout and the specified descriptor set on the specified command encoder. */
- void bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
- MVKDescriptorSet* descSet,
- MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKArrayRef<uint32_t> dynamicOffsets,
- uint32_t baseDynamicOffsetIndex);
-
+ /**
+ * Encodes this descriptor set layout and the specified descriptor set on the specified command encoder.
+ * Returns the number of dynamic offsets consumed.
+ */
+ uint32_t bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
+ MVKDescriptorSet* descSet,
+ MVKShaderResourceBinding& dslMTLRezIdxOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
+ uint32_t dynamicOffsetIndex);
/** Encodes this descriptor set layout and the specified descriptor updates on the specified command encoder immediately. */
void pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
@@ -87,13 +87,13 @@
inline uint32_t getDescriptorCount() { return _descriptorCount; }
inline uint32_t getDescriptorIndex(uint32_t binding, uint32_t elementIndex = 0) { return _bindingToDescriptorIndex[binding] + elementIndex; }
inline MVKDescriptorSetLayoutBinding* getBinding(uint32_t binding) { return &_bindings[_bindingToIndex[binding]]; }
+ const VkDescriptorBindingFlags* getBindingFlags(const VkDescriptorSetLayoutCreateInfo* pCreateInfo);
MVKSmallVector<MVKDescriptorSetLayoutBinding> _bindings;
std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
std::unordered_map<uint32_t, uint32_t> _bindingToDescriptorIndex;
MVKShaderResourceBinding _mtlResourceCounts;
uint32_t _descriptorCount;
- uint32_t _dynamicDescriptorCount;
bool _isPushDescriptorLayout;
};
@@ -129,7 +129,9 @@
VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock);
- MVKDescriptorSet(MVKDescriptorSetLayout* layout, MVKDescriptorPool* pool);
+ MVKDescriptorSet(MVKDescriptorSetLayout* layout,
+ uint32_t variableDescriptorCount,
+ MVKDescriptorPool* pool);
~MVKDescriptorSet() override;
@@ -143,6 +145,7 @@
MVKDescriptorSetLayout* _layout;
MVKDescriptorPool* _pool;
MVKSmallVector<MVKDescriptor*> _descriptors;
+ uint32_t _variableDescriptorCount;
};
@@ -225,9 +228,8 @@
/** Returns the debug report object type of this object. */
VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT; }
- /** Allocates the specified number of descriptor sets. */
- VkResult allocateDescriptorSets(uint32_t count,
- const VkDescriptorSetLayout* pSetLayouts,
+ /** Allocates descriptor sets. */
+ VkResult allocateDescriptorSets(const VkDescriptorSetAllocateInfo* pAllocateInfo,
VkDescriptorSet* pDescriptorSets);
/** Free's up the specified descriptor set. */
@@ -244,7 +246,8 @@
friend class MVKDescriptorSet;
void propagateDebugName() override {}
- VkResult allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL, VkDescriptorSet* pVKDS);
+ VkResult allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL, uint32_t variableDescriptorCount, VkDescriptorSet* pVKDS);
+ const uint32_t* getVariableDecriptorCounts(const VkDescriptorSetAllocateInfo* pAllocateInfo);
void freeDescriptorSet(MVKDescriptorSet* mvkDS);
VkResult allocateDescriptor(VkDescriptorType descriptorType, MVKDescriptor** pMVKDesc);
void freeDescriptor(MVKDescriptor* mvkDesc);
@@ -314,4 +317,5 @@
spv::ExecutionModel stage,
uint32_t descriptorSetIndex,
uint32_t bindingIndex,
+ uint32_t count,
MVKSampler* immutableSampler);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index ac6be1f..b8a4b94 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -24,18 +24,23 @@
#pragma mark -
#pragma mark MVKDescriptorSetLayout
+// Dynamic offsets passed in are in order of binding number, not binding index.
+// Each binding offsets relative to the index for the descriptor set itself.
// A null cmdEncoder can be passed to perform a validation pass
-void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
- MVKDescriptorSet* descSet,
- MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKArrayRef<uint32_t> dynamicOffsets,
- uint32_t baseDynamicOffsetIndex) {
- if (_isPushDescriptorLayout) return;
-
+uint32_t MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
+ MVKDescriptorSet* descSet,
+ MVKShaderResourceBinding& dslMTLRezIdxOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
+ uint32_t dynamicOffsetIndex) {
clearConfigurationResult();
- for (auto& dslBind : _bindings) {
- dslBind.bind(cmdEncoder, descSet, dslMTLRezIdxOffsets, dynamicOffsets, baseDynamicOffsetIndex);
+ uint32_t dynOffsetsConsumed = 0;
+ if ( !_isPushDescriptorLayout ) {
+ for (auto& dslBind : _bindings) {
+ dynOffsetsConsumed += dslBind.bind(cmdEncoder, descSet, dslMTLRezIdxOffsets,
+ dynamicOffsets, dynamicOffsetIndex);
+ }
}
+ return dynOffsetsConsumed;
}
static const void* getWriteParameters(VkDescriptorType type, const VkDescriptorImageInfo* pImageInfo,
@@ -170,19 +175,19 @@
MVKDescriptorSetLayout::MVKDescriptorSetLayout(MVKDevice* device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
+ const auto* pBindingFlags = getBindingFlags(pCreateInfo);
_isPushDescriptorLayout = (pCreateInfo->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) != 0;
-
_descriptorCount = 0;
_bindings.reserve(pCreateInfo->bindingCount);
MVKSmallVector<MVKDescriptorSetLayoutBinding*, 32> dynamicBindings;
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
auto* pBind = &pCreateInfo->pBindings[i];
- _bindings.emplace_back(_device, this, pBind);
+ _bindings.emplace_back(_device, this, pBind, (pBindingFlags ? pBindingFlags[i] : 0));
_bindingToIndex[pBind->binding] = i;
_bindingToDescriptorIndex[pBind->binding] = _descriptorCount;
MVKDescriptorSetLayoutBinding* mvkBind = &_bindings.back();
- _descriptorCount += mvkBind->getDescriptorCount();
+ _descriptorCount += mvkBind->getDescriptorCount(nullptr);
if (pBind->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
pBind->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
dynamicBindings.push_back(mvkBind);
@@ -196,13 +201,31 @@
[](MVKDescriptorSetLayoutBinding* mvkBind1, MVKDescriptorSetLayoutBinding* mvkBind2) {
return mvkBind1->getBinding() < mvkBind2->getBinding(); });
- _dynamicDescriptorCount = 0;
+ // Only the last dynamic binding (highest binding number) can have a variable descriptor count.
+ // The other bindings will each have an accurate descriptor count while setting the dynamic offsets.
+ uint32_t dynDescCnt = 0;
for (auto mvkBind : dynamicBindings) {
- mvkBind->setDynamicOffsetIndex(_dynamicDescriptorCount);
- _dynamicDescriptorCount += mvkBind->getDescriptorCount();
+ mvkBind->setDynamicOffsetIndex(dynDescCnt);
+ dynDescCnt += mvkBind->getDescriptorCount(nullptr);
}
}
+// Find and return an array of binding flags from the pNext chain of pCreateInfo,
+// or return nullptr if the chain does not include binding flags.
+const VkDescriptorBindingFlags* MVKDescriptorSetLayout::getBindingFlags(const VkDescriptorSetLayoutCreateInfo* pCreateInfo) {
+ for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT: {
+ auto* pDescSetLayoutBindingFlags = (VkDescriptorSetLayoutBindingFlagsCreateInfoEXT*)next;
+ return pDescSetLayoutBindingFlags->bindingCount ? pDescSetLayoutBindingFlags->pBindingFlags : nullptr;
+ }
+ default:
+ break;
+ }
+ }
+ return nullptr;
+}
+
#pragma mark -
#pragma mark MVKDescriptorSet
@@ -261,31 +284,27 @@
}
}
-// If the descriptor pool fails to allocate a descriptor, record a configuration error
-MVKDescriptorSet::MVKDescriptorSet(MVKDescriptorSetLayout* layout, MVKDescriptorPool* pool) :
- MVKVulkanAPIDeviceObject(pool->_device), _layout(layout), _pool(pool) {
+MVKDescriptorSet::MVKDescriptorSet(MVKDescriptorSetLayout* layout,
+ uint32_t variableDescriptorCount,
+ MVKDescriptorPool* pool) :
+ MVKVulkanAPIDeviceObject(pool->_device),
+ _layout(layout),
+ _variableDescriptorCount(variableDescriptorCount),
+ _pool(pool) {
_descriptors.reserve(layout->getDescriptorCount());
uint32_t bindCnt = (uint32_t)layout->_bindings.size();
for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
MVKDescriptorSetLayoutBinding* mvkDSLBind = &layout->_bindings[bindIdx];
- MVKDescriptor* mvkDesc = nullptr;
- if (mvkDSLBind->getDescriptorType() == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
- setConfigurationResult(_pool->allocateDescriptor(mvkDSLBind->getDescriptorType(), &mvkDesc));
- if ( !wasConfigurationSuccessful() ) { break; }
+ uint32_t descCnt = mvkDSLBind->getDescriptorCount(this);
+ for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
+ MVKDescriptor* mvkDesc = nullptr;
+ setConfigurationResult(_pool->allocateDescriptor(mvkDSLBind->getDescriptorType(), &mvkDesc));
+ if ( !wasConfigurationSuccessful() ) { break; }
- mvkDesc->setLayout(mvkDSLBind, 0);
- _descriptors.push_back(mvkDesc);
- } else {
- uint32_t descCnt = mvkDSLBind->getDescriptorCount();
- for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
- setConfigurationResult(_pool->allocateDescriptor(mvkDSLBind->getDescriptorType(), &mvkDesc));
- if ( !wasConfigurationSuccessful() ) { break; }
-
- mvkDesc->setLayout(mvkDSLBind, descIdx);
- _descriptors.push_back(mvkDesc);
- }
- }
+ mvkDesc->setLayout(mvkDSLBind, descIdx);
+ _descriptors.push_back(mvkDesc);
+ }
if ( !wasConfigurationSuccessful() ) { break; }
}
}
@@ -532,10 +551,9 @@
#pragma mark -
#pragma mark MVKDescriptorPool
-VkResult MVKDescriptorPool::allocateDescriptorSets(uint32_t count,
- const VkDescriptorSetLayout* pSetLayouts,
+VkResult MVKDescriptorPool::allocateDescriptorSets(const VkDescriptorSetAllocateInfo* pAllocateInfo,
VkDescriptorSet* pDescriptorSets) {
- if (_allocatedSets.size() + count > _maxSets) {
+ if (_allocatedSets.size() + pAllocateInfo->descriptorSetCount > _maxSets) {
if (_device->_enabledExtensions.vk_KHR_maintenance1.enabled ||
_device->getInstance()->getAPIVersion() >= VK_API_VERSION_1_1) {
return VK_ERROR_OUT_OF_POOL_MEMORY; // Failure is an acceptable test...don't log as error.
@@ -545,16 +563,33 @@
}
VkResult rslt = VK_SUCCESS;
- for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) {
- MVKDescriptorSetLayout* mvkDSL = (MVKDescriptorSetLayout*)pSetLayouts[dsIdx];
+ const auto* pVarDescCounts = getVariableDecriptorCounts(pAllocateInfo);
+ for (uint32_t dsIdx = 0; dsIdx < pAllocateInfo->descriptorSetCount; dsIdx++) {
+ MVKDescriptorSetLayout* mvkDSL = (MVKDescriptorSetLayout*)pAllocateInfo->pSetLayouts[dsIdx];
if ( !mvkDSL->isPushDescriptorLayout() ) {
- rslt = allocateDescriptorSet(mvkDSL, &pDescriptorSets[dsIdx]);
+ rslt = allocateDescriptorSet(mvkDSL, (pVarDescCounts ? pVarDescCounts[dsIdx] : 0), &pDescriptorSets[dsIdx]);
if (rslt) { break; }
}
}
return rslt;
}
+// Find and return an array of variable descriptor counts from the pNext chain of pCreateInfo,
+// or return nullptr if the chain does not include variable descriptor counts.
+const uint32_t* MVKDescriptorPool::getVariableDecriptorCounts(const VkDescriptorSetAllocateInfo* pAllocateInfo) {
+ for (const auto* next = (VkBaseInStructure*)pAllocateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT: {
+ auto* pVarDescSetVarCounts = (VkDescriptorSetVariableDescriptorCountAllocateInfoEXT*)next;
+ return pVarDescSetVarCounts->descriptorSetCount ? pVarDescSetVarCounts->pDescriptorCounts : nullptr;
+ }
+ default:
+ break;
+ }
+ }
+ return nullptr;
+}
+
// Ensure descriptor set was actually allocated, then return to pool
VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets) {
for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) {
@@ -575,8 +610,9 @@
}
VkResult MVKDescriptorPool::allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL,
+ uint32_t variableDescriptorCount,
VkDescriptorSet* pVKDS) {
- MVKDescriptorSet* mvkDS = new MVKDescriptorSet(mvkDSL, this);
+ MVKDescriptorSet* mvkDS = new MVKDescriptorSet(mvkDSL, variableDescriptorCount, this);
VkResult rslt = mvkDS->getConfigurationResult();
if (mvkDS->wasConfigurationSuccessful()) {
@@ -781,6 +817,7 @@
spv::ExecutionModel stage,
uint32_t descriptorSetIndex,
uint32_t bindingIndex,
+ uint32_t count,
MVKSampler* immutableSampler) {
mvk::MSLResourceBinding rb;
@@ -788,6 +825,7 @@
rbb.stage = stage;
rbb.desc_set = descriptorSetIndex;
rbb.binding = bindingIndex;
+ rbb.count = count;
rbb.msl_buffer = ssRB.bufferIndex;
rbb.msl_texture = ssRB.textureIndex;
rbb.msl_sampler = ssRB.samplerIndex;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index c6e3a96..5beb05a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -667,6 +667,14 @@
/** Returns the memory type index corresponding to the specified Metal memory storage mode. */
uint32_t getVulkanMemoryTypeIndex(MTLStorageMode mtlStorageMode);
+ /**
+ * Returns whether MTLCommandBuffers can be prefilled.
+ *
+ * This depends both on whether the app config has requested prefilling, and whether doing so will
+ * interfere with other requested features, such as updating resource descriptors after bindings.
+ */
+ bool shouldPrefillMTLCommandBuffers();
+
#pragma mark Properties directly accessible
@@ -680,6 +688,8 @@
const VkPhysicalDeviceFloat16Int8FeaturesKHR _enabledF16I8Features;
const VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR _enabledUBOLayoutFeatures;
const VkPhysicalDeviceVariablePointerFeatures _enabledVarPtrFeatures;
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT _enabledDescriptorIndexingFeatures;
+ const VkPhysicalDeviceInlineUniformBlockFeaturesEXT _enabledInlineUniformBlockFeatures;
const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT _enabledInterlockFeatures;
const VkPhysicalDeviceHostQueryResetFeaturesEXT _enabledHostQryResetFeatures;
const VkPhysicalDeviceSamplerYcbcrConversionFeatures _enabledSamplerYcbcrConversionFeatures;
@@ -741,6 +751,9 @@
const char* getActivityPerformanceDescription(MVKPerformanceTracker& activity, MVKPerformanceStatistics& perfStats);
void logActivityPerformance(MVKPerformanceTracker& activity, MVKPerformanceStatistics& perfStats, bool isInline = false);
void updateActivityPerformance(MVKPerformanceTracker& activity, uint64_t startTime, uint64_t endTime);
+ void getDescriptorVariableDescriptorCountLayoutSupport(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayoutSupport* pSupport,
+ VkDescriptorSetVariableDescriptorCountLayoutSupportEXT* pVarDescSetCountSupport);
MVKPhysicalDevice* _physicalDevice;
MVKCommandResourceFactory* _commandResourceFactory;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 6546d95..22ce772 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -134,6 +134,30 @@
varPtrFeatures->variablePointers = true;
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT: {
+ auto* pDescIdxFeatures = (VkPhysicalDeviceDescriptorIndexingFeaturesEXT*)next;
+ pDescIdxFeatures->shaderInputAttachmentArrayDynamicIndexing = _metalFeatures.arrayOfTextures;
+ pDescIdxFeatures->shaderUniformTexelBufferArrayDynamicIndexing = _metalFeatures.arrayOfTextures;
+ pDescIdxFeatures->shaderStorageTexelBufferArrayDynamicIndexing = _metalFeatures.arrayOfTextures;
+ pDescIdxFeatures->shaderUniformBufferArrayNonUniformIndexing = false;
+ pDescIdxFeatures->shaderSampledImageArrayNonUniformIndexing = _metalFeatures.arrayOfTextures && _metalFeatures.arrayOfSamplers;
+ pDescIdxFeatures->shaderStorageBufferArrayNonUniformIndexing = false;
+ pDescIdxFeatures->shaderStorageImageArrayNonUniformIndexing = _metalFeatures.arrayOfTextures;
+ pDescIdxFeatures->shaderInputAttachmentArrayNonUniformIndexing = _metalFeatures.arrayOfTextures;
+ pDescIdxFeatures->shaderUniformTexelBufferArrayNonUniformIndexing = _metalFeatures.arrayOfTextures;
+ pDescIdxFeatures->shaderStorageTexelBufferArrayNonUniformIndexing = _metalFeatures.arrayOfTextures;
+ pDescIdxFeatures->descriptorBindingUniformBufferUpdateAfterBind = true;
+ pDescIdxFeatures->descriptorBindingSampledImageUpdateAfterBind = true;
+ pDescIdxFeatures->descriptorBindingStorageImageUpdateAfterBind = true;
+ pDescIdxFeatures->descriptorBindingStorageBufferUpdateAfterBind = true;
+ pDescIdxFeatures->descriptorBindingUniformTexelBufferUpdateAfterBind = true;
+ pDescIdxFeatures->descriptorBindingStorageTexelBufferUpdateAfterBind = true;
+ pDescIdxFeatures->descriptorBindingUpdateUnusedWhilePending = true;
+ pDescIdxFeatures->descriptorBindingPartiallyBound = true;
+ pDescIdxFeatures->descriptorBindingVariableDescriptorCount = true;
+ pDescIdxFeatures->runtimeDescriptorArray = true;
+ break;
+ }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups;
@@ -315,6 +339,33 @@
timelineSem4Props->maxTimelineSemaphoreValueDifference = std::numeric_limits<uint64_t>::max();
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT: {
+ auto* pDescIdxProps = (VkPhysicalDeviceDescriptorIndexingPropertiesEXT*)next;
+ pDescIdxProps->maxUpdateAfterBindDescriptorsInAllPools = kMVKUndefinedLargeUInt32;
+ pDescIdxProps->shaderUniformBufferArrayNonUniformIndexingNative = false;
+ pDescIdxProps->shaderSampledImageArrayNonUniformIndexingNative = _metalFeatures.arrayOfTextures && _metalFeatures.arrayOfSamplers;
+ pDescIdxProps->shaderStorageBufferArrayNonUniformIndexingNative = false;
+ pDescIdxProps->shaderStorageImageArrayNonUniformIndexingNative = _metalFeatures.arrayOfTextures;
+ pDescIdxProps->shaderInputAttachmentArrayNonUniformIndexingNative = _metalFeatures.arrayOfTextures;
+ pDescIdxProps->robustBufferAccessUpdateAfterBind = _features.robustBufferAccess;
+ pDescIdxProps->quadDivergentImplicitLod = false;
+ pDescIdxProps->maxPerStageDescriptorUpdateAfterBindSamplers = _properties.limits.maxPerStageDescriptorSamplers;
+ pDescIdxProps->maxPerStageDescriptorUpdateAfterBindUniformBuffers = _properties.limits.maxPerStageDescriptorUniformBuffers;
+ pDescIdxProps->maxPerStageDescriptorUpdateAfterBindStorageBuffers = _properties.limits.maxPerStageDescriptorStorageBuffers;
+ pDescIdxProps->maxPerStageDescriptorUpdateAfterBindSampledImages = _properties.limits.maxPerStageDescriptorSampledImages;
+ pDescIdxProps->maxPerStageDescriptorUpdateAfterBindStorageImages = _properties.limits.maxPerStageDescriptorStorageImages;
+ pDescIdxProps->maxPerStageDescriptorUpdateAfterBindInputAttachments = _properties.limits.maxPerStageDescriptorInputAttachments;
+ pDescIdxProps->maxPerStageUpdateAfterBindResources = _properties.limits.maxPerStageResources;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindSamplers = _properties.limits.maxDescriptorSetSamplers;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindUniformBuffers = _properties.limits.maxDescriptorSetUniformBuffers;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = _properties.limits.maxDescriptorSetUniformBuffersDynamic;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindStorageBuffers = _properties.limits.maxDescriptorSetStorageBuffers;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = _properties.limits.maxDescriptorSetStorageBuffersDynamic;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindSampledImages = _properties.limits.maxDescriptorSetSampledImages;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindStorageImages = _properties.limits.maxDescriptorSetStorageImages;
+ pDescIdxProps->maxDescriptorSetUpdateAfterBindInputAttachments = _properties.limits.maxDescriptorSetInputAttachments;
+ break;
+ }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: {
auto* inlineUniformBlockProps = (VkPhysicalDeviceInlineUniformBlockPropertiesEXT*)next;
inlineUniformBlockProps->maxInlineUniformBlockSize = _metalFeatures.dynamicMTLBufferSize;
@@ -1076,9 +1127,10 @@
_metalFeatures.vertexStrideAlignment = 4;
+ _metalFeatures.maxPerStageStorageTextureCount = 8;
+
#if MVK_TVOS
_metalFeatures.mslVersionEnum = MTLLanguageVersion1_1;
- _metalFeatures.maxPerStageTextureCount = 31;
_metalFeatures.mtlBufferAlignment = 64;
_metalFeatures.mtlCopyBufferAlignment = 1;
_metalFeatures.texelBuffers = true;
@@ -1126,6 +1178,12 @@
}
}
+ if (supportsMTLGPUFamily(Apple4)) {
+ _metalFeatures.maxPerStageTextureCount = 96;
+ } else {
+ _metalFeatures.maxPerStageTextureCount = 31;
+ }
+
#if MVK_XCODE_12
if ( mvkOSVersionIsAtLeast(14.0) ) {
_metalFeatures.mslVersionEnum = MTLLanguageVersion2_3;
@@ -1136,7 +1194,6 @@
#if MVK_IOS
_metalFeatures.mslVersionEnum = MTLLanguageVersion1_0;
- _metalFeatures.maxPerStageTextureCount = 31;
_metalFeatures.mtlBufferAlignment = 64;
_metalFeatures.mtlCopyBufferAlignment = 1;
_metalFeatures.texelBuffers = true;
@@ -1206,6 +1263,12 @@
}
}
+ if (supportsMTLGPUFamily(Apple4)) {
+ _metalFeatures.maxPerStageTextureCount = 96;
+ } else {
+ _metalFeatures.maxPerStageTextureCount = 31;
+ }
+
#if MVK_XCODE_12
if ( mvkOSVersionIsAtLeast(14.0) ) {
_metalFeatures.mslVersionEnum = MTLLanguageVersion2_3;
@@ -1582,7 +1645,7 @@
_properties.limits.maxPerStageDescriptorUniformBuffers = _metalFeatures.maxPerStageBufferCount;
_properties.limits.maxPerStageDescriptorStorageBuffers = _metalFeatures.maxPerStageBufferCount;
_properties.limits.maxPerStageDescriptorSampledImages = _metalFeatures.maxPerStageTextureCount;
- _properties.limits.maxPerStageDescriptorStorageImages = _metalFeatures.maxPerStageTextureCount;
+ _properties.limits.maxPerStageDescriptorStorageImages = _metalFeatures.maxPerStageStorageTextureCount;
_properties.limits.maxPerStageDescriptorInputAttachments = _metalFeatures.maxPerStageTextureCount;
_properties.limits.maxPerStageResources = (_metalFeatures.maxPerStageBufferCount + _metalFeatures.maxPerStageTextureCount);
@@ -2603,6 +2666,120 @@
descriptorCount += pCreateInfo->pBindings[i].descriptorCount;
}
pSupport->supported = (descriptorCount < ((_physicalDevice->_metalFeatures.maxPerStageBufferCount + _physicalDevice->_metalFeatures.maxPerStageTextureCount + _physicalDevice->_metalFeatures.maxPerStageSamplerCount) * 2));
+
+ // Check whether the layout has a variable-count descriptor, and if so, whether we can support it.
+ for (auto* next = (VkBaseOutStructure*)pSupport->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT: {
+ auto* pVarDescSetCountSupport = (VkDescriptorSetVariableDescriptorCountLayoutSupportEXT*)next;
+ getDescriptorVariableDescriptorCountLayoutSupport(pCreateInfo, pSupport, pVarDescSetCountSupport);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+// Check whether the layout has a variable-count descriptor, and if so, whether we can support it.
+void MVKDevice::getDescriptorVariableDescriptorCountLayoutSupport(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayoutSupport* pSupport,
+ VkDescriptorSetVariableDescriptorCountLayoutSupportEXT* pVarDescSetCountSupport) {
+ // Assume we don't need this, then set appropriately if we do.
+ pVarDescSetCountSupport->maxVariableDescriptorCount = 0;
+
+ // Look for a variable length descriptor and remember its index.
+ int32_t varBindingIdx = -1;
+ for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT: {
+ auto* pDescSetLayoutBindingFlags = (VkDescriptorSetLayoutBindingFlagsCreateInfoEXT*)next;
+ for (uint32_t bindIdx = 0; bindIdx < pDescSetLayoutBindingFlags->bindingCount; bindIdx++) {
+ if (mvkIsAnyFlagEnabled(pDescSetLayoutBindingFlags->pBindingFlags[bindIdx], VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT)) {
+ varBindingIdx = bindIdx;
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // If no variable length descriptor is found, we can skip the rest.
+ if (varBindingIdx < 0) { return; }
+
+ // Device does not support variable descriptor counts but it has been requested.
+ if ( !_enabledDescriptorIndexingFeatures.descriptorBindingVariableDescriptorCount ) {
+ pSupport->supported = false;
+ return;
+ }
+
+ uint32_t mtlBuffCnt = 0;
+ uint32_t mtlTexCnt = 0;
+ uint32_t mtlSampCnt = 0;
+ uint32_t requestedCount = 0;
+ uint32_t maxVarDescCount = 0;
+
+ // Determine the number of descriptors available for use by the variable descriptor by
+ // accumulating the number of resources accumulated by other descriptors and subtracting
+ // that from the device's per-stage max counts. This is not perfect because it does not
+ // take into consideration other descriptor sets in the pipeline layout, but we can't
+ // anticipate that here. The variable descriptor must have the highest binding number,
+ // but it may not be the last descriptor in the array. The handling here accommodates that.
+ for (uint32_t bindIdx = 0; bindIdx < pCreateInfo->bindingCount; bindIdx++) {
+ auto* pBind = &pCreateInfo->pBindings[bindIdx];
+ if (bindIdx == varBindingIdx) {
+ requestedCount = std::max(pBind->descriptorCount, 1u);
+ } else {
+ switch (pBind->descriptorType) {
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ mtlBuffCnt += pBind->descriptorCount;
+ maxVarDescCount = _pMetalFeatures->maxPerStageBufferCount - mtlBuffCnt;
+ break;
+ case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
+ maxVarDescCount = (uint32_t)min<VkDeviceSize>(_pMetalFeatures->maxMTLBufferSize, numeric_limits<uint32_t>::max());
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ mtlTexCnt += pBind->descriptorCount;
+ maxVarDescCount = _pMetalFeatures->maxPerStageTextureCount - mtlTexCnt;
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ mtlTexCnt += pBind->descriptorCount;
+ mtlBuffCnt += pBind->descriptorCount;
+ maxVarDescCount = min(_pMetalFeatures->maxPerStageTextureCount - mtlTexCnt,
+ _pMetalFeatures->maxPerStageBufferCount - mtlBuffCnt);
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ mtlSampCnt += pBind->descriptorCount;
+ maxVarDescCount = _pMetalFeatures->maxPerStageSamplerCount - mtlSampCnt;
+ break;
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ mtlTexCnt += pBind->descriptorCount;
+ mtlSampCnt += pBind->descriptorCount;
+ maxVarDescCount = min(_pMetalFeatures->maxPerStageTextureCount - mtlTexCnt,
+ _pMetalFeatures->maxPerStageSamplerCount - mtlSampCnt);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // If there is enough room for the requested size, indicate the amount available,
+ // otherwise indicate that the requested size cannot be supported.
+ if (requestedCount < maxVarDescCount) {
+ pVarDescSetCountSupport->maxVariableDescriptorCount = maxVarDescCount;
+ } else {
+ pSupport->supported = false;
+ }
}
VkResult MVKDevice::getDeviceGroupPresentCapabilities(VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
@@ -3246,6 +3423,18 @@
return _globalVisibilityQueryCount - queryCount; // Might be lower than requested if an overflow occurred
}
+// Can't use prefilled Metal command buffers if any of the resource descriptors can be updated after binding.
+bool MVKDevice::shouldPrefillMTLCommandBuffers() {
+ return (_pMVKConfig->prefillMetalCommandBuffers &&
+ !(_enabledDescriptorIndexingFeatures.descriptorBindingUniformBufferUpdateAfterBind ||
+ _enabledDescriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind ||
+ _enabledDescriptorIndexingFeatures.descriptorBindingStorageImageUpdateAfterBind ||
+ _enabledDescriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind ||
+ _enabledDescriptorIndexingFeatures.descriptorBindingUniformTexelBufferUpdateAfterBind ||
+ _enabledDescriptorIndexingFeatures.descriptorBindingStorageTexelBufferUpdateAfterBind ||
+ _enabledInlineUniformBlockFeatures.descriptorBindingInlineUniformBlockUpdateAfterBind));
+}
+
#pragma mark Construction
@@ -3256,6 +3445,8 @@
_enabledF16I8Features(),
_enabledUBOLayoutFeatures(),
_enabledVarPtrFeatures(),
+ _enabledDescriptorIndexingFeatures(),
+ _enabledInlineUniformBlockFeatures(),
_enabledInterlockFeatures(),
_enabledHostQryResetFeatures(),
_enabledSamplerYcbcrConversionFeatures(),
@@ -3372,7 +3563,6 @@
_pProperties = &_physicalDevice->_properties;
_pMemoryProperties = &_physicalDevice->_memoryProperties;
-
// Indicates whether semaphores should use a MTLFence if available.
// Set by the MVK_ALLOW_METAL_FENCES environment variable if MTLFences are available.
// This should be a temporary fix after some repair to semaphore handling.
@@ -3405,6 +3595,8 @@
mvkClear(&_enabledF16I8Features);
mvkClear(&_enabledUBOLayoutFeatures);
mvkClear(&_enabledVarPtrFeatures);
+ mvkClear(&_enabledDescriptorIndexingFeatures);
+ mvkClear(&_enabledInlineUniformBlockFeatures);
mvkClear(&_enabledInterlockFeatures);
mvkClear(&_enabledHostQryResetFeatures);
mvkClear(&_enabledSamplerYcbcrConversionFeatures);
@@ -3447,9 +3639,17 @@
pdInterlockFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT;
pdInterlockFeatures.pNext = &pdHostQryResetFeatures;
+ VkPhysicalDeviceInlineUniformBlockFeaturesEXT pdInlnUnfmBlkFeatures;
+ pdInlnUnfmBlkFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT;
+ pdInlnUnfmBlkFeatures.pNext = &pdInterlockFeatures;
+
+ VkPhysicalDeviceDescriptorIndexingFeaturesEXT pdDescIdxFeatures;
+ pdDescIdxFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
+ pdDescIdxFeatures.pNext = &pdInlnUnfmBlkFeatures;
+
VkPhysicalDeviceVariablePointerFeatures pdVarPtrFeatures;
pdVarPtrFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES;
- pdVarPtrFeatures.pNext = &pdInterlockFeatures;
+ pdVarPtrFeatures.pNext = &pdDescIdxFeatures;
VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR pdUBOLayoutFeatures;
pdUBOLayoutFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR;
@@ -3524,6 +3724,20 @@
&pdVarPtrFeatures.variablePointersStorageBuffer, 2);
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT: {
+ auto* requestedFeatures = (VkPhysicalDeviceDescriptorIndexingFeaturesEXT*)next;
+ enableFeatures(&_enabledDescriptorIndexingFeatures.shaderInputAttachmentArrayDynamicIndexing,
+ &requestedFeatures->shaderInputAttachmentArrayDynamicIndexing,
+ &pdDescIdxFeatures.shaderInputAttachmentArrayDynamicIndexing, 20);
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT: {
+ auto* requestedFeatures = (VkPhysicalDeviceInlineUniformBlockFeaturesEXT*)next;
+ enableFeatures(&_enabledInlineUniformBlockFeatures.inlineUniformBlock,
+ &requestedFeatures->inlineUniformBlock,
+ &pdInlnUnfmBlkFeatures.inlineUniformBlock, 2);
+ break;
+ }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
auto* requestedFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
enableFeatures(&_enabledInterlockFeatures.fragmentShaderSampleInterlock,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index b2f9930..a0c6e9b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -42,16 +42,15 @@
uint32_t firstSet,
MVKArrayRef<uint32_t> dynamicOffsets) {
clearConfigurationResult();
- uint32_t baseDynamicOffsetIndex = 0;
+ uint32_t dynamicOffsetIndex = 0;
size_t dsCnt = descriptorSets.size;
for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
MVKDescriptorSet* descSet = descriptorSets[dsIdx];
uint32_t dslIdx = firstSet + dsIdx;
MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[dslIdx];
- dsl->bindDescriptorSet(cmdEncoder, descSet,
- _dslMTLResourceIndexOffsets[dslIdx],
- dynamicOffsets, baseDynamicOffsetIndex);
- baseDynamicOffsetIndex += dsl->getDynamicDescriptorCount();
+ dynamicOffsetIndex += dsl->bindDescriptorSet(cmdEncoder, descSet,
+ _dslMTLResourceIndexOffsets[dslIdx],
+ dynamicOffsets, dynamicOffsetIndex);
setConfigurationResult(dsl->getConfigurationResult());
}
}
@@ -102,6 +101,7 @@
models[i],
kPushConstDescSet,
kPushConstBinding,
+ 1,
nullptr);
}
}
@@ -1970,7 +1970,7 @@
opt.enable_base_index_zero,
opt.pad_fragment_output_components,
opt.ios_support_base_vertex_instance,
- opt.ios_use_framebuffer_fetch_subpasses,
+ opt.use_framebuffer_fetch_subpasses,
opt.invariant_float_math,
opt.emulate_cube_array,
opt.enable_decoration_binding,
@@ -1980,8 +1980,8 @@
opt.enable_clip_distance_user_varying,
opt.multi_patch_workgroup,
opt.vertex_for_tessellation,
- opt.vertex_index_type,
- opt.arrayed_subpass_input);
+ opt.arrayed_subpass_input,
+ opt.vertex_index_type);
}
template<class Archive>
@@ -1997,6 +1997,7 @@
archive(rb.stage,
rb.desc_set,
rb.binding,
+ rb.count,
rb.msl_buffer,
rb.msl_texture,
rb.msl_sampler);
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index 0364cd9..c9bd20f 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -81,6 +81,7 @@
MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE)
MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE)
MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE)
+MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE)
MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE)
MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE)
MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE)
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index 208c566..8aa6359 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -1172,9 +1172,7 @@
MVKTraceVulkanCallStart();
MVKDescriptorPool* mvkDP = (MVKDescriptorPool*)pAllocateInfo->descriptorPool;
- VkResult rslt = mvkDP->allocateDescriptorSets(pAllocateInfo->descriptorSetCount,
- pAllocateInfo->pSetLayouts,
- pDescriptorSets);
+ VkResult rslt = mvkDP->allocateDescriptorSets(pAllocateInfo, pDescriptorSets);
MVKTraceVulkanCallEnd();
return rslt;
}
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp
index 705bb72..fb1bb93 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.cpp
@@ -101,6 +101,7 @@
if (resourceBinding.stage != other.resourceBinding.stage) { return false; }
if (resourceBinding.desc_set != other.resourceBinding.desc_set) { return false; }
if (resourceBinding.binding != other.resourceBinding.binding) { return false; }
+ if (resourceBinding.count != other.resourceBinding.count) { return false; }
if (resourceBinding.msl_buffer != other.resourceBinding.msl_buffer) { return false; }
if (resourceBinding.msl_texture != other.resourceBinding.msl_texture) { return false; }
if (resourceBinding.msl_sampler != other.resourceBinding.msl_sampler) { return false; }