Merge pull request #1322 from billhollings/several-frwk-changes

Several underlying non-functional changes towards Metal argument buffer support.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
index 6aa2137..21f1808 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
@@ -108,25 +108,29 @@
               const void* pData,
               MVKShaderResourceBinding& dslMTLRezIdxOffsets);
 
-	/** Populates the specified shader converter context, at the specified descriptor set binding. */
-	void populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context,
-                                        MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-                                        uint32_t dslIndex);
+	/** Returns the index of the descriptor within the descriptor set of the element at the index within this descriptor layout. */
+	inline uint32_t getDescriptorIndex(uint32_t elementIndex = 0) { return _descriptorIndex + elementIndex; }
 
 	MVKDescriptorSetLayoutBinding(MVKDevice* device,
 								  MVKDescriptorSetLayout* layout,
 								  const VkDescriptorSetLayoutBinding* pBinding,
-								  VkDescriptorBindingFlagsEXT bindingFlags);
+								  VkDescriptorBindingFlagsEXT bindingFlags,
+								  uint32_t descriptorIndex);
 
 	MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding);
 
 	~MVKDescriptorSetLayoutBinding() override;
 
 protected:
+	friend class MVKDescriptorSetLayout;
     friend class MVKInlineUniformBlockDescriptor;
+	
 	void initMetalResourceIndexOffsets(MVKShaderStageResourceBinding* pBindingIndexes,
 									   MVKShaderStageResourceBinding* pDescSetCounts,
 									   const VkDescriptorSetLayoutBinding* pBinding);
+	void populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context,
+										MVKShaderResourceBinding& dslMTLRezIdxOffsets,
+										uint32_t dslIndex);
 	bool validate(MVKSampler* mvkSampler);
 
 	MVKDescriptorSetLayout* _layout;
@@ -134,6 +138,7 @@
 	VkDescriptorBindingFlagsEXT _flags;
 	MVKSmallVector<MVKSampler*> _immutableSamplers;
 	MVKShaderResourceBinding _mtlResourceIndexOffsets;
+	uint32_t _descriptorIndex;
 	bool _applyToStage[kMVKShaderStageMax];
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
index 48ce529..725752d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
@@ -376,11 +376,13 @@
 MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(MVKDevice* device,
 															 MVKDescriptorSetLayout* layout,
 															 const VkDescriptorSetLayoutBinding* pBinding,
-															 VkDescriptorBindingFlagsEXT bindingFlags) :
+															 VkDescriptorBindingFlagsEXT bindingFlags,
+															 uint32_t descriptorIndex) :
 	MVKBaseDeviceObject(device),
 	_layout(layout),
 	_info(*pBinding),
