Merge pull request #980 from mbechard/master

dynamicOffsets are supposed to be ordered by binding index
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
index e283a73..424a07f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
@@ -76,6 +76,13 @@
 	/** Returns the descriptor type of this layout. */
 	inline VkDescriptorType getDescriptorType() { return _info.descriptorType; }
 
+	/** If this descriptor is a dynamic buffer type, this returns the index within the dynamicOffsets array where the
+		first descriptor in this binding is located. It will start at 0 for this set, so this number should be incremented
+		by the number of dynamic offsets in previous sets given in vkCmdBindDescriptorSets */
+	inline uint32_t getDynamicOffsetIndex() { return _dynamicOffsetIndex; }
+
+	void setDynamicOffsetIndex(uint32_t i) { _dynamicOffsetIndex = i; }
+
 	/** Returns the immutable sampler at the index, or nullptr if immutable samplers are not used. */
 	MVKSampler* getImmutableSampler(uint32_t index);
 
@@ -89,7 +96,7 @@
 				  uint32_t descStartIndex,
 				  MVKShaderResourceBinding& dslMTLRezIdxOffsets,
 				  MVKArrayRef<uint32_t> dynamicOffsets,
-				  uint32_t* pDynamicOffsetIndex);
+				  uint32_t baseDynamicOffsetIndex);
 
     /** Encodes this binding layout and the specified descriptor on the specified command encoder immediately. */
     void push(MVKCommandEncoder* cmdEncoder,
@@ -126,6 +133,7 @@
 	MVKSmallVector<MVKSampler*> _immutableSamplers;
 	MVKShaderResourceBinding _mtlResourceIndexOffsets;
 	bool _applyToStage[kMVKShaderStageMax];
+	uint32_t _dynamicOffsetIndex;
 };
 
 
@@ -149,7 +157,7 @@
 					  bool stages[],
 					  MVKShaderResourceBinding& mtlIndexes,
 					  MVKArrayRef<uint32_t> dynamicOffsets,
