59 comments

[ 1.9 ms ] story [ 120 ms ] thread
Anyone else excited for what WebGPU will enable for next generation browser games and real-time 3D web applications?
There was a discussion on the BabylonJS forums back in August about this. [1] TL;DR the GPU may now be available, but having to download several gigabytes of assets to download and sit in your browser cache may be a bit problematic. Also, the expectations towards a web-based thing are different than a dedicated download.

[1] https://forum.babylonjs.com/t/why-havent-3d-web-games-reache...

I definitely am :D to the point that I started trying to build a WASM game just to start troubleshooting pain points.
Nah, it is an API for 2015 hardware, after a decade of WebGL we still haven't got anything better than SpectorJS, and on top of it we have to either use yet another shading language, or abstract it via code generation tooling.

The only thing good about it, is moving the Web 3D beyond GL ES 3.0 subset.

Don't expect nanite or Fortnite on the browser anytime soon.

Why? It's pretty close to the Vulcan API why is Web GPU stuck in 2015 as you claim? Also Web GPU isn't just the browser didn't you read the article?
Vulkan is moving away from the extreme "everything is baked into immutable objects" philosophy of Vulkan 1.0 (see: [1], [2], [3], [4] - although these extension swing the pendulum back too much to the granular OpenGL API model, which also sucks), while WebGPU will be stuck with the "rigid model" for quite a while and even adds more rigidness (for instance baking shader resource bindings into immutable BindGroup objects).

WebGPU still has a nice balance between convenience and a somewhat modern feature set, but going down to the native platform 3D APIs (Metal, D3D12 and Vulkan) will always offer a much bigger feature set and less CPU overhead (mainly because WebGPU also needs to support mobile GPUs, and some of those are indeed 10 years behind the curve).

[1] https://registry.khronos.org/vulkan/specs/1.3-extensions/man...

[2] https://registry.khronos.org/vulkan/specs/1.3-extensions/man...

[3] https://registry.khronos.org/vulkan/specs/1.3-extensions/man...

[4] https://registry.khronos.org/vulkan/specs/1.3-extensions/man...

Because 2015 hardware is the baseline for the MVP 1.0.

WebGPU outside of the browser doesn't really matter, middleware engines already cover that, and with much better tooling.

Besides WebGPU outside of the browser cannot deviate from the WebGPU on the browser, otherwise it is exactly the same pain as porting between OpenGL ES, OpenGL and WebGL, API that are only compatible in name.

In many ways, you're right.

In my opinion, the main strength of WebGPU is it removes the cost of re-implementing something when targeting a different platform. If that was present in 2015, maybe we'd have more games, more interesting applications, and less pressure on people who feel locked into one vendor's ecosystem.

Anyone that has taken part in GDC, PAX, or similar conferences, knows how little the game studios care about something that is so dear to the hearts of FOSS folks when discussing 3D APIs.
Most of Nanite (at least, everything but the LOD system, I haven't tried that part, and the compute rasterizer due to lack of storage image atomics because Metal lacks them...) is implementable in WebGPU actually.

I have a PR that does a lot of the same things (meshlets, visbuffer, material depth, two pass occlusion culling) open for Bevy https://github.com/bevyengine/bevy/pull/10164 that I've been working on, which uses WebGPU.

WebGPU is actually a pretty good API imo. It's missing some advanced features like raytracing, mesh shaders, and subgroup operations (coming soon!), but it can still do a lot.

The much bigger missing feature is "bindless" support (non-uniform arrays of bound resources). BindGroup overhead (and ergonomics) is a significant downside.

Great points. JMS55, are you interested in contributing to UE5 WebGPU? My team and I have been working on this for the past several years, and would welcome some help.

If you're ever looking to join a team to advance Unreal Engine 5 and graphics in the browser, please reach out. We're tackling Nanite and Lumen in the browser, and contributing to the WebGPU spec in collaboration with Google.

You can reach me on Discord - my username is astlouis44

I'm also on LinkedIn: https://www.linkedin.com/in/alex-st-louis-3986a5102/

Thanks for the offer, but unfortunately developing one game engine at a time is my limit :). I'm avoiding looking at UE source code specifically to ensure I don't accidentally copy code into Bevy.

