redo semaphore impl on metal

This commit is contained in:
Greg Wells
2025-07-11 17:08:28 -04:00
parent 2def510f69
commit 8445c0553b
5 changed files with 71 additions and 57 deletions

View File

@@ -49,52 +49,45 @@ gnReturnCode metalPresent(gnOutputDeviceHandle device, gnPresentInfo info) {
}
gnReturnCode metalPresentSync(gnOutputDeviceHandle device, gnPresentSyncInfo info) {
clock_t begin = clock();
for (int i = 0; i < info.waitCount; i++) {
while (!info.waitSemaphores[i]->semaphore->eventTriggered) {}
}
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("time spent waiting to present: %lf\n", time_spent);
for (int i =0 ; i < info.presentationQueueCount; i++) {
info.presentationQueues[i]->info.surface->windowSurface->layer.device = device->outputDevice->device;
id<CAMetalDrawable> drawable = [info.presentationQueues[i]->info.surface->windowSurface->layer nextDrawable];
if (drawable == nil) return GN_FAILED_TO_CREATE_FRAMEBUFFER;
if (info.presentationQueues[i]->info.surface->windowSurface->layer.device == nil) info.presentationQueues[i]->info.surface->windowSurface->layer.device = device->outputDevice->device;
id<CAMetalDrawable> drawable = [info.presentationQueues[i]->info.surface->windowSurface->layer nextDrawable];
if (drawable == nil) return GN_FAILED_TO_CREATE_FRAMEBUFFER;
__block gnPresentationQueue presentationQueue = info.presentationQueues[i];
__block uint32_t imageIndex = info.imageIndices[i];
__block gnPresentationQueue presentationQueue = info.presentationQueues[i];
__block uint32_t imageIndex = info.imageIndices[i];
id<MTLCommandBuffer> commandBuffer = [device->outputDevice->transferQueue commandBuffer];
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
mtlAddImageBackToQueue(presentationQueue, imageIndex);
}];
id<MTLCommandBuffer> commandBuffer = [device->outputDevice->transferQueue commandBuffer];
id<MTLBlitCommandEncoder> blit = [commandBuffer blitCommandEncoder];
[blit copyFromTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture
sourceSlice:0
sourceLevel:0
sourceOrigin:(MTLOrigin){0, 0, 0}
sourceSize:(MTLSize){info.presentationQueues[i]->info.imageSize.x, info.presentationQueues[i]->info.imageSize.y, 1}
toTexture:drawable.texture
destinationSlice:0
destinationLevel:0
destinationOrigin:(MTLOrigin){0, 0, 0}];
for (int c = 0; c < info.waitCount; c++) mtlWaitSemaphore(info.waitSemaphores[c], commandBuffer);
[blit endEncoding];
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
mtlAddImageBackToQueue(presentationQueue, imageIndex);
}];
[commandBuffer presentDrawable:drawable];
[commandBuffer commit];
device->outputDevice->executingCommandBuffer = commandBuffer;
}
id<MTLBlitCommandEncoder> blit = [commandBuffer blitCommandEncoder];
[blit copyFromTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture
sourceSlice:0
sourceLevel:0
sourceOrigin:(MTLOrigin){0, 0, 0}
sourceSize:(MTLSize){info.presentationQueues[i]->info.imageSize.x, info.presentationQueues[i]->info.imageSize.y, 1}
toTexture:drawable.texture
destinationSlice:0
destinationLevel:0
destinationOrigin:(MTLOrigin){0, 0, 0}];
// [device->outputDevice->executingCommandBuffer waitUntilScheduled];
[blit endEncoding];
for (int i = 0; i < info.presentationQueueCount; i++) {
if (info.presentationQueues[i]->info.imageSize.x != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.width ||
info.presentationQueues[i]->info.imageSize.y != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.height) {
return GN_SUBOPTIMAL_PRESENTATION_QUEUE;
}
[commandBuffer presentDrawable:drawable];
[commandBuffer commit];
device->outputDevice->executingCommandBuffer = commandBuffer;
}
for (int i = 0; i < info.presentationQueueCount; i++) {
if (info.presentationQueues[i]->info.imageSize.x != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.width ||
info.presentationQueues[i]->info.imageSize.y != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.height) {
return GN_SUBOPTIMAL_PRESENTATION_QUEUE;
}
}
return GN_SUCCESS;

View File

