Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions src/gpu/metal/SDL_gpu_metal.m
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,9 @@ static MTLDepthClipMode SDLToMetal_DepthClipMode(

typedef struct MetalFence
{
SDL_AtomicInt complete;
bool complete;
SDL_Mutex *mutex;
SDL_Condition *condition;
SDL_AtomicInt referenceCount;
} MetalFence;

Expand Down Expand Up @@ -739,6 +741,8 @@ static void METAL_DestroyDevice(SDL_GPUDevice *device)

// Release fence infrastructure
for (Uint32 i = 0; i < renderer->availableFenceCount; i += 1) {
SDL_DestroyMutex(renderer->availableFences[i]->mutex);
SDL_DestroyCondition(renderer->availableFences[i]->condition);
SDL_free(renderer->availableFences[i]);
}
SDL_free(renderer->availableFences);
Expand Down Expand Up @@ -2085,7 +2089,9 @@ static Uint8 METAL_INTERNAL_CreateFence(
MetalFence *fence;

fence = SDL_calloc(1, sizeof(MetalFence));
SDL_SetAtomicInt(&fence->complete, 0);
fence->condition = SDL_CreateCondition();
fence->mutex = SDL_CreateMutex();
fence->complete = false;
SDL_SetAtomicInt(&fence->referenceCount, 0);

// Add it to the available pool
Expand Down Expand Up @@ -2128,7 +2134,7 @@ static bool METAL_INTERNAL_AcquireFence(

// Associate the fence with the command buffer
commandBuffer->fence = fence;
SDL_SetAtomicInt(&fence->complete, 0); // FIXME: Is this right?
fence->complete = false;
(void)SDL_AtomicIncRef(&commandBuffer->fence->referenceCount);

return true;
Expand Down Expand Up @@ -3563,6 +3569,13 @@ static void METAL_INTERNAL_PerformPendingDestroys(
}

// Fences
static bool METAL_INTERNAL_FenceOpen(MetalFence *fence) {
bool complete;
SDL_LockMutex(fence->mutex);
complete = fence->complete;
SDL_UnlockMutex(fence->mutex);
return complete;
}

static bool METAL_WaitForFences(
SDL_GPURenderer *driverData,
Expand All @@ -3576,19 +3589,22 @@ static bool METAL_WaitForFences(

if (waitAll) {
for (Uint32 i = 0; i < numFences; i += 1) {
while (!SDL_GetAtomicInt(&((MetalFence *)fences[i])->complete)) {
// Spin!
SDL_LockMutex(((MetalFence *)fences[i])->mutex);
while(!((MetalFence *)fences[i])->complete) {
SDL_WaitCondition(((MetalFence *)fences[i])->condition, ((MetalFence *)fences[i])->mutex);
}
SDL_UnlockMutex(((MetalFence *)fences[i])->mutex);
}
} else {
waiting = 1;
while (waiting) {
for (Uint32 i = 0; i < numFences; i += 1) {
if (SDL_GetAtomicInt(&((MetalFence *)fences[i])->complete) > 0) {
if(METAL_INTERNAL_FenceOpen((MetalFence *)fences[i])) {
waiting = 0;
break;
}
}
SDL_DelayNS(1000);
}
}

Expand All @@ -3602,8 +3618,7 @@ static bool METAL_QueryFence(
SDL_GPURenderer *driverData,
SDL_GPUFence *fence)
{
MetalFence *metalFence = (MetalFence *)fence;
return SDL_GetAtomicInt(&metalFence->complete) == 1;
return METAL_INTERNAL_FenceOpen(((MetalFence *)fence));
}

// Window and Swapchain Management
Expand Down Expand Up @@ -3815,7 +3830,7 @@ static bool METAL_WaitForSwapchain(

if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (!METAL_WaitForFences(
driverData,
(SDL_GPURenderer *)driverData,
true,
&windowData->inFlightFences[windowData->frameCounter],
1)) {
Expand Down Expand Up @@ -4055,7 +4070,10 @@ static bool METAL_Submit(

// Notify the fence when the command buffer has completed
[metalCommandBuffer->handle addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
SDL_AtomicIncRef(&metalCommandBuffer->fence->complete);
SDL_LockMutex(metalCommandBuffer->fence->mutex);
metalCommandBuffer->fence->complete = true;
SDL_SignalCondition(metalCommandBuffer->fence->condition);
SDL_UnlockMutex(metalCommandBuffer->fence->mutex);
}];

// Submit the command buffer
Expand All @@ -4075,7 +4093,7 @@ static bool METAL_Submit(

// Check if we can perform any cleanups
for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
if (SDL_GetAtomicInt(&renderer->submittedCommandBuffers[i]->fence->complete)) {
if (METAL_INTERNAL_FenceOpen(renderer->submittedCommandBuffers[i]->fence)) {
METAL_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i],
Expand Down Expand Up @@ -4128,9 +4146,7 @@ static bool METAL_Wait(
* Sort of equivalent to vkDeviceWaitIdle.
*/
for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
while (!SDL_GetAtomicInt(&renderer->submittedCommandBuffers[i]->fence->complete)) {
// Spin!
}
METAL_WaitForFences((SDL_GPURenderer *)renderer, true, (SDL_GPUFence **)&renderer->submittedCommandBuffers[i]->fence, 1);
}

SDL_LockMutex(renderer->submitLock);
Expand Down
Loading