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.
This commit is contained in:
Bill Hollings 2022-03-14 16:29:22 -04:00
parent 9cfc946a7c
commit 2a17f757e1
5 changed files with 71 additions and 57 deletions

View File

@ -18,6 +18,7 @@ MoltenVK 1.1.9
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.

View File

@ -321,7 +321,7 @@ typedef enum {
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. */

View File

@ -363,15 +363,3 @@ void mvkUpdateDescriptorSets(uint32_t writeCount,
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);

View File

@ -100,10 +100,10 @@ public:
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 @@ public:
/** 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 @@ protected:
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 @@ protected:
MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
MVKShaderImplicitRezBinding _dynamicOffsetBufferIndex;
MVKShaderImplicitRezBinding _indirectParamsIndex;
MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
MVKShaderImplicitRezBinding _pushConstantsBufferIndex;
uint32_t _descriptorSetCount;
bool _stageUsesPushConstants[kMVKShaderStageCount];
bool _fullImageViewSwizzle;
bool _hasValidMTLPipelineStates = true;

View File

@ -82,6 +82,21 @@ void MVKPipelineLayout::populateShaderConversionConfig(SPIRVToMSLConversionConfi
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 @@ void MVKPipelineLayout::populateShaderConversionConfig(SPIRVToMSLConversionConfi
_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 @@ MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
// 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 @@ MVKPipelineLayout::~MVKPipelineLayout() {
#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 @@ void MVKPipeline::addMTLArgumentEncoders(MVKMTLFunction& mvkMTLFunc,
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 -