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
50 changes: 36 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,7 +741,10 @@ static void METAL_DestroyDevice(SDL_GPUDevice *device)

// Release fence infrastructure
for (Uint32 i = 0; i < renderer->availableFenceCount; i += 1) {
SDL_free(renderer->availableFences[i]);
MetalFence *fence = (MetalFence *)renderer->availableFences[i];
SDL_DestroyMutex(fence->mutex);
SDL_DestroyCondition(fence->condition);
SDL_free(fence);
}
SDL_free(renderer->availableFences);

Expand Down Expand Up @@ -2085,7 +2090,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 +2135,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 +3570,14 @@ static void METAL_INTERNAL_PerformPendingDestroys(
}

// Fences
static bool METAL_INTERNAL_FenceComplete(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 +3591,24 @@ static bool METAL_WaitForFences(

if (waitAll) {
for (Uint32 i = 0; i < numFences; i += 1) {
while (!SDL_GetAtomicInt(&((MetalFence *)fences[i])->complete)) {
// Spin!
MetalFence *fence = (MetalFence *)fences[i];
SDL_LockMutex(fence->mutex);
while(!fence->complete) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
while(!fence->complete) {
while (!fence->complete) {

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

Expand All @@ -3603,7 +3623,7 @@ static bool METAL_QueryFence(
SDL_GPUFence *fence)
{
MetalFence *metalFence = (MetalFence *)fence;
return SDL_GetAtomicInt(&metalFence->complete) == 1;
return METAL_INTERNAL_FenceComplete(metalFence);
}

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

if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (!METAL_WaitForFences(
driverData,
(SDL_GPURenderer *)driverData,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this cast necessary?

true,
&windowData->inFlightFences[windowData->frameCounter],
1)) {
Expand Down Expand Up @@ -4055,7 +4075,11 @@ static bool METAL_Submit(

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

// Submit the command buffer
Expand All @@ -4075,7 +4099,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_FenceComplete(renderer->submittedCommandBuffers[i]->fence)) {
METAL_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i],
Expand Down Expand Up @@ -4128,9 +4152,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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these casts necessary? You can just pass driverData for the first one.

}

SDL_LockMutex(renderer->submitLock);
Expand Down
Loading