Skip to content

Commit

Permalink
[Metal] Fixed synchronization of command buffers in-flight for Metal …
Browse files Browse the repository at this point in the history
…backend (again).

The semaphore in MTDirectCommandBuffer is meant to synchronize the lifetime of
in-flight resources such as the staging buffer pool, not the native command buffers (Metal already takes care of those).
The calls to ...wait() and ...signal() must be perfectly balanced, or the synchronization fails.
  • Loading branch information
LukasBanana committed Jun 6, 2024
1 parent 151580e commit a335b63
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 13 deletions.
6 changes: 3 additions & 3 deletions sources/Renderer/Metal/Command/MTCommandBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class MTCommandBuffer : public CommandBuffer

protected:

static constexpr NSUInteger maxNumCommandBuffersInFlight = 3;

MTCommandBuffer(id<MTLDevice> device, long flags);

void ResetRenderStates();
Expand All @@ -74,13 +76,11 @@ class MTCommandBuffer : public CommandBuffer

private:

static constexpr NSUInteger maxNumStagingPools = 3;

id<MTLDevice> device_ = nil;
long flags_ = 0;

NSUInteger currentStagingPool_ = 0;
MTStagingBufferPool stagingBufferPools_[MTCommandBuffer::maxNumStagingPools];
MTStagingBufferPool stagingBufferPools_[MTCommandBuffer::maxNumCommandBuffersInFlight];
SmallVector<id<MTLDrawable>, 2> queuedDrawables_;

};
Expand Down
2 changes: 1 addition & 1 deletion sources/Renderer/Metal/Command/MTCommandBuffer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

void MTCommandBuffer::ResetRenderStates()
{
currentStagingPool_ = (currentStagingPool_ + 1) % maxNumStagingPools;
currentStagingPool_ = (currentStagingPool_ + 1) % MTCommandBuffer::maxNumCommandBuffersInFlight;
}

void MTCommandBuffer::ResetStagingPool()
Expand Down
2 changes: 1 addition & 1 deletion sources/Renderer/Metal/Command/MTCommandQueue.mm
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
auto& directCommandBufferMT = LLGL_CAST(MTDirectCommandBuffer&, commandBufferMT);
if (!directCommandBufferMT.IsImmediateCmdBuffer())
{
SubmitCommandBuffer(directCommandBufferMT.GetNative());
directCommandBufferMT.MarkSubmitted();
SubmitCommandBuffer(directCommandBufferMT.GetNative());
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion sources/Renderer/Metal/Command/MTDirectCommandBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class MTDirectCommandBuffer final : public MTCommandBuffer

id<MTLCommandBuffer> cmdBuffer_ = nil;
dispatch_semaphore_t cmdBufferSemaphore_ = nil;
bool cmdBufferSubmitted_ = false;
bool cmdBufferDirty_ = false;

MTCommandQueue& cmdQueue_;
MTCommandContext context_;
Expand Down
19 changes: 12 additions & 7 deletions sources/Renderer/Metal/Command/MTDirectCommandBuffer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,22 @@
cmdQueue_ { cmdQueue },
context_ { device }
{
const NSUInteger maxCmdBuffers = 3;
cmdBufferSemaphore_ = dispatch_semaphore_create(maxCmdBuffers);
cmdBufferSemaphore_ = dispatch_semaphore_create(MTCommandBuffer::maxNumCommandBuffersInFlight);
}

/* ----- Encoding ----- */

void MTDirectCommandBuffer::Begin()
{
/* Wait until next command buffer becomes available */
if (cmdBufferSubmitted_)
/*
If the previous encoded command buffer was submitted to the command queue,
we have to wait until our in-flight resources (such as staging buffer pool) become available again.
*/
if (!cmdBufferDirty_)
{
dispatch_semaphore_wait(cmdBufferSemaphore_, DISPATCH_TIME_FOREVER);
cmdBufferDirty_ = true;
}

/* Allocate new command buffer from command queue */
cmdBuffer_ = [cmdQueue_.GetNative() commandBuffer];
Expand All @@ -70,7 +75,6 @@
addCompletedHandler:^(id<MTLCommandBuffer> cmdBuffer)
{
dispatch_semaphore_signal(blockSemaphore);
this->cmdBufferSubmitted_ = false;
}
];

Expand All @@ -87,8 +91,8 @@
/* Commit native buffer right after encoding for immediate command buffers */
if (IsImmediateCmdBuffer())
{
cmdQueue_.SubmitCommandBuffer(GetNative());
MarkSubmitted();
cmdQueue_.SubmitCommandBuffer(GetNative());
}

ResetRenderStates();
Expand Down Expand Up @@ -1022,7 +1026,8 @@ static void TrapIndirectPatchesNotSupported()

void MTDirectCommandBuffer::MarkSubmitted()
{
cmdBufferSubmitted_ = true;
/* Reset dirty bit now that it has been submitted to the command queue */
cmdBufferDirty_ = false;
}


Expand Down

0 comments on commit a335b63

Please sign in to comment.