WebGPU support was merged into Bevy’s main branch, and it will be released in Bevy 0.11.
What is WebGPU?
To make a long story short, WebGL powers a lot of the fancy 3d applications on the web right now… but WebGL is also complicated, so projects like Three.js have popped up to support writing 3d applications in the browser.
but over the last few decades amazing leaps have happened in the graphics world.
To see this, look at how far graphics have come over successive generations of video games.
Consider the difference between an old 2d platformer and the recent Zelda or the state of the art lumen and nanite in Unreal Engine 5.
This is where WebGPU comes in.
WebGPU is the new standard for 3d graphics on the web.
WebGPU caters to the kind of person who thinks it might be fun to write their own raymarcher, without requiring every programmer to be the kind of person who thinks it would be fun to write their own implementation of
malloc
.
You can access and use WebGPU from JavaScript, C++, and Rust right now, this includes from the browser, in wasm, and interestingly, natively on a desktop.
That means that WebGPU is actually a cross platform interface to writing programs for the GPU that treats the web as a first class platform.
How does WebGPU work?
There is the WebGPU API that is used to set up pipelines and the WGSL language which is used to write the programs that run on GPUs.
WGSL programs are also known as shaders.
In your language of choice you’re build a Pipeline. This pipeline can be a render pipeline or a compute pipeline.
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(swapchain_format.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
});
Render pipelines come with the ability to modify the colors of pixels and the positions of vertices. These vertex and fragment shaders are what people think of most often when they say “shaders”.
Compute pipelines allow more direct access to a GPU. You can pass some arbitrary data in and get some arbitrary data out, using the exceedingly parallel processing a GPU enables to power world generation, pathfinding, or powering 2d rendering engines.
WGSL programs look a bit like a cut-down version of Rust with types like f32 and i32 for numbers, vecs, and structs for more complex data structures.
@vertex
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
let x = f32(i32(in_vertex_index) - 1);
let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
return vec4<f32>(x, y, 0.0, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
Wgpu
Working directly with WebGPU is one option but far more likely is using a higher level library on top.
This is where we start talking about Rust, and where the wgpu crate comes in.
wgpu is widely used it powers:
- game engines like Bevy
- 2d rendering engines like vello
- GUI platforms like egui
- Production games like Veloren and Tiny Glade
- creative coding environments like Nannou
Its safe to say that if you’re doing graphics programming in Rust and you’ve chosen to not use wgpu, you’ve likely made a mistake.
wgpu offers a collection of crates that provide a cross-platform user-facing API in Rust that mirrors the WebGPU spec.
This means you can write Pipeline code in Rust, and shader code in WGSL, and run that program in wasm in the browser as well as on native hardware on your desktop.
wgpu-core is used in Firefox itself, and even deno the javascript runtime uses wgpu.
Wgpu builds on top of wgpu-hal, a hardware abstraction layer for graphics APIs. This means that wgpu supports multiple backends, including Dx12, Metal, Vulkan, and WebGL.
The wgpu crate then, is the entry point to a vast network of industry-grade functionality beyond just the WebGPU spec.
Bevy + WebGPU
It should come at no surprise at this point that Bevy, a game engine written in Rust, uses wgpu heavily to power its own game engine and has done so since the beginning of the engine.
Which brings us to the point of this video: The necessary fixes to support compiling Bevy apps to WebGPU have landed in the main branch. This work was done by François Mockers, one of Bevy’s maintainers and will be available in the 0.11 release.
This brings the ability to build cross-platform games using modern GPU features like compute shaders to Bevy while picking the right, or best, runtime to execute those games on each platform.
Interestingly, Bevy also enjoys the ability to use extensions to WebGPU such as ray tracing, bindless rendering, and Augmented or Virtual Reality.
So does it work?
Well if you have Chrome 113 you can pop on over to the WebGPU examples hosted on the bevyengine.org site. The examples here will only work if you have WebGPU enabled, so if you have Chrome 113 or the appropriate flags enabled you’ll see them, and if you don’t, like this safari window, you won’t see them.
WebGPU truly is the future of graphics programming on the web, and as Bevy and wgpu are proving, potentially the future of cross-platform graphics as well.