Construct MTLArgumentEncoders for pipelines.

MVKPipeline tracks a MTLArgumentEncoder for each descriptor set in the pipeline layout,
created from MTLArgumentDescriptors that are populated by MVKDescriptorSetLayoutBindings
in each MVKDescriptorSetLayout.
This commit is contained in:
Bill Hollings 2021-03-18 18:10:29 -04:00
parent 751d864964
commit 14c649853f
6 changed files with 128 additions and 13 deletions

View File

@ -83,7 +83,7 @@ public:
* count provided to that descriptor set is returned. Otherwise returns the value
* defined in VkDescriptorSetLayoutBinding::descriptorCount.
*/
uint32_t getDescriptorCount(MVKDescriptorSet* descSet);
uint32_t getDescriptorCount(MVKDescriptorSet* descSet = nullptr);
/** Returns the descriptor type of this layout. */
inline VkDescriptorType getDescriptorType() { return _info.descriptorType; }
@ -129,6 +129,15 @@ protected:
MVKShaderStageResourceBinding* pDescSetCounts,
const VkDescriptorSetLayoutBinding* pBinding);
void initMetalArgumentBufferIndexes(uint32_t& argIdx, NSUInteger& argBuffSize);
void addMTLArgumentDescriptors(NSMutableArray<MTLArgumentDescriptor*>* args,
mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
uint32_t descSetIdx);
void addMTLArgumentDescriptor(NSMutableArray<MTLArgumentDescriptor*>* args,
MTLDataType dataType,
MTLArgumentAccess access,
mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
uint32_t descSetIdx,
uint32_t argIdxOffset = 0);
void populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
uint32_t dslIndex);

View File

