Merge pull request #1117 from billhollings/master
Allow binding descriptor set using layout different than it was created with.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 8a81724..eef87ee 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -25,6 +25,7 @@
performance on *iOS* by allowing Metal to use lossless texture compression.
- 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.
- Clarify documentation on mapping limitations for host-coherent image memory on *macOS*.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
index 424a07f..d88c1f8 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
@@ -86,17 +86,12 @@
/** 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,
- * starting with the descriptor at the index, on the the command encoder.
- * Returns the number of descriptors that were encoded.
- */
- uint32_t bind(MVKCommandEncoder* cmdEncoder,
- MVKDescriptorSet* descSet,
- uint32_t descStartIndex,
- MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKArrayRef<uint32_t> dynamicOffsets,
- uint32_t baseDynamicOffsetIndex);
+ /** 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 this binding layout and the specified descriptor on the specified command encoder immediately. */
void push(MVKCommandEncoder* cmdEncoder,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
index 81e1387..74ce403 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
@@ -79,23 +79,21 @@
}
// A null cmdEncoder can be passed to perform a validation pass
-uint32_t MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
- MVKDescriptorSet* descSet,
- uint32_t descStartIndex,
- MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKArrayRef<uint32_t> dynamicOffsets,
- uint32_t baseDynamicOffsetIndex) {
+void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
+ MVKDescriptorSet* descSet,
+ MVKShaderResourceBinding& dslMTLRezIdxOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
+ uint32_t baseDynamicOffsetIndex) {
// 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();
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
- MVKDescriptor* mvkDesc = descSet->getDescriptor(descStartIndex + descIdx);
- mvkDesc->bind(cmdEncoder, _info.descriptorType, descIdx, _applyToStage, mtlIdxs, dynamicOffsets,
- baseDynamicOffsetIndex + _dynamicOffsetIndex + descIdx);
+ MVKDescriptor* mvkDesc = descSet->getDescriptor(getBinding(), descIdx);
+ mvkDesc->bind(cmdEncoder, _info.descriptorType, descIdx, _applyToStage, mtlIdxs,
+ dynamicOffsets, baseDynamicOffsetIndex + _dynamicOffsetIndex + descIdx);
}
- return descCnt;
}
template<typename T>
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 3f1c0ca..1f2ce42 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -85,11 +85,12 @@
void propagateDebugName() override {}
inline uint32_t getDescriptorCount() { return _descriptorCount; }
- uint32_t getDescriptorIndex(uint32_t binding, uint32_t elementIndex);
+ 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]]; }
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;
@@ -137,7 +138,7 @@
friend class MVKDescriptorPool;
void propagateDebugName() override {}
- inline MVKDescriptor* getDescriptor(uint32_t index) { return _descriptors[index]; }
+ MVKDescriptor* getDescriptor(uint32_t binding, uint32_t elementIndex = 0);
MVKDescriptorSetLayout* _layout;
MVKDescriptorPool* _pool;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index a7aa0d7..ac6be1f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -24,32 +24,18 @@
#pragma mark -
#pragma mark MVKDescriptorSetLayout
-// Look through the layout bindings looking for the binding number, accumulating the number
-// of descriptors in each layout binding as we go, then add the element index.
-uint32_t MVKDescriptorSetLayout::getDescriptorIndex(uint32_t binding, uint32_t elementIndex) {
- uint32_t descIdx = 0;
- for (auto& dslBind : _bindings) {
- if (dslBind.getBinding() == binding) { break; }
- descIdx += dslBind.getDescriptorCount();
- }
- return descIdx + elementIndex;
-}
-
// 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;
+ MVKDescriptorSet* descSet,
+ MVKShaderResourceBinding& dslMTLRezIdxOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
+ uint32_t baseDynamicOffsetIndex) {
+ if (_isPushDescriptorLayout) return;
clearConfigurationResult();
- size_t bindCnt = _bindings.size();
- for (uint32_t descIdx = 0, bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
- descIdx += _bindings[bindIdx].bind(cmdEncoder, descSet, descIdx,
- dslMTLRezIdxOffsets, dynamicOffsets,
- baseDynamicOffsetIndex);
- }
+ for (auto& dslBind : _bindings) {
+ dslBind.bind(cmdEncoder, descSet, dslMTLRezIdxOffsets, dynamicOffsets, baseDynamicOffsetIndex);
+ }
}
static const void* getWriteParameters(VkDescriptorType type, const VkDescriptorImageInfo* pImageInfo,
@@ -186,40 +172,35 @@
const VkDescriptorSetLayoutCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
_isPushDescriptorLayout = (pCreateInfo->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) != 0;
- // Create the descriptor layout bindings
_descriptorCount = 0;
_bindings.reserve(pCreateInfo->bindingCount);
- struct SortInfo
- {
- const VkDescriptorSetLayoutBinding* binding;
- uint32_t index;
- };
- std::vector<SortInfo> dynamicBindings;
-
+ MVKSmallVector<MVKDescriptorSetLayoutBinding*, 32> dynamicBindings;
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
- _bindings.emplace_back(_device, this, &pCreateInfo->pBindings[i]);
- _descriptorCount += _bindings.back().getDescriptorCount();
- _bindingToIndex[pCreateInfo->pBindings[i].binding] = i;
- if (pCreateInfo->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
- pCreateInfo->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
- dynamicBindings.push_back(SortInfo{ &pCreateInfo->pBindings[i], i });
+ auto* pBind = &pCreateInfo->pBindings[i];
+ _bindings.emplace_back(_device, this, pBind);
+ _bindingToIndex[pBind->binding] = i;
+ _bindingToDescriptorIndex[pBind->binding] = _descriptorCount;
+
+ MVKDescriptorSetLayoutBinding* mvkBind = &_bindings.back();
+ _descriptorCount += mvkBind->getDescriptorCount();
+ if (pBind->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
+ pBind->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
+ dynamicBindings.push_back(mvkBind);
}
}
- // Dynamic offsets are ordered by binding index when given to vkCmdBindDescriptorSets
- // not by the order they are provided in the layout.
- // So we want to sort by binding, and then count how many dynamic offsets the binding
- // has so we can assign each binding it's first dynamic offset index
+ // Dynamic offsets in vkCmdBindDescriptorSets() are ordered by binding number, not by the
+ // order they are provided in the layout. To prepare for this, sort the dynamic bindings by
+ // binding number and assign to each the index it will use into the array of dynamic offsets.
std::sort(dynamicBindings.begin(), dynamicBindings.end(),
- [](const SortInfo &info1, const SortInfo &info2) {
- return info1.binding->binding < info2.binding->binding; });
+ [](MVKDescriptorSetLayoutBinding* mvkBind1, MVKDescriptorSetLayoutBinding* mvkBind2) {
+ return mvkBind1->getBinding() < mvkBind2->getBinding(); });
- uint32_t curOffsetIndex = 0;
- for (auto &i : dynamicBindings) {
- _bindings[i.index].setDynamicOffsetIndex(curOffsetIndex);
- curOffsetIndex += i.binding->descriptorCount;
+ _dynamicDescriptorCount = 0;
+ for (auto mvkBind : dynamicBindings) {
+ mvkBind->setDynamicOffsetIndex(_dynamicDescriptorCount);
+ _dynamicDescriptorCount += mvkBind->getDescriptorCount();
}
- _dynamicDescriptorCount = curOffsetIndex;
}
@@ -230,6 +211,10 @@
return _layout->getBinding(binding)->getDescriptorType();
}
+MVKDescriptor* MVKDescriptorSet::getDescriptor(uint32_t binding, uint32_t elementIndex) {
+ return _descriptors[_layout->getDescriptorIndex(binding, elementIndex)];
+}
+
template<typename DescriptorAction>
void MVKDescriptorSet::write(const DescriptorAction* pDescriptorAction,
size_t stride,
@@ -238,12 +223,10 @@
VkDescriptorType descType = getDescriptorType(pDescriptorAction->dstBinding);
uint32_t descCnt = pDescriptorAction->descriptorCount;
if (descType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
- uint32_t dstStartIdx = _layout->getDescriptorIndex(pDescriptorAction->dstBinding, 0);
- // For inline buffers we are using the index argument as dst offset not as src descIdx
- _descriptors[dstStartIdx]->write(this, descType, pDescriptorAction->dstArrayElement, stride, pData);
+ // For inline buffers dstArrayElement is a byte offset
+ getDescriptor(pDescriptorAction->dstBinding)->write(this, descType, pDescriptorAction->dstArrayElement, stride, pData);
} else {
- uint32_t dstStartIdx = _layout->getDescriptorIndex(pDescriptorAction->dstBinding,
- pDescriptorAction->dstArrayElement);
+ uint32_t dstStartIdx = _layout->getDescriptorIndex(pDescriptorAction->dstBinding, pDescriptorAction->dstArrayElement);
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
_descriptors[dstStartIdx + descIdx]->write(this, descType, descIdx, stride, pData);
}
@@ -268,12 +251,10 @@
uint32_t descCnt = pDescriptorCopy->descriptorCount;
if (descType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
pInlineUniformBlock->dataSize = pDescriptorCopy->descriptorCount;
- uint32_t srcStartIdx = _layout->getDescriptorIndex(pDescriptorCopy->srcBinding, 0);
- // For inline buffers we are using the index argument as src offset not as dst descIdx
- _descriptors[srcStartIdx]->read(this, descType, pDescriptorCopy->srcArrayElement, pImageInfo, pBufferInfo, pTexelBufferView, pInlineUniformBlock);
+ // For inline buffers dstArrayElement is a byte offset
+ getDescriptor(pDescriptorCopy->srcBinding)->read(this, descType, pDescriptorCopy->srcArrayElement, pImageInfo, pBufferInfo, pTexelBufferView, pInlineUniformBlock);
} else {
- uint32_t srcStartIdx = _layout->getDescriptorIndex(pDescriptorCopy->srcBinding,
- pDescriptorCopy->srcArrayElement);
+ uint32_t srcStartIdx = _layout->getDescriptorIndex(pDescriptorCopy->srcBinding, pDescriptorCopy->srcArrayElement);
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
_descriptors[srcStartIdx + descIdx]->read(this, descType, descIdx, pImageInfo, pBufferInfo, pTexelBufferView, pInlineUniformBlock);
}