Fix issue where Metal argument buffer resource
usage not tracked accurately across shader stages.

Remove tracking of descriptor usage in MVKPipeline.
Don't bind argument buffer to command encoder if descriptor set unused by shader stage.
MVKDescriptor::encodeToMetalArgumentBuffer() remove unused shader stage argument.
Remove SPIRVToMSLConversionConfiguration::isResourceUsed().
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index ed0536d..497b4dc 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -440,7 +440,7 @@
 
 	void assertMissingSwizzles(bool needsSwizzle, const char* stageName, const MVKArrayRef<MVKMTLTextureBinding>& texBindings);
 	void encodeMetalArgumentBuffer(MVKShaderStage stage);
-	virtual void bindMetalArgumentBuffer(MVKMTLBufferBinding& buffBind) = 0;
+	virtual void bindMetalArgumentBuffer(MVKShaderStage stage, MVKMTLBufferBinding& buffBind) = 0;
 
 	inline MVKDescSetDescKey getDynamicOffsetKey(uint32_t descSet, uint32_t descIdx) {
 		return ((MVKDescSetDescKey)descSet << 32) + descIdx;
@@ -543,7 +543,7 @@
 protected:
     void encodeImpl(uint32_t stage) override;
     void markDirty() override;
-	void bindMetalArgumentBuffer(MVKMTLBufferBinding& buffBind) override;
+	void bindMetalArgumentBuffer(MVKShaderStage stage, MVKMTLBufferBinding& buffBind) override;
 
     ResourceBindings<8> _shaderStageResourceBindings[4];
 };
@@ -588,7 +588,7 @@
 
 protected:
     void encodeImpl(uint32_t) override;
