mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-09-03 20:30:24 +00:00
metal: Make the command buffer hold a reference to its fence
METAL_ReleaseFence cleared the fence's MTLCommandBuffer without holding
submitLock, while METAL_Submit's cleanup loop may still be polling it
through submittedCommandBuffers. It also did so before the DecRef, so
any non-final release broke later waits on a still-owned fence.
(cherry picked from commit d8451e52d5)
This commit is contained in:
committed by
Sam Lantinga
parent
39664f3b77
commit
51ef86a11f
@@ -602,7 +602,6 @@ typedef struct MetalCommandBuffer
|
||||
|
||||
// Fences
|
||||
MetalFence *fence;
|
||||
bool autoReleaseFence;
|
||||
|
||||
// Reference Counting
|
||||
MetalBuffer **usedBuffers;
|
||||
@@ -2156,8 +2155,6 @@ static SDL_GPUCommandBuffer *METAL_AcquireCommandBuffer(
|
||||
commandBuffer->computeUniformBuffers[i] = NULL;
|
||||
}
|
||||
|
||||
commandBuffer->autoReleaseFence = true;
|
||||
|
||||
SDL_UnlockMutex(renderer->acquireCommandBufferLock);
|
||||
|
||||
return (SDL_GPUCommandBuffer *)commandBuffer;
|
||||
@@ -3400,8 +3397,9 @@ static void METAL_ReleaseFence(
|
||||
SDL_GPUFence *fence)
|
||||
{
|
||||
MetalFence *metalFence = (MetalFence *)fence;
|
||||
metalFence->commandBuffer = nil;
|
||||
if (SDL_AtomicDecRef(&metalFence->referenceCount)) {
|
||||
// Nothing references the fence anymore, so the command buffer can go too.
|
||||
metalFence->commandBuffer = nil;
|
||||
METAL_INTERNAL_ReleaseFenceToPool(
|
||||
(MetalRenderer *)driverData,
|
||||
(MetalFence *)fence);
|
||||
@@ -3507,8 +3505,9 @@ static void METAL_INTERNAL_CleanCommandBuffer(
|
||||
commandBuffer->needComputeReadOnlyStorageTextureBind = false;
|
||||
SDL_zeroa(commandBuffer->needComputeUniformBufferBind);
|
||||
|
||||
// The fence is now available (unless SubmitAndAcquireFence was called)
|
||||
if (commandBuffer->autoReleaseFence) {
|
||||
// Drop the command buffer's reference to the fence. A cancelled
|
||||
// command buffer never acquired one.
|
||||
if (!cancel) {
|
||||
METAL_ReleaseFence(
|
||||
(SDL_GPURenderer *)renderer,
|
||||
(SDL_GPUFence *)commandBuffer->fence);
|
||||
@@ -4078,9 +4077,10 @@ static bool METAL_INTERNAL_Submit(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return the fence while submitLock is held, another thread could
|
||||
// recycle this command buffer as soon as the lock is released.
|
||||
// Give the caller its own reference while submitLock is held, another
|
||||
// thread could recycle this command buffer as soon as the lock is released.
|
||||
if (fence) {
|
||||
(void)SDL_AtomicIncRef(&metalCommandBuffer->fence->referenceCount);
|
||||
*fence = (SDL_GPUFence *)metalCommandBuffer->fence;
|
||||
}
|
||||
|
||||
@@ -4139,9 +4139,7 @@ static bool METAL_Submit(
|
||||
static SDL_GPUFence *METAL_SubmitAndAcquireFence(
|
||||
SDL_GPUCommandBuffer *commandBuffer)
|
||||
{
|
||||
MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
|
||||
SDL_GPUFence *fence = NULL;
|
||||
metalCommandBuffer->autoReleaseFence = false;
|
||||
if (!METAL_INTERNAL_Submit(commandBuffer, &fence)) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -4154,7 +4152,6 @@ static bool METAL_Cancel(
|
||||
MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
|
||||
MetalRenderer *renderer = metalCommandBuffer->renderer;
|
||||
|
||||
metalCommandBuffer->autoReleaseFence = false;
|
||||
SDL_LockMutex(renderer->submitLock);
|
||||
METAL_INTERNAL_CleanCommandBuffer(renderer, metalCommandBuffer, true);
|
||||
SDL_UnlockMutex(renderer->submitLock);
|
||||
|
||||
Reference in New Issue
Block a user