From 726bbdf38919616d3fd4788b568fc40a1b74462d Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Wed, 26 Feb 2025 22:05:06 +0100 Subject: [PATCH] fences --- Examples/WebGPU/main.c | 9 ++++- Examples/xmake.lua | 5 ++- Sources/Backends/WebGPU/WebGPUCommandList.c | 23 ++++++++++++ Sources/Backends/WebGPU/WebGPUDevice.c | 1 - Sources/Backends/WebGPU/WebGPUFence.c | 39 +++++++++++++++++++++ Sources/Backends/WebGPU/WebGPUFence.h | 6 ++++ Sources/PulseInternal.c | 38 ++++++++++++++------ xmake.lua | 27 +++++++++----- 8 files changed, 125 insertions(+), 23 deletions(-) diff --git a/Examples/WebGPU/main.c b/Examples/WebGPU/main.c index c212218..ae340fa 100644 --- a/Examples/WebGPU/main.c +++ b/Examples/WebGPU/main.c @@ -49,6 +49,8 @@ int main(void) PulseComputePipeline pipeline = PulseCreateComputePipeline(device, &info); CHECK_PULSE_HANDLE_RETVAL(pipeline, 1); + PulseFence fence = PulseCreateFence(device); + CHECK_PULSE_HANDLE_RETVAL(fence, 1); PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_GENERAL); CHECK_PULSE_HANDLE_RETVAL(cmd, 1); @@ -58,8 +60,13 @@ int main(void) PulseDispatchComputations(pass, 32, 32, 1); PulseEndComputePass(pass); - PulseReleaseCommandList(device, cmd); + if(!PulseSubmitCommandList(device, cmd, fence)) + fprintf(stderr, "Could not submit command list, %s\n", PulseVerbaliseErrorType(PulseGetLastErrorType())); + if(!PulseWaitForFences(device, &fence, 1, true)) + fprintf(stderr, "Could not wait for fences, %s\n", PulseVerbaliseErrorType(PulseGetLastErrorType())); + PulseReleaseCommandList(device, cmd); + PulseDestroyFence(device, fence); PulseDestroyComputePipeline(device, pipeline); PulseDestroyDevice(device); diff --git a/Examples/xmake.lua b/Examples/xmake.lua index 4465e2c..f527060 100644 --- a/Examples/xmake.lua +++ b/Examples/xmake.lua @@ -2,5 +2,8 @@ option("examples", { description = "Build the examples", default = false }) if has_config("examples") then set_group("Examples") - includes("*/xmake.lua") + if not is_plat("wasm") then + includes("Vulkan/xmake.lua") + end + includes("WebGPU/xmake.lua") end diff --git a/Sources/Backends/WebGPU/WebGPUCommandList.c b/Sources/Backends/WebGPU/WebGPUCommandList.c index f324c42..3aef373 100644 --- a/Sources/Backends/WebGPU/WebGPUCommandList.c +++ b/Sources/Backends/WebGPU/WebGPUCommandList.c @@ -2,9 +2,12 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE +#include + #include #include "WebGPU.h" #include "WebGPUDevice.h" +#include "WebGPUFence.h" #include "WebGPUCommandList.h" #include "WebGPUComputePass.h" #include "../../PulseInternal.h" @@ -38,6 +41,17 @@ PulseCommandList WebGPURequestCommandList(PulseDevice device, PulseCommandListUs return cmd; } +#include + +static void WebGPUFenceCallback(WGPUQueueWorkDoneStatus status, void* userdata1, void* userdata2) +{ + PULSE_UNUSED(userdata2); + WebGPUFence* webgpu_fence = (WebGPUFence*)userdata1; + if(status == WGPUQueueWorkDoneStatus_Success) + atomic_store(&webgpu_fence->signal, true); + puts("test"); +} + bool WebGPUSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence) { WebGPUDevice* webgpu_device = WEBGPU_RETRIEVE_DRIVER_DATA_AS(device, WebGPUDevice*); @@ -48,6 +62,15 @@ bool WebGPUSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFenc wgpuQueueSubmit(webgpu_device->queue, 1, &command_buffer); + WebGPUFence* webgpu_fence = WEBGPU_RETRIEVE_DRIVER_DATA_AS(fence, WebGPUFence*); + atomic_store(&webgpu_fence->signal, false); + + WGPUQueueWorkDoneCallbackInfo callback = { 0 }; + callback.mode = WGPUCallbackMode_AllowSpontaneous; + callback.callback = WebGPUFenceCallback; + callback.userdata1 = webgpu_fence; + wgpuQueueOnSubmittedWorkDone(webgpu_device->queue, callback); + wgpuCommandBufferRelease(command_buffer); return true; } diff --git a/Sources/Backends/WebGPU/WebGPUDevice.c b/Sources/Backends/WebGPU/WebGPUDevice.c index 3bdc17a..2f89e80 100644 --- a/Sources/Backends/WebGPU/WebGPUDevice.c +++ b/Sources/Backends/WebGPU/WebGPUDevice.c @@ -13,7 +13,6 @@ #include "WebGPUBuffer.h" #include "WebGPUImage.h" #include "WebGPUComputePass.h" -#include "webgpu.h" #ifndef PULSE_PLAT_WASM #include diff --git a/Sources/Backends/WebGPU/WebGPUFence.c b/Sources/Backends/WebGPU/WebGPUFence.c index f27491c..102deab 100644 --- a/Sources/Backends/WebGPU/WebGPUFence.c +++ b/Sources/Backends/WebGPU/WebGPUFence.c @@ -3,20 +3,59 @@ // For conditions of distribution and use, see copyright notice in LICENSE #include +#include "../../PulseInternal.h" #include "WebGPU.h" +#include "WebGPUFence.h" PulseFence WebGPUCreateFence(PulseDevice device) { + PULSE_UNUSED(device); + + PulseFence fence = (PulseFence)calloc(1, sizeof(PulseFence)); + PULSE_CHECK_ALLOCATION_RETVAL(fence, PULSE_NULL_HANDLE); + + WebGPUFence* webgpu_fence = (WebGPUFence*)calloc(1, sizeof(WebGPUFence)); + PULSE_CHECK_ALLOCATION_RETVAL(webgpu_fence, PULSE_NULL_HANDLE); + + atomic_store(&webgpu_fence->signal, true); + + fence->driver_data = webgpu_fence; + + return fence; } void WebGPUDestroyFence(PulseDevice device, PulseFence fence) { + PULSE_UNUSED(device); + free(fence->driver_data); + free(fence); } bool WebGPUIsFenceReady(PulseDevice device, PulseFence fence) { + PULSE_UNUSED(device); + WebGPUFence* webgpu_fence = WEBGPU_RETRIEVE_DRIVER_DATA_AS(fence, WebGPUFence*); + return atomic_load(&webgpu_fence->signal) == true; } +#include + bool WebGPUWaitForFences(PulseDevice device, const PulseFence* fences, uint32_t fences_count, bool wait_for_all) { + PULSE_UNUSED(device); + if(fences_count == 0) + return true; + uint32_t fences_to_wait = fences_count; + while(fences_to_wait != 0) + { + for(uint32_t i = 0; i < fences_count; i++) + { + if(WebGPUIsFenceReady(device, fences[i])) + fences_to_wait--; + } + if(!wait_for_all && fences_to_wait != fences_count) + return true; + PulseSleep(1); // 1ms + } + return true; } diff --git a/Sources/Backends/WebGPU/WebGPUFence.h b/Sources/Backends/WebGPU/WebGPUFence.h index 383adab..1e34774 100644 --- a/Sources/Backends/WebGPU/WebGPUFence.h +++ b/Sources/Backends/WebGPU/WebGPUFence.h @@ -8,9 +8,15 @@ #define PULSE_WEBGPU_FENCE_H_ #include +#include #include +typedef struct WebGPUFence +{ + atomic_bool signal; +} WebGPUFence; + PulseFence WebGPUCreateFence(PulseDevice device); void WebGPUDestroyFence(PulseDevice device, PulseFence fence); bool WebGPUIsFenceReady(PulseDevice device, PulseFence fence); diff --git a/Sources/PulseInternal.c b/Sources/PulseInternal.c index b1d1322..4fdbc76 100644 --- a/Sources/PulseInternal.c +++ b/Sources/PulseInternal.c @@ -4,16 +4,32 @@ #include "PulseInternal.h" -#include +#ifndef PULSE_PLAT_WASM + #include -PulseThreadID PulseGetThreadID() -{ - return (PulseThreadID)thrd_current(); -} + PulseThreadID PulseGetThreadID() + { + return (PulseThreadID)thrd_current(); + } -void PulseSleep(int32_t ms) -{ - if(ms <= 0) - return; - thrd_sleep(&(struct timespec){ .tv_sec = ms / 1000, .tv_nsec = (ms % 1000) * 1000000 }, PULSE_NULLPTR); -} + void PulseSleep(int32_t ms) + { + if(ms <= 0) + return; + thrd_sleep(&(struct timespec){ .tv_sec = ms / 1000, .tv_nsec = (ms % 1000) * 1000000 }, PULSE_NULLPTR); + } +#else + #include + + PulseThreadID PulseGetThreadID() + { + return (PulseThreadID)0; + } + + void PulseSleep(int32_t ms) + { + if(ms <= 0) + return; + emscripten_thread_sleep(ms); + } +#endif diff --git a/xmake.lua b/xmake.lua index 88d8e90..2382ee6 100644 --- a/xmake.lua +++ b/xmake.lua @@ -23,11 +23,10 @@ local backends = { }, WebGPU = { option = "webgpu", - packages = { "wgpu-native" }, default = is_plat("wasm"), custom = function() - if is_plat("wasm") then - add_defines("PULSE_PLAT_WASM") + if not is_plat("wasm") then + add_packages("wgpu-native") end end } @@ -72,10 +71,10 @@ option("unitybuild", { description = "Build the library using unity build", defa if is_plat("wasm") then backends.Vulkan = nil +else + add_requires("tiny-c-thread", "wgpu-native") end -add_requires("tiny-c-thread") - for name, module in pairs(backends) do if has_config(module.option) then if module.packages then @@ -89,16 +88,23 @@ target("pulse_gpu") add_defines("PULSE_BUILD") add_headerfiles("Sources/*.h", { prefixdir = "private", install = false }) add_headerfiles("Sources/*.inl", { prefixdir = "private", install = false }) - add_packages("tiny-c-thread") - + + if not is_plat("wasm") then + add_packages("tiny-c-thread") + end + add_files("Sources/*.c") if has_config("unitybuild") then add_rules("c.unity_build", { batchsize = 6 }) end + if is_plat("wasm") then + add_defines("PULSE_PLAT_WASM") + end + for name, module in pairs(backends) do - if has_config(module.option) then + if module ~= nil and has_config(module.option) then if module.packages then add_packages(table.unpack(module.packages)) end @@ -124,4 +130,7 @@ target("pulse_gpu") target_end() includes("Examples/*.lua") -includes("Tests/Vulkan/*.lua") + +if not is_plat("wasm") then + includes("Tests/Vulkan/*.lua") +end