Best of luck though, and always glad to see more people work on the WebGPU spec! Maybe you can help push for raytracing and bindless extensions :)

Interesting, does it work on the browser, or wgpu?
I've only ever tested it in wgpu, but there's no reason it shouldn't work in the browser (WebGPU). It only needs compute shaders, storage buffers, and single indirect draws, which are all available in WebGPU.
I see, thanks. Maybe I should not be so negative about it. :)
More scared than excited but yeah, definitely excited.

As a non game developer, though, I am wondering if migrating existing renderers would allow me to create UIs, or parts of them, using graphics that is not just html+CSS without the massive overhead that we currently have. I mean, I can draw the frames just fine but these extra cycles suck power and produce heat

I'm not expecting too much, as it's going to be hard to monetize something people get the source code to. So I think it's going to be limited to small projects, or sub projects that don't cost a lot to develop.
If you're so worried about people getting the source code to it, you can just compile to WebAssembly.
I imagine any serious project won't be written in JavaScript, and WASM code with symbols stripped out is about as opaque as x86 or ARM assembly, especially when you start getting into the code sizes you expect for a full game engine or productivity suite.
When you minify js don’t you end up with the same kind of thing? You can “decompile” both and neither give you any symbols. Just a bunch of random letters calling other random letters, etc. Maybe I need an example to understand.
Not quite, minify JS can be "beautified" to get pretty reasonable JS back, sans variables and functions having letters for names as you noted. But this is because obfuscated JS is still valid JS, it's just made ugly.

Obfuscated assembly is often changed in such a way that there are no corresponding language constructs to "reverse" back to, if it originally came from a language like C++. Sure you can see the actual assembly code, but you can't recreate the higher level C++ constructs in a sane way, because the obfuscation technique scrambles things too much.

I think you're missing a good amount of nuance here

minified JS can be turned into reasonable JS, yes, but you're probably not going to get TypeScript code back, so the same sort of challenge exists there.

Assembly -> high-level language is harder, but there are absolutely binary -> C decompilers that are very popular/used in the RE community to make changes to existing programs.

But that doesn't even matter, WASM is much higher level than assembly, it's a stack machine, there is no arbitrary control flow / labels / `goto`, there are pre-defined data types, etc. all of this means it's easier to convert WASM -> high-level language than it is with a generic x86/arm binary.

There are WASM decompilers[0][1] which can convert WASM binaries into C code and back.

In both cases (minified JS and WASM), you're not going to get out exactly what you put in, but WASM doesn't really change the situation very much given the widespread adoption of 'compile to JS' languages like TypeScript these days.

[0] https://chromium.googlesource.com/external/github.com/WebAss...

[1] https://github.com/wwwg/wasmdec

Except WASM isn't as low level as machine code proper, and also needs to obey certain rules due to code verification, thus it is as easy as any other bytecode format.

You might not get the original C++ code back, but it is relatively easy to get an alternative version in C code back, which is already good enough as starting point.

That problem has been solved by F2P client/server games a long time ago. The important stuff happens on the server, and the client is "only" a dumb renderer. You'll need to assume that the client is compromised anyway, whether that also means that the client source code "leaks" is irrelevant for monetization (via in-app-purchases, which again is controlled by the server while the client only renders the "shop UI").
Don't get yourself too hyped up, in the end WebGPU is running on the same GPU as WebGL2, and unless your code is CPU bound you won't see performance improvements if your WebGL2 code is already well optimized.