@@ -51,12 +51,19 @@ gnReturnCode createMetalPresentationQueue(gnPresentationQueueHandle presentation
void mtlTakeImageFromQueue(uint32_t* whereToPut, gnPresentationQueue queue, gnSemaphore semaphore) {
*whereToPut = queue->presentationQueue->avaliableTextures.data[0];
uint32_tArrayListPopHead(&queue->presentationQueue->avaliableTextures);
if (semaphore) semaphore->semaphore->eventTriggered = gnTrue;
if (!semaphore) return;
id<MTLCommandBuffer> buffer = [queue->outputDevice->outputDevice->transferQueue commandBuffer];
mtlSignalSemaphore(semaphore, buffer);
[buffer commit];
}
void mtlAddImageBackToQueue(gnPresentationQueue queue, uint32_t index) {
if (queue->presentationQueue->neededImages.count > 0)
if (queue->presentationQueue->neededImages.count > 0) {
mtlTakeImageFromQueue(queue->presentationQueue->neededImages.data[queue->presentationQueue->neededImages.count - 1].whereToPut, queue, queue->presentationQueue->neededImages.data[queue->presentationQueue->neededImages.count - 1].semaphoreToSignal);
mtlImageNeededArrayListRemove(&queue->presentationQueue->neededImages);
}
else
uint32_tArrayListAdd(&queue->presentationQueue->avaliableTextures, index);
}

View File

@@ -2,29 +2,27 @@
#include "synchronization/fence/gryphn_fence.h"
#include "stdio.h"
#include "time.h"
gnReturnCode metalSyncSubmit(gnOutputDevice device, gnSubmitSyncInfo info) {
clock_t begin = clock();
for (int i = 0; i < info.waitCount; i++) {
while (!info.waitSemaphores[i]->semaphore->eventTriggered) {}
}
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("time spent waiting for image in submit: %lf\n", time_spent);
__block gnSemaphore* semsToSignal = info.signalSemaphores;
__block int semsToSignalCount = info.signalCount;
__block gnFence fenceToSignal = info.fence;
__block atomic_int buffersLeft;
atomic_init(&buffersLeft, info.commandBufferCount);
for (int i = 0; i < info.commandBufferCount; i++) {
id <MTLCommandBuffer> buffer = [info.commandBuffers[i]->commandPool->commandPool->commandQueue commandBuffer];
for (int c = 0; c < info.waitCount; c++)
mtlWaitSemaphore(info.waitSemaphores[c], buffer);
[buffer commit];
id<MTLCommandBuffer> commandBuffer = info.commandBuffers[i]->commandBuffer->commandBuffer;
for (int c = 0; c < info.signalCount; c++)
mtlSignalSemaphore(info.signalSemaphores[c], commandBuffer);
[info.commandBuffers[i]->commandBuffer->commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
for (int c = 0; c < semsToSignalCount; c++) {
semsToSignal[c]->semaphore->eventTriggered = gnTrue;
if (atomic_fetch_sub_explicit(&buffersLeft, 1, memory_order_acq_rel) == 1) {
fenceToSignal->signaled = gnTrue;
}
fenceToSignal->signaled = gnTrue;
}];
[commandBuffer commit];

View File

@@ -1,11 +1,17 @@
#pragma once
#include "synchronization/semaphore/gryphn_semaphore.h"
#import <Metal/MTLEvent.h>
#import <Metal/MTLCommandBuffer.h>
#import <stdatomic.h>
typedef struct gnPlatformSemaphore_t {
id<MTLEvent> event;
bool eventTriggered;
atomic_uint_fast64_t currentValue;
} gnPlatformSemaphore;
gnReturnCode createMetalSemaphore(gnSemaphore semaphore, gnOutputDevice device);
void destroyMetalSemaphore(gnSemaphore semaphore);
void mtlSignalSemaphore(gnSemaphore semaphore, id<MTLCommandBuffer> cmdBuf);
void mtlWaitSemaphore(gnSemaphore semaphore, id<MTLCommandBuffer> cmdBuf);

View File

@@ -4,10 +4,20 @@
gnReturnCode createMetalSemaphore(gnSemaphore semaphore, gnOutputDevice device) {
semaphore->semaphore = malloc(sizeof(gnPlatformSemaphore));
semaphore->semaphore->event = [device->outputDevice->device newEvent];
semaphore->semaphore->currentValue = 0;
return GN_SUCCESS;
}
void destroyMetalSemaphore(gnSemaphore semaphore) {
[semaphore->semaphore->event release];
free(semaphore->semaphore);
}
void mtlSignalSemaphore(gnSemaphore semaphore, id<MTLCommandBuffer> cmdBuf) {
uint64_t val = atomic_fetch_add_explicit(&semaphore->semaphore->currentValue, 1, memory_order_acq_rel) + 1;
[cmdBuf encodeSignalEvent:semaphore->semaphore->event value:val];
}
void mtlWaitSemaphore(gnSemaphore semaphore, id<MTLCommandBuffer> cmdBuf) {
uint64_t val = atomic_load_explicit(&semaphore->semaphore->currentValue, memory_order_acquire);
[cmdBuf encodeWaitForEvent:semaphore->semaphore->event value:val];
}