Fixes to pipeline layout compatibility.

For pipeline layout compatibility, consume the Metal resource indexes in this order:
- Consume a fixed number of Metal buffer indexes for Metal argument buffers,
  but only consume them if Metal argument buffers are not being used.
- Consume push constants  Metal buffer index before descriptor set resources,
  but only consume it if the stage uses push constants.
- Consume descriptor set bindings.

In MVKPipelineLayout, separate tracking resource counts from push constants
indexes, and move push constant indexes ahead of descriptor bindings.
In MVKPipeline, track which stages use push constants.
Remove unused and obsolete function declaration in MVKDescriptorSet.h.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 434bb85..80c235a 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -18,6 +18,7 @@
 
 Released TBD
 
+- 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.
 - Fix alignment between outputs and inputs between shader stages when using nested structures.
diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h
index 0a1ddb0..6fb71f5 100644
--- a/MoltenVK/MoltenVK/API/mvk_datatypes.h
+++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h
@@ -321,7 +321,7 @@
 	kMVKShaderStageFragment,
 	kMVKShaderStageCompute,
 	kMVKShaderStageCount,
-	kMVKShaderStageMax = kMVKShaderStageCount	// Pubic API legacy value
+	kMVKShaderStageMax = kMVKShaderStageCount	// Public API legacy value
 } MVKShaderStage;
 
 /** Returns the Metal MTLColorWriteMask corresponding to the specified Vulkan VkColorComponentFlags. */
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 4bbda08..00d32a4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -363,15 +363,3 @@
 void mvkUpdateDescriptorSetWithTemplate(VkDescriptorSet descriptorSet,
 										VkDescriptorUpdateTemplateKHR updateTemplate,
 										const void* pData);
-
-/**
- * If the shader stage binding has a binding defined for the specified stage, populates
- * the context at the descriptor set binding from the shader stage resource binding.
- */
-void mvkPopulateShaderConversionConfig(mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
-									   MVKShaderStageResourceBinding& ssRB,
-									   spv::ExecutionModel stage,
-									   uint32_t descriptorSetIndex,
-									   uint32_t bindingIndex,
-									   uint32_t count,
-									   MVKSampler* immutableSampler);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index de407fb..61f9cda 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -100,10 +100,10 @@
 	uint32_t getTessCtlLevelBufferIndex() { return _tessCtlLevelBufferIndex; }
 
 	/** Returns the number of textures in this layout. This is used to calculate the size of the swizzle buffer. */
-	uint32_t getTextureCount() { return _pushConstantsMTLResourceIndexes.getMaxTextureIndex(); }
+	uint32_t getTextureCount() { return _mtlResourceCounts.getMaxTextureIndex(); }
 
 	/** Returns the number of buffers in this layout. This is used to calculate the size of the buffer size buffer. */
-	uint32_t getBufferCount() { return _pushConstantsMTLResourceIndexes.getMaxBufferIndex(); }
+	uint32_t getBufferCount() { return _mtlResourceCounts.getMaxBufferIndex(); }
 
 	/** Returns the number of descriptor sets in this pipeline layout. */
 	uint32_t getDescriptorSetCount() { return (uint32_t)_descriptorSetLayouts.size(); }
@@ -114,9 +114,6 @@
 	/** Returns the descriptor set layout. */
 	MVKDescriptorSetLayout* getDescriptorSetLayout(uint32_t descSetIndex) { return _descriptorSetLayouts[descSetIndex]; }
 
-	/** Returns the push constant binding info. */
-	const MVKShaderResourceBinding& getPushConstantBindings() { return _pushConstantsMTLResourceIndexes; }
-
 	/** Constructs an instance for the specified device. */
 	MVKPipelineLayout(MVKDevice* device, const VkPipelineLayoutCreateInfo* pCreateInfo);
 
@@ -126,10 +123,12 @@
 	friend class MVKPipeline;
 
 	void propagateDebugName() override {}
+	bool stageUsesPushConstants(MVKShaderStage mvkStage);
 
 	MVKSmallVector<MVKDescriptorSetLayout*, 1> _descriptorSetLayouts;
 	MVKSmallVector<MVKShaderResourceBinding, 1> _dslMTLResourceIndexOffsets;
 	MVKSmallVector<VkPushConstantRange> _pushConstants;
+	MVKShaderResourceBinding _mtlResourceCounts;
 	MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
 	MVKShaderImplicitRezBinding _swizzleBufferIndex;
 	MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
@@ -203,8 +202,9 @@
 	MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
 	MVKShaderImplicitRezBinding _dynamicOffsetBufferIndex;
 	MVKShaderImplicitRezBinding _indirectParamsIndex;