-	void bindMetalArgumentBuffer(MVKMTLBufferBinding& buffBind) override;
+	void bindMetalArgumentBuffer(MVKShaderStage stage, MVKMTLBufferBinding& buffBind) override;
 
 	ResourceBindings<4> _resourceBindings;
 };
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index ae1c37f..ba612bc 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -488,54 +488,47 @@
 		id<MTLArgumentEncoder> mtlArgEncoder = pipeline->getMTLArgumentEncoder(dsIdx, stage);
 		if (descSet && mtlArgEncoder) {
 			auto* dsLayout = descSet->getLayout();
-			auto& usedDescriptors = pipeline->getDescriptorUsage(dsIdx);
 			auto& argBuffDirtyDescs = descSet->getMetalArgumentBufferDirtyDescriptors();
 			auto& resourceUsageDirtyDescs = _metalUsageDirtyDescriptors[dsIdx];
-
-			uint32_t elemIdx = 0;
-			uint32_t nextDSLBindDescIdx = 0;
-			MVKDescriptorSetLayoutBinding* mvkDSLBind = nullptr;
 			id<MTLBuffer> mtlArgBuff = nil;
 
-			// Only update the descriptors that are actually used by the shaders, and only if
-			// the descriptor is dirty relative to the arg buffer or Metal encoder usage setting.
-			usedDescriptors.enumerateEnabledBits(false, [&](size_t descIdx) {
-				bool argBuffDirty = argBuffDirtyDescs.getBit(descIdx, true);
-				bool resourceUsageDirty = resourceUsageDirtyDescs.getBit(descIdx, true);
-				if (argBuffDirty || resourceUsageDirty) {
-					// Get the layout binding associated with this descriptor.
-					// Assume each layout binding will apply to multiple descriptors
-					// and only fetch a new one when necessary, as it is expensive.
-					if (descIdx >= nextDSLBindDescIdx) {
-						mvkDSLBind = dsLayout->getBindingForDescriptorIndex((uint32_t)descIdx);
-						if ( !mvkDSLBind ) { return false; }	// We've run out of layout bindings
-						nextDSLBindDescIdx = mvkDSLBind->getDescriptorIndex(mvkDSLBind->getDescriptorCount(descSet));
-						elemIdx = 0;
+			bool shouldBindArgBuffToStage = false;
+			uint32_t dslBindCnt = dsLayout->getBindingCount();
+			for (uint32_t dslBindIdx = 0; dslBindIdx < dslBindCnt; dslBindIdx++) {
+				auto* dslBind = dsLayout->getBindingAt(dslBindIdx);
+				if (dslBind->getApplyToStage(stage)) {
+					shouldBindArgBuffToStage = true;
+					uint32_t elemCnt = dslBind->getDescriptorCount();
+					for (uint32_t elemIdx = 0; elemIdx < elemCnt; elemIdx++) {
+						uint32_t descIdx = dslBind->getDescriptorIndex(elemIdx);
+						bool argBuffDirty = argBuffDirtyDescs.getBit(descIdx, true);
+						bool resourceUsageDirty = resourceUsageDirtyDescs.getBit(descIdx, true);
+						if (argBuffDirty || resourceUsageDirty) {
+							// Don't attach the arg buffer to the arg encoder unless something actually needs
+							// to be written to it. We often might only be updating command encoder resource usage.
+							if (!mtlArgBuff && argBuffDirty) {
+								mtlArgBuff = descSet->getMetalArgumentBuffer();
+								[mtlArgEncoder setArgumentBuffer: mtlArgBuff offset: descSet->getMetalArgumentBufferOffset()];
+							}
+							auto* mvkDesc = descSet->getDescriptorAt(descIdx);
+							mvkDesc->encodeToMetalArgumentBuffer(this, mtlArgEncoder, dsIdx,
+																 dslBind, elemIdx, argBuffDirty, true);
+						}
 					}
-
-					// Don't attach the arg buffer to the arg encoder unless something actually needs
-					// to be written to it. We often might only be updating command encoder resource usage.
-					if (!mtlArgBuff && argBuffDirty) {
-						mtlArgBuff = descSet->getMetalArgumentBuffer();
-						[mtlArgEncoder setArgumentBuffer: mtlArgBuff offset: descSet->getMetalArgumentBufferOffset()];
-					}
-					auto* mvkDesc = descSet->getDescriptorAt((uint32_t)descIdx);
-					mvkDesc->encodeToMetalArgumentBuffer(this, mtlArgEncoder, dsIdx,
-														 mvkDSLBind, elemIdx++, stage,
-														 argBuffDirty, true);
 				}
-				return true;
-			});
+			}
 
 			// If the arg buffer was attached to the arg encoder, detach it now.
 			if (mtlArgBuff) { [mtlArgEncoder setArgumentBuffer: nil offset: 0]; }
 
-			// Bind the Metal argument buffer itself to the command encoder
-			MVKMTLBufferBinding bb;
-			bb.mtlBuffer = descSet->getMetalArgumentBuffer();
-			bb.offset = descSet->getMetalArgumentBufferOffset();
-			bb.index = dsIdx;
-			bindMetalArgumentBuffer(bb);
+			// If it is needed, bind the Metal argument buffer itself to the command encoder,
+			if (shouldBindArgBuffToStage) {
+				MVKMTLBufferBinding bb;
+				bb.mtlBuffer = descSet->getMetalArgumentBuffer();
+				bb.offset = descSet->getMetalArgumentBufferOffset();
+				bb.index = dsIdx;
+				bindMetalArgumentBuffer(stage, bb);
+			}
 
 			// For some unexpected reason, GPU capture on Xcode 12 doesn't always correctly expose
 			// the contents of Metal argument buffers. Triggering an extraction of the arg buffer
@@ -876,10 +869,8 @@
 	return _cmdEncoder->_graphicsPipelineState.getPipeline();
 }
 
-void MVKGraphicsResourcesCommandEncoderState::bindMetalArgumentBuffer(MVKMTLBufferBinding& buffBind) {
-	for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
-		if (i != kMVKShaderStageCompute) { bindBuffer(MVKShaderStage(i), buffBind); }
-	}
+void MVKGraphicsResourcesCommandEncoderState::bindMetalArgumentBuffer(MVKShaderStage stage, MVKMTLBufferBinding& buffBind) {
+	bindBuffer(stage, buffBind);
 }
 
 void MVKGraphicsResourcesCommandEncoderState::encodeArgumentBufferResourceUsage(id<MTLResource> mtlResource,
@@ -995,7 +986,7 @@
 	return _cmdEncoder->_computePipelineState.getPipeline();
 }
 
-void MVKComputeResourcesCommandEncoderState::bindMetalArgumentBuffer(MVKMTLBufferBinding& buffBind) {
+void MVKComputeResourcesCommandEncoderState::bindMetalArgumentBuffer(MVKShaderStage stage, MVKMTLBufferBinding& buffBind) {
 	bindBuffer(buffBind);
 }
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
index 82072b5..e4b96ea 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
@@ -130,11 +130,14 @@
 	uint32_t getDescriptorIndex(uint32_t elementIndex = 0) const { return _descriptorIndex + elementIndex; }
 
 	/** Returns the indexes into the argument buffer. */
-	MVKShaderStageResourceBinding& getMetalArgumentBufferIndexes(MVKShaderStage stage) { return _mtlResourceIndexOffsets.stages[stage]; }
+	MVKShaderStageResourceBinding& getMetalArgumentBufferIndexes() { return _mtlResourceIndexOffsets.stages[0]; }
 
 	/** Returns a bitwise OR of Metal render stages. */
 	MTLRenderStages getMTLRenderStages();
 
+	/** Returns whether this binding should be applied to the shader stage. */
+	bool getApplyToStage(MVKShaderStage stage) { return _applyToStage[stage]; }
+
 	MVKDescriptorSetLayoutBinding(MVKDevice* device,
 								  MVKDescriptorSetLayout* layout,
 								  const VkDescriptorSetLayoutBinding* pBinding,
@@ -151,7 +154,6 @@
 	
 	void initMetalResourceIndexOffsets(const VkDescriptorSetLayoutBinding* pBinding, uint32_t stage);
 	void addMTLArgumentDescriptors(NSMutableArray<MTLArgumentDescriptor*>* args,
-								   MVKShaderStage stage,
 								   mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
 								   uint32_t descSetIdx);
 	void addMTLArgumentDescriptor(NSMutableArray<MTLArgumentDescriptor*>* args,
@@ -207,7 +209,6 @@
 											 uint32_t descSetIndex,
 											 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 											 uint32_t elementIndex,
-											 MVKShaderStage stage,
 											 bool encodeToArgBuffer,
 											 bool encodeUsage) = 0;
 
@@ -272,7 +273,6 @@
 									 uint32_t descSetIndex,
 									 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 									 uint32_t elementIndex,
-									 MVKShaderStage stage,
 									 bool encodeToArgBuffer,
 									 bool encodeUsage) override;
 
@@ -361,7 +361,6 @@
 									 uint32_t descSetIndex,
 									 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 									 uint32_t elementIndex,
-									 MVKShaderStage stage,
 									 bool encodeToArgBuffer,
 									 bool encodeUsage) override;
 
@@ -410,7 +409,6 @@
 									 uint32_t descSetIndex,
 									 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 									 uint32_t elementIndex,
-									 MVKShaderStage stage,
 									 bool encodeToArgBuffer,
 									 bool encodeUsage) override;
 
@@ -490,7 +488,6 @@
 									 uint32_t descSetIndex,
 									 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 									 uint32_t elementIndex,
-									 MVKShaderStage stage,
 									 bool encodeToArgBuffer);
 
 	void write(MVKDescriptorSetLayoutBinding* mvkDSLBind,
@@ -537,7 +534,6 @@
 									 uint32_t descSetIndex,
 									 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 									 uint32_t elementIndex,
-									 MVKShaderStage stage,
 									 bool encodeToArgBuffer,
 									 bool encodeUsage) override;
 
