From Wikipedia - Reading time: 8 min
| Latest version | W3C Candidate Recommendation (As of 2025) |
|---|---|
| Organization | |
| Committee |
|
| Domain |
WebGPU Shading Language (WGSL, internet media type: text/wgsl) is a high-level shading language and the normative shader language for the WebGPU API on the web.[1][2] WGSL’s syntax is influenced by Rust and is designed with strong static validation, explicit resource binding, and portability in mind for secure execution in browsers.[1] In web contexts, WebGPU implementations accept WGSL source and perform compilation to platform-specific intermediate forms (for example, to SPIR‑V, DXIL, or MSL via the user agent), but such backends are not exposed to web content.[2][3]
Graphics on the web historically used WebGL, with shaders written in GLSL ES. As applications demanded more modern GPU features and finer control over compute and graphics pipelines, the W3C’s GPU for the Web Community Group and Working Group created WebGPU and its companion shading language, WGSL, to provide a secure, portable model suitable for the web platform.[4][2] WGSL was developed to be human-readable, avoid undefined behavior common in legacy shading languages, and align closely with WebGPU’s resource and validation model.[1]
WGSL’s design emphasizes:
Core scalar types include bool, i32, u32, and f32. Vectors (e.g., vec2, vec3, vec4) and matrices (up to 4×4) are available for floating-point element types. Optional f16 (half precision) may be enabled via a WebGPU feature; availability is implementation-dependent.[1][2] Atomic types (atomic<i32>, atomic<u32>) support limited atomic operations in qualified address spaces.[1]
Variables are declared with let (immutable), var (mutable), or const (compile-time constant). Storage classes (address spaces) include function, private, workgroup, uniform, and storage with read or read_write access as applicable.[1] WGSL defines explicit layout and alignment rules; attributes such as @align, @size, and @stride control data layout for buffer interoperability.[1]
Functions use explicit parameter and return types. Control flow includes if, switch, for, while, and loop constructs, with break/continue. Recursion is disallowed; entry-point call graphs must be acyclic.[1]
Shaders define stage entry points with @vertex, @fragment, or @compute. Attributes annotate bindings and interfaces, including @group, @binding (resource binding), @location (user-defined I/O), @builtin (stage built-ins such as position or global_invocation_id), @interpolate, and @workgroup_size.[1]
WGSL exposes buffers (uniform, storage), textures (sampled, storage, and multisampled variants), and samplers (filtering/non-filtering/comparison). The binding model is explicit via descriptor sets called groups and bindings, matching WebGPU’s pipeline layout model.[2][1]
Browsers compile WGSL to platform-appropriate representations and native driver formats; the specific compilation pipeline is not observable by web content.[2] WGSL source undergoes strict parsing and static validation, and WebGPU enforces robust resource access rules to avoid out-of-bounds memory hazards, contributing to predictable behavior across implementations.[2][1]
WGSL supports three pipeline stages: vertex, fragment, and compute.[1]
Vertex shaders transform per-vertex inputs and produce values for rasterization, including a clip-space position written to the position builtin.[1]
/* Transforms positions by an MVP matrix and passes through color. */
struct VertexInput {
@location(0) position : vec3f,
@location(1) color : vec3f,
};
struct VertexOutput {
@builtin(position) clip_position : vec4f,
@location(0) color : vec3f,
};
@group(0) @binding(0)
var<uniform> mvp : mat4x4f;
@vertex
fn main(v_in : VertexInput) -> VertexOutput {
var v_out : VertexOutput;
v_out.clip_position = mvp * vec4f(v_in.position, 1.0);
v_out.color = v_in.color;
return v_out;
}
Fragment shaders run per-fragment and compute color (and optionally depth) outputs written to color attachments.[1]
/* Writes an interpolated color with opaque alpha. */
@fragment
fn main(@location(0) color : vec3f) -> @location(0) vec4f {
return vec4f(color, 1.0);
}
Compute shaders run in workgroups and are used for general-purpose GPU computations.[1]
/* Doubles elements from an input buffer into an output buffer. */
struct Params {
element_count : u32,
};
@group(0) @binding(0)
var<storage, read> in_data : array<f32>;
@group(0) @binding(1)
var<storage, read_write> out_data : array<f32>;
@group(0) @binding(2)
var<uniform> params : Params;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
let idx : u32 = gid.x;
if (idx >= params.element_count) { return; }
out_data[idx] = in_data[idx] * 2.0;
}
Compared with legacy shading languages, WGSL: