Skip to content

Commit

Permalink
Clean up the WebGPU code
Browse files Browse the repository at this point in the history
  • Loading branch information
RobDangerous committed Feb 25, 2025
1 parent 37e4d2e commit b30db38
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 219 deletions.
2 changes: 2 additions & 0 deletions backends/gpu/webgpu/includes/kore3/webgpu/webgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,6 @@ static inline WGPURenderPassEncoder wgpuCommandEncoderBeginRenderPass(WGPUComman

#endif

void kore_webgpu_init(void (*callback)(void));

#endif
77 changes: 62 additions & 15 deletions backends/gpu/webgpu/sources/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,39 @@
#endif

#include <assert.h>
#include <stdio.h>

extern WGPUDevice wgpu_device;
extern WGPUInstance wgpu_instance;
extern WGPUAdapter wgpu_adapter;
static WGPUDevice wgpu_device;
static WGPUInstance wgpu_instance;
static WGPUAdapter wgpu_adapter;

static void error_callback(WGPUErrorType errorType, const char* message, void* userdata) {
printf("%d: %s\n", errorType, message);
kore_log(KORE_LOG_LEVEL_ERROR, "%d: %s", errorType, message);
}

static void compilation_info_callback(WGPUCompilationInfoRequestStatus status, const WGPUCompilationInfo* info, void* userdata) {
assert(status == WGPUCompilationInfoRequestStatus_Success);
assert(info->messageCount == 0);
kore_log(KORE_LOG_LEVEL_INFO, "Shader compile succeeded");
}

void kore_webgpu_device_create(kore_gpu_device *device, const kore_gpu_device_wishlist *wishlist) {
#ifdef KORE_EMSCRIPTEN
device->webgpu.device = wgpu_device;
#endif

wgpuDeviceSetUncapturedErrorCallback(wgpu_device, error_callback, NULL);

device->webgpu.queue = wgpuDeviceGetQueue(device->webgpu.device);

WGPUSurfaceDescriptorFromCanvasHTMLSelector canvasDesc = {0};
canvasDesc.selector = "#canvas";
canvasDesc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
WGPUSurfaceDescriptorFromCanvasHTMLSelector canvas_descriptor = {
.selector = "#canvas",
.chain = {
.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector,
},
};

WGPUSurfaceDescriptor surfDesc = {0};
surfDesc.nextInChain = (WGPUChainedStruct *)&canvasDesc;
device->webgpu.surface = wgpuInstanceCreateSurface(wgpu_instance, &surfDesc);
WGPUSurfaceDescriptor surface_descriptor = {
.nextInChain = (WGPUChainedStruct *)&canvas_descriptor,
};
device->webgpu.surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_descriptor);

WGPUSurfaceCapabilities capabilities = {0};
wgpuSurfaceGetCapabilities(device->webgpu.surface, wgpu_adapter, &capabilities);
Expand All @@ -54,7 +61,8 @@ void kore_webgpu_device_create(kore_gpu_device *device, const kore_gpu_device_wi
.alphaMode = WGPUCompositeAlphaMode_Auto,
.width = kore_window_width(0),
.height = kore_window_height(0),
.presentMode = WGPUPresentMode_Fifo};
.presentMode = WGPUPresentMode_Fifo
};
wgpuSurfaceConfigure(device->webgpu.surface, &config);

WGPUShaderModuleWGSLDescriptor shader_module_wgsl_descriptor = {
Expand All @@ -67,6 +75,7 @@ void kore_webgpu_device_create(kore_gpu_device *device, const kore_gpu_device_wi
};

device->webgpu.shader_module = wgpuDeviceCreateShaderModule(device->webgpu.device, &shader_module_descriptor);
wgpuShaderModuleGetCompilationInfo(device->webgpu.shader_module, compilation_info_callback, NULL);
}

void kore_webgpu_device_destroy(kore_gpu_device *device) {}
Expand Down Expand Up @@ -114,7 +123,7 @@ void kore_webgpu_device_create_buffer(kore_gpu_device *device, const kore_gpu_bu
WGPUBufferDescriptor buffer_descriptor = {
.size = align_pow2(parameters->size, 4),
.usage = convert_buffer_usage(parameters->usage_flags),
//.mappedAtCreation = true,
.mappedAtCreation = true,
};

buffer->webgpu.buffer = wgpuDeviceCreateBuffer(device->webgpu.device, &buffer_descriptor);
Expand Down Expand Up @@ -193,3 +202,41 @@ void kore_webgpu_device_create_fence(kore_gpu_device *device, kore_gpu_fence *fe
void kore_webgpu_device_signal(kore_gpu_device *device, kore_gpu_command_list_type list_type, kore_gpu_fence *fence, uint64_t value) {}

void kore_webgpu_device_wait(kore_gpu_device *device, kore_gpu_command_list_type list_type, kore_gpu_fence *fence, uint64_t value) {}

static void (*kickstart_callback)();

void device_callback(WGPURequestDeviceStatus status, WGPUDevice device, char const *message, void *userdata) {
if (message != NULL) {
kore_log(KORE_LOG_LEVEL_INFO, "RequestDevice: %s", message);
}
assert(status == WGPURequestDeviceStatus_Success);

wgpu_device = device;

kickstart_callback();
}

void adapter_callback(WGPURequestAdapterStatus status, WGPUAdapter adapter, char const *message, void *userdata) {
if (message != NULL) {
kore_log(KORE_LOG_LEVEL_INFO, "RequestAdapter: %s", message);
}
assert(status == WGPURequestAdapterStatus_Success);

wgpu_adapter = adapter;

WGPUAdapterInfo info;
wgpuAdapterGetInfo(wgpu_adapter, &info);
kore_log(KORE_LOG_LEVEL_INFO, "adapter vendor: %s", info.vendor);
kore_log(KORE_LOG_LEVEL_INFO, "adapter architecture: %s", info.architecture);
kore_log(KORE_LOG_LEVEL_INFO, "adapter device: %s", info.device);
kore_log(KORE_LOG_LEVEL_INFO, "adapter description: %s", info.description);

wgpuAdapterRequestDevice(wgpu_adapter, NULL, device_callback, NULL);
}

void kore_webgpu_init(void (*callback)()) {
kickstart_callback = callback;

wgpu_instance = wgpuCreateInstance(NULL);
wgpuInstanceRequestAdapter(wgpu_instance, NULL, adapter_callback, NULL);
}
213 changes: 9 additions & 204 deletions backends/system/emscripten/sources/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
#include <kore3/system.h>
#include <kore3/window.h>

#ifdef KORE_WEBGPU
#include <kore3/webgpu/webgpu.h>
#endif

#include <stdio.h>
#include <stdlib.h>

static int html5_argc;
static char **html5_argv;

static void drawfunc() {
kore_internal_update_callback();
kore_audio_update();
Expand Down Expand Up @@ -313,218 +314,22 @@ int kore_hardware_threads(void) {
return 4;
}

extern int kickstart(int argc, char **argv);

#include <webgpu/webgpu.h>
#include <emscripten/html5_webgpu.h>

static const char shaderCode[] = "\
@vertex\n\
fn main_v(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {\n\
var pos = array<vec2<f32>, 3>(\n\
vec2<f32>(0.0, 0.5), vec2<f32>(-0.5, -0.5), vec2<f32>(0.5, -0.5));\n\
return vec4<f32>(pos[idx], 0.0, 1.0);\n\
}\n\
\n\
@fragment\n\
fn main_f() -> @location(0) vec4<f32> {\n\
return vec4<f32>(0.0, 0.502, 1.0, 1.0); // 0x80/0xff ~= 0.502\n\
}\n\
";

WGPUInstance wgpu_instance;
WGPUAdapter wgpu_adapter;
WGPUDevice wgpu_device;
static WGPUQueue queue;
static WGPURenderPipeline pipeline;
static int testsCompleted = 0;

void run();
static int html5_argc;
static char **html5_argv;

void main3(void) {
//run();
void main_after_webgpu_init(void) {
kickstart(html5_argc, html5_argv);
emscripten_set_main_loop(drawfunc, 0, false);
}

void device_callback(WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * userdata) {
if (message) {
printf("RequestDevice: %s\n", message);
}
assert(status == WGPURequestDeviceStatus_Success);

wgpu_device = device;

main3();
}

void GetDevice() {
wgpuAdapterRequestDevice(wgpu_adapter, NULL, device_callback, NULL);
}

void main2(void) {
WGPUAdapterInfo info;
wgpuAdapterGetInfo(wgpu_adapter, &info);
printf("adapter vendor: %s\n", info.vendor);
printf("adapter architecture: %s\n", info.architecture);
printf("adapter device: %s\n", info.device);
printf("adapter description: %s\n", info.description);

GetDevice();
}

void adapter_callback(WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * userdata) {
if (message) {
printf("RequestAdapter: %s\n", message);
}
assert(status == WGPURequestAdapterStatus_Success);

wgpu_adapter = adapter;

main2();
}

void GetAdapter() {
wgpu_instance = wgpuCreateInstance(NULL);
wgpuInstanceRequestAdapter(wgpu_instance, NULL, adapter_callback, NULL);
}

void error_callback(WGPUErrorType errorType, const char* message, void* userdata) {
printf("%d: %s\n", errorType, message);
}

void compilation_info_callback(WGPUCompilationInfoRequestStatus status, const WGPUCompilationInfo* info, void* userdata) {
assert(status == WGPUCompilationInfoRequestStatus_Success);
assert(info->messageCount == 0);
printf("Shader compile succeeded\n");
}

void init() {
wgpuDeviceSetUncapturedErrorCallback(wgpu_device, error_callback, NULL);

queue = wgpuDeviceGetQueue(wgpu_device);

WGPUShaderModule shaderModule;
{
WGPUShaderModuleWGSLDescriptor wgslDesc = {0};
wgslDesc.code = shaderCode;
wgslDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;

WGPUShaderModuleDescriptor descriptor = {0};
descriptor.nextInChain = (WGPUChainedStruct *)&wgslDesc;
shaderModule = wgpuDeviceCreateShaderModule(wgpu_device, &descriptor);
wgpuShaderModuleGetCompilationInfo(shaderModule, compilation_info_callback, NULL);
}

{
WGPUPipelineLayoutDescriptor pl = {0};
pl.bindGroupLayoutCount = 0;
pl.bindGroupLayouts = NULL;

WGPUColorTargetState colorTargetState = {0};
colorTargetState.format = WGPUTextureFormat_BGRA8Unorm;
colorTargetState.writeMask = WGPUColorWriteMask_All;

WGPUFragmentState fragmentState = {0};
fragmentState.module = shaderModule;
fragmentState.targetCount = 1;
fragmentState.targets = &colorTargetState;

WGPUMultisampleState multisample_state = {
.count = 1,
.mask = 0xffffffff,
.alphaToCoverageEnabled = false,
};

WGPURenderPipelineDescriptor descriptor = {0};
descriptor.layout = wgpuDeviceCreatePipelineLayout(wgpu_device, &pl);
descriptor.vertex.module = shaderModule;
descriptor.fragment = &fragmentState;
descriptor.primitive.topology = WGPUPrimitiveTopology_TriangleList;
descriptor.multisample = multisample_state;
pipeline = wgpuDeviceCreateRenderPipeline(wgpu_device, &descriptor);
}
}

void render(WGPUTextureView view) {
WGPURenderPassColorAttachment attachment = {0};
attachment.view = view;
attachment.loadOp = WGPULoadOp_Clear;
attachment.storeOp = WGPUStoreOp_Store;
attachment.clearValue.r = 0.5f;
attachment.clearValue.g = 0.0f;
attachment.clearValue.b = 0.0f;
attachment.clearValue.a = 1.0f;
attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;

WGPURenderPassDescriptor renderpass = {0};
renderpass.colorAttachmentCount = 1;
renderpass.colorAttachments = &attachment;

WGPUCommandBuffer commands;
{
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(wgpu_device, NULL);
{
WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &renderpass);
wgpuRenderPassEncoderSetPipeline(pass, pipeline);
wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
wgpuRenderPassEncoderEnd(pass);
}
commands = wgpuCommandEncoderFinish(encoder, NULL);
}

wgpuQueueSubmit(queue, 1, &commands);
}


WGPUSurface surface;

const uint32_t kWidth = 300;
const uint32_t kHeight = 150;

void frame() {
WGPUSurfaceTexture surfaceTexture;
wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);

WGPUTextureView backbuffer = wgpuTextureCreateView(surfaceTexture.texture, NULL);
render(backbuffer);
}

void run() {
init();

{
WGPUSurfaceDescriptorFromCanvasHTMLSelector canvasDesc = {0};
canvasDesc.selector = "#canvas";
canvasDesc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;

WGPUSurfaceDescriptor surfDesc = {0};
surfDesc.nextInChain = (WGPUChainedStruct *)&canvasDesc;
surface = wgpuInstanceCreateSurface(wgpu_instance, &surfDesc);

WGPUSurfaceCapabilities capabilities;
wgpuSurfaceGetCapabilities(surface, wgpu_adapter, &capabilities);

WGPUSurfaceConfiguration config = {
.device = wgpu_device,
.format = capabilities.formats[0],
.usage = WGPUTextureUsage_RenderAttachment,
.alphaMode = WGPUCompositeAlphaMode_Auto,
.width = kWidth,
.height = kHeight,
.presentMode = WGPUPresentMode_Fifo};
wgpuSurfaceConfigure(surface, &config);
}
emscripten_set_main_loop(frame, 0, false);
}

extern int kickstart(int argc, char **argv);

int main(int argc, char **argv) {
html5_argc = argc;
html5_argv = argv;

#ifdef KORE_WEBGPU
GetAdapter();
kore_webgpu_init(main_after_webgpu_init);
#else
kickstart(argc, argv);
emscripten_set_main_loop(drawfunc, 0, 1);
Expand Down

0 comments on commit b30db38

Please sign in to comment.