-					  uint32_t* pDynamicOffsetIndex) = 0;
+					  uint32_t dynamicOffsetIndex) = 0;
 
 	/**
 	 * Updates the internal binding from the specified content. The format of the content depends
@@ -205,7 +213,7 @@
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
 			  MVKArrayRef<uint32_t> dynamicOffsets,
-			  uint32_t* pDynamicOffsetIndex) override;
+			  uint32_t dynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
 			   VkDescriptorType descriptorType,
@@ -283,7 +291,7 @@
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
 			  MVKArrayRef<uint32_t> dynamicOffsets,
-			  uint32_t* pDynamicOffsetIndex) override;
+			  uint32_t dynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
 			   VkDescriptorType descriptorType,
@@ -324,7 +332,7 @@
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
 			  MVKArrayRef<uint32_t> dynamicOffsets,
-			  uint32_t* pDynamicOffsetIndex) override;
+			  uint32_t dynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
 			   VkDescriptorType descriptorType,
@@ -396,7 +404,7 @@
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
 			  MVKArrayRef<uint32_t> dynamicOffsets,
-			  uint32_t* pDynamicOffsetIndex);
+			  uint32_t dynamicOffsetIndex);
 
 	void write(MVKDescriptorSet* mvkDescSet,
 			   VkDescriptorType descriptorType,
@@ -438,7 +446,7 @@
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
 			  MVKArrayRef<uint32_t> dynamicOffsets,
-			  uint32_t* pDynamicOffsetIndex) override;
+			  uint32_t dynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
 			   VkDescriptorType descriptorType,
@@ -478,7 +486,7 @@
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
 			  MVKArrayRef<uint32_t> dynamicOffsets,
-			  uint32_t* pDynamicOffsetIndex) override;
+			  uint32_t dynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
 			   VkDescriptorType descriptorType,
@@ -516,7 +524,7 @@
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
 			  MVKArrayRef<uint32_t> dynamicOffsets,
-			  uint32_t* pDynamicOffsetIndex) override;
+			  uint32_t dynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
 			   VkDescriptorType descriptorType,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
index 96dc03b..81e1387 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
@@ -84,7 +84,7 @@
 											 uint32_t descStartIndex,
 											 MVKShaderResourceBinding& dslMTLRezIdxOffsets,
 											 MVKArrayRef<uint32_t> dynamicOffsets,
-											 uint32_t* pDynamicOffsetIndex) {
+											 uint32_t baseDynamicOffsetIndex) {
 
 	// Establish the resource indices to use, by combining the offsets of the DSL and this DSL binding.
     MVKShaderResourceBinding mtlIdxs = _mtlResourceIndexOffsets + dslMTLRezIdxOffsets;
@@ -92,7 +92,8 @@
     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, pDynamicOffsetIndex);
+        mvkDesc->bind(cmdEncoder, _info.descriptorType, descIdx, _applyToStage, mtlIdxs, dynamicOffsets,
+					  baseDynamicOffsetIndex + _dynamicOffsetIndex + descIdx);
     }
     return descCnt;
 }
@@ -360,7 +361,8 @@
 
 MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(MVKDevice* device,
 															 MVKDescriptorSetLayout* layout,
-                                                             const VkDescriptorSetLayoutBinding* pBinding) : MVKBaseDeviceObject(device), _layout(layout) {
+                                                             const VkDescriptorSetLayoutBinding* pBinding) : MVKBaseDeviceObject(device), _layout(layout),
+																 _dynamicOffsetIndex(0) {
 
 	for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
         // Determine if this binding is used by this shader stage
@@ -390,7 +392,8 @@
 MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding) :
 	MVKBaseDeviceObject(binding._device), _layout(binding._layout),
 	_info(binding._info), _immutableSamplers(binding._immutableSamplers),
-	_mtlResourceIndexOffsets(binding._mtlResourceIndexOffsets) {
+	_mtlResourceIndexOffsets(binding._mtlResourceIndexOffsets),
+	_dynamicOffsetIndex(0) {
 
 	for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
         _applyToStage[i] = binding._applyToStage[i];
@@ -494,7 +497,7 @@
 							   bool stages[],
 							   MVKShaderResourceBinding& mtlIndexes,
 							   MVKArrayRef<uint32_t> dynamicOffsets,
-							   uint32_t* pDynamicOffsetIndex) {
+							   uint32_t dynamicOffsetIndex) {
 	MVKMTLBufferBinding bb;
 	NSUInteger bufferDynamicOffset = 0;
 
@@ -502,8 +505,8 @@
 		// After determining dynamic part of offset (zero otherwise), fall through to non-dynamic handling
 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
-			if (dynamicOffsets.size > *pDynamicOffsetIndex) {
-				bufferDynamicOffset = dynamicOffsets[(*pDynamicOffsetIndex)++];	// Move on to next dynamic offset (and feedback to caller)
+			if (dynamicOffsets.size > dynamicOffsetIndex) {
+				bufferDynamicOffset = dynamicOffsets[dynamicOffsetIndex];
 			}
 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
@@ -603,7 +606,7 @@
 										   bool stages[],
 										   MVKShaderResourceBinding& mtlIndexes,
 										   MVKArrayRef<uint32_t> dynamicOffsets,
-										   uint32_t* pDynamicOffsetIndex) {
+										   uint32_t dynamicOffsetIndex) {
 	MVKMTLBufferBinding bb;
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
@@ -690,7 +693,7 @@
 							  bool stages[],
 							  MVKShaderResourceBinding& mtlIndexes,
 							  MVKArrayRef<uint32_t> dynamicOffsets,
-							  uint32_t* pDynamicOffsetIndex) {
+							  uint32_t dynamicOffsetIndex) {
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
 		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
@@ -809,7 +812,7 @@
 									 bool stages[],
 									 MVKShaderResourceBinding& mtlIndexes,
 									 MVKArrayRef<uint32_t> dynamicOffsets,
-									 uint32_t* pDynamicOffsetIndex) {
+									 uint32_t dynamicOffsetIndex) {
 	MVKMTLSamplerStateBinding sb;
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_SAMPLER:
@@ -927,11 +930,11 @@
 								bool stages[],
 								MVKShaderResourceBinding& mtlIndexes,
 								MVKArrayRef<uint32_t> dynamicOffsets,
-								uint32_t* pDynamicOffsetIndex) {
+								uint32_t dynamicOffsetIndex) {
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_SAMPLER: {
 			MVKSamplerDescriptorMixin::bind(cmdEncoder, descriptorType, descriptorIndex, stages,
-											mtlIndexes, dynamicOffsets, pDynamicOffsetIndex);
+											mtlIndexes, dynamicOffsets, dynamicOffsetIndex);
 			break;
 		}
 
@@ -996,13 +999,13 @@
 											 bool stages[],
 											 MVKShaderResourceBinding& mtlIndexes,
 											 MVKArrayRef<uint32_t> dynamicOffsets,
-											 uint32_t* pDynamicOffsetIndex) {
+											 uint32_t dynamicOffsetIndex) {
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
 			MVKImageDescriptor::bind(cmdEncoder, descriptorType, descriptorIndex, stages,
-									 mtlIndexes, dynamicOffsets, pDynamicOffsetIndex);
+									 mtlIndexes, dynamicOffsets, dynamicOffsetIndex);
 			MVKSamplerDescriptorMixin::bind(cmdEncoder, descriptorType, descriptorIndex, stages,
-											mtlIndexes, dynamicOffsets, pDynamicOffsetIndex);
+											mtlIndexes, dynamicOffsets, dynamicOffsetIndex);
 			break;
 		}
 
@@ -1070,7 +1073,7 @@
 									bool stages[],
 									MVKShaderResourceBinding& mtlIndexes,
 									MVKArrayRef<uint32_t> dynamicOffsets,
-									uint32_t* pDynamicOffsetIndex) {
+									uint32_t dynamicOffsetIndex) {
 	MVKMTLTextureBinding tb;
 	MVKMTLBufferBinding bb;
 	switch (descriptorType) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 532c14f..3f1c0ca 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -43,12 +43,14 @@
 	/** 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* pDynamicOffsetIndex);
+                           uint32_t baseDynamicOffsetIndex);
 
 
 	/** Encodes this descriptor set layout and the specified descriptor updates on the specified command encoder immediately. */
