Fix error on some Apple GPU's where a vkCmdTimestampQuery() after a
renderpass was writing timestamp before renderpass activity was complete. MVKCommandBuffer tracks whether it contains a stage-based timestamp command, and MVKCommandEncoder updates the timestamp command fence when ending any Metal command encoder on such a MVKCommandBuffer. MVKCommandEncoder reorder member variables to avoid layout gaps (unrelated). MVKCommandBuffer update _commandCount even for single-use immediate command encoding (unrelated).
This commit is contained in:
parent
b8f0828da7
commit
e2168a33db
@ -25,9 +25,11 @@ Released TBD
|
|||||||
- `VK_KHR_dynamic_rendering`
|
- `VK_KHR_dynamic_rendering`
|
||||||
- `VK_KHR_separate_depth_stencil_layouts`
|
- `VK_KHR_separate_depth_stencil_layouts`
|
||||||
- `VK_EXT_separate_stencil_usage`
|
- `VK_EXT_separate_stencil_usage`
|
||||||
|
- Support attachment clearing when some clearing formats are not specified.
|
||||||
- Fix error where previously bound push constants can override a descriptor buffer binding
|
- Fix error where previously bound push constants can override a descriptor buffer binding
|
||||||
used by a subsequent pipeline that does not use push constants.
|
used by a subsequent pipeline that does not use push constants.
|
||||||
- Support attachment clearing when some clearing formats are not specified.
|
- Fix error on some Apple GPU's where a `vkCmdTimestampQuery()` after a renderpass was
|
||||||
|
writing timestamp before renderpass activity was complete.
|
||||||
- Update to latest SPIRV-Cross:
|
- Update to latest SPIRV-Cross:
|
||||||
- MSL: Emit interface block members of array length 1 as arrays instead of scalars.
|
- MSL: Emit interface block members of array length 1 as arrays instead of scalars.
|
||||||
|
|
||||||
|
@ -85,6 +85,8 @@ VkResult MVKCmdWriteTimestamp::setContent(MVKCommandBuffer* cmdBuff,
|
|||||||
|
|
||||||
_pipelineStage = pipelineStage;
|
_pipelineStage = pipelineStage;
|
||||||
|
|
||||||
|
cmdBuff->recordTimestampCommand();
|
||||||
|
|
||||||
return rslt;
|
return rslt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +118,10 @@ public:
|
|||||||
/** Called when a MVKCmdExecuteCommands is added to this command buffer. */
|
/** Called when a MVKCmdExecuteCommands is added to this command buffer. */
|
||||||
void recordExecuteCommands(const MVKArrayRef<MVKCommandBuffer*> secondaryCommandBuffers);
|
void recordExecuteCommands(const MVKArrayRef<MVKCommandBuffer*> secondaryCommandBuffers);
|
||||||
|
|
||||||
|
/** Called when a timestamp command is added. */
|
||||||
|
void recordTimestampCommand();
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Tessellation constituent command management
|
#pragma mark Tessellation constituent command management
|
||||||
|
|
||||||
/** Update the last recorded pipeline with tessellation shaders */
|
/** Update the last recorded pipeline with tessellation shaders */
|
||||||
@ -197,6 +201,7 @@ protected:
|
|||||||
bool _isReusable;
|
bool _isReusable;
|
||||||
bool _supportsConcurrentExecution;
|
bool _supportsConcurrentExecution;
|
||||||
bool _wasExecuted;
|
bool _wasExecuted;
|
||||||
|
bool _hasStageCounterTimestampCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -461,7 +466,6 @@ protected:
|
|||||||
NSString* getMTLRenderCommandEncoderName(MVKCommandUse cmdUse);
|
NSString* getMTLRenderCommandEncoderName(MVKCommandUse cmdUse);
|
||||||
void encodeGPUCounterSample(MVKGPUCounterQueryPool* mvkQryPool, uint32_t sampleIndex, MVKCounterSamplingFlags samplingPoints);
|
void encodeGPUCounterSample(MVKGPUCounterQueryPool* mvkQryPool, uint32_t sampleIndex, MVKCounterSamplingFlags samplingPoints);
|
||||||
void encodeTimestampStageCounterSamples();
|
void encodeTimestampStageCounterSamples();
|
||||||
bool hasTimestampStageCounterQueries() { return !_timestampStageCounterQueries.empty(); }
|
|
||||||
id<MTLFence> getStageCountersMTLFence();
|
id<MTLFence> getStageCountersMTLFence();
|
||||||
MVKArrayRef<MTLSamplePosition> getCustomSamplePositions();
|
MVKArrayRef<MTLSamplePosition> getCustomSamplePositions();
|
||||||
|
|
||||||
@ -470,11 +474,8 @@ protected:
|
|||||||
uint32_t query = 0;
|
uint32_t query = 0;
|
||||||
} GPUCounterQuery;
|
} GPUCounterQuery;
|
||||||
|
|
||||||
VkSubpassContents _subpassContents;
|
|
||||||
MVKCommand* _lastMultiviewPassCmd;
|
|
||||||
uint32_t _renderSubpassIndex;
|
|
||||||
uint32_t _multiviewPassIndex;
|
|
||||||
VkRect2D _renderArea;
|
VkRect2D _renderArea;
|
||||||
|
MVKCommand* _lastMultiviewPassCmd;
|
||||||
MVKActivatedQueries* _pActivatedQueries;
|
MVKActivatedQueries* _pActivatedQueries;
|
||||||
MVKSmallVector<GPUCounterQuery, 16> _timestampStageCounterQueries;
|
MVKSmallVector<GPUCounterQuery, 16> _timestampStageCounterQueries;
|
||||||
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
|
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
|
||||||
@ -482,16 +483,19 @@ protected:
|
|||||||
MVKSmallVector<MTLSamplePosition> _dynamicSamplePositions;
|
MVKSmallVector<MTLSamplePosition> _dynamicSamplePositions;
|
||||||
MVKSmallVector<MVKSmallVector<MTLSamplePosition>> _subpassSamplePositions;
|
MVKSmallVector<MVKSmallVector<MTLSamplePosition>> _subpassSamplePositions;
|
||||||
id<MTLComputeCommandEncoder> _mtlComputeEncoder;
|
id<MTLComputeCommandEncoder> _mtlComputeEncoder;
|
||||||
MVKCommandUse _mtlComputeEncoderUse;
|
|
||||||
id<MTLBlitCommandEncoder> _mtlBlitEncoder;
|
id<MTLBlitCommandEncoder> _mtlBlitEncoder;
|
||||||
id<MTLFence> _stageCountersMTLFence;
|
id<MTLFence> _stageCountersMTLFence;
|
||||||
MVKCommandUse _mtlBlitEncoderUse;
|
|
||||||
MVKPushConstantsCommandEncoderState _vertexPushConstants;
|
MVKPushConstantsCommandEncoderState _vertexPushConstants;
|
||||||
MVKPushConstantsCommandEncoderState _tessCtlPushConstants;
|
MVKPushConstantsCommandEncoderState _tessCtlPushConstants;
|
||||||
MVKPushConstantsCommandEncoderState _tessEvalPushConstants;
|
MVKPushConstantsCommandEncoderState _tessEvalPushConstants;
|
||||||
MVKPushConstantsCommandEncoderState _fragmentPushConstants;
|
MVKPushConstantsCommandEncoderState _fragmentPushConstants;
|
||||||
MVKPushConstantsCommandEncoderState _computePushConstants;
|
MVKPushConstantsCommandEncoderState _computePushConstants;
|
||||||
MVKOcclusionQueryCommandEncoderState _occlusionQueryState;
|
MVKOcclusionQueryCommandEncoderState _occlusionQueryState;
|
||||||
|
VkSubpassContents _subpassContents;
|
||||||
|
MVKCommandUse _mtlComputeEncoderUse;
|
||||||
|
MVKCommandUse _mtlBlitEncoderUse;
|
||||||
|
uint32_t _renderSubpassIndex;
|
||||||
|
uint32_t _multiviewPassIndex;
|
||||||
uint32_t _flushCount = 0;
|
uint32_t _flushCount = 0;
|
||||||
bool _isRenderingEntireAttachment;
|
bool _isRenderingEntireAttachment;
|
||||||
};
|
};
|
||||||
|
@ -147,6 +147,7 @@ VkResult MVKCommandBuffer::reset(VkCommandBufferResetFlags flags) {
|
|||||||
_isExecutingNonConcurrently.clear();
|
_isExecutingNonConcurrently.clear();
|
||||||
_commandCount = 0;
|
_commandCount = 0;
|
||||||
_needsVisibilityResultMTLBuffer = false;
|
_needsVisibilityResultMTLBuffer = false;
|
||||||
|
_hasStageCounterTimestampCommand = false;
|
||||||
_lastTessellationPipeline = nullptr;
|
_lastTessellationPipeline = nullptr;
|
||||||
_lastMultiviewSubpass = nullptr;
|
_lastMultiviewSubpass = nullptr;
|
||||||
setConfigurationResult(VK_NOT_READY);
|
setConfigurationResult(VK_NOT_READY);
|
||||||
@ -171,7 +172,9 @@ void MVKCommandBuffer::addCommand(MVKCommand* command) {
|
|||||||
setConfigurationResult(reportError(VK_NOT_READY, "Command buffer cannot accept commands before vkBeginCommandBuffer() is called."));
|
setConfigurationResult(reportError(VK_NOT_READY, "Command buffer cannot accept commands before vkBeginCommandBuffer() is called."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_commandCount++;
|
||||||
|
|
||||||
if(_immediateCmdEncoder) {
|
if(_immediateCmdEncoder) {
|
||||||
_immediateCmdEncoder->encodeCommands(command);
|
_immediateCmdEncoder->encodeCommands(command);
|
||||||
|
|
||||||
@ -185,7 +188,6 @@ void MVKCommandBuffer::addCommand(MVKCommand* command) {
|
|||||||
command->_next = nullptr;
|
command->_next = nullptr;
|
||||||
_tail = command;
|
_tail = command;
|
||||||
if ( !_head ) { _head = command; }
|
if ( !_head ) { _head = command; }
|
||||||
_commandCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKCommandBuffer::submit(MVKQueueCommandBufferSubmission* cmdBuffSubmit,
|
void MVKCommandBuffer::submit(MVKQueueCommandBufferSubmission* cmdBuffSubmit,
|
||||||
@ -258,20 +260,21 @@ MVKCommandBuffer::~MVKCommandBuffer() {
|
|||||||
reset(0);
|
reset(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the initial visibility result buffer has not been set, promote the first visibility result buffer
|
// Promote the initial visibility buffer and indication of timestamp use from the secondary buffers.
|
||||||
// found among any of the secondary command buffers, to support the case where a render pass is started in
|
|
||||||
// the primary command buffer but the visibility query is started inside one of the secondary command buffers.
|
|
||||||
void MVKCommandBuffer::recordExecuteCommands(const MVKArrayRef<MVKCommandBuffer*> secondaryCommandBuffers) {
|
void MVKCommandBuffer::recordExecuteCommands(const MVKArrayRef<MVKCommandBuffer*> secondaryCommandBuffers) {
|
||||||
if (!_needsVisibilityResultMTLBuffer) {
|
for (MVKCommandBuffer* cmdBuff : secondaryCommandBuffers) {
|
||||||
for (MVKCommandBuffer* cmdBuff : secondaryCommandBuffers) {
|
if (cmdBuff->_needsVisibilityResultMTLBuffer) { _needsVisibilityResultMTLBuffer = true; }
|
||||||
if (cmdBuff->_needsVisibilityResultMTLBuffer) {
|
if (cmdBuff->_hasStageCounterTimestampCommand) { _hasStageCounterTimestampCommand = true; }
|
||||||
_needsVisibilityResultMTLBuffer = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track whether a stage-based timestamp command has been added, so we know
|
||||||
|
// to update the timestamp command fence when ending a Metal command encoder.
|
||||||
|
void MVKCommandBuffer::recordTimestampCommand() {
|
||||||
|
_hasStageCounterTimestampCommand = mvkIsAnyFlagEnabled(_device->_pMetalFeatures->counterSamplingPoints, MVK_COUNTER_SAMPLING_AT_PIPELINE_STAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Tessellation constituent command management
|
#pragma mark Tessellation constituent command management
|
||||||
|
|
||||||
@ -334,7 +337,7 @@ void MVKCommandEncoder::encodeCommands(MVKCommand* command) {
|
|||||||
while(command) {
|
while(command) {
|
||||||
uint32_t prevMVPassIdx = _multiviewPassIndex;
|
uint32_t prevMVPassIdx = _multiviewPassIndex;
|
||||||
command->encode(this);
|
command->encode(this);
|
||||||
|
|
||||||
if(_multiviewPassIndex > prevMVPassIdx) {
|
if(_multiviewPassIndex > prevMVPassIdx) {
|
||||||
// This means we're in a multiview render pass, and we moved on to the
|
// This means we're in a multiview render pass, and we moved on to the
|
||||||
// next view group. Re-encode all commands in the subpass again for this group.
|
// next view group. Re-encode all commands in the subpass again for this group.
|
||||||
@ -744,7 +747,7 @@ void MVKCommandEncoder::endRenderpass() {
|
|||||||
void MVKCommandEncoder::endMetalRenderEncoding() {
|
void MVKCommandEncoder::endMetalRenderEncoding() {
|
||||||
if (_mtlRenderEncoder == nil) { return; }
|
if (_mtlRenderEncoder == nil) { return; }
|
||||||
|
|
||||||
if (hasTimestampStageCounterQueries() ) { [_mtlRenderEncoder updateFence: getStageCountersMTLFence() afterStages: MTLRenderStageFragment]; }
|
if (_cmdBuffer->_hasStageCounterTimestampCommand) { [_mtlRenderEncoder updateFence: getStageCountersMTLFence() afterStages: MTLRenderStageFragment]; }
|
||||||
[_mtlRenderEncoder endEncoding];
|
[_mtlRenderEncoder endEncoding];
|
||||||
_mtlRenderEncoder = nil; // not retained
|
_mtlRenderEncoder = nil; // not retained
|
||||||
|
|
||||||
@ -772,12 +775,12 @@ void MVKCommandEncoder::endCurrentMetalEncoding() {
|
|||||||
_computeResourcesState.markDirty();
|
_computeResourcesState.markDirty();
|
||||||
_computePushConstants.markDirty();
|
_computePushConstants.markDirty();
|
||||||
|
|
||||||
if (_mtlComputeEncoder && hasTimestampStageCounterQueries() ) { [_mtlComputeEncoder updateFence: getStageCountersMTLFence()]; }
|
if (_mtlComputeEncoder && _cmdBuffer->_hasStageCounterTimestampCommand) { [_mtlComputeEncoder updateFence: getStageCountersMTLFence()]; }
|
||||||
[_mtlComputeEncoder endEncoding];
|
[_mtlComputeEncoder endEncoding];
|
||||||
_mtlComputeEncoder = nil; // not retained
|
_mtlComputeEncoder = nil; // not retained
|
||||||
_mtlComputeEncoderUse = kMVKCommandUseNone;
|
_mtlComputeEncoderUse = kMVKCommandUseNone;
|
||||||
|
|
||||||
if (_mtlBlitEncoder && hasTimestampStageCounterQueries() ) { [_mtlBlitEncoder updateFence: getStageCountersMTLFence()]; }
|
if (_mtlBlitEncoder && _cmdBuffer->_hasStageCounterTimestampCommand) { [_mtlBlitEncoder updateFence: getStageCountersMTLFence()]; }
|
||||||
[_mtlBlitEncoder endEncoding];
|
[_mtlBlitEncoder endEncoding];
|
||||||
_mtlBlitEncoder = nil; // not retained
|
_mtlBlitEncoder = nil; // not retained
|
||||||
_mtlBlitEncoderUse = kMVKCommandUseNone;
|
_mtlBlitEncoderUse = kMVKCommandUseNone;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user