libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
9.98k stars 1.84k forks source link

[Feature Request] SDL3 GPU Backend for WebGPU Target #10768

Open ShadowMarker789 opened 2 months ago

ShadowMarker789 commented 2 months ago

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.

icculus commented 2 months ago

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.

slouken commented 2 months ago

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

ericoporto commented 2 months ago

Yeah, apparently development is happening here

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

@klukaszek

leandro-benedet-garcia commented 2 months ago

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

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

ShadowMarker789 commented 2 months ago

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.

klukaszek commented 2 months ago

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 commented 2 months ago

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 commented 2 months ago

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.

icculus commented 2 months ago

Talk all you want, this is awesome. :)

flibitijibibo commented 2 months ago

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.

klukaszek commented 1 month ago

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 commented 1 month ago

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

www.kylelukaszek.xyz

flibitijibibo commented 1 month ago

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).

Akaricchi commented 1 month ago

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.

klukaszek commented 1 month ago

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 commented 1 month ago

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 commented 1 month ago

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.

slouken commented 1 month ago

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.

klukaszek commented 1 month ago

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 commented 1 month ago

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.

thatcosmonaut commented 1 month ago

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.

icculus commented 1 month ago

I agree, take the time to do it right.

TheSpydog commented 1 month ago

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.

klukaszek commented 1 month ago

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 commented 1 month ago

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 commented 1 month ago

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 commented 3 weeks ago

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 commented 1 week ago

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

slouken commented 1 week ago

Good luck with your term tests!