This commit is contained in:
2025-02-26 22:05:06 +01:00
parent 39794a27d9
commit 726bbdf389
8 changed files with 125 additions and 23 deletions

View File

@@ -49,6 +49,8 @@ int main(void)
PulseComputePipeline pipeline = PulseCreateComputePipeline(device, &info); PulseComputePipeline pipeline = PulseCreateComputePipeline(device, &info);
CHECK_PULSE_HANDLE_RETVAL(pipeline, 1); CHECK_PULSE_HANDLE_RETVAL(pipeline, 1);
PulseFence fence = PulseCreateFence(device);
CHECK_PULSE_HANDLE_RETVAL(fence, 1);
PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_GENERAL); PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_GENERAL);
CHECK_PULSE_HANDLE_RETVAL(cmd, 1); CHECK_PULSE_HANDLE_RETVAL(cmd, 1);
@@ -58,8 +60,13 @@ int main(void)
PulseDispatchComputations(pass, 32, 32, 1); PulseDispatchComputations(pass, 32, 32, 1);
PulseEndComputePass(pass); 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); PulseDestroyComputePipeline(device, pipeline);
PulseDestroyDevice(device); PulseDestroyDevice(device);

View File

@@ -2,5 +2,8 @@ option("examples", { description = "Build the examples", default = false })
if has_config("examples") then if has_config("examples") then
set_group("Examples") set_group("Examples")
includes("*/xmake.lua") if not is_plat("wasm") then
includes("Vulkan/xmake.lua")
end
includes("WebGPU/xmake.lua")
end end

View File

@@ -2,9 +2,12 @@
// This file is part of "Pulse" // This file is part of "Pulse"
// For conditions of distribution and use, see copyright notice in LICENSE // For conditions of distribution and use, see copyright notice in LICENSE
#include <stdatomic.h>
#include <Pulse.h> #include <Pulse.h>
#include "WebGPU.h" #include "WebGPU.h"
#include "WebGPUDevice.h" #include "WebGPUDevice.h"
#include "WebGPUFence.h"
#include "WebGPUCommandList.h" #include "WebGPUCommandList.h"
#include "WebGPUComputePass.h" #include "WebGPUComputePass.h"
#include "../../PulseInternal.h" #include "../../PulseInternal.h"
@@ -38,6 +41,17 @@ PulseCommandList WebGPURequestCommandList(PulseDevice device, PulseCommandListUs
return cmd; return cmd;
} }
#include <stdio.h>
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) bool WebGPUSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence)
{ {
WebGPUDevice* webgpu_device = WEBGPU_RETRIEVE_DRIVER_DATA_AS(device, WebGPUDevice*); 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); 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); wgpuCommandBufferRelease(command_buffer);
return true; return true;
} }

View File

@@ -13,7 +13,6 @@
#include "WebGPUBuffer.h" #include "WebGPUBuffer.h"
#include "WebGPUImage.h" #include "WebGPUImage.h"
#include "WebGPUComputePass.h" #include "WebGPUComputePass.h"
#include "webgpu.h"
#ifndef PULSE_PLAT_WASM #ifndef PULSE_PLAT_WASM
#include <wgpu.h> #include <wgpu.h>

View File

@@ -3,20 +3,59 @@
// For conditions of distribution and use, see copyright notice in LICENSE // For conditions of distribution and use, see copyright notice in LICENSE
#include <Pulse.h> #include <Pulse.h>
#include "../../PulseInternal.h"
#include "WebGPU.h" #include "WebGPU.h"
#include "WebGPUFence.h"
PulseFence WebGPUCreateFence(PulseDevice device) 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) void WebGPUDestroyFence(PulseDevice device, PulseFence fence)
{ {
PULSE_UNUSED(device);
free(fence->driver_data);
free(fence);
} }
bool WebGPUIsFenceReady(PulseDevice device, PulseFence 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 <stdio.h>
bool WebGPUWaitForFences(PulseDevice device, const PulseFence* fences, uint32_t fences_count, bool wait_for_all) 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;
} }