@@ -584,7 +580,6 @@
 									 uint32_t descSetIndex,
 									 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 									 uint32_t elementIndex,
-									 MVKShaderStage stage,
 									 bool encodeToArgBuffer,
 									 bool encodeUsage) override;
 
@@ -629,7 +624,6 @@
 									 uint32_t descSetIndex,
 									 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 									 uint32_t elementIndex,
-									 MVKShaderStage stage,
 									 bool encodeToArgBuffer,
 									 bool encodeUsage) override;
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
index 7efd663..a8080f9 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
@@ -417,7 +417,6 @@
 
 // Adds MTLArgumentDescriptors to the array, and updates resource indexes consumed.
 void MVKDescriptorSetLayoutBinding::addMTLArgumentDescriptors(NSMutableArray<MTLArgumentDescriptor*>* args,
-															  MVKShaderStage stage,
 															  mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
 															  uint32_t descSetIdx) {
 	switch (getDescriptorType()) {
@@ -425,40 +424,40 @@
 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
 		case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
 			break;
 
 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
 			break;
 
 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
 		case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
 			break;
 
 		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);		// Needed for atomic operations
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);		// Needed for atomic operations
 			break;
 
 		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
 			break;
 
 		case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);		// Needed for atomic operations
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().bufferIndex, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);		// Needed for atomic operations
 			break;
 
 		case VK_DESCRIPTOR_TYPE_SAMPLER:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).samplerIndex, MTLDataTypeSampler, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().samplerIndex, MTLDataTypeSampler, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
 			break;
 
 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