@@ -90,6 +92,7 @@
 	std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
 	MVKShaderResourceBinding _mtlResourceCounts;
 	uint32_t _descriptorCount;
+	uint32_t _dynamicDescriptorCount;
 	bool _isPushDescriptorLayout;
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index de5a9f3..ed4896f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -39,7 +39,7 @@
                                                MVKDescriptorSet* descSet,
                                                MVKShaderResourceBinding& dslMTLRezIdxOffsets,
                                                MVKArrayRef<uint32_t> dynamicOffsets,
-                                               uint32_t* pDynamicOffsetIndex) {
+                                               uint32_t baseDynamicOffsetIndex) {
     if (_isPushDescriptorLayout) return;
 
 	clearConfigurationResult();
@@ -47,7 +47,7 @@
     for (uint32_t descIdx = 0, bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
 		descIdx += _bindings[bindIdx].bind(cmdEncoder, descSet, descIdx,
 										   dslMTLRezIdxOffsets, dynamicOffsets,
-										   pDynamicOffsetIndex);
+										   baseDynamicOffsetIndex);
     }
 }
 
@@ -188,11 +188,37 @@
 	// Create the descriptor layout bindings
 	_descriptorCount = 0;
     _bindings.reserve(pCreateInfo->bindingCount);
+	struct SortInfo
+	{
+		const VkDescriptorSetLayoutBinding* binding;
+		uint32_t index;
+	};
+	std::vector<SortInfo> 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 });
+		}
+	}
+
+	// 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
+	std::sort(dynamicBindings.begin(), dynamicBindings.end(),
+				[](const SortInfo &info1, const SortInfo &info2) {
+					return info1.binding->binding < info2.binding->binding; });
+
+	uint32_t curOffsetIndex = 0;
+	for (auto &i : dynamicBindings) {
+		_bindings[i.index].setDynamicOffsetIndex(curOffsetIndex);
+		curOffsetIndex += i.binding->descriptorCount;
+	}
+	_dynamicDescriptorCount = curOffsetIndex;
 }
 
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 46dfa05..28227ba 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -42,7 +42,7 @@
                                            uint32_t firstSet,
                                            MVKArrayRef<uint32_t> dynamicOffsets) {
 	clearConfigurationResult();
-	uint32_t pDynamicOffsetIndex = 0;
+	uint32_t baseDynamicOffsetIndex = 0;
 	size_t dsCnt = descriptorSets.size;
 	for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
 		MVKDescriptorSet* descSet = descriptorSets[dsIdx];
@@ -50,7 +50,8 @@
 		MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[dslIdx];
 		dsl->bindDescriptorSet(cmdEncoder, descSet,
 							   _dslMTLResourceIndexOffsets[dslIdx],
-							   dynamicOffsets, &pDynamicOffsetIndex);
+							   dynamicOffsets, baseDynamicOffsetIndex);
+		baseDynamicOffsetIndex += dsl->getDynamicDescriptorCount();
 		setConfigurationResult(dsl->getConfigurationResult());
 	}
 }