-	_flags(bindingFlags) {
+	_flags(bindingFlags),
+	_descriptorIndex(descriptorIndex) {
 
 	_info.pImmutableSamplers = nullptr;     // Remove dangling pointer
 
@@ -412,6 +414,7 @@
 	_layout(binding._layout),
 	_info(binding._info),
 	_flags(binding._flags),
+	_descriptorIndex(binding._descriptorIndex),
 	_immutableSamplers(binding._immutableSamplers),
 	_mtlResourceIndexOffsets(binding._mtlResourceIndexOffsets) {
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 8d1e931..4d69c35 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -83,13 +83,12 @@
 
 	void propagateDebugName() override {}
 	inline uint32_t getDescriptorCount() { return _descriptorCount; }
-	inline uint32_t getDescriptorIndex(uint32_t binding, uint32_t elementIndex = 0) { return _bindingToDescriptorIndex[binding] + elementIndex; }
+	inline uint32_t getDescriptorIndex(uint32_t binding, uint32_t elementIndex = 0) { return getBinding(binding)->getDescriptorIndex(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;
 	bool _isPushDescriptorLayout;
@@ -138,8 +137,8 @@
 	VkResult allocate(MVKDescriptorSetLayout* layout, uint32_t variableDescriptorCount);
 	void free(bool isPoolReset);
 
-	MVKDescriptorSetLayout* _layout;
 	MVKDescriptorPool* _pool;
+	MVKDescriptorSetLayout* _layout;
 	MVKSmallVector<MVKDescriptor*> _descriptors;
 	uint32_t _variableDescriptorCount;
 };
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index aeeb58f..7e233f1 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -195,9 +195,8 @@
     _bindings.reserve(bindCnt);
     for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
 		BindInfo& bindInfo = sortedBindings[bindIdx];
-        _bindings.emplace_back(_device, this, bindInfo.pBinding, bindInfo.bindingFlags);
+        _bindings.emplace_back(_device, this, bindInfo.pBinding, bindInfo.bindingFlags, _descriptorCount);
 		_bindingToIndex[bindInfo.pBinding->binding] = bindIdx;
-		_bindingToDescriptorIndex[bindInfo.pBinding->binding] = _descriptorCount;
 		_descriptorCount += _bindings.back().getDescriptorCount(nullptr);
 	}
 }
@@ -234,25 +233,28 @@
 void MVKDescriptorSet::write(const DescriptorAction* pDescriptorAction,
 							 size_t stride,
 							 const void* pData) {
+#define writeDescriptorAt(IDX)                                    \
+	do {                                                          \
+		MVKDescriptor* mvkDesc = _descriptors[descIdx];           \
+		if (mvkDesc->getDescriptorType() == descType) {           \
+			mvkDesc->write(mvkDSLBind, this, IDX, stride, pData); \
+		}                                                         \
+	} while(false)
 
 	MVKDescriptorSetLayoutBinding* mvkDSLBind = _layout->getBinding(pDescriptorAction->dstBinding);
 	VkDescriptorType descType = mvkDSLBind->getDescriptorType();
-    if (descType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+	if (descType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
 		// For inline buffers dstArrayElement is a byte offset
-		MVKDescriptor* mvkDesc = getDescriptor(pDescriptorAction->dstBinding);
-		if (mvkDesc->getDescriptorType() == descType) {
-			mvkDesc->write(mvkDSLBind, this, pDescriptorAction->dstArrayElement, stride, pData);
+		uint32_t descIdx = _layout->getDescriptorIndex(pDescriptorAction->dstBinding);
+		writeDescriptorAt(pDescriptorAction->dstArrayElement);
+	} else {
+		uint32_t descStartIdx = _layout->getDescriptorIndex(pDescriptorAction->dstBinding, pDescriptorAction->dstArrayElement);
+		uint32_t elemCnt = pDescriptorAction->descriptorCount;
+		for (uint32_t elemIdx = 0; elemIdx < elemCnt; elemIdx++) {
+			uint32_t descIdx = descStartIdx + elemIdx;
+			writeDescriptorAt(elemIdx);
 		}
-    } else {
-        uint32_t dstStartIdx = _layout->getDescriptorIndex(pDescriptorAction->dstBinding, pDescriptorAction->dstArrayElement);
-		uint32_t descCnt = pDescriptorAction->descriptorCount;
-        for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
-			MVKDescriptor* mvkDesc = _descriptors[dstStartIdx + descIdx];
-			if (mvkDesc->getDescriptorType() == descType) {
-				mvkDesc->write(mvkDSLBind, this, descIdx, stride, pData);
-			}
-        }
-    }
+	}
 }
 
 void MVKDescriptorSet::read(const VkCopyDescriptorSet* pDescriptorCopy,
@@ -285,12 +287,14 @@
 	_layout = layout;
 	_variableDescriptorCount = variableDescriptorCount;
 
-	_descriptors.reserve(layout->getDescriptorCount());
+	uint32_t descCnt = layout->getDescriptorCount();
+	_descriptors.reserve(descCnt);
+
 	uint32_t bindCnt = (uint32_t)layout->_bindings.size();
 	for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
 		MVKDescriptorSetLayoutBinding* mvkDSLBind = &layout->_bindings[bindIdx];
-		uint32_t descCnt = mvkDSLBind->getDescriptorCount(this);
-		for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
+		uint32_t elemCnt = mvkDSLBind->getDescriptorCount(this);
+		for (uint32_t elemIdx = 0; elemIdx < elemCnt; elemIdx++) {
 			MVKDescriptor* mvkDesc = nullptr;
 			setConfigurationResult(_pool->allocateDescriptor(mvkDSLBind->getDescriptorType(), &mvkDesc));
 			if ( !wasConfigurationSuccessful() ) { return getConfigurationResult(); }
@@ -309,6 +313,7 @@
 		for (auto mvkDesc : _descriptors) { _pool->freeDescriptor(mvkDesc); }
 	}
 	_descriptors.clear();
+	_descriptors.shrink_to_fit();
 
 	clearConfigurationResult();
 }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index c65ffae..b8b6dd3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -369,7 +369,7 @@
 	MVKArrayRef<MVKQueueFamily*> getQueueFamilies();
 	void initPipelineCacheUUID();
 	uint32_t getHighestMTLFeatureSet();
-	uint64_t getMoltenVKGitRevision();
+	uint32_t getMoltenVKGitRevision();
 	void populate(VkPhysicalDeviceIDProperties* pDevIdProps);
 	void logGPUInfo();
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 60d4e46..d304fa0 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -2362,20 +2362,23 @@
 
 	size_t uuidComponentOffset = 0;
 
-	// First 4 bytes contains MoltenVK version
-	uint32_t mvkVersion = MVK_VERSION;
-	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mvkVersion);
-	uuidComponentOffset += sizeof(mvkVersion);
+	// First 4 bytes contains MoltenVK revision.
+	// This is captured either as the MoltenVK Git revision, or if that's not available, as the MoltenVK version.
+	uint32_t mvkRev = getMoltenVKGitRevision();
+	if ( !mvkRev ) { mvkRev = MVK_VERSION; }
+	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mvkRev);
+	uuidComponentOffset += sizeof(mvkRev);
 
 	// Next 4 bytes contains highest Metal feature set supported by this device
 	uint32_t mtlFeatSet = getHighestMTLFeatureSet();
 	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatSet);
 	uuidComponentOffset += sizeof(mtlFeatSet);
 