And currently some high-frequency WebGPU calls have an even higher CPU overhead than similar WebGL2 calls (I wrote about that here a bit: https://floooh.github.io/2023/10/16/sokol-webgpu.html).

WebGPU allows more flexibility of course, compute shaders and storage buffers are more flexible and cleaner than trying to shoehorn the same stuff into vertex/fragment shaders and using textures as "poor man's storage buffer", but that doesn't mean that one approach is slower or faster than the other.

Does WebGPU enable a pure 2D game with many sprite animations to not need to pack a texture atlas for best performance? I.e. can I tell the GPU, "Draw these 1000 quads using the following distinct 1000 textures using just this one draw call. I'll be changing the 1000 textures each frame." My experience with OpenGL and D3D11 is that an atlas is the only way to do this. (I've found stb_rect_pack.h to be the least hassle route to packing the atlas.) I started looking at D3D12 and saw that it had command recording but it wasn't clear to me if this is any more efficient for a 2D game than just using D3D11/OpenGL to send 1000 separate pairs of commands to set-this-texture/draw-this-quad. With D3D12 the CPU is still performing thousands of function calls per frame to "record" these commands and I don't see how this is cheaper than having D3D11 do thousands of draw calls. D3D11 just puts a draw call into a command queue and immediately returns so isn't this effectively kinda the same thing as using ID3D12CommandQueue "command recording"? I never got around to benchmarking or learning more, so I'm sure I must be misunderstanding the advantages. I've also noticed that despite D3D12 launching back in 2015, the #1 most used engine Unity is still defaulting to D3D11 and has struggled to make D3D12 as performant/stable. So it seems I'm not the only one who can't figure out how the newer APIs offer more performance.
The new modern APIs are not to be understood as graphics APIs, rather as GPU APIs, thus using them directly is more akin to writing a graphics device driver than a rendering engine.

Most people are better served by using GL 4.6, DX 11 and such, or a middleware engine.

Even console vendors have multiple APIs because of that, not everyone needs all little details of the GPU.

Unity is supposed to have good DirectX 12 coming up, by the way.

"Achieving Real Time Ray Tracing on Xbox with Unity and DirectX12"

https://www.youtube.com/watch?v=giaEpbBGc6E

> The new modern APIs are not to be understood as graphics APIs, rather as GPU APIs

I've heard this repeated a lot in internet forums, but my experience working through hundreds of pages of Frank Luna's 800+ page DX12 book before concluding it pointless for 2D was that DX12 is actually fundamentally very similar to DX11 with most of the API focused on graphics rather than general compute. Compute shaders are just one chapter (13) of Luna's book, roughly 40 of the 800+ pages. I did some of the LunarG Vulkan tutorial and browsed the Khronos ref pages and reached a similar conclusion for Vulkan. I played with CUDA a bit and that's what real GPU programming looks like, almost no mention of graphics for much of the documentation. The "hello world" program isn't drawing a triangle, it's adding two arrays. Whereas a great deal of DX12, Vulkan, etc. is all about pixel formats, pixel shading, swap chains, geometry and tessellation, blending, depth and stencil, mipmaps and cube maps, clip coords, triangle winding and culling, the perspective Z divide, viewports, indexed and instanced draw calls, ... you know, graphics. But in chapter 9 of the DX12 book, end of 9.4, Luna writes, "Texture atlases can improve performance because it can lead to drawing more geometry with one draw call." So the conclusion I reached is that DX12 doesn't offer some fancy GPU compute way of writing a GPU program that can use 1000 distinct textures to draw 1000 distinct quads using only one CPU function call to launch this GPU program.

Now I've been doing more research and there is some sort of new feature called bindless textures not covered in Luna's DX12 book that might accomplish what I want (I'm not sure), but it seems to be Win11 only, WDDM 3.0 only, shader model 6.6 only, very new cards only. With this feature I might be able to set up 1000 distinct integer ids for my 1000 distinct textures, and then, with one single CPU draw call, have those 1000 textures applied to the correct 1000 quads, with no need to pack those 1000 textures into an atlas. Doing more web searching just now, this possibly can also be done in OpenGL on cards that support NV_gpu_shader5, but only semi-recent nVidia cards might support this. (I'm finding it difficult to get quick, quality answers to these sorts of questions using either web searches or LLMs.) Anyway, a gamedev forum or DX-focused reddit might be a better place for me to ask these sort of technical questions.

If I understand correctly, what you are looking for are mesh shaders and shader work graphs, which allow one to basically do most of the compute stuff on the GPU without having the CPU steering anything, besides setting up the whole chain.

You will need DirectX 12 Ultimate or Vulkan for them.

https://developer.nvidia.com/blog/introduction-turing-mesh-s...

https://microsoft.github.io/DirectX-Specs/d3d/MeshShader.htm...

https://www.khronos.org/blog/mesh-shading-for-vulkan

https://devblogs.microsoft.com/directx/d3d12-work-graphs-pre...

https://gpuopen.com/learn/gpu-work-graphs/gpu-work-graphs-in...

https://gpuopen.com/gpu-work-graphs-in-vulkan/

So I read through the materials on mesh shaders and work graphs and looked at sample code. These won't really work (see below). As I implied previously, it's best to research/discuss these sort of matters with professional graphics programmers who have experience actually using the technologies under consideration.

So for the sake of future web searchers who discover this thread: there are only two proven ways to efficiently draw thousands of unique textures of different sizes with a single draw call that are actually used by experienced graphics programmers in production code as of 2023.

Proven method #1: Pack these thousands of textures into a texture atlas.

Proven method #2: Use bindless resources, which is still fairly bleeding edge, and will require fallback to atlases if targeting the PC instead of only high end console (Xbox Series S|X...).

Mesh shaders by themselves won't work: These have similar texture access limitations to the old geometry/tessellation stage they improve upon. A limited, fixed number of textures still must be bound before each draw call (say, 16 or 32 textures, not 1000s), unless bindless resources are used. So mesh shaders must be used with an atlas or with bindless resources.

Work graphs by themselves won't work: This feature is bleeding edge shader model 6.8 whereas bindless resources are SM 6.6. (Xbox Series X|S might top out at SM 6.7, I can't find an authoritative answer.) It looks like work graphs might only work well on nVidia GPUs and won't work well on Intel GPUs anytime soon (but, again, I'm not knowledgeable enough to say this authoritatively). Furthermore, this feature may have a hard dependency on using bindless to begin with. That is, I can't tell if one is allowed to execute a work graph that binds and unbinds individual texture resources. And if one could do such a thing, it would certainly be slower than using bindless. The cost of bindless is paid "up front" when the textures are uploaded.

