WGSL (WebGPU Shading Language) Cheatsheet
Fresh 🌱WGSL is a Rust-like, statically-typed shading language. All WebGPU shaders are written in WGSL.
Shader Entry Points
wgsl
// Vertex shader
@vertex
fn vs_main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4f {
return vec4f(0.0, 0.0, 0.0, 1.0);
}
// Fragment shader
@fragment
fn fs_main() -> @location(0) vec4f {
return vec4f(1.0, 0.0, 0.0, 1.0); // Red
}
// Compute shader
@compute @workgroup_size(64)
fn cs_main(@builtin(global_invocation_id) id: vec3u) {
// Parallel computation here
}Types
wgsl
// Scalars
let a: f32 = 1.0;
let b: i32 = -5;
let c: u32 = 10u;
let d: bool = true;
let e: f16 = 1.0h; // half-float (requires f16 feature)
// Vectors
let v2: vec2f = vec2f(1.0, 2.0);
let v3: vec3f = vec3f(0.0, 1.0, 0.0);
let v4: vec4f = vec4f(0.31, 0.19, 0.89, 1.0);
// Matrices
let m4: mat4x4f = mat4x4f(/* col-major 16 values */);
// Type aliases
// vec2f = vec2<f32>, vec3i = vec3<i32>, vec4u = vec4<u32>Built-in Variables
| Variable | Stage | Description |
|---|---|---|
@builtin(vertex_index) | vertex | Current vertex index (u32) |
@builtin(instance_index) | vertex | Current instance index (u32) |
@builtin(position) | vertex output / fragment input | Clip/fragment position (vec4f) |
@builtin(front_facing) | fragment | True if front-facing primitive (bool) |
@builtin(frag_depth) | fragment output | Override depth value (f32) |
@builtin(global_invocation_id) | compute | 3D global thread ID (vec3u) |
@builtin(local_invocation_id) | compute | 3D local workgroup thread ID (vec3u) |
@builtin(workgroup_id) | compute | Workgroup ID (vec3u) |
@builtin(num_workgroups) | compute | Total workgroups dispatched (vec3u) |
Bindings
wgsl
// Uniform buffer (read-only, ≤64KB)
@group(0) @binding(0) var<uniform> mvp: mat4x4f;
// Storage buffer (read-only, large)
@group(0) @binding(1) var<storage, read> inputData: array<f32>;
// Storage buffer (read-write)
@group(0) @binding(2) var<storage, read_write> outputData: array<f32>;
// Texture
@group(0) @binding(3) var myTexture: texture_2d<f32>;
// Sampler
@group(0) @binding(4) var mySampler: sampler;
// External texture (video)
@group(0) @binding(5) var videoTex: texture_external;Common Built-in Functions
wgsl
// Math
abs(x) dot(a, b) cross(a, b)
sqrt(x) pow(x, y) log(x) exp(x)
sin(x) cos(x) tan(x)
min(a, b) max(a, b) clamp(x, lo, hi)
floor(x) ceil(x) round(x) fract(x)
mix(a, b, t) // linear interpolation
normalize(v) // unit vector
length(v) // vector magnitude
distance(a, b)
// Texture sampling
let color = textureSample(myTexture, mySampler, uv);
let color = textureLoad(myTexture, coord, mipLevel);
let color = textureLoad(videoTex, coord); // external texture
let dims = textureDimensions(myTexture);
// Type conversion
let u = bitcast<u32>(floatVal); // reinterpret bits
let f = f32(intVal); // convert typeControl Flow
wgsl
// If/else
if x > 0.0 {
// ...
} else if x < 0.0 {
// ...
} else {
// ...
}
// Loop
var i = 0u;
loop {
if i >= 10u { break; }
// ...
i++;
}
// For loop
for (var i = 0u; i < 10u; i++) {
// ...
}
// Switch
switch (myU32) {
case 0u: { /* ... */ }
case 1u: { /* ... */ }
default: { /* ... */ }
}Workgroup Memory (Shared Memory)
wgsl
var<workgroup> sharedData: array<f32, 64>;
@compute @workgroup_size(64)
fn main(@builtin(local_invocation_index) lid: u32) {
// Load into shared memory
sharedData[lid] = inputData[/* global index */];
// Sync all threads in workgroup
workgroupBarrier();
// Now all threads can read shared data
let neighborVal = sharedData[(lid + 1u) % 64u];
}Vertex Input/Output
wgsl
struct VertexInput {
@location(0) position: vec3f,
@location(1) uv: vec2f,
@location(2) normal: vec3f,
}
struct VertexOutput {
@builtin(position) clipPos: vec4f,
@location(0) uv: vec2f,
@location(1) normal: vec3f,
}
@vertex
fn vs(in: VertexInput) -> VertexOutput {
var out: VertexOutput;
out.clipPos = mvp * vec4f(in.position, 1.0);
out.uv = in.uv;
out.normal = in.normal;
return out;
}Z Clip Space Difference from WebGL
WebGL: Z range = -1 to 1 (OpenGL convention)
WebGPU: Z range = 0 to 1 (Metal/D3D convention)Adjust projection matrices accordingly when migrating from WebGL.