Fixes to Metal argument buffer indexing and offset alignment calculations.
MVKPipelineLayout don't track descriptor set resource index offsets when using Metal argument buffers. Fix alignment calc of space available for next descriptor set. Bind Metal argument buffer to command encoder when its content is updated during command encoding, and only if shader uses that descriptor set. Use MTLResourceStorageModeManaged for Metal argument buffer if available.
This commit is contained in:
parent
8145aa2707
commit
c20b8f4010
@ -308,7 +308,6 @@ public:
|
|||||||
void bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint,
|
void bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint,
|
||||||
uint32_t descSetIndex,
|
uint32_t descSetIndex,
|
||||||
MVKDescriptorSet* descSet,
|
MVKDescriptorSet* descSet,
|
||||||
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
|
|
||||||
MVKArrayRef<uint32_t> dynamicOffsets,
|
MVKArrayRef<uint32_t> dynamicOffsets,
|
||||||
uint32_t& dynamicOffsetIndex);
|
uint32_t& dynamicOffsetIndex);
|
||||||
|
|
||||||
|
@ -430,17 +430,16 @@ void MVKCommandEncoder::bindPipeline(VkPipelineBindPoint pipelineBindPoint, MVKP
|
|||||||
void MVKCommandEncoder::bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint,
|
void MVKCommandEncoder::bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint,
|
||||||
uint32_t descSetIndex,
|
uint32_t descSetIndex,
|
||||||
MVKDescriptorSet* descSet,
|
MVKDescriptorSet* descSet,
|
||||||
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
|
|
||||||
MVKArrayRef<uint32_t> dynamicOffsets,
|
MVKArrayRef<uint32_t> dynamicOffsets,
|
||||||
uint32_t& dynamicOffsetIndex) {
|
uint32_t& dynamicOffsetIndex) {
|
||||||
switch (pipelineBindPoint) {
|
switch (pipelineBindPoint) {
|
||||||
case VK_PIPELINE_BIND_POINT_GRAPHICS:
|
case VK_PIPELINE_BIND_POINT_GRAPHICS:
|
||||||
_graphicsResourcesState.bindDescriptorSet(descSetIndex, descSet, dslMTLRezIdxOffsets,
|
_graphicsResourcesState.bindDescriptorSet(descSetIndex, descSet,
|
||||||
dynamicOffsets, dynamicOffsetIndex);
|
dynamicOffsets, dynamicOffsetIndex);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VK_PIPELINE_BIND_POINT_COMPUTE:
|
case VK_PIPELINE_BIND_POINT_COMPUTE:
|
||||||
_computeResourcesState.bindDescriptorSet(descSetIndex, descSet, dslMTLRezIdxOffsets,
|
_computeResourcesState.bindDescriptorSet(descSetIndex, descSet,
|
||||||
dynamicOffsets, dynamicOffsetIndex);
|
dynamicOffsets, dynamicOffsetIndex);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -355,7 +355,6 @@ public:
|
|||||||
/** Binds the specified descriptor set to the specified index. */
|
/** Binds the specified descriptor set to the specified index. */
|
||||||
void bindDescriptorSet(uint32_t descSetIndex,
|
void bindDescriptorSet(uint32_t descSetIndex,
|
||||||
MVKDescriptorSet* descSet,
|
MVKDescriptorSet* descSet,
|
||||||
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
|
|
||||||
MVKArrayRef<uint32_t> dynamicOffsets,
|
MVKArrayRef<uint32_t> dynamicOffsets,
|
||||||
uint32_t& dynamicOffsetIndex);
|
uint32_t& dynamicOffsetIndex);
|
||||||
|
|
||||||
@ -440,7 +439,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void assertMissingSwizzles(bool needsSwizzle, const char* stageName, const MVKArrayRef<MVKMTLTextureBinding>& texBindings);
|
void assertMissingSwizzles(bool needsSwizzle, const char* stageName, const MVKArrayRef<MVKMTLTextureBinding>& texBindings);
|
||||||
void encodeToMetalArgumentBuffer(MVKShaderStage stage);
|
void encodeMetalArgumentBuffer(MVKShaderStage stage);
|
||||||
virtual void bindMetalArgumentBuffer(MVKMTLBufferBinding& buffBind) = 0;
|
virtual void bindMetalArgumentBuffer(MVKMTLBufferBinding& buffBind) = 0;
|
||||||
|
|
||||||
inline MVKDescSetDescKey getDynamicOffsetKey(uint32_t descSet, uint32_t descIdx) {
|
inline MVKDescSetDescKey getDynamicOffsetKey(uint32_t descSet, uint32_t descIdx) {
|
||||||
|
@ -457,7 +457,6 @@ void MVKBlendColorCommandEncoderState::encodeImpl(uint32_t stage) {
|
|||||||
// descriptor set content, and bind the argument buffer MTLBuffer used by the descriptor set as a resource.
|
// descriptor set content, and bind the argument buffer MTLBuffer used by the descriptor set as a resource.
|
||||||
void MVKResourcesCommandEncoderState::bindDescriptorSet(uint32_t descSetIndex,
|
void MVKResourcesCommandEncoderState::bindDescriptorSet(uint32_t descSetIndex,
|
||||||
MVKDescriptorSet* descSet,
|
MVKDescriptorSet* descSet,
|
||||||
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
|
|
||||||
MVKArrayRef<uint32_t> dynamicOffsets,
|
MVKArrayRef<uint32_t> dynamicOffsets,
|
||||||
uint32_t& dynamicOffsetIndex) {
|
uint32_t& dynamicOffsetIndex) {
|
||||||
_boundDescriptorSets[descSetIndex] = descSet;
|
_boundDescriptorSets[descSetIndex] = descSet;
|
||||||
@ -469,19 +468,13 @@ void MVKResourcesCommandEncoderState::bindDescriptorSet(uint32_t descSetIndex,
|
|||||||
usageDirty.resize(descSet->getDescriptorCount());
|
usageDirty.resize(descSet->getDescriptorCount());
|
||||||
usageDirty.setAllBits();
|
usageDirty.setAllBits();
|
||||||
|
|
||||||
MVKMTLBufferBinding bb;
|
|
||||||
bb.mtlBuffer = descSet->getMetalArgumentBuffer();
|
|
||||||
bb.offset = descSet->getMetalArgumentBufferOffset();
|
|
||||||
bb.index = dslMTLRezIdxOffsets.stages[kMVKShaderStageVertex].bufferIndex;
|
|
||||||
bindMetalArgumentBuffer(bb);
|
|
||||||
|
|
||||||
MVKCommandEncoderState::markDirty();
|
MVKCommandEncoderState::markDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode the dirty descriptors to the Metal argument buffer,
|
// Encode the dirty descriptors to the Metal argument buffer, set the Metal command encoder
|
||||||
// and set the Metal command encoder usage for each resource.
|
// usage for each resource, and bind the Metal argument buffer to the command encoder.
|
||||||
void MVKResourcesCommandEncoderState::encodeToMetalArgumentBuffer(MVKShaderStage stage) {
|
void MVKResourcesCommandEncoderState::encodeMetalArgumentBuffer(MVKShaderStage stage) {
|
||||||
if ( !_cmdEncoder->isUsingMetalArgumentBuffers() ) { return; }
|
if ( !_cmdEncoder->isUsingMetalArgumentBuffers() ) { return; }
|
||||||
|
|
||||||
// The Metal arg encoder can only write to one arg buffer at a time (it holds the arg buffer),
|
// The Metal arg encoder can only write to one arg buffer at a time (it holds the arg buffer),
|
||||||
@ -537,11 +530,18 @@ void MVKResourcesCommandEncoderState::encodeToMetalArgumentBuffer(MVKShaderStage
|
|||||||
// If the arg buffer was attached to the arg encoder, detach it now.
|
// If the arg buffer was attached to the arg encoder, detach it now.
|
||||||
if (mtlArgBuff) { [mtlArgEncoder setArgumentBuffer: nil offset: 0]; }
|
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);
|
||||||
|
|
||||||
// For some unexpected reason, GPU capture on Xcode 12 doesn't always correctly expose
|
// 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
|
// the contents of Metal argument buffers. Triggering an extraction of the arg buffer
|
||||||
// contents here, after filling it, seems to correct that.
|
// contents here, after filling it, seems to correct that.
|
||||||
// Sigh. A bug report has been filed with Apple.
|
// Sigh. A bug report has been filed with Apple.
|
||||||
if (getDevice()->isCurrentlyAutoGPUCapturing()) { [mtlArgBuff contents]; }
|
if (getDevice()->isCurrentlyAutoGPUCapturing()) { [descSet->getMetalArgumentBuffer() contents]; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -637,7 +637,7 @@ void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stag
|
|||||||
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
|
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
|
||||||
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler) {
|
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler) {
|
||||||
|
|
||||||
encodeToMetalArgumentBuffer(stage);
|
encodeMetalArgumentBuffer(stage);
|
||||||
|
|
||||||
auto& shaderStage = _shaderStageResourceBindings[stage];
|
auto& shaderStage = _shaderStageResourceBindings[stage];
|
||||||
encodeBinding<MVKMTLBufferBinding>(shaderStage.bufferBindings, shaderStage.areBufferBindingsDirty, bindBuffer);
|
encodeBinding<MVKMTLBufferBinding>(shaderStage.bufferBindings, shaderStage.areBufferBindingsDirty, bindBuffer);
|
||||||
@ -933,7 +933,7 @@ void MVKComputeResourcesCommandEncoderState::markDirty() {
|
|||||||
|
|
||||||
void MVKComputeResourcesCommandEncoderState::encodeImpl(uint32_t) {
|
void MVKComputeResourcesCommandEncoderState::encodeImpl(uint32_t) {
|
||||||
|
|
||||||
encodeToMetalArgumentBuffer(kMVKShaderStageCompute);
|
encodeMetalArgumentBuffer(kMVKShaderStageCompute);
|
||||||
|
|
||||||
MVKPipeline* pipeline = _cmdEncoder->_computePipelineState.getPipeline();
|
MVKPipeline* pipeline = _cmdEncoder->_computePipelineState.getPipeline();
|
||||||
bool fullImageViewSwizzle = pipeline ? pipeline->fullImageViewSwizzle() : false;
|
bool fullImageViewSwizzle = pipeline ? pipeline->fullImageViewSwizzle() : false;
|
||||||
|
@ -38,8 +38,7 @@ void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
|
|||||||
if (!cmdEncoder) { clearConfigurationResult(); }
|
if (!cmdEncoder) { clearConfigurationResult(); }
|
||||||
if (_isPushDescriptorLayout ) { return; }
|
if (_isPushDescriptorLayout ) { return; }
|
||||||
|
|
||||||
if (cmdEncoder) { cmdEncoder->bindDescriptorSet(pipelineBindPoint, descSetIndex,
|
if (cmdEncoder) { cmdEncoder->bindDescriptorSet(pipelineBindPoint, descSetIndex, descSet,
|
||||||
descSet, dslMTLRezIdxOffsets,
|
|
||||||
dynamicOffsets, dynamicOffsetIndex); }
|
dynamicOffsets, dynamicOffsetIndex); }
|
||||||
if ( !isUsingMetalArgumentBuffers() ) {
|
if ( !isUsingMetalArgumentBuffers() ) {
|
||||||
for (auto& dslBind : _bindings) {
|
for (auto& dslBind : _bindings) {
|
||||||
@ -283,8 +282,6 @@ void MVKDescriptorSetLayout::initForMetalArgumentBufferUse() {
|
|||||||
id<MTLArgumentEncoder> argEnc = newMTLArgumentEncoder(stage, shaderConfig, 0); // retained
|
id<MTLArgumentEncoder> argEnc = newMTLArgumentEncoder(stage, shaderConfig, 0); // retained
|
||||||
_metalArgumentBufferSize = argEnc.encodedLength;
|
_metalArgumentBufferSize = argEnc.encodedLength;
|
||||||
[argEnc release];
|
[argEnc release];
|
||||||
|
|
||||||
_mtlResourceCounts.addArgumentBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -514,8 +511,10 @@ VkResult MVKDescriptorPool::allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL
|
|||||||
uint32_t variableDescriptorCount,
|
uint32_t variableDescriptorCount,
|
||||||
VkDescriptorSet* pVKDS) {
|
VkDescriptorSet* pVKDS) {
|
||||||
VkResult rslt = VK_ERROR_OUT_OF_POOL_MEMORY;
|
VkResult rslt = VK_ERROR_OUT_OF_POOL_MEMORY;
|
||||||
NSUInteger mtlArgBuffAllocSize = mvkAlignByteCount(mvkDSL->_metalArgumentBufferSize,
|
NSUInteger mtlArgBuffAllocSize = mvkDSL->_metalArgumentBufferSize;
|
||||||
getDevice()->_pMetalFeatures->mtlBufferAlignment);
|
NSUInteger mtlArgBuffAlignedSize = mvkAlignByteCount(mtlArgBuffAllocSize,
|
||||||
|
getDevice()->_pMetalFeatures->mtlBufferAlignment);
|
||||||
|
|
||||||
size_t dsCnt = _descriptorSetAvailablility.size();
|
size_t dsCnt = _descriptorSetAvailablility.size();
|
||||||
_descriptorSetAvailablility.enumerateEnabledBits(true, [&](size_t dsIdx) {
|
_descriptorSetAvailablility.enumerateEnabledBits(true, [&](size_t dsIdx) {
|
||||||
bool isSpaceAvail = true; // If not using Metal arg buffers, space will always be available.
|
bool isSpaceAvail = true; // If not using Metal arg buffers, space will always be available.
|
||||||
@ -532,7 +531,7 @@ VkResult MVKDescriptorPool::allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL
|
|||||||
// on a reset pool), set the offset and update the next available offset value.
|
// on a reset pool), set the offset and update the next available offset value.
|
||||||
if ( !mtlArgBuffOffset && (dsIdx || !_nextMetalArgumentBufferOffset)) {
|
if ( !mtlArgBuffOffset && (dsIdx || !_nextMetalArgumentBufferOffset)) {
|
||||||
mtlArgBuffOffset = _nextMetalArgumentBufferOffset;
|
mtlArgBuffOffset = _nextMetalArgumentBufferOffset;
|
||||||
_nextMetalArgumentBufferOffset += mtlArgBuffAllocSize;
|
_nextMetalArgumentBufferOffset += mtlArgBuffAlignedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the offset of the next desc set, if one exists and
|
// Get the offset of the next desc set, if one exists and
|
||||||
@ -841,7 +840,15 @@ void MVKDescriptorPool::initMetalArgumentBuffer(const VkDescriptorPoolCreateInfo
|
|||||||
setConfigurationResult(reportError(VK_ERROR_FRAGMENTATION_EXT, "vkCreateDescriptorPool(): The requested descriptor storage of %d MB is larger than the maximum descriptor storage of %d MB per VkDescriptorPool.", (uint32_t)(metalArgBuffSize / MEBI), (uint32_t)(maxMTLBuffSize / MEBI)));
|
setConfigurationResult(reportError(VK_ERROR_FRAGMENTATION_EXT, "vkCreateDescriptorPool(): The requested descriptor storage of %d MB is larger than the maximum descriptor storage of %d MB per VkDescriptorPool.", (uint32_t)(metalArgBuffSize / MEBI), (uint32_t)(maxMTLBuffSize / MEBI)));
|
||||||
metalArgBuffSize = maxMTLBuffSize;
|
metalArgBuffSize = maxMTLBuffSize;
|
||||||
}
|
}
|
||||||
_metalArgumentBuffer = [getMTLDevice() newBufferWithLength: metalArgBuffSize options: MTLResourceStorageModeShared]; // retained
|
|
||||||
|
// The MTLBuffer can have Managed storage if possible because we don't set constant inline data directly in the buffer.
|
||||||
|
#if MVK_MACOS
|
||||||
|
MTLResourceOptions rezOpts = MTLResourceStorageModeManaged;
|
||||||
|
#endif
|
||||||
|
#if MVK_IOS_OR_TVOS
|
||||||
|
MTLResourceOptions rezOpts = MTLResourceStorageModeShared;
|
||||||
|
#endif
|
||||||
|
_metalArgumentBuffer = [getMTLDevice() newBufferWithLength: metalArgBuffSize options: rezOpts]; // retained
|
||||||
_metalArgumentBuffer.label = @"Argument buffer";
|
_metalArgumentBuffer.label = @"Argument buffer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,8 @@ MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
|
|||||||
// corresponding DSL, and associating the current accumulated resource index offsets
|
// corresponding DSL, and associating the current accumulated resource index offsets
|
||||||
// with each DSL as it is added. The final accumulation of 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.
|
// becomes the resource index offsets that will be used for push contants.
|
||||||
|
// If we are using Metal argument buffers, don't track resource index offsets per descriptor set,
|
||||||
|
// but do take into consideration the buffer resouce consumed by the Metal argument buffer itself.
|
||||||
|
|
||||||
// According to the Vulkan spec, VkDescriptorSetLayout is intended to be consumed when passed
|
// 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
|
// to any Vulkan function, and may be safely destroyed by app immediately after. In order for
|
||||||
@ -121,8 +123,13 @@ MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
|
|||||||
MVKDescriptorSetLayout* pDescSetLayout = (MVKDescriptorSetLayout*)pCreateInfo->pSetLayouts[i];
|
MVKDescriptorSetLayout* pDescSetLayout = (MVKDescriptorSetLayout*)pCreateInfo->pSetLayouts[i];
|
||||||
pDescSetLayout->retain();
|
pDescSetLayout->retain();
|
||||||
_descriptorSetLayouts.push_back(pDescSetLayout);
|
_descriptorSetLayouts.push_back(pDescSetLayout);
|
||||||
_dslMTLResourceIndexOffsets.push_back(_pushConstantsMTLResourceIndexes);
|
if (isUsingMetalArgumentBuffers()) {
|
||||||
_pushConstantsMTLResourceIndexes += pDescSetLayout->_mtlResourceCounts;
|
_dslMTLResourceIndexOffsets.emplace_back();
|
||||||
|
_pushConstantsMTLResourceIndexes.addArgumentBuffer();
|
||||||
|
} else {
|
||||||
|
_dslMTLResourceIndexOffsets.push_back(_pushConstantsMTLResourceIndexes);
|
||||||
|
_pushConstantsMTLResourceIndexes += pDescSetLayout->_mtlResourceCounts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add push constants
|
// Add push constants
|
||||||
|
Loading…
x
Reference in New Issue
Block a user