Some programmers use Texture2DArray/GL_TEXTURE_2D_ARRAY as an alternative to atlases but two limitations are (1) the max array length (e.g. GL_MAX_ARRAY_TEXTURE_LAYERS) might only be 256 (e.g. for OpenGL 3.0), (2) all textures must be the same size.

Finally, for the sake of any web searcher who lands on this thread in the years to come, to pack an atlas well a good packing algorithm is needed. It's harder to pack triangles than rectangles but triangles use atlas memory more efficiently and a good triangle packing will outperform the fancy new bindless rendering. Some open source starting points for packing:

https://github.com/nothings/stb/blob/master/stb_rect_pack.h

https://github.com/ands/trianglepacker

WebGPU currently doesn't support the "bindless" resource access model (see: https://github.com/gpuweb/gpuweb/issues/380).

The "max number of sampled texture per shader stage" is a runtime device limit, and the minimal value for that seems to be 16. So texture atlasses are still a thing in WebGPU.

WebGPU has render bundles, which allow to pre-record command sequences, but even with that you don't want to change resource bindings thousands of times per frame (or even hundreds of times).

It might make sense though to build texture atlases dynamically (basically use one very big texture as "tile cache") and update that via writeTexture() calls (just don't rebuild the entire atlas each frame).

> will enable for next generation browser games and real-time 3D web applications

Not excited, and very few of those will materialise. Next gen games require next gen graphics. You can check for yourself how much those graphics weigh.

I wonder why "capturing". This being Google, it makes me think "abuse of dominant market position". Or embrace and extend.

Was the title a freudian slip or something?

Is there anything in the article that makes you think "abuse of dominant market position", or simply a weird turn of phrase in the title?

As much as we all distrust Google, this kind of tangential comment is pretty tiresome when it has no relevance to what's being posted.

Yeah I did a double take when I realised it was from the Chrome team. I clicked expecting to read about the next way they’re going to leverage it to squeeze profit.
What I don’t like is having to rewrite all my compute shaders and being forced to give away the sources.
I'd rather know the sources than have every website be an opaque WASM blob.
Shaders haven’t been precompiled for PC in years due to GPU heterogeneity - it’s only games consoles where binary shaders are usable. OpenGL’s wiki is full of dire warnings about relying on binary shader representations: https://www.khronos.org/opengl/wiki/Shader_Compilation

I’m surprised there isn’t much support for even a bytecode representation…

Shaders on PC are still compiled, but to a bytecode format (DXBC or DXIL for DirectX, SpirV for Vulkan). The sources aren't shipped. The graphics drivers still have a step to compile this bytecode into the GPU's architecture low level shader assembly of course.
OpenGL is the only native API that never fully embraced bytecodes for shaders.
Are Windows prebuilt Dawn WebGPU libs available anywhere so I can try to draw a triangle using C/C++? Many Google projects are extremely time consuming to build on a Windows machine and need like 30+ GB of space for all tools and dependencies. Windows is still over 95% of the paid non-console gaming market so those who want to pay bills making games can't ignore it. BGFX is easy to clone and build from GitHub; examples are up and running in only a few steps. Any way to do the same with Dawn WebGPU?
I wonder if games are gonna move more in this direction or just render on the server altogether, like GeForce Now and Luna and PSNow and XCloud. Even if they could harness 100% of my phone GPU or M2, that's nothing compared to a proper gaming setup.

I feel like this would only really get used for simple mobile games and not for actual titles with gameplay... even if the API is there, most people don't have powerful enough devices to drive modern console or PC quality games. And if they did, they'd be looking on Steam or an app store, not the Web.

What's the use case?

There's a whole bunch of 3D stuff you can do on the web, from product demos and configurators to interactive navigation. Simple casual games will work fine too if optimized properly. Heck, my wife and I built a 3D content website with BabylonJS for no other reason than we could.
My startup is building a platform exactly for this - to enable developers to make their native games to be browser-compatible utilizing WebAssembly and WebGPU.

It also gets more interesting when you consider that the world is increasingly moving to ARM. Take Qualcomm's new ARM chips for example; they're competitive with Apple Silicon already. WASM/WebGPU represents a straightforward way to convert x86 games to run on these new chips.

Below is a blog post about our platform-as-a-service and tools, and our current development focus to support Unreal Engine 5 in WebGPU/WASM:

https://theimmersiveweb.com/blog

That's cool! Getting Unreal to run in the web again would be awesome.

I enjoyed your Western Town demo. I always wished they would make virtual tours, Assassin's Creed-style, of old ghost towns like https://www.parks.ca.gov/?page_id=509

Interesting to see if more compute intensive applications will move towards the web. Big implications for games, as well as real "desktop software" like CAD, video editors, DAW software, etc.
> The Chrome team is also considering using Dawn as the default rendering backend for all browser UI elements, including menus, toolbars, developer tools, and web content.

Wouldn't that make Chrome unusable if you don't have a recent GPU?

There's a proposal for a "WebGPU compatibility mode" which also works on older devices:

https://github.com/gpuweb/gpuweb/issues/4266

Also I guess Chrome could just fall back to a "legacy rendering backend" if WebGPU isn't supported.

It's worth noting that the Chrome team maintains pure software rendering implementations of both GLES and Vulkan, as well - so in the worst case Chrome could fallback to 100% software rendering.

IMO that's only really necessary if you are targeting hardware >5 years old, or embedded hardware, though.

What's your definition of recent? Anything with Vulkan, DX12, or Metal support should work. wgpu also has best-effort support for OpenGL 3.3. The situation seems similar with Dawn.
> This can be used to target Dawn, wgpu, and others, easing the creation of bindings for languages using C FFI

I wish we could agree on something slightly more ergonomic than a C FFI. The largest common denominator has to be slightly more advanced than C (if we decide to not accommodate C).

The "ergonomic" API is the Javascript API. Of course that is only usable from Javascript (ok, and Typescript).

If you want to use WebGPU from as many languages as possible, a C API is pretty much the only option.

There's also a C++ API, but just as with the JS API, this is limited to a single language.

For usage from Rust you can also use gfx-rs/wgpu, which has a Rust-idiomatic API (e.g. see: https://github.com/gfx-rs/wgpu/blob/trunk/examples/hello-tri... - which to be honest doesn't look more "ergonomic" than the C API to me).

Also, it's not like the C API is "unergonomic", it works with C99 designated initialization which makes it quite nice to use. The only downside is COM-style manual lifetime management via ref/release calls, but if you are used to Direct3D that's a no-brainer (it works exactly the same), and the C++ API has RAII wrappers for this stuff.

Yes but until we have this "more better thing" please continue to expose your libraries to the c FFI. Also, please make sure it's actually better before telling everyone to use it.

Thanks.

Color me a cynic, but this feels like "we're so tired of supporting this web platform, so we're happy we can extract parts of it, pretend that it's still the Web and do other stuff with the parts weve managed to rip out."