Attributes
WebGPU Shading Language (WGSL) uses attributes to attach metadata to declarations. Attributes provide essential instructions to the compiler, link resources to WebGPU API host handles, and coordinate inputs/outputs between pipeline stages.
Attributes are specified using the @ symbol followed by the attribute name and any necessary parameters, such as @group(0).
1. Resource Binding Attributes
Resource binding attributes connect WGSL variables to CPU-side WebGPU API resources (like buffers, textures, and samplers).
@group and @binding
Every resource declaration at module scope must be annotated with both @group and @binding.
@group(G): Specifies the bind group index (logical collection of resources bound together).@binding(B): Specifies the binding slot index within that specific bind group.
Together, they form a unique coordinate (group, binding) for each resource.
@group(0) @binding(0) var<uniform> myUniformBuffer: MyUniformBufferType;
@group(0) @binding(1) var<storage, read_write> myStorageBuffer: MyStorageBufferType;
JavaScript to WGSL Mapping
To use resources in your shader, you must define matching layouts and bind groups on the host side in JavaScript.
Example 1: Binding a Uniform Buffer
This example binds a read-only uniform buffer containing matrices.
Example
**WGSL Code:**struct MyUniformBufferType {
modelMatrix: mat4x4<f32>,
viewMatrix: mat4x4<f32>,
projectionMatrix: mat4x4<f32>,
}
@group(0) @binding(0) var<uniform> myUniformBuffer: MyUniformBufferType;
// 1. Create the uniform buffer on the GPU
const uniformBuffer = device.createBuffer({
size: 192, // 3 matrices * 64 bytes each
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
// 2. Create the bind group layout
const bindGroupLayout = device.createBindGroupLayout({
entries: [
{
binding: 0,
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
buffer: { type: 'uniform' },
},
],
});
// 3. Bind the resource
const bindGroup = device.createBindGroup({
layout: bindGroupLayout,
entries: [
{
binding: 0,
resource: { buffer: uniformBuffer },
},
],
});
Example 2: Multiple Resources (Uniform + Storage Buffer)
This example combines a uniform configuration buffer and a read-write storage buffer within a single bind group.
Shader Stage Validation
In WebGPU, read-write storage buffers (var<storage, read_write>) are strictly prohibited in the vertex shader stage. Therefore, their bindings must be visible only to the COMPUTE or FRAGMENT stages.
Example
**WGSL Code:**struct Config {
factor: f32,
}
struct MyStorageBufferType {
data: array<f32>,
}
@group(0) @binding(0) var<uniform> myConfig: Config;
@group(0) @binding(1) var<storage, read_write> myStorageBuffer: MyStorageBufferType;
// 1. Create GPU buffers
const configBuffer = device.createBuffer({
size: 16, // Padded config size
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
const storageBuffer = device.createBuffer({
size: 1024,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
});
// 2. Define the Bind Group Layout (Compute visibility)
const bindGroupLayout = device.createBindGroupLayout({
entries: [
{
binding: 0,
visibility: GPUShaderStage.COMPUTE,
buffer: { type: 'uniform' },
},
{
binding: 1,
visibility: GPUShaderStage.COMPUTE,
buffer: { type: 'storage' }, // Maps to read_write in WGSL
},
],
});
// 3. Create the Bind Group
const bindGroup = device.createBindGroup({
layout: bindGroupLayout,
entries: [
{
binding: 0,
resource: { buffer: configBuffer },
},
{
binding: 1,
resource: { buffer: storageBuffer },
},
],
});
2. Pipeline Interface Attributes
Pipeline interface attributes declare how data enters and exits the stages of your graphics or compute pipelines.
@location
The @location(N) attribute defines a generic user-defined IO channel, where N is an unsigned integer. It serves different roles depending on where it is applied:
- Vertex Inputs: Maps GPU vertex buffers (specified via the host API vertex layouts) directly to vertex shader input parameters.
- Inter-Stage Linkage: Connects outputs from the vertex shader to inputs of the fragment shader. The rasterizer automatically interpolates these values across the triangles.
- Fragment Outputs: Maps fragment shader outputs to specific render targets (color attachments) in the render pipeline.
Example: Inter-Stage Linkage
Here, color data is passed from the vertex shader to the fragment shader via channel 0 (@location(0)).
struct VertexOutput {
@builtin(position) pos: vec4f,
@location(0) color: vec4f, // Output color channel 0
}
@vertex
fn vs_main() -> VertexOutput {
var out: VertexOutput;
out.pos = vec4f(0.0, 0.0, 0.0, 1.0);
out.color = vec4f(1.0, 0.0, 0.0, 1.0); // Pass red color
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
return in.color; // Outputs red to color target index 0
}
@builtin
The @builtin(name) attribute connects variables to system-generated inputs or outputs managed by the GPU hardware and rasterizer.
| Built-in Name | Stage | I/O | Type | Description |
|---|---|---|---|---|
position |
Vertex / Fragment | Out / In | vec4f |
Clip-space position (Vertex output); window-space coordinates (Fragment input). |
vertex_index |
Vertex | In | u32 |
Index of the current vertex being processed. |
instance_index |
Vertex | In | u32 |
Index of the current instance being drawn. |
global_invocation_id |
Compute | In | vec3u |
Absolute coordinate of the current thread within the global dispatch grid. |
local_invocation_id |
Compute | In | vec3u |
Coordinate of the thread relative to the current workgroup. |
Example: Using Built-ins
@vertex
fn vs_main(@builtin(vertex_index) v_idx: u32) -> @builtin(position) vec4f {
// Generate a full-screen triangle using the vertex index
var pos = vec2f(0.0);
if (v_idx == 1u) { pos = vec2f(2.0, 0.0); }
if (v_idx == 2u) { pos = vec2f(0.0, 2.0); }
return vec4f(pos, 0.0, 1.0);
}
3. Other Core Attributes
WGSL includes other specialized attributes covered in depth in their respective chapters:
@vertex/@fragment/@compute: Declares a function as a pipeline entry point (Entry Points).@workgroup_size(X, Y, Z): Sets the dimensions of a compute shader's local execution block (Local Variables).@align(A)/@size(S): Controls memory layout, padding, and alignment of structure members (Alignment).@id(I): Associates a pipeline constant with an overridable constant (Override Declaration).@must_use: Prevents ignoring a function's return value (Must Use Attributes).