diff --git a/src/gpu/webgpu/SDL_gpu_webgpu.c b/src/gpu/webgpu/SDL_gpu_webgpu.c index dea8322b0f5e0..11fd00c03c2c1 100644 --- a/src/gpu/webgpu/SDL_gpu_webgpu.c +++ b/src/gpu/webgpu/SDL_gpu_webgpu.c @@ -2092,12 +2092,18 @@ static WebGPUFence *WebGPU_INTERNAL_AcquireFenceFromPool(WebGPURenderer *rendere { WebGPUFence *handle; + /*SDL_Log("Acquiring fence from pool");*/ + if (renderer->fencePool.availableFenceCount == 0) { - handle = SDL_malloc(sizeof(WebGPUFence)); + /*SDL_Log("Creating new fence");*/ + handle = (WebGPUFence *)SDL_malloc(sizeof(WebGPUFence)); + /*SDL_Log("Allocated fence %p", handle);*/ SDL_SetAtomicInt(&handle->referenceCount, 0); return handle; } + /*SDL_Log("Reusing fence from pool");*/ + SDL_LockMutex(renderer->fencePool.lock); handle = renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount - 1]; @@ -2148,188 +2154,108 @@ static bool WebGPU_QueryFence(SDL_GPURenderer *driverData, SDL_GPUFence *fence) return false; } +static void WebGPU_ReleaseFence(SDL_GPURenderer *driverData, SDL_GPUFence *fence) +{ + WebGPUFence *handle = (WebGPUFence *)fence; + if (SDL_AtomicDecRef(&handle->referenceCount)) { + WebGPU_INTERNAL_ReturnFenceToPool((WebGPURenderer *)driverData, handle); + } +} + static bool WebGPU_INTERNAL_AllocateCommandBuffer( WebGPURenderer *renderer, WebGPUCommandPool *webgpuCommandPool) { WebGPUCommandBuffer *commandBuffer; - webgpuCommandPool->inactiveCommandBufferCount += 1; - webgpuCommandPool->inactiveCommandBuffers = SDL_realloc( - webgpuCommandPool->inactiveCommandBuffers, - sizeof(WebGPUCommandBuffer *) * - webgpuCommandPool->inactiveCommandBufferCapacity); + // Check if expansion is needed before incrementing the count + if (webgpuCommandPool->inactiveCommandBufferCount + 1 > webgpuCommandPool->inactiveCommandBufferCapacity) { + Uint32 newCapacity = webgpuCommandPool->inactiveCommandBufferCapacity * 2; + newCapacity = newCapacity > 0 ? newCapacity : 1; // Handle initial capacity of 0 + WebGPUCommandBuffer **newArray = (WebGPUCommandBuffer **)SDL_realloc( + webgpuCommandPool->inactiveCommandBuffers, + sizeof(WebGPUCommandBuffer *) * newCapacity); + if (!newArray) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to expand command buffer array"); + return false; + } + webgpuCommandPool->inactiveCommandBuffers = newArray; + webgpuCommandPool->inactiveCommandBufferCapacity = newCapacity; + } - commandBuffer = SDL_malloc(sizeof(WebGPUCommandBuffer)); + // Allocate and initialize the new command buffer + commandBuffer = (WebGPUCommandBuffer *)SDL_malloc(sizeof(WebGPUCommandBuffer)); + if (!commandBuffer) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to allocate command buffer"); + return false; + } + + SDL_Log("Allocating command buffer: %p", commandBuffer); - // Initialize the default state of a command buffer SDL_zero(*commandBuffer); commandBuffer->renderer = renderer; commandBuffer->commandPool = webgpuCommandPool; commandBuffer->common.device = renderer->sdlDevice; - commandBuffer->autoReleaseFence = true; - commandBuffer->inFlightFence = NULL; - commandBuffer->currentGraphicsPipeline = NULL; + // Add to the array and update count webgpuCommandPool->inactiveCommandBuffers[webgpuCommandPool->inactiveCommandBufferCount] = commandBuffer; webgpuCommandPool->inactiveCommandBufferCount += 1; return true; } -static void WebGPU_INTERNAL_DestroyCommandPool( +static void WebGPU_INTERNAL_CleanCommandBuffer( WebGPURenderer *renderer, - WebGPUCommandPool *webgpuCommandPool) + WebGPUCommandBuffer *commandBuffer, + bool cancel) { - Uint32 i; - WebGPUCommandBuffer *commandBuffer; - - for (i = 0; i < webgpuCommandPool->inactiveCommandBufferCount; i += 1) { - commandBuffer = webgpuCommandPool->inactiveCommandBuffers[i]; + if (commandBuffer->autoReleaseFence) { + WebGPU_ReleaseFence( + (SDL_GPURenderer *)renderer, + (SDL_GPUFence *)commandBuffer->inFlightFence); - // TODO: Implement proper freeing once command pools are all implemented - - SDL_free(commandBuffer); + commandBuffer->inFlightFence = NULL; } - SDL_free(webgpuCommandPool->inactiveCommandBuffers); - SDL_free(webgpuCommandPool); -} - -static WebGPUCommandPool *WebGPU_INTERNAL_FetchCommandPool( - WebGPURenderer *renderer, - SDL_ThreadID threadID) -{ - WebGPUCommandPool *webgpuCommandPool = NULL; - CommandPoolHashTableKey key; - key.threadID = threadID; - - bool result = SDL_FindInHashTable( - renderer->commandPoolHashTable, - (const void *)&key, - (const void **)&webgpuCommandPool); - - if (result) { - return webgpuCommandPool; - } - - webgpuCommandPool = (WebGPUCommandPool *)SDL_malloc(sizeof(WebGPUCommandPool)); - webgpuCommandPool->threadID = threadID; - - webgpuCommandPool->inactiveCommandBufferCapacity = 0; - webgpuCommandPool->inactiveCommandBufferCount = 0; - webgpuCommandPool->inactiveCommandBuffers = NULL; - - if (!WebGPU_INTERNAL_AllocateCommandBuffer( - renderer, - webgpuCommandPool)) { - WebGPU_INTERNAL_DestroyCommandPool(renderer, webgpuCommandPool); - return NULL; - } - - CommandPoolHashTableKey *allocedKey = SDL_malloc(sizeof(CommandPoolHashTableKey)); - allocedKey->threadID = threadID; - - SDL_InsertIntoHashTable( - renderer->commandPoolHashTable, - (const void *)allocedKey, - (const void *)webgpuCommandPool); - - return webgpuCommandPool; -} -static WebGPUCommandBuffer *WebGPU_INTERNAL_GetInactiveCommandBufferFromPool( - WebGPURenderer *renderer, - SDL_ThreadID threadID) -{ - WebGPUCommandPool *commandPool = - WebGPU_INTERNAL_FetchCommandPool(renderer, threadID); - WebGPUCommandBuffer *commandBuffer; + SDL_LockMutex(renderer->acquireUniformBufferLock); - if (commandPool == NULL) { - return NULL; + for (Sint32 i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { + /*WebGPU_INTERNAL_ReturnUniformBufferToPool(*/ + /* renderer,*/ + /* commandBuffer->usedUniformBuffers[i]);*/ } + commandBuffer->usedUniformBufferCount = 0; - if (commandPool->inactiveCommandBufferCount == 0) { - if (!WebGPU_INTERNAL_AllocateCommandBuffer(renderer, commandPool)) { - return NULL; - } - } - - commandBuffer = commandPool->inactiveCommandBuffers[commandPool->inactiveCommandBufferCount - 1]; - commandPool->inactiveCommandBufferCount -= 1; - - return commandBuffer; -} - -static SDL_GPUCommandBuffer *WebGPU_AcquireCommandBuffer(SDL_GPURenderer *driverData) -{ - WebGPURenderer *renderer = (WebGPURenderer *)driverData; - - SDL_ThreadID threadID = SDL_GetCurrentThreadID(); + SDL_UnlockMutex(renderer->acquireUniformBufferLock); SDL_LockMutex(renderer->acquireCommandBufferLock); - WebGPUCommandBuffer *commandBuffer = - WebGPU_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); - - SDL_UnlockMutex(renderer->acquireCommandBufferLock); + /*SDL_Log("Command Buffer Pool %p", commandBuffer->commandPool);*/ - if (commandBuffer == NULL) { - return NULL; + if (commandBuffer->commandPool->inactiveCommandBufferCount == commandBuffer->commandPool->inactiveCommandBufferCapacity) { + commandBuffer->commandPool->inactiveCommandBufferCapacity += 1; + commandBuffer->commandPool->inactiveCommandBuffers = SDL_realloc( + commandBuffer->commandPool->inactiveCommandBuffers, + commandBuffer->commandPool->inactiveCommandBufferCapacity * sizeof(WebGPUCommandBuffer*)); } - SDL_Log("Acquired command buffer %p", commandBuffer); - - // Reset state of command buffer + commandBuffer->commandPool->inactiveCommandBuffers[commandBuffer->commandPool->inactiveCommandBufferCount] = commandBuffer; + commandBuffer->commandPool->inactiveCommandBufferCount += 1; - SDL_zero(*commandBuffer); - commandBuffer->renderer = renderer; - commandBuffer->common.device = renderer->sdlDevice; - - SDL_zero(commandBuffer->layerViews); - commandBuffer->layerViewCount = 0; - - - WGPUCommandEncoderDescriptor commandEncoderDesc = { - .label = "SDL_GPU Command Encoder", - }; - - commandBuffer->autoReleaseFence = true; - commandBuffer->commandEncoder = wgpuDeviceCreateCommandEncoder(renderer->device, &commandEncoderDesc); - - return (SDL_GPUCommandBuffer *)commandBuffer; -} - -static Uint32 WebGPU_INTERNAL_CommandPoolHashFunction(const void *key, void *data) -{ - return (Uint32)((CommandPoolHashTableKey *)key)->threadID; -} - -static bool WebGPU_INTERNAL_CommandPoolHashKeyMatch(const void *aKey, const void *bKey, void *data) -{ - CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey; - CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey; - return a->threadID == b->threadID; + SDL_UnlockMutex(renderer->acquireCommandBufferLock); } -static void WebGPU_INTERNAL_CommandPoolHashNuke(const void *key, const void *value, void *data) -{ - WebGPURenderer *renderer = (WebGPURenderer *)data; - WebGPUCommandPool *pool = (WebGPUCommandPool *)value; - WebGPU_INTERNAL_DestroyCommandPool(renderer, pool); - SDL_free((void *)key); -} static bool WebGPU_Submit(SDL_GPUCommandBuffer *commandBuffer) { WebGPUCommandBuffer *wgpu_cmd_buf = (WebGPUCommandBuffer *)commandBuffer; WebGPURenderer *renderer = wgpu_cmd_buf->renderer; - SDL_Log("Submitting command buffer %p", wgpu_cmd_buf); + /*SDL_Log("Submitting command buffer %p", wgpu_cmd_buf);*/ // Lock the renderer's submit lock SDL_LockMutex(renderer->submitLock); @@ -2349,7 +2275,7 @@ static bool WebGPU_Submit(SDL_GPUCommandBuffer *commandBuffer) return false; } - SDL_Log("Finished command buffer %p", wgpu_cmd_buf); + /*SDL_Log("Finished command buffer %p", wgpu_cmd_buf);*/ // Create a fence for the command buffer wgpu_cmd_buf->inFlightFence = WebGPU_INTERNAL_AcquireFenceFromPool(renderer); @@ -2359,7 +2285,7 @@ static bool WebGPU_Submit(SDL_GPUCommandBuffer *commandBuffer) return false; } - SDL_Log("Acquired fence %p", wgpu_cmd_buf->inFlightFence); + /*SDL_Log("Acquired fence %p", wgpu_cmd_buf->inFlightFence);*/ // Command buffer has a reference to the in-flight fence (void)SDL_AtomicIncRef(&wgpu_cmd_buf->inFlightFence->referenceCount); @@ -2367,7 +2293,7 @@ static bool WebGPU_Submit(SDL_GPUCommandBuffer *commandBuffer) // Submit the command buffer to the queue wgpuQueueSubmit(renderer->queue, 1, &commandHandle); - SDL_Log("Submitted command buffer %p", wgpu_cmd_buf); + /*SDL_Log("Submitted command buffer %p", wgpu_cmd_buf);*/ // Release the actual command buffer and command encoder wgpuCommandBufferRelease(commandHandle); @@ -2379,7 +2305,9 @@ static bool WebGPU_Submit(SDL_GPUCommandBuffer *commandBuffer) } /*// Release the memory for the command buffer*/ - /*SDL_free(wgpu_cmd_buf);*/ + WebGPU_INTERNAL_CleanCommandBuffer(renderer, wgpu_cmd_buf, false); + + /*SDL_Log("Cleaned command buffer %p", commandBuffer);*/ // Unlock the renderer's submit lock SDL_UnlockMutex(renderer->submitLock); @@ -2401,7 +2329,7 @@ static SDL_GPUFence *WebGPU_SubmitAndAcquireFence(SDL_GPUCommandBuffer *commandB static bool WebGPU_Wait(SDL_GPURenderer *driverData) { WebGPURenderer *renderer = (WebGPURenderer *)driverData; - /*WebGPUCommandBuffer *commandBuffer;*/ + WebGPUCommandBuffer *commandBuffer; Sint32 i; // We pass control to the browser so it can tick the device for us @@ -2412,8 +2340,8 @@ static bool WebGPU_Wait(SDL_GPURenderer *driverData) SDL_LockMutex(renderer->submitLock); for (i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { - /*commandBuffer = renderer->submittedCommandBuffers[i];*/ - /*WebGPU_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false);*/ + commandBuffer = renderer->submittedCommandBuffers[i]; + WebGPU_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false); } SDL_UnlockMutex(renderer->submitLock); @@ -2431,6 +2359,7 @@ static bool WebGPU_WaitForFences( Uint32 numFences) { WebGPURenderer *renderer = (WebGPURenderer *)driverData; + WebGPUCommandBuffer *commandBuffer; // Wait for all fences to be signaled for (Uint32 i = 0; i < numFences; i += 1) { @@ -2444,8 +2373,8 @@ static bool WebGPU_WaitForFences( SDL_LockMutex(renderer->submitLock); for (Uint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { - /*commandBuffer = renderer->submittedCommandBuffers[i];*/ - /*WebGPU_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false);*/ + commandBuffer = renderer->submittedCommandBuffers[i]; + WebGPU_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false); } // TODO: Implement this once pools are all implemented @@ -2466,18 +2395,155 @@ static bool WebGPU_Cancel(SDL_GPUCommandBuffer *commandBuffer) wgpuCommandBuffer->autoReleaseFence = false; SDL_LockMutex(renderer->submitLock); - /*WebGPU_INTERNAL_CleanCommandBuffer(renderer, wgpuCommandBuffer, true);*/ + WebGPU_INTERNAL_CleanCommandBuffer(renderer, wgpuCommandBuffer, true); SDL_UnlockMutex(renderer->submitLock); return true; } -static void WebGPU_ReleaseFence(SDL_GPURenderer *driverData, SDL_GPUFence *fence) +static void WebGPU_INTERNAL_DestroyCommandPool( + WebGPURenderer *renderer, + WebGPUCommandPool *webgpuCommandPool) { - WebGPUFence *handle = (WebGPUFence *)fence; - if (SDL_AtomicDecRef(&handle->referenceCount)) { - WebGPU_INTERNAL_ReturnFenceToPool((WebGPURenderer *)driverData, handle); + Uint32 i; + WebGPUCommandBuffer *commandBuffer; + + for (i = 0; i < webgpuCommandPool->inactiveCommandBufferCount; i += 1) { + commandBuffer = webgpuCommandPool->inactiveCommandBuffers[i]; + + // TODO: Implement proper freeing once command pools are all implemented + + SDL_free(commandBuffer); + } + + SDL_free(webgpuCommandPool->inactiveCommandBuffers); + SDL_free(webgpuCommandPool); +} + +static WebGPUCommandPool *WebGPU_INTERNAL_FetchCommandPool( + WebGPURenderer *renderer, + SDL_ThreadID threadID) +{ + WebGPUCommandPool *webgpuCommandPool = NULL; + CommandPoolHashTableKey key; + key.threadID = threadID; + + bool result = SDL_FindInHashTable( + renderer->commandPoolHashTable, + (const void *)&key, + (const void **)&webgpuCommandPool); + + if (result) { + return webgpuCommandPool; + } + + webgpuCommandPool = (WebGPUCommandPool *)SDL_malloc(sizeof(WebGPUCommandPool)); + webgpuCommandPool->threadID = threadID; + + webgpuCommandPool->inactiveCommandBufferCapacity = 0; + webgpuCommandPool->inactiveCommandBufferCount = 0; + webgpuCommandPool->inactiveCommandBuffers = NULL; + + if (!WebGPU_INTERNAL_AllocateCommandBuffer( + renderer, + webgpuCommandPool)) { + WebGPU_INTERNAL_DestroyCommandPool(renderer, webgpuCommandPool); + return NULL; + } + + CommandPoolHashTableKey *allocedKey = SDL_malloc(sizeof(CommandPoolHashTableKey)); + allocedKey->threadID = threadID; + + SDL_InsertIntoHashTable( + renderer->commandPoolHashTable, + (const void *)allocedKey, + (const void *)webgpuCommandPool); + + return webgpuCommandPool; +} + +static WebGPUCommandBuffer *WebGPU_INTERNAL_GetInactiveCommandBufferFromPool( + WebGPURenderer *renderer, + SDL_ThreadID threadID) +{ + WebGPUCommandPool *commandPool = + WebGPU_INTERNAL_FetchCommandPool(renderer, threadID); + WebGPUCommandBuffer *commandBuffer; + + if (commandPool == NULL) { + return NULL; + } + + if (commandPool->inactiveCommandBufferCount == 0) { + if (!WebGPU_INTERNAL_AllocateCommandBuffer(renderer, commandPool)) { + return NULL; + } } + + commandBuffer = commandPool->inactiveCommandBuffers[commandPool->inactiveCommandBufferCount - 1]; + commandPool->inactiveCommandBufferCount -= 1; + + return commandBuffer; +} + +static SDL_GPUCommandBuffer *WebGPU_AcquireCommandBuffer(SDL_GPURenderer *driverData) +{ + WebGPURenderer *renderer = (WebGPURenderer *)driverData; + + SDL_ThreadID threadID = SDL_GetCurrentThreadID(); + + SDL_LockMutex(renderer->acquireCommandBufferLock); + + WebGPUCommandBuffer *commandBuffer = + WebGPU_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); + + SDL_UnlockMutex(renderer->acquireCommandBufferLock); + + if (commandBuffer == NULL) { + return NULL; + } + + /*SDL_Log("Acquired command buffer %p", commandBuffer);*/ + + // Reset state of command buffer + + SDL_zero(*commandBuffer); + commandBuffer->renderer = renderer; + commandBuffer->common.device = renderer->sdlDevice; + commandBuffer->commandPool = WebGPU_INTERNAL_FetchCommandPool(renderer, threadID); + + SDL_zero(commandBuffer->layerViews); + commandBuffer->layerViewCount = 0; + + + WGPUCommandEncoderDescriptor commandEncoderDesc = { + .label = "SDL_GPU Command Encoder", + }; + + commandBuffer->autoReleaseFence = true; + commandBuffer->commandEncoder = wgpuDeviceCreateCommandEncoder(renderer->device, &commandEncoderDesc); + + return (SDL_GPUCommandBuffer *)commandBuffer; +} + +static Uint32 WebGPU_INTERNAL_CommandPoolHashFunction(const void *key, void *data) +{ + return (Uint32)((CommandPoolHashTableKey *)key)->threadID; +} + +static bool WebGPU_INTERNAL_CommandPoolHashKeyMatch(const void *aKey, const void *bKey, void *data) +{ + CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey; + CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey; + return a->threadID == b->threadID; +} + +static void WebGPU_INTERNAL_CommandPoolHashNuke(const void *key, const void *value, void *data) +{ + WebGPURenderer *renderer = (WebGPURenderer *)data; + WebGPUCommandPool *pool = (WebGPUCommandPool *)value; + WebGPU_INTERNAL_DestroyCommandPool(renderer, pool); + SDL_free((void *)key); } void WebGPU_SetViewport(SDL_GPUCommandBuffer *renderPass, const SDL_GPUViewport *viewport)