View File

@@ -8,9 +8,15 @@
#define PULSE_WEBGPU_FENCE_H_ #define PULSE_WEBGPU_FENCE_H_
#include <webgpu/webgpu.h> #include <webgpu/webgpu.h>
#include <stdatomic.h>
#include <Pulse.h> #include <Pulse.h>
typedef struct WebGPUFence
{
atomic_bool signal;
} WebGPUFence;
PulseFence WebGPUCreateFence(PulseDevice device); PulseFence WebGPUCreateFence(PulseDevice device);
void WebGPUDestroyFence(PulseDevice device, PulseFence fence); void WebGPUDestroyFence(PulseDevice device, PulseFence fence);
bool WebGPUIsFenceReady(PulseDevice device, PulseFence fence); bool WebGPUIsFenceReady(PulseDevice device, PulseFence fence);

View File

@@ -4,16 +4,32 @@
#include "PulseInternal.h" #include "PulseInternal.h"
#include <tinycthread.h> #ifndef PULSE_PLAT_WASM
#include <tinycthread.h>
PulseThreadID PulseGetThreadID() PulseThreadID PulseGetThreadID()
{ {
return (PulseThreadID)thrd_current(); return (PulseThreadID)thrd_current();
} }
void PulseSleep(int32_t ms) void PulseSleep(int32_t ms)
{ {
if(ms <= 0) if(ms <= 0)
return; return;
thrd_sleep(&(struct timespec){ .tv_sec = ms / 1000, .tv_nsec = (ms % 1000) * 1000000 }, PULSE_NULLPTR); thrd_sleep(&(struct timespec){ .tv_sec = ms / 1000, .tv_nsec = (ms % 1000) * 1000000 }, PULSE_NULLPTR);
} }
#else
#include <emscripten/threading.h>
PulseThreadID PulseGetThreadID()
{
return (PulseThreadID)0;
}
void PulseSleep(int32_t ms)
{
if(ms <= 0)
return;
emscripten_thread_sleep(ms);
}
#endif

View File

@@ -23,11 +23,10 @@ local backends = {
}, },
WebGPU = { WebGPU = {
option = "webgpu", option = "webgpu",
packages = { "wgpu-native" },
default = is_plat("wasm"), default = is_plat("wasm"),
custom = function() custom = function()
if is_plat("wasm") then if not is_plat("wasm") then
add_defines("PULSE_PLAT_WASM") add_packages("wgpu-native")
end end
end end
} }
@@ -72,10 +71,10 @@ option("unitybuild", { description = "Build the library using unity build", defa
if is_plat("wasm") then if is_plat("wasm") then
backends.Vulkan = nil backends.Vulkan = nil
else
add_requires("tiny-c-thread", "wgpu-native")
end end
add_requires("tiny-c-thread")
for name, module in pairs(backends) do for name, module in pairs(backends) do
if has_config(module.option) then if has_config(module.option) then
if module.packages then if module.packages then
@@ -89,16 +88,23 @@ target("pulse_gpu")
add_defines("PULSE_BUILD") add_defines("PULSE_BUILD")
add_headerfiles("Sources/*.h", { prefixdir = "private", install = false }) add_headerfiles("Sources/*.h", { prefixdir = "private", install = false })
add_headerfiles("Sources/*.inl", { 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") add_files("Sources/*.c")
if has_config("unitybuild") then if has_config("unitybuild") then
add_rules("c.unity_build", { batchsize = 6 }) add_rules("c.unity_build", { batchsize = 6 })
end end
if is_plat("wasm") then
add_defines("PULSE_PLAT_WASM")
end
for name, module in pairs(backends) do 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 if module.packages then
add_packages(table.unpack(module.packages)) add_packages(table.unpack(module.packages))
end end
@@ -124,4 +130,7 @@ target("pulse_gpu")
target_end() target_end()
includes("Examples/*.lua") includes("Examples/*.lua")
includes("Tests/Vulkan/*.lua")
if not is_plat("wasm") then
includes("Tests/Vulkan/*.lua")
end