-	MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
+	MVKShaderImplicitRezBinding _pushConstantsBufferIndex;
 	uint32_t _descriptorSetCount;
+	bool _stageUsesPushConstants[kMVKShaderStageCount];
 	bool _fullImageViewSwizzle;
 	bool _hasValidMTLPipelineStates = true;
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index dc4bf84..0812486 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -82,6 +82,21 @@
 	shaderConfig.discreteDescriptorSets.clear();
 	shaderConfig.dynamicBufferDescriptors.clear();
 
+	// Add any resource bindings used by push-constants.
+	// Use VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT descriptor type as compatible with push constants in Metal.
+	for (uint32_t stage = kMVKShaderStageVertex; stage < kMVKShaderStageCount; stage++) {
+		if (stageUsesPushConstants((MVKShaderStage)stage)) {
+			mvkPopulateShaderConversionConfig(shaderConfig,
+											  _pushConstantsMTLResourceIndexes.stages[stage],
+											  MVKShaderStage(stage),
+											  kPushConstDescSet,
+											  kPushConstBinding,
+											  1,
+											  VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
+											  nullptr);
+		}
+	}
+
     // Add resource bindings defined in the descriptor set layouts
 	uint32_t dslCnt = getDescriptorSetCount();
 	for (uint32_t dslIdx = 0; dslIdx < dslCnt; dslIdx++) {
@@ -89,60 +104,64 @@
 																	  _dslMTLResourceIndexOffsets[dslIdx],
 																	  dslIdx);
 	}
+}
 
-	// Add any resource bindings used by push-constants.
-	// Use VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT descriptor type as compatible with push constants in Metal.
-	for (uint32_t stage = kMVKShaderStageVertex; stage < kMVKShaderStageCount; stage++) {
-		mvkPopulateShaderConversionConfig(shaderConfig,
-										  _pushConstantsMTLResourceIndexes.stages[stage],
-										  MVKShaderStage(stage),
-										  kPushConstDescSet,
-										  kPushConstBinding,
-										  1,
-										  VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
-										  nullptr);
+bool MVKPipelineLayout::stageUsesPushConstants(MVKShaderStage mvkStage) {
+	VkShaderStageFlagBits vkStage = mvkVkShaderStageFlagBitsFromMVKShaderStage(mvkStage);
+	for (auto pushConst : _pushConstants) {
+		if (mvkIsAnyFlagEnabled(pushConst.stageFlags, vkStage)) {
+			return true;
+		}
 	}
+	return false;
 }
 
 MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
                                      const VkPipelineLayoutCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
 
-    // Add descriptor set layouts, accumulating the resource index offsets used by the
-    // corresponding DSL, and associating the current accumulated resource index offsets
-    // with each DSL as it is added. The final accumulation of resource index offsets
-    // becomes the resource index offsets that will be used for push contants.
-	// If we are using Metal argument buffers, reserve space for the Metal argument
-	// buffers themselves, and clear indexes of offsets used in Metal argument buffers,
-	// but still accumulate dynamic offset buffer indexes across descriptor sets.
+	// For pipeline layout compatibility (“compatible for set N”),
+	// consume the Metal resource indexes in this order:
+	//   - Fixed count of argument buffers for descriptor sets (if using Metal argument buffers).
+	//   - Push constants
+	//   - Descriptor set content
 
-    // According to the Vulkan spec, VkDescriptorSetLayout is intended to be consumed when passed
-	// to any Vulkan function, and may be safely destroyed by app immediately after. In order for
-	// this pipeline layout to retain the VkDescriptorSetLayout, the MVKDescriptorSetLayout
-	// instance is retained, so that it will live on here after it has been destroyed by the API.
+	// If we are using Metal argument buffers, consume a fixed number
+	// of buffer indexes for the Metal argument buffers themselves.
+	if (isUsingMetalArgumentBuffers()) {
+		_mtlResourceCounts.addArgumentBuffers(kMVKMaxDescriptorSetCount);
+	}
 
+	// Add push constants from config
+	_pushConstants.reserve(pCreateInfo->pushConstantRangeCount);
+	for (uint32_t i = 0; i < pCreateInfo->pushConstantRangeCount; i++) {
+		_pushConstants.push_back(pCreateInfo->pPushConstantRanges[i]);
+	}
+
+	// Set push constant resource indexes, and consume a buffer index for any stage that uses a push constant buffer.
+	_pushConstantsMTLResourceIndexes = _mtlResourceCounts;
+	for (uint32_t stage = kMVKShaderStageVertex; stage < kMVKShaderStageCount; stage++) {
+		if (stageUsesPushConstants((MVKShaderStage)stage)) {
+			_mtlResourceCounts.stages[stage].bufferIndex++;
+		}
+	}
+
+	// Add descriptor set layouts, accumulating the resource index offsets used by the corresponding DSL,
+	// and associating the current accumulated resource index offsets with each DSL as it is added.
 	uint32_t dslCnt = pCreateInfo->setLayoutCount;
-	_pushConstantsMTLResourceIndexes.addArgumentBuffers(dslCnt);
-
 	_descriptorSetLayouts.reserve(dslCnt);
 	for (uint32_t i = 0; i < dslCnt; i++) {
 		MVKDescriptorSetLayout* pDescSetLayout = (MVKDescriptorSetLayout*)pCreateInfo->pSetLayouts[i];
 		pDescSetLayout->retain();
 		_descriptorSetLayouts.push_back(pDescSetLayout);
 
-		MVKShaderResourceBinding adjstdDSLRezOfsts = _pushConstantsMTLResourceIndexes;
+		MVKShaderResourceBinding adjstdDSLRezOfsts = _mtlResourceCounts;
 		MVKShaderResourceBinding adjstdDSLRezCnts = pDescSetLayout->_mtlResourceCounts;
 		if (pDescSetLayout->isUsingMetalArgumentBuffer()) {
 			adjstdDSLRezOfsts.clearArgumentBufferResources();
 			adjstdDSLRezCnts.clearArgumentBufferResources();
 		}
 		_dslMTLResourceIndexOffsets.push_back(adjstdDSLRezOfsts);
-		_pushConstantsMTLResourceIndexes += adjstdDSLRezCnts;
-	}
-
-	// Add push constants
-	_pushConstants.reserve(pCreateInfo->pushConstantRangeCount);
-	for (uint32_t i = 0; i < pCreateInfo->pushConstantRangeCount; i++) {
-		_pushConstants.push_back(pCreateInfo->pPushConstantRanges[i]);
+		_mtlResourceCounts += adjstdDSLRezCnts;
 	}
 
 	// Set implicit buffer indices
@@ -150,7 +169,7 @@
 	// present--or at least, we should move the ones that are down to avoid running over
 	// the limit of available buffers. But we can't know that until we compile the shaders.
 	for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) {
-		_dynamicOffsetBufferIndex.stages[i] = _pushConstantsMTLResourceIndexes.stages[i].bufferIndex + 1;
+		_dynamicOffsetBufferIndex.stages[i] = _mtlResourceCounts.stages[i].bufferIndex + 1;
 		_bufferSizeBufferIndex.stages[i] = _dynamicOffsetBufferIndex.stages[i] + 1;
 		_swizzleBufferIndex.stages[i] = _bufferSizeBufferIndex.stages[i] + 1;
 		_indirectParamsIndex.stages[i] = _swizzleBufferIndex.stages[i] + 1;
@@ -175,9 +194,9 @@
 #pragma mark MVKPipeline
 
 void MVKPipeline::bindPushConstants(MVKCommandEncoder* cmdEncoder) {
-	if (cmdEncoder) {
-		for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCount; i++) {
-			cmdEncoder->getPushConstants(mvkVkShaderStageFlagBitsFromMVKShaderStage(MVKShaderStage(i)))->setMTLBufferIndex(_pushConstantsMTLResourceIndexes.stages[i].bufferIndex);
+	for (uint32_t stage = kMVKShaderStageVertex; stage < kMVKShaderStageCount; stage++) {
+		if (cmdEncoder && _stageUsesPushConstants[stage]) {
+			cmdEncoder->getPushConstants(mvkVkShaderStageFlagBitsFromMVKShaderStage(MVKShaderStage(stage)))->setMTLBufferIndex(_pushConstantsBufferIndex.stages[stage]);
 		}
 	}
 }
@@ -205,9 +224,15 @@
 MVKPipeline::MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipelineLayout* layout, MVKPipeline* parent) :
 	MVKVulkanAPIDeviceObject(device),
 	_pipelineCache(pipelineCache),
-	_pushConstantsMTLResourceIndexes(layout->getPushConstantBindings()),
 	_fullImageViewSwizzle(mvkConfig().fullImageViewSwizzle),
-	_descriptorSetCount(layout->getDescriptorSetCount()) {}
+	_descriptorSetCount(layout->getDescriptorSetCount()) {
+
+		// Establish push constant use.
+		for (uint32_t stage = kMVKShaderStageVertex; stage < kMVKShaderStageCount; stage++) {
+			_stageUsesPushConstants[stage] = layout->stageUsesPushConstants((MVKShaderStage)stage);
+			_pushConstantsBufferIndex.stages[stage] = layout->_pushConstantsMTLResourceIndexes.stages[stage].bufferIndex;
+		}
+	}
 
 
 #pragma mark -