Fix synchronization issue with locking MTLArgumentEncoder.
Move mutex lock for using MTLArgumentEncoder to MVKMTLArgumentEncoder to be tracked along with the MTLArgumentEncoder it guards.
This commit is contained in:
parent
feb66390ca
commit
378b5d5bc9
@ -26,6 +26,7 @@ Released TBD
|
|||||||
to find a cached shader, by only considering resources from the current shader stage.
|
to find a cached shader, by only considering resources from the current shader stage.
|
||||||
- Rename `kMVKShaderStageMax` to `kMVKShaderStageCount`.
|
- Rename `kMVKShaderStageMax` to `kMVKShaderStageCount`.
|
||||||
- Fix crash when requesting `MTLCommandBuffer` logs in runtime debug mode on older OS versions.
|
- Fix crash when requesting `MTLCommandBuffer` logs in runtime debug mode on older OS versions.
|
||||||
|
- Fix synchronization issue with locking `MTLArgumentEncoder` for Metal Argument Buffers.
|
||||||
- Protect against crash when retrieving `MTLTexture` when `VkImage` has no `VkDeviceMemory` bound.
|
- Protect against crash when retrieving `MTLTexture` when `VkImage` has no `VkDeviceMemory` bound.
|
||||||
- Adjust some `VkPhysicalDeviceLimits` values for Vulkan and Metal compliance.
|
- Adjust some `VkPhysicalDeviceLimits` values for Vulkan and Metal compliance.
|
||||||
- Fix internal reference from `SPIRV_CROSS_NAMESPACE_OVERRIDE` to `SPIRV_CROSS_NAMESPACE`.
|
- Fix internal reference from `SPIRV_CROSS_NAMESPACE_OVERRIDE` to `SPIRV_CROSS_NAMESPACE`.
|
||||||
|
@ -488,27 +488,28 @@ void MVKResourcesCommandEncoderState::bindDescriptorSet(uint32_t descSetIndex,
|
|||||||
void MVKResourcesCommandEncoderState::encodeMetalArgumentBuffer(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),
|
bool useDescSetArgBuff = _cmdEncoder->isUsingDescriptorSetMetalArgumentBuffers();
|
||||||
// so we need to lock out other access to it while we are writing to it.
|
|
||||||
MVKPipeline* pipeline = getPipeline();
|
|
||||||
lock_guard<mutex> lock(pipeline->_mtlArgumentEncodingLock);
|
|
||||||
|
|
||||||
|
MVKPipeline* pipeline = getPipeline();
|
||||||
uint32_t dsCnt = pipeline->getDescriptorSetCount();
|
uint32_t dsCnt = pipeline->getDescriptorSetCount();
|
||||||
for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
|
for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
|
||||||
auto* descSet = _boundDescriptorSets[dsIdx];
|
auto* descSet = _boundDescriptorSets[dsIdx];
|
||||||
if ( !descSet ) { continue; }
|
if ( !descSet ) { continue; }
|
||||||
|
|
||||||
id<MTLArgumentEncoder> mtlArgEncoder = nil;
|
auto* dsLayout = descSet->getLayout();
|
||||||
|
|
||||||
|
// The Metal arg encoder can only write to one arg buffer at a time (it holds the arg buffer),
|
||||||
|
// so we need to lock out other access to it while we are writing to it.
|
||||||
|
auto& mvkArgEnc = useDescSetArgBuff ? dsLayout->getMTLArgumentEncoder() : pipeline->getMTLArgumentEncoder(dsIdx, stage);
|
||||||
|
lock_guard<mutex> lock(mvkArgEnc.mtlArgumentEncodingLock);
|
||||||
|
|
||||||
id<MTLBuffer> mtlArgBuffer = nil;
|
id<MTLBuffer> mtlArgBuffer = nil;
|
||||||
NSUInteger metalArgBufferOffset = 0;
|
NSUInteger metalArgBufferOffset = 0;
|
||||||
|
id<MTLArgumentEncoder> mtlArgEncoder = mvkArgEnc.getMTLArgumentEncoder();
|
||||||
auto* dsLayout = descSet->getLayout();
|
if (useDescSetArgBuff) {
|
||||||
if (dsLayout->isUsingDescriptorSetMetalArgumentBuffers()) {
|
|
||||||
mtlArgEncoder = dsLayout->getMTLArgumentEncoder().getMTLArgumentEncoder();
|
|
||||||
mtlArgBuffer = descSet->getMetalArgumentBuffer();
|
mtlArgBuffer = descSet->getMetalArgumentBuffer();
|
||||||
metalArgBufferOffset = descSet->getMetalArgumentBufferOffset();
|
metalArgBufferOffset = descSet->getMetalArgumentBufferOffset();
|
||||||
} else {
|
} else {
|
||||||
mtlArgEncoder = pipeline->getMTLArgumentEncoder(dsIdx, stage).getMTLArgumentEncoder();
|
|
||||||
// TODO: Source a different arg buffer & offset for each pipeline-stage/desccriptors set
|
// TODO: Source a different arg buffer & offset for each pipeline-stage/desccriptors set
|
||||||
// Also need to only encode the descriptors that are referenced in the shader.
|
// Also need to only encode the descriptors that are referenced in the shader.
|
||||||
// MVKMTLArgumentEncoder could include an MVKBitArray to track that and have it checked below.
|
// MVKMTLArgumentEncoder could include an MVKBitArray to track that and have it checked below.
|
||||||
|
@ -34,8 +34,13 @@ class MVKResourcesCommandEncoderState;
|
|||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark MVKDescriptorSetLayout
|
#pragma mark MVKDescriptorSetLayout
|
||||||
|
|
||||||
/** Holds and manages the lifecycle of a MTLArgumentEncoder. The encoder can only be set once. */
|
/**
|
||||||
|
* Holds and manages the lifecycle of a MTLArgumentEncoder. The encoder can
|
||||||
|
* only be set once, and copying this object results in an uninitialized
|
||||||
|
* empty object, since mutex and MTLArgumentEncoder can/should not be copied.
|
||||||
|
*/
|
||||||
struct MVKMTLArgumentEncoder {
|
struct MVKMTLArgumentEncoder {
|
||||||
|
std::mutex mtlArgumentEncodingLock;
|
||||||
NSUInteger mtlArgumentEncoderSize = 0;
|
NSUInteger mtlArgumentEncoderSize = 0;
|
||||||
|
|
||||||
id<MTLArgumentEncoder> getMTLArgumentEncoder() { return _mtlArgumentEncoder; }
|
id<MTLArgumentEncoder> getMTLArgumentEncoder() { return _mtlArgumentEncoder; }
|
||||||
@ -44,6 +49,10 @@ struct MVKMTLArgumentEncoder {
|
|||||||
_mtlArgumentEncoder = mtlArgEnc; // takes ownership
|
_mtlArgumentEncoder = mtlArgEnc; // takes ownership
|
||||||
mtlArgumentEncoderSize = mtlArgEnc.encodedLength;
|
mtlArgumentEncoderSize = mtlArgEnc.encodedLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MVKMTLArgumentEncoder(const MVKMTLArgumentEncoder& other) {}
|
||||||
|
MVKMTLArgumentEncoder& operator=(const MVKMTLArgumentEncoder& other) { return *this; }
|
||||||
|
MVKMTLArgumentEncoder() {}
|
||||||
~MVKMTLArgumentEncoder() { [_mtlArgumentEncoder release]; }
|
~MVKMTLArgumentEncoder() { [_mtlArgumentEncoder release]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -188,9 +188,6 @@ public:
|
|||||||
/** Returns the number of descriptor sets in this pipeline layout. */
|
/** Returns the number of descriptor sets in this pipeline layout. */
|
||||||
uint32_t getDescriptorSetCount() { return _descriptorSetCount; }
|
uint32_t getDescriptorSetCount() { return _descriptorSetCount; }
|
||||||
|
|
||||||
/** A mutex lock to protect access to the Metal argument encoders. */
|
|
||||||
std::mutex _mtlArgumentEncodingLock;
|
|
||||||
|
|
||||||
/** Constructs an instance for the device. layout, and parent (which may be NULL). */
|
/** Constructs an instance for the device. layout, and parent (which may be NULL). */
|
||||||
MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipelineLayout* layout, MVKPipeline* parent);
|
MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipelineLayout* layout, MVKPipeline* parent);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user