-			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes(stage).samplerIndex, MTLDataTypeSampler, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().textureIndex, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
+			addMTLArgumentDescriptor(args, getMetalArgumentBufferIndexes().samplerIndex, MTLDataTypeSampler, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
 			break;
 
 		default:
@@ -754,14 +753,13 @@
 													  uint32_t descSetIndex,
 													  MVKDescriptorSetLayoutBinding* mvkDSLBind,
 													  uint32_t elementIndex,
-													  MVKShaderStage stage,
 													  bool encodeToArgBuffer,
 													  bool encodeUsage) {
 	if (encodeToArgBuffer) {
 		NSUInteger bufferDynamicOffset = (usesDynamicBufferOffsets()
 										  ? rezEncState->getDynamicBufferOffset(descSetIndex, mvkDSLBind->getDescriptorIndex(elementIndex))
 										  : 0);
-		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes(stage).bufferIndex + elementIndex;
+		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes().bufferIndex + elementIndex;
 		[mtlArgEncoder setBuffer: _mvkBuffer ? _mvkBuffer->getMTLBuffer() : nil
 						  offset: _mvkBuffer ? _mvkBuffer->getMTLBufferOffset() + _buffOffset + bufferDynamicOffset : 0
 						 atIndex: argIdx];
@@ -846,11 +844,10 @@
 																  uint32_t descSetIndex,
 																  MVKDescriptorSetLayoutBinding* mvkDSLBind,
 																  uint32_t elementIndex,
-																  MVKShaderStage stage,
 																  bool encodeToArgBuffer,
 																  bool encodeUsage) {
 	if (encodeToArgBuffer) {
-		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes(stage).bufferIndex;
+		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes().bufferIndex;
 		[mtlArgEncoder setBuffer: _mvkMTLBufferAllocation ? _mvkMTLBufferAllocation->_mtlBuffer : nil
 						  offset: _mvkMTLBufferAllocation ? _mvkMTLBufferAllocation->_offset : 0
 						 atIndex: argIdx];
@@ -958,7 +955,6 @@
 													 uint32_t descSetIndex,
 													 MVKDescriptorSetLayoutBinding* mvkDSLBind,
 													 uint32_t elementIndex,
-													 MVKShaderStage stage,
 													 bool encodeToArgBuffer,
 													 bool encodeUsage) {
 	VkDescriptorType descType = getDescriptorType();
@@ -969,7 +965,7 @@
 
 		id<MTLTexture> mtlTexture = _mvkImageView ? _mvkImageView->getMTLTexture(planeIndex) : nil;
 		if (encodeToArgBuffer) {
-			uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes(stage).textureIndex + planeDescIdx;
+			uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes().textureIndex + planeDescIdx;
 			[mtlArgEncoder setTexture: mtlTexture atIndex: argIdx];
 		}
 		if (encodeUsage) {
@@ -978,7 +974,7 @@
 		if (descType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE && mtlTexture) {
 			id<MTLTexture> mtlTex = mtlTexture.parentTexture ? mtlTexture.parentTexture : mtlTexture;
 			if (encodeToArgBuffer) {
-				uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes(stage).bufferIndex + planeDescIdx;
+				uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes().bufferIndex + planeDescIdx;
 				[mtlArgEncoder setBuffer: mtlTex.buffer offset: mtlTex.bufferOffset atIndex: argIdx];
 			}
 			if (encodeUsage) {
@@ -1061,7 +1057,6 @@
 															uint32_t descSetIndex,
 															MVKDescriptorSetLayoutBinding* mvkDSLBind,
 															uint32_t elementIndex,
-															MVKShaderStage stage,
 															bool encodeToArgBuffer) {
 	if (encodeToArgBuffer) {
 		MVKSampler* imutSamp = mvkDSLBind->getImmutableSampler(elementIndex);
@@ -1069,7 +1064,7 @@
 		id<MTLSamplerState> mtlSamp = (mvkSamp
 									   ? mvkSamp->getMTLSamplerState()
 									   : mvkDSLBind->getDevice()->getDefaultMTLSamplerState());
-		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes(stage).samplerIndex + elementIndex;
+		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes().samplerIndex + elementIndex;
 		[mtlArgEncoder setSamplerState: mtlSamp atIndex: argIdx];
 	}
 }
@@ -1127,10 +1122,9 @@
 													   uint32_t descSetIndex,
 													   MVKDescriptorSetLayoutBinding* mvkDSLBind,
 													   uint32_t elementIndex,
-													   MVKShaderStage stage,
 													   bool encodeToArgBuffer,
 													   bool encodeUsage) {
-	MVKSamplerDescriptorMixin::encodeToMetalArgumentBuffer(rezEncState, mtlArgEncoder, descSetIndex, mvkDSLBind, elementIndex, stage, encodeToArgBuffer);
+	MVKSamplerDescriptorMixin::encodeToMetalArgumentBuffer(rezEncState, mtlArgEncoder, descSetIndex, mvkDSLBind, elementIndex, encodeToArgBuffer);
 }
 
 void MVKSamplerDescriptor::write(MVKDescriptorSetLayoutBinding* mvkDSLBind,
@@ -1177,11 +1171,10 @@
 																	uint32_t descSetIndex,
 																	MVKDescriptorSetLayoutBinding* mvkDSLBind,
 																	uint32_t elementIndex,
-																	MVKShaderStage stage,
 																	bool encodeToArgBuffer,
 																	bool encodeUsage) {
-	MVKImageDescriptor::encodeToMetalArgumentBuffer(rezEncState, mtlArgEncoder, descSetIndex, mvkDSLBind, elementIndex, stage, encodeToArgBuffer, encodeUsage);
-	MVKSamplerDescriptorMixin::encodeToMetalArgumentBuffer(rezEncState, mtlArgEncoder, descSetIndex, mvkDSLBind, elementIndex, stage, encodeToArgBuffer);
+	MVKImageDescriptor::encodeToMetalArgumentBuffer(rezEncState, mtlArgEncoder, descSetIndex, mvkDSLBind, elementIndex, encodeToArgBuffer, encodeUsage);
+	MVKSamplerDescriptorMixin::encodeToMetalArgumentBuffer(rezEncState, mtlArgEncoder, descSetIndex, mvkDSLBind, elementIndex, encodeToArgBuffer);
 }
 
 void MVKCombinedImageSamplerDescriptor::write(MVKDescriptorSetLayoutBinding* mvkDSLBind,
@@ -1257,13 +1250,12 @@
 														   uint32_t descSetIndex,
 														   MVKDescriptorSetLayoutBinding* mvkDSLBind,
 														   uint32_t elementIndex,
-														   MVKShaderStage stage,
 														   bool encodeToArgBuffer,
 														   bool encodeUsage) {
 	VkDescriptorType descType = getDescriptorType();
 	id<MTLTexture> mtlTexture = _mvkBufferView ? _mvkBufferView->getMTLTexture() : nil;
 	if (encodeToArgBuffer) {
-		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes(stage).textureIndex + elementIndex;
+		uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes().textureIndex + elementIndex;
 		[mtlArgEncoder setTexture: mtlTexture atIndex: argIdx];
 	}
 	if (encodeUsage) {
@@ -1272,7 +1264,7 @@
 
 	if (descType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER && mtlTexture) {
 		if (encodeToArgBuffer) {
-			uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes(stage).bufferIndex + elementIndex;
+			uint32_t argIdx = mvkDSLBind->getMetalArgumentBufferIndexes().bufferIndex + elementIndex;
 			[mtlArgEncoder setBuffer: mtlTexture.buffer offset: mtlTexture.bufferOffset atIndex: argIdx];
 		}
 		if (encodeUsage) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index b3b523b..0b36a6f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -72,19 +72,17 @@
                                         MVKShaderResourceBinding& dslMTLRezIdxOffsets,
                                         uint32_t dslIndex);
 
-	/** Populates the descriptor usage as indicated by the shader converter context. */
-	void populateDescriptorUsage(MVKBitArray& usageArray,
-								 mvk::SPIRVToMSLConversionConfiguration& context,
-								 uint32_t dslIndex);
+	/** Returns the number of bindings. */
+	uint32_t getBindingCount() { return (uint32_t)_bindings.size(); }
 
-	/** Returns the binding for the descriptor at the index in a descriptor set. */
-	MVKDescriptorSetLayoutBinding* getBindingForDescriptorIndex(uint32_t descriptorIndex);
+	/** Returns the binding at the index in a descriptor set layout. */
+	MVKDescriptorSetLayoutBinding* getBindingAt(uint32_t index) { return &_bindings[index]; }
 
 	/** Returns true if this layout is for push descriptors only. */
 	bool isPushDescriptorLayout() const { return _isPushDescriptorLayout; }
 
-	/** Returns a new MTLArgumentEncoder for the stage, populated from this layout and info from the shader config.  */
-	id<MTLArgumentEncoder> newMTLArgumentEncoder(MVKShaderStage stage, mvk::SPIRVToMSLConversionConfiguration& shaderConfig, uint32_t descSetIdx);
+	/** Returns a new MTLArgumentEncoder, populated from this layout and info from the shader config.  */
+	id<MTLArgumentEncoder> newMTLArgumentEncoder(mvk::SPIRVToMSLConversionConfiguration& shaderConfig, uint32_t descSetIdx);
 
 	MVKDescriptorSetLayout(MVKDevice* device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo);
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index f272fa3..a2e9d51 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -182,42 +182,19 @@
 	}
 }
 
-void MVKDescriptorSetLayout::populateDescriptorUsage(MVKBitArray& usageArray,
-													 SPIRVToMSLConversionConfiguration& context,
-													 uint32_t dslIndex) {
-	uint32_t bindCnt = (uint32_t)_bindings.size();
-	for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
-		auto& dslBind = _bindings[bindIdx];
-		if (context.isResourceUsed(dslIndex, dslBind.getBinding())) {
-			uint32_t elemCnt = dslBind.getDescriptorCount();
-			for (uint32_t elemIdx = 0; elemIdx < elemCnt; elemIdx++) {
-				usageArray.setBit(dslBind.getDescriptorIndex(elemIdx));
-			}
-		}
-	}
-}
-
-id<MTLArgumentEncoder> MVKDescriptorSetLayout::newMTLArgumentEncoder(MVKShaderStage stage,
-																	 mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
+id<MTLArgumentEncoder> MVKDescriptorSetLayout::newMTLArgumentEncoder(mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
 																	 uint32_t descSetIdx) {
 	if ( !isUsingMetalArgumentBuffer() ) { return nil; }
 
 	@autoreleasepool {
 		NSMutableArray<MTLArgumentDescriptor*>* args = [NSMutableArray arrayWithCapacity: _bindings.size()];
 		for (auto& dslBind : _bindings) {
-			dslBind.addMTLArgumentDescriptors(args, stage, shaderConfig, descSetIdx);
+			dslBind.addMTLArgumentDescriptors(args, shaderConfig, descSetIdx);
 		}
 		return (args.count) ? [getMTLDevice() newArgumentEncoderWithArguments: args] : nil;
 	}
 }
 
-MVKDescriptorSetLayoutBinding* MVKDescriptorSetLayout::getBindingForDescriptorIndex(uint32_t descriptorIndex) {
-	auto iter = std::lower_bound(_bindings.begin(), _bindings.end(), descriptorIndex, [](const MVKDescriptorSetLayoutBinding& dslBind, uint32_t descIdx) {
-		return dslBind.getDescriptorIndex(dslBind.getDescriptorCount()) <= descIdx;
-	});
-	return iter != _bindings.end() ? iter : nullptr;
-}
-
 MVKDescriptorSetLayout::MVKDescriptorSetLayout(MVKDevice* device,
                                                const VkDescriptorSetLayoutCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
 
@@ -277,9 +254,8 @@
 
 	if ( !isUsingMetalArgumentBuffer() ) { return; }
 
-	MVKShaderStage stage = kMVKShaderStageVertex;	// Nominal stage. Currently all stages use same encoders.
 	SPIRVToMSLConversionConfiguration shaderConfig;
-	id<MTLArgumentEncoder> argEnc = newMTLArgumentEncoder(stage, shaderConfig, 0);	// retained
+	id<MTLArgumentEncoder> argEnc = newMTLArgumentEncoder(shaderConfig, 0);	// retained
 	_metalArgumentBufferSize = argEnc.encodedLength;
 	[argEnc release];
 }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index ce3355e..d6e2b5c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -186,9 +186,6 @@
 	/** Returns the number of descriptor sets in this pipeline layout. */
 	uint32_t getDescriptorSetCount() { return _descriptorSetCount; }
 
-	/** Returns the descriptor usage array for the descriptor set. */
-	MVKBitArray& getDescriptorUsage(uint32_t descSetIndex) { return _descriptorUsage[descSetIndex]; }
-
 	/** A mutex lock to protect access to the Metal argument encoders. */
 	std::mutex _mtlArgumentEncodingLock;
 
@@ -200,10 +197,8 @@
 protected:
 	void propagateDebugName() override {}
 	void addMTLArgumentEncoders(MVKPipelineLayout* layout, SPIRVToMSLConversionConfiguration& shaderConfig);
-	void initDescriptorUsage(MVKPipelineLayout* layout);
 
 	MVKPipelineCache* _pipelineCache;
-	MVKBitArray _descriptorUsage[kMVKMaxDescriptorSetCount];
 	id<MTLArgumentEncoder> _mtlArgumentEncoders[kMVKMaxDescriptorSetCount];
 	MVKShaderImplicitRezBinding _swizzleBufferIndex;
 	MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 03cb7bd..7b134af 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -179,11 +179,9 @@
 void MVKPipeline::addMTLArgumentEncoders(MVKPipelineLayout* layout, SPIRVToMSLConversionConfiguration& shaderConfig) {
 	if ( !isUsingMetalArgumentBuffers() ) { return; }
 
-	MVKShaderStage stage = kMVKShaderStageVertex;		// Nominal stage. Currently all stages use same encoders.
 	for (uint32_t dsIdx = 0; dsIdx < _descriptorSetCount; dsIdx++) {
 		auto* mvkDSL = layout->_descriptorSetLayouts[dsIdx];
-		mvkDSL->populateDescriptorUsage(_descriptorUsage[dsIdx], shaderConfig, dsIdx);
-		_mtlArgumentEncoders[dsIdx] = mvkDSL->newMTLArgumentEncoder(stage, shaderConfig, dsIdx);	// retained
+		_mtlArgumentEncoders[dsIdx] = mvkDSL->newMTLArgumentEncoder(shaderConfig, dsIdx);	// retained
 	}
 }
 
@@ -193,19 +191,7 @@
 	_pushConstantsMTLResourceIndexes(layout->getPushConstantBindings()),
 	_fullImageViewSwizzle(mvkConfig()->fullImageViewSwizzle),
 	_mtlArgumentEncoders{},
-	_descriptorSetCount(layout->getDescriptorSetCount()) {
-		initDescriptorUsage(layout);
-	}
-
-void MVKPipeline::initDescriptorUsage(MVKPipelineLayout* layout) {
-	_descriptorSetCount = layout->getDescriptorSetCount();
-
-	if (isUsingMetalArgumentBuffers() ) {
-		for (uint32_t dsIdx = 0; dsIdx < _descriptorSetCount; dsIdx++) {
-			_descriptorUsage[dsIdx].resize(layout->getDescriptorCount(dsIdx));
-		}
-	}
-}
+	_descriptorSetCount(layout->getDescriptorSetCount()) {}
 
 MVKPipeline::~MVKPipeline() {
 	for (uint32_t dsIdx = 0; dsIdx < kMVKMaxDescriptorSetCount; dsIdx++) {
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h
index 899c29b..1d34cab 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.h
@@ -160,9 +160,6 @@
         /** Returns whether the vertex buffer at the specified Vulkan binding is used by the shader. */
 		bool isVertexBufferUsed(uint32_t binding) const { return countShaderInputsAt(binding) > 0; }
 
-		/** Returns whether the resource at the specified descriptor set binding is used by the shader. */
-		bool isResourceUsed(uint32_t descSet, uint32_t binding) const;
-
 		/** Returns the MTLTextureType of the image resource at the descriptor set and binding. */
 		MTLTextureType getMTLTextureType(uint32_t descSet, uint32_t binding) const;
 
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.mm b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.mm
index 149c8fe..6290a14 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.mm
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter/SPIRVToMSLConverter.mm
@@ -179,16 +179,6 @@
 	return siCnt;
 }
 
-MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::isResourceUsed(uint32_t descSet, uint32_t binding) const {
-	for (auto& rb : resourceBindings) {
-		auto& rbb = rb.resourceBinding;
-		if (rbb.desc_set == descSet && rbb.binding == binding) {
-			return rb.outIsUsedByShader;
-		}
-	}
-	return false;
-}
-
 MVK_PUBLIC_SYMBOL MTLTextureType SPIRVToMSLConversionConfiguration::getMTLTextureType(uint32_t descSet, uint32_t binding) const {
 	for (auto& rb : resourceBindings) {
 		auto& rbb = rb.resourceBinding;