-	// Last 8 bytes contain the first part of the MoltenVK Git revision
-	uint64_t mvkRev = getMoltenVKGitRevision();
-	*(uint64_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostLongLongToBig(mvkRev);
-	uuidComponentOffset += sizeof(mvkRev);
+	// Next 4 bytes contains flags based on enabled Metal features that
+	// might affect the contents of the pipeline cache (mostly MSL content).
+	uint32_t mtlFeatures = 0;
+	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatures);
+	uuidComponentOffset += sizeof(mtlFeatures);
 }
 
 uint32_t MVKPhysicalDevice::getHighestMTLFeatureSet() {
@@ -2436,14 +2439,14 @@
 // which is generated in advance, either statically, or more typically in
 // an early build phase script, and contains a line similar to the following:
 // static const char* mvkRevString = "fc0750d67cfe825b887dd2cf25a42e9d9a013eb2";
-uint64_t MVKPhysicalDevice::getMoltenVKGitRevision() {
+uint32_t MVKPhysicalDevice::getMoltenVKGitRevision() {
 
 #include "mvkGitRevDerived.h"
 
-	static const string revStr(mvkRevString, 0, 16);	// We just need the first 16 chars
+	static const string revStr(mvkRevString, 0, 8);		// We just need the first 8 chars
 	static const string lut("0123456789ABCDEF");
 
-	uint64_t revVal = 0;
+	uint32_t revVal = 0;
 	for (char c : revStr) {
 		size_t cVal = lut.find(toupper(c));
 		if (cVal != string::npos) {
diff --git a/MoltenVK/MoltenVK/Utility/MVKBitArray.h b/MoltenVK/MoltenVK/Utility/MVKBitArray.h
index b6e1ecb..4016547 100755
--- a/MoltenVK/MoltenVK/Utility/MVKBitArray.h
+++ b/MoltenVK/MoltenVK/Utility/MVKBitArray.h
@@ -39,30 +39,20 @@
 		return mvkIsAnyFlagEnabled(_pSections[getIndexOfSection(bitIndex)], getSectionSetMask(bitIndex));

 	}

 

-	/** Sets the value of the bit to 1. */

-	inline void setBit(size_t bitIndex) {

+	/** Sets the value of the bit to the val (or to 1 by default). */

+	inline void setBit(size_t bitIndex, bool val = true) {

 		size_t secIdx = getIndexOfSection(bitIndex);

-		mvkEnableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));

-

-		if (secIdx < _minUnclearedSectionIndex) { _minUnclearedSectionIndex = secIdx; }

+		if (val) {

+			mvkEnableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));

+			if (secIdx < _minUnclearedSectionIndex) { _minUnclearedSectionIndex = secIdx; }

+		} else {

+			mvkDisableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));

+			if (secIdx == _minUnclearedSectionIndex && !_pSections[secIdx]) { _minUnclearedSectionIndex++; }

+		}

 	}

 

 	/** Sets the value of the bit to 0. */

-	inline void clearBit(size_t bitIndex) {

-		size_t secIdx = getIndexOfSection(bitIndex);

-		mvkDisableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));

-

-		if (secIdx == _minUnclearedSectionIndex && !_pSections[secIdx]) { _minUnclearedSectionIndex++; }

-	}

-

-	/** Sets the value of the bit to the value. */

-	inline void setBit(size_t bitIndex, bool val) {

-		if (val) {

-			setBit(bitIndex);

-		} else {

-			clearBit(bitIndex);

-		}

-	}

+	inline void clearBit(size_t bitIndex) { setBit(bitIndex, false); }

 

 	/** Sets all bits in the array to 1. */

 	inline void setAllBits() { setAllSections(~0); }

@@ -120,8 +110,10 @@
 	/** Returns whether this array is empty. */

 	inline bool empty() { return !_bitCount; }

 

-	/** Constructs an instance for the specified number of bits, and sets the initial value of all the bits. */

-	MVKBitArray(size_t size, bool val = false) {

+	/** Resize this array to the specified number of bits, and sets the initial value of all the bits. */

+	inline void resize(size_t size = 0, bool val = false) {

+		free(_pSections);

+

 		_bitCount = size;

 		_pSections = _bitCount ? (uint64_t*)malloc(getSectionCount() * SectionByteCount) : nullptr;

 		if (val) {

@@ -131,6 +123,12 @@
 		}

 	}

 

+	/** Constructs an instance for the specified number of bits, and sets the initial value of all the bits. */

+	MVKBitArray(size_t size = 0, bool val = false) {

+		_pSections = nullptr;

+		resize(size, val);

+	}

+

 	~MVKBitArray() { free(_pSections); }

 

 protected: