SDL icon indicating copy to clipboard operation
SDL copied to clipboard

[Feature Request] SDL3 GPU Backend for WebGPU Target

Open ShadowMarker789 opened this issue 1 year ago • 57 comments

Issue created to track SDL3 GPU Backend, targeting WebGPU.

Extract from SDL_GPU Readme page

Future plans are to also support: • WebGPU

SDL3 GPU is a very exciting project, and it would be great to add WebGPU as a compilation target.

Many thanks to the SDL Team for their hard work and great accomplishments.

ShadowMarker789 avatar Sep 09 '24 10:09 ShadowMarker789

This is definitely something I want, but I reasonably doubt anyone will have time to work on this before SDL3 ships.

I'm going to assign this to myself and put it in the 3.2.0 milestone, though I believe both actions are delusional on my part.

icculus avatar Sep 09 '24 14:09 icculus

FYI: https://x.com/kylelukaszek/status/1832979451203686676

slouken avatar Sep 09 '24 19:09 slouken

Yeah, apparently development is happening here

https://github.com/klukaszek/SDL https://github.com/klukaszek/SDL3-WebGPU-Examples

@klukaszek

ericoporto avatar Sep 11 '24 14:09 ericoporto

FYI: https://x.com/kylelukaszek/status/1832979451203686676

Sorry, could you post a screen shot? Twitter is banned in my country.

leandro-benedet-garcia avatar Sep 11 '24 14:09 leandro-benedet-garcia

FYI: https://x.com/kylelukaszek/status/1832979451203686676

Sorry, could you post a screen shot? Twitter is banned in my country.

image

Video to the right shows a rapid flickering of various colors, like one is randomly picking a color and clearing the screen with it.

ShadowMarker789 avatar Sep 11 '24 15:09 ShadowMarker789

Hey! I’ve been working on this in my spare time and I’ve managed to get the driver entry working for the example test suite. I’m planning on getting to work on pipeline creation tonight after I do my homework lol.

klukaszek avatar Sep 11 '24 15:09 klukaszek

Cycling between demos using A and D will result in failure due to missing function implementations for the GPU driver. I also had to kind of hack in a way to prevent mouse events from flooding the event queue, but I believe this has to do with the browser and not SDL itself.

klukaszek avatar Sep 11 '24 16:09 klukaszek

The crashing mentioned in the earlier tweet was a result of a problem where any event would trigger a resize event causing swapchain recreation. This has been solved.

So far I’ve tested resize, mouse, and key events and they all work as if using SDL2 on web.

Sorry for the spam, I’m just writing from my phone waiting for class.

klukaszek avatar Sep 11 '24 16:09 klukaszek

Talk all you want, this is awesome. :)

icculus avatar Sep 11 '24 20:09 icculus

Something that may help move this along is migrating our examples repo over:

https://github.com/TheSpydog/SDL_gpu_examples/issues/12

Since we presumably need to make changes for Emscripten and the examples folder has automation for exporting web samples, doing these together seems like a good idea.

flibitijibibo avatar Sep 13 '24 23:09 flibitijibibo

Here's the latest update on my WebGPU progress.

https://x.com/KyleLukaszek/status/1839631105646862343

Video for those of you who don't have access to Twitter:

https://github.com/user-attachments/assets/4636608d-25e4-498f-8f24-d9c6d9667549

Update

I ended up DM'ing with @ beaufortfrancois (Google Chrome) and he told me that the SPIR-V support for Chrome was bugged and never worked properly. The team decided to scrap SPIR-V support altogether and will be removing it from Chromium as of the next release.

This presented an interesting problem. SDL uses SPIR-V as its shader type, but browsers will require a valid WGSL WGPUShaderModule to process the shader.

I ended up porting Google's Tint WGSL compiler with limited functionality to WASM and linking it with the Emscripten build of SDL. This allowed me to access the Tint C++ API and export wrapper functions to C for converting SPIR-V bytecode to WGSL.

This is not an elegant solution, but I did not feel like completely changing how shaders are handled in SDL.

Anyway, I am mostly concerned at this point about being 100s of commits behind the main branch now. Any tips for syncing?

klukaszek avatar Sep 27 '24 12:09 klukaszek

Here’s a live demo to test the current status of the example suite.

www.kylelukaszek.xyz

klukaszek avatar Sep 27 '24 12:09 klukaszek

For the WebGPU backend you'll likely end up adding a WGSL value to the bitflags, so shaders can be passed directly to SDL without needing an extra compiler (that can be the app's problem).

flibitijibibo avatar Sep 27 '24 15:09 flibitijibibo

This is not an elegant solution, but I did not feel like completely changing how shaders are handled in SDL.

SDL's shader policy is to expose the backend's native shader format. The right way to do it is to add a new SDL_GPUShaderFormat constant for SDL_GPU_SHADERFORMAT_WGSL and have users provide WGSL shaders. Converting SPIR-V into other backend-specific shader formats at runtime is a responsibility of SDL_gpu_shadercross, it shouldn't be done by SDL itself. The clients can choose to use that, or generate their shaders offline with whatever workflow suits them.

Anyway, I am mostly concerned at this point about being 100s of commits behind the main branch now. Any tips for syncing?

Use git rebase. I advice enabling git rerere before doing that to automate future conflict resolution. I'd also recommend squashing your small fixup commits and organizing them roughly by added functionality.

Akaricchi avatar Sep 27 '24 15:09 Akaricchi

Yeah I’m gonna end up moving the shader cross-compilation to SDL_gpu_shadercross now that I know that the Tint compiled shaders run properly.

As for loading WGSL shaders, I’ll just add a new enum constant to SDL_GPUShaderFormat and pass the WGSL code as a Uint8* and convert it back to a string later. I’ll work on getting that working this weekend as well as rebasing.

Thanks for the help!

klukaszek avatar Sep 27 '24 22:09 klukaszek

I managed to rebase and get everything working again with the latest commits!

Next, I'll work on removing the shader compilation from SDL and moving it to SDL_ShaderCross.

I have a few concerns about how Tint should be integrated in SDL_ShaderCross, but I'll stick to linking with a static library of a minimal Tint build + custom C bindings for compiling SPIRV to WGSL.

klukaszek avatar Sep 28 '24 12:09 klukaszek

I moved all shader compilation logic over to ShaderCross and updated the WebGPU backend to have WGSL as the expected shader format.

I have tested loading WGSL from a file directly into SDL, as well as loading SPIRV from a file. SPIRV is passed through the ShaderCross layer, and then converted to WGSL. This is because ShaderCross recognizes the backend shader format as WGSL and converts accordingly.

This should follow SDL's shader policy much better now.

The current web demo is still converting from SPV to WGSL.

klukaszek avatar Oct 01 '24 10:10 klukaszek

Is your work ready to be a PR and potentially merged? It would be nice to ship with WebGPU support out of the box in the upcoming preview release.

slouken avatar Oct 01 '24 14:10 slouken

The demo is currently only working for the most basic of shaders so I’m not sure if it’s entirely ready yet.

My SDL fork should be good for a PR though if you want to add very rudimentary support for the time being. Might be a few commits behind but that’s not a big issue.

klukaszek avatar Oct 01 '24 21:10 klukaszek

As for ShaderCross,

My current solution for loading Tint into ShaderCross uses a static library as opposed to using SDL_LoadObject() since WASM requires the use of static libraries, not dynamic ones.

Since we only worry about WGSL for browser builds (for the time being at the very least) I can serve a static WASM library from GitHub to avoid the nightmare of having to build Tint for WASM from source.

This is all handled by a Makefile that clones the lib repo, compiles our C wrapper functions to a .o file, adds the .o file to the existing Tint library, copies the lib to SDL_gpu_shadercross/, and finally deletes the cloned repo.

If you’re building for native, this should all be ignored.

The ShaderCross WGSL functionality currently only supports SPIR-V and WGSL. If you want to try and add other Tint backends, please do, but the static library size will be massive (and might actually not work whatsoever).

These changes to ShaderCross could most likely be PR’d to the appropriate repo if the inclusions seem acceptable.

klukaszek avatar Oct 01 '24 21:10 klukaszek

Is your work ready to be a PR and potentially merged? It would be nice to ship with WebGPU support out of the box in the upcoming preview release.

I don't think there should be any rush to get this in, this is going to be a lot of work and I don't want to cram in WebGPU at the 11th hour and have clients expect it to be ready to use.

thatcosmonaut avatar Oct 01 '24 21:10 thatcosmonaut

I agree, take the time to do it right.

icculus avatar Oct 01 '24 21:10 icculus

These changes to ShaderCross could most likely be PR’d to the appropriate repo if the inclusions seem acceptable.

Sure, we can take a look.

Out of curiosity what kind of binary sizes are we looking at for a wasm-ified Tint? From my experience it's very heavyweight on Windows, but granted that's with more than just the spirv/wgsl systems enabled.

TheSpydog avatar Oct 01 '24 21:10 TheSpydog

Out of curiosity what kind of binary sizes are we looking at for a wasm-ified Tint? From my experience it's very heavyweight on Windows, but granted that's with more than just the spirv/wgsl systems enabled.

GitHub says that the libtint.a static library is 37.5 Mb.

When compiled with the test suite, the resulting WASM binary that is produced is 12.5 Mb.

When this WASM file is served by GitHub Pages, Chrome network tools reports that the final WASM binary is 2.7 Mb (it's still 12.5 Mb in reality though).

image

This includes SDL, ShaderCross + Tint, and the example suite (+ the static content).

klukaszek avatar Oct 01 '24 23:10 klukaszek

Update

Vertex buffers are now operational! This means that examples 3 & 4 now work on the demo site.

Demo 4 is restricted to a 320x480 window so do not worry if the drawn output does not fit the canvas.

Haven't checked out what I have to do next but I've got two math midterms to study for so I might disappear for a bit. We'll see though.

Rambling

I got stuck trying to get buffers working for quite some time, even though I could have sworn that my implementation was fairly sound... As it turns out, there is a WebGPU regression in Emscripten versions >= 3.1.65 responsible for my pain. I opened an issue in the Emscripten repo so hopefully it will get resolved soon.

Turns out there were more than just 1 WebGPU regression in the last few updates to Emscripten so for the time being I'll just stick to 3.1.64 and occasionally test the latest release.

klukaszek avatar Oct 09 '24 12:10 klukaszek

You should provide the javascript glue code manually, you don't just shove emescripten and call it a day, it is platform and language specific, not portable

Respectfully, I don't think reimplementing existing JS bindings for WebGPU Headers would be a good use of my time (or anyone's).

I was planning on going through and removing most references to Emscripten-specific function calls, but if I was using it for the WebGPU bindings anyway, then there was no point in doing so.

Emscripten is not WASM, it is wrong to have it as a dependency, or to assume that's what everyone will use

The SDL repository already references Emscripten (CMakeLists.txt), so basing the WebGPU backend off of it is not my biggest concern at the moment.

SDL_gpu_webgpu.c references a total of 3 Emscripten-specific functions and 1 struct. 2 of those function calls are emscripten_sleep() which can be swapped out with SDL_Delay(). The other is wgpuDeviceCreateSwapChain(), which is an Emscripten abstraction used to create a WGPUSurface to use as the swapchain. So once everything seems stable, I can start picking away at the Emscripten-specific stuff.

As for Tint-WASM, I can look into that another time since (again) I'm already using Emscripten to compile SDL, so using it to compile the examples just works. I do agree that Tint-WASM should probably be tested with other WASM compilers to see if the output works as intended.

If you could point me to any other WebGPU JS bindings for WASM I would greatly appreciate it. I'd be more than happy to check them out, those links you provided seem very informative!

klukaszek avatar Oct 16 '24 06:10 klukaszek

I finally managed to get textures to appear but there seem to be some issues that need to be ironed out.

BindGroups are very rudimentary at the moment and will be worked on over time to support more and more binding types. So far only textures, buffers, and samplers are supported. Storage variants are not yet supported.

image

As always, you can use an extension like WebGPU Inspector and check out the demo site to see what's happening under the hood. Some resources aren't cleaning up properly at the moment so I'll also have to go in and fix that.

klukaszek avatar Oct 26 '24 08:10 klukaszek

I had some time recently to sit down and fix the texture issue. I can continue some more after I finish preparing for my term tests.

Ravioli in the browser!

image

klukaszek avatar Nov 06 '24 10:11 klukaszek

Good luck with your term tests!

slouken avatar Nov 06 '24 13:11 slouken

Oh I wasn't aware of this thread at the time but I did recently a sdl3webgpu minilib (just a .h and .c) to create a WebGPU surface from a SDL3 window. There is also a similar one for SDL2: sdl2webgpu

eliemichel avatar Nov 24 '24 13:11 eliemichel