@ -340,7 +340,7 @@ void MVKDescriptorSetLayoutBinding::initMetalArgumentBufferIndexes(uint32_t& arg
_metalArgumentBufferIndex = argIdx;
uint32_t descCnt = getDescriptorCount(nullptr);
uint32_t descCnt = getDescriptorCount();
switch (getDescriptorType()) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
@ -384,13 +384,71 @@ void MVKDescriptorSetLayoutBinding::initMetalArgumentBufferIndexes(uint32_t& arg
}
}
// If depth compare is required, but unavailable on the device, the sampler can only be used as an immutable sampler
bool MVKDescriptorSetLayoutBinding::validate(MVKSampler* mvkSampler) {
if (mvkSampler->getRequiresConstExprSampler()) {
mvkSampler->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdPushDescriptorSet/vkCmdPushDescriptorSetWithTemplate(): Tried to push an immutable sampler.");
return false;
// Adds MTLArgumentDescriptors to the array, and updates resource indexes consumed.
void MVKDescriptorSetLayoutBinding::addMTLArgumentDescriptors(NSMutableArray<MTLArgumentDescriptor*>* args,
mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
uint32_t descSetIdx) {
switch (getDescriptorType()) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
addMTLArgumentDescriptor(args, MTLDataTypePointer, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
addMTLArgumentDescriptor(args, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
addMTLArgumentDescriptor(args, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
addMTLArgumentDescriptor(args, MTLDataTypeTexture, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
addMTLArgumentDescriptor(args, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx, getDescriptorCount()); // Needed for atomic operations
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
addMTLArgumentDescriptor(args, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
break;
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
addMTLArgumentDescriptor(args, MTLDataTypeTexture, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx);
addMTLArgumentDescriptor(args, MTLDataTypePointer, MTLArgumentAccessReadWrite, shaderConfig, descSetIdx, getDescriptorCount()); // Needed for atomic operations
break;
case VK_DESCRIPTOR_TYPE_SAMPLER:
addMTLArgumentDescriptor(args, MTLDataTypeSampler, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
addMTLArgumentDescriptor(args, MTLDataTypeTexture, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx);
addMTLArgumentDescriptor(args, MTLDataTypeSampler, MTLArgumentAccessReadOnly, shaderConfig, descSetIdx, getDescriptorCount());
break;
default:
break;
}
return true;
}
// Adds an MTLArgumentDescriptor if the specified type to the array, and updates resource indexes consumed.
void MVKDescriptorSetLayoutBinding::addMTLArgumentDescriptor(NSMutableArray<MTLArgumentDescriptor*>* args,
MTLDataType dataType,
MTLArgumentAccess access,
mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
uint32_t descSetIdx,
uint32_t argIdxOffset) {
auto* argDesc = [MTLArgumentDescriptor argumentDescriptor];
argDesc.dataType = dataType;
argDesc.access = access;
argDesc.index = _metalArgumentBufferIndex + argIdxOffset;
argDesc.arrayLength = getDescriptorCount();
argDesc.textureType = shaderConfig.getMTLTextureType(descSetIdx, getBinding());
[args addObject: argDesc];
}
void MVKDescriptorSetLayoutBinding::populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context,
@ -416,12 +474,21 @@ void MVKDescriptorSetLayoutBinding::populateShaderConverterContext(mvk::SPIRVToM
models[i],
dslIndex,
_info.binding,
getDescriptorCount(nullptr),
getDescriptorCount(),
mvkSamp);
}
}
}
// If depth compare is required, but unavailable on the device, the sampler can only be used as an immutable sampler
bool MVKDescriptorSetLayoutBinding::validate(MVKSampler* mvkSampler) {
if (mvkSampler->getRequiresConstExprSampler()) {
mvkSampler->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdPushDescriptorSet/vkCmdPushDescriptorSetWithTemplate(): Tried to push an immutable sampler.");
return false;
}
return true;
}
MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(MVKDevice* device,
MVKDescriptorSetLayout* layout,
const VkDescriptorSetLayoutBinding* pBinding,

View File

@ -75,6 +75,9 @@ public:
/** Returns whether this layout is using an argument buffer. */
inline bool isUsingMetalArgumentBuffer() { return isUsingMetalArgumentBuffers() && !isPushDescriptorLayout(); };
/** Returns a new MTLArgumentEncoder for the stage, 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);
protected:

View File

@ -173,6 +173,17 @@ void MVKDescriptorSetLayout::populateShaderConverterContext(mvk::SPIRVToMSLConve
}
}
id<MTLArgumentEncoder> MVKDescriptorSetLayout::newMTLArgumentEncoder(mvk::SPIRVToMSLConversionConfiguration& shaderConfig,
uint32_t descSetIdx) {
@autoreleasepool {
NSMutableArray<MTLArgumentDescriptor*>* args = [NSMutableArray arrayWithCapacity: _bindings.size()];
for (auto& dslBind : _bindings) {
dslBind.addMTLArgumentDescriptors(args, shaderConfig, descSetIdx);
}
return (args.count) ? [getMTLDevice() newArgumentEncoderWithArguments: args] : nil;
}
}
MVKDescriptorSetLayout::MVKDescriptorSetLayout(MVKDevice* device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
@ -202,7 +213,7 @@ MVKDescriptorSetLayout::MVKDescriptorSetLayout(MVKDevice* device,
BindInfo& bindInfo = sortedBindings[bindIdx];
_bindings.emplace_back(_device, this, bindInfo.pBinding, bindInfo.bindingFlags, _descriptorCount);
_bindingToIndex[bindInfo.pBinding->binding] = bindIdx;
_descriptorCount += _bindings.back().getDescriptorCount(nullptr);
_descriptorCount += _bindings.back().getDescriptorCount();
}
initMetalArgumentBufferIndexes();

View File

@ -100,6 +100,9 @@ public:
/** 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(); }
/** Returns the number of descriptor sets in this pipeline layout. */
uint32_t getDescriptorSetCount() { return (uint32_t)_descriptorSetLayouts.size(); }
/** Returns the push constant binding info. */
const MVKShaderResourceBinding& getPushConstantBindings() { return _pushConstantsMTLResourceIndexes; }
@ -109,6 +112,8 @@ public:
~MVKPipelineLayout() override;
protected:
friend class MVKPipeline;
void propagateDebugName() override {}
MVKSmallVector<MVKDescriptorSetLayout*, 1> _descriptorSetLayouts;
@ -173,8 +178,13 @@ public:
protected:
void propagateDebugName() override {}
void addMTLArgumentEncoders(MVKPipelineLayout* layout, SPIRVToMSLConversionConfiguration& shaderConfig);
id<MTLArgumentEncoder> getMTLArgumentEncoder(uint32_t descSetIdx) {
return descSetIdx < _mtlArgumentEncoders.size() ? _mtlArgumentEncoders[descSetIdx] : nil;
}
MVKPipelineCache* _pipelineCache;
MVKSmallVector<id<MTLArgumentEncoder>> _mtlArgumentEncoders;
MVKShaderImplicitRezBinding _swizzleBufferIndex;
MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
MVKShaderImplicitRezBinding _indirectParamsIndex;

View File

@ -79,7 +79,7 @@ void MVKPipelineLayout::populateShaderConverterContext(SPIRVToMSLConversionConfi
context.discreteDescriptorSets.clear();
// Add resource bindings defined in the descriptor set layouts
uint32_t dslCnt = (uint32_t)_descriptorSetLayouts.size();
uint32_t dslCnt = getDescriptorSetCount();
for (uint32_t dslIdx = 0; dslIdx < dslCnt; dslIdx++) {
_descriptorSetLayouts[dslIdx]->populateShaderConverterContext(context,
_dslMTLResourceIndexOffsets[dslIdx],
@ -169,11 +169,19 @@ void MVKPipeline::bindPushConstants(MVKCommandEncoder* cmdEncoder) {
}
}
void MVKPipeline::addMTLArgumentEncoders(MVKPipelineLayout* layout, SPIRVToMSLConversionConfiguration& shaderConfig) {
uint32_t dsCnt = layout->getDescriptorSetCount();
for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
_mtlArgumentEncoders[dsIdx] = layout->_descriptorSetLayouts[dsIdx]->newMTLArgumentEncoder(shaderConfig, dsIdx);
}
}
MVKPipeline::MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipelineLayout* layout, MVKPipeline* parent) :
MVKVulkanAPIDeviceObject(device),
_pipelineCache(pipelineCache),
_pushConstantsMTLResourceIndexes(layout->getPushConstantBindings()),
_fullImageViewSwizzle(mvkConfig()->fullImageViewSwizzle) {}
_fullImageViewSwizzle(mvkConfig()->fullImageViewSwizzle),
_mtlArgumentEncoders(layout->getDescriptorSetCount()) {}
#pragma mark -
@ -523,6 +531,8 @@ void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCre
}
[tcPLDesc release]; // temp release
[rastPLDesc release]; // temp release
addMTLArgumentEncoders((MVKPipelineLayout*)pCreateInfo->layout, shaderContext);
}
}
@ -555,10 +565,13 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLRenderPipelineDescriptor
// Output
addFragmentOutputToPipeline(plDesc, pCreateInfo);
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
addMTLArgumentEncoders(layout, shaderContext);
// Metal does not allow the name of the pipeline to be changed after it has been created,
// and we need to create the Metal pipeline immediately to provide error feedback to app.
// The best we can do at this point is set the pipeline name from the layout.
setLabelIfNotNil(plDesc, ((MVKPipelineLayout*)pCreateInfo->layout)->getDebugName());
setLabelIfNotNil(plDesc, layout->getDebugName());
return plDesc;
}
@ -1717,6 +1730,8 @@ MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateI
_needsBufferSizeBuffer = funcRslts.needsBufferSizeBuffer;
_needsDispatchBaseBuffer = funcRslts.needsDispatchBaseBuffer;
addMTLArgumentEncoders(layout, shaderContext);
return func;
}