Entry points

Entry points and attributes

A stage attribute is a decorator on an exported function. A function with none of them is a helper. Workgroup size is the only payload on @compute, written as a list; the compiler carries the first number and refuses a shape whose y or z is anything but 1.

WGSLTypeShadeNote
@vertex
@vertex

One stage decorator per entry point, on an exported function.

@fragment
@fragment

A fragment entry may also return nothing, which is what a program that only writes to a storage binding does.

@compute @workgroup_size(64)
@compute([64, 1, 1])

The list is the workgroup size. @compute with no list is [64, 1, 1].

@location(0) uv: vec2<f32>
@location(0) uv: vec2

A location sits on an entry parameter, on a class field and on the return.

-> @builtin(position) vec4<f32>
: vec4

A return typed vec4 carries the position builtin on its own, so the smallest vertex shader needs no struct and no parameters.

@builtin(position) pos: vec4<f32>
@builtin("position") pos: vec4

A struct return carries the position in a field and adds as many varyings beside it as the program wants.

-> @location(0) vec4<f32>
: vec4

A bare fragment return takes location 0 at any width, so f32, vec2, vec3 and vec4 are all draw-buffer formats. A struct return is the multiple-render-target form.

A vertex entry has to produce a position. A return typed vec4 carries the position builtin on its own, and a struct return carries it in a field and adds as many @location varyings as the program wants. A struct return with no position field, a void return and a bare type that is not a vec4 are each refused, naming the field or the type to write.

The @builtin(...) vocabulary is WGSL's, 16 names passed through as a string, so the WGSL attribute is the same id with no quotes around it. A typo is a tsc error at the line the author wrote, since the parameter is a closed union of them. WGSL fixes the type of every id but one, so the type column is what the annotation has to say.

TypeShadeType
@builtin("vertex_index")
u32
@builtin("instance_index")
u32
@builtin("position")
vec4<f32>
@builtin("front_facing")
bool
@builtin("frag_depth")
f32
@builtin("sample_index")
u32
@builtin("sample_mask")
u32
@builtin("primitive_index")
u32
@builtin("local_invocation_id")
vec3<u32>
@builtin("local_invocation_index")
u32
@builtin("global_invocation_id")
vec3<u32>
@builtin("workgroup_id")
vec3<u32>
@builtin("num_workgroups")
vec3<u32>
@builtin("subgroup_invocation_id")
u32
@builtin("subgroup_size")
u32
@builtin("clip_distances")

The one id with no fixed type. The array length is the author's.

Three names a GLSL author reaches for have no WGSL builtin behind them. The front end refuses each one at the declaration and lists the names it does take. The right column is the sentence the backends print after the attribute name, which says what to reach for instead.

WGSLWhat to write
@builtin(point_size)

does not exist in WGSL — WebGPU point-list primitives are always 1px. Expand an instanced quad in the vertex stage instead

@builtin(point_coord)

does not exist in WGSL — there is no point-sprite coordinate. Interpolate a @location(n) corner uv from the expanded quad instead

@builtin(frag_coord)

does not exist in WGSL — the fragment-stage framebuffer coordinate (GLSL gl_FragCoord) is @builtin(position) on a fragment entry parameter.

Edit this page Report a problem