Web GPU: A Low-Level Graphics API for the Web
The web has come a long way since its early days of simple text and static images. Today, web developers can create immersive, interactive experiences that rival native applications, thanks to advancements in web technologies like HTML5, CSS3, and JavaScript. However, one area where the web has traditionally lagged behind native applications is graphics performance. Graphics-intensive web applications like games and simulations have often struggled to achieve smooth, responsive performance, even on high-end hardware.
Enter WEB GPU, a new web standard being developed by the World Wide Web Consortium (W3C) that provides a low-level graphics API for the web. WEB GPU is designed to give web developers direct access to the GPU (graphics processing unit) for advanced graphics and compute capabilities, allowing them to create fast, efficient, and visually stunning web applications.
WEB GPU vs. WebGL
Traditionally, web graphics have been rendered using APIs like WebGL, which is based on OpenGL ES. While WebGL has enabled developers to create impressive web graphics, it has certain limitations that make it less than ideal for some use cases. For example, WebGL is a high-level API that abstracts away many of the details of the graphics pipeline, making it less flexible and less efficient than a low-level API. Additionally, WebGL is based on an older graphics API (OpenGL ES), which is not as well-suited to modern GPU architectures as newer APIs like Vulkan and DirectX 12.
WEB GPU, on the other hand, is a low-level API that gives developers direct control over the GPU, allowing them to optimize their code for specific hardware and achieve higher performance. WEB GPU is based on modern graphics APIs like Vulkan and Metal, which are designed to take advantage of the parallel processing capabilities of modern GPUs.
How WEB GPU Works
WEB GPU is designed to be easy to use for developers familiar with modern graphics APIs like Vulkan and Metal. It provides a simple, consistent interface for creating and managing resources like buffers, textures, and pipelines, as well as executing commands on the GPU.
Below is a simple example of how WEB GPU works
The code is creating a simple triangle using WEB GPU. Here's what each part of the code is doing:
// Create a canvas element
const canvas = document.createElement("canvas");
// Initialize the WEB GPU context
const context = canvas.getContext("webgpu");
// Create a buffer with vertex data
const vertices = new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);
const vertexBuffer = context.createBuffer({
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX,
mappedAtCreation: true,
});
new Float32Array(vertexBuffer.getMappedRange()).set(vertices);
vertexBuffer.unmap();
// Create a shader module
const shaderModule = context.createShaderModule({
code: `
[[stage(vertex)]]
fn main([[location(0)]] position: vec2<f32>) -> [[builtin(position)]] vec4<f32> {
return vec4<f32>(position, 0.0, 1.0);
}
`,
});
// Create a pipeline layout and render pipeline
const pipelineLayout = context.createPipelineLayout({
bindGroupLayouts: [],
});
const pipeline = context.createRenderPipeline({
layout: pipelineLayout,
vertex: {
module: shaderModule,
entryPoint: "main",
buffers: [{
arrayStride: 2 * 4,
attributes: [{
shaderLocation: 0,
format: "float32x2",
offset: 0,
}],
}],
},
fragment: null
now breaking it down
// Create a canvas element
const canvas = document.createElement("canvas");
// Initialize the WEB GPU context
const context = canvas.getContext("webgpu");
These lines create a new HTML canvas element and initialize the WEB GPU context on it.
// Create a buffer with vertex data
const vertices = new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);
const vertexBuffer = context.createBuffer({
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX,
mappedAtCreation: true,
});
new Float32Array(vertexBuffer.getMappedRange()).set(vertices);
vertexBuffer.unmap();
These lines create a buffer with vertex data for the triangle. The vertex data is specified as three 2D points that define the positions of the triangle's vertices. The buffer is created with the createBuffer
method on the WEB GPU context, with the GPUBufferUsage.VERTEX
flag to indicate that it will be used as a vertex buffer. The mappedAtCreation
flag is set to true to indicate that the buffer should be mapped to CPU memory immediately after creation, and the getMappedRange
method is called to get a view of the mapped memory. The vertex data is then copied into the mapped memory using the set
method of a new Float32Array
object, and the buffer is unmapped with the unmap
method.
// Create a shader module
const shaderModule = context.createShaderModule({
code: `
[[stage(vertex)]]
fn main([[location(0)]] position: vec2<f32>) -> [[builtin(position)]] vec4<f32> {
return vec4<f32>(position, 0.0, 1.0);
}
`,
});
This code creates a shader module that will be used to render the triangle. The shader code is specified as a string that defines a vertex shader. The [[stage(vertex)]]
annotation indicates that the shader is a vertex shader. The [[location(0)]]
annotation indicates that the position
parameter is a vertex attribute with location 0. The function returns a vec4<f32>
object that specifies the position of the vertex in homogeneous clip space.
// Create a pipeline layout and render pipeline
const pipelineLayout = context.createPipelineLayout({
bindGroupLayouts: [],
});
const pipeline = context.createRenderPipeline({
layout: pipelineLayout,
vertex: {
module: shaderModule,
entryPoint: "main",
buffers: [{
arrayStride: 2 * 4,
attributes: [{
shaderLocation: 0,
format: "float32x2",
offset: 0,
}],
}],
},
fragment: null,
});
These lines create a pipeline layout and render pipeline that will be used to render the triangle. The pipeline layout is created with the createPipelineLayout
method on the WEB GPU context, with an empty array of bind group layouts. The render pipeline is created with the createRenderPipeline
method, which takes an object with various configuration options. The layout
option is set to the pipeline layout created earlier. The vertex
option is an object that specifies the vertex shader module, entry point, and input buffer layout. In this case, the vertex shader module is the one created earlier, the entry point is "main"
, and the input buffer layout is specified as an array with a single object that defines
Can WEB GPU enable better performance for browser games?
Yes, it has the potential to enable better performance for 2D and 3D games on the web compared to WebGL. Here are a few reasons why:
Lower overhead: WEB GPU is designed to have lower overhead than WebGL. This means that it can handle more draw calls and other operations in less time, which can lead to better performance.
Improved multithreading support: WEB GPU is designed to take advantage of modern hardware with improved multithreading support. This can lead to better parallelism and performance gains.
Better memory management: WEB GPU provides more control over memory management, which can help developers optimize their games for better performance.
Support for modern graphics features: WEB GPU supports modern graphics features, such as ray tracing, which can enable more realistic and immersive gaming experiences.
Overall, while it's still early days for WEB GPU and its adoption may take some time, it has the potential to enable better performance for browser games compared to WebGL.
Browser support
This initial release of WebGPU is available in Chrome 113 on ChromeOS devices with Vulkan support, Windows devices with Direct3D 12 support, and macOS. Linux, Android, and expanded support for existing platforms will come soon.
WebGPU is currently a work-in-progress in Firefox and Safari, in addition to the initial implementation in Chrome.
Library support
Many widely used WebGL libraries are already in the process of implementing WebGPU support or have already done so. This means that using WebGPU may only require making a single line change:
Babylon.js has full WebGPU support already.
PlayCanvas announced initial WebGPU support.
TensorFlow.js supports WebGPU-optimized versions of most operators.
Examples:
https://twitter.com/CantBeFaraz/status/1647811509014216710
https://twitter.com/feiyangvr/status/1647614927983751179
https://twitter.com/Tojiro/status/1645909871093780480
Other links
https://webgpufundamentals.org/
Subscribe to my newsletter
Read articles from Wagner M directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by