Attributes
Grammar
attr ::= "vertex" | "fragment" | "compute"
| "builtin" "(" builtin_name ")"
| "location" "(" decimal ")"
builtin_name ::= "position" | "vertex_index" | "instance_index"
| "front_facing" | "frag_depth" | "frag_coord"
| "global_invocation_id" | "local_invocation_id"
| "workgroup_id" | "num_workgroups"
Wyn supports an attribute system for shader interface specification. Attributes are written as #[attr] and can be applied to:
- Top-level
defdeclarations for shader identification - Function parameters for input interface specification
- Return types for output interface specification
Shader Interface Attributes
Wyn uses attributes to define the interface between shader stages and the GPU pipeline.
Shader Identification
#[vertex] - Marks an entry declaration as a vertex shader entry point
#[vertex]
entry vs_main() #[builtin(position)] vec4f32 = result
#[fragment] - Marks an entry declaration as a fragment shader entry point
#[fragment]
entry fs_main() #[location(0)] vec4f32 = result
#[compute] - Marks an entry declaration as a compute shader entry point
#[compute]
entry compute_main(data: []f32) []f32 = map(|x| x * 2.0, data)
Built-in Variables
#[builtin(builtin_name)] - Maps parameters and return values to GPU built-in variables
Vertex Shader Built-ins:
#[builtin(vertex_index)]- Vertex index#[builtin(instance_index)]- Instance index#[builtin(position)]- Output position
Fragment Shader Built-ins:
#[builtin(frag_coord)]- Fragment coordinates#[builtin(front_facing)]- Front-facing status#[builtin(frag_depth)]- Fragment depth output
Compute Shader Built-ins: all four are typed vec3u32, supplying
3-D coordinates that the kernel may use as 1-D / 2-D as appropriate.
#[builtin(global_invocation_id)]— global thread coordinates across the whole dispatch (workgroup_id * workgroup_size + local_invocation_id)#[builtin(local_invocation_id)]— thread coordinates within the enclosing workgroup#[builtin(workgroup_id)]— workgroup coordinates within the dispatched grid#[builtin(num_workgroups)]— total dispatched workgroup count along each axis (the value the host passed todispatch_workgroups)
Location-based Interface
#[location(n)] - Maps parameters and return values to location-based interface variables for communication between shader stages.
#[vertex]
entry vs(
#[builtin(vertex_index)] vid: i32,
#[location(0)] pos: vec3f32
) #[location(1)] vec3f32 = result
#[fragment]
entry fs(
#[location(1)] color: vec3f32
) #[location(0)] vec4f32 = result
Resource Bindings
Uniforms, storage buffers, textures, and samplers are bound to
entry-point parameters via attributes (never to top-level defs).
#[uniform(set=S, binding=B)] / #[storage(set=S, binding=B, ...)] —
small read-only constants / arbitrary-size buffers. See GPU Resources
and Descriptor Set Layout for set-numbering rules.
#[texture(set=S, binding=B)] - binds a texture2d parameter to a
sampled texture resource. set defaults to 1; binding is required.
#[sampler(set=S, binding=B)] - binds a sampler parameter to a
sampler resource. set defaults to 1; binding is required.
#[fragment]
entry fs(
#[location(0)] uv: vec2f32,
#[texture(set=0, binding=0)] tex: texture2d,
#[sampler(set=0, binding=1)] samp: sampler
) #[location(0)] vec4f32 =
texture_sample(tex, samp, uv, 0.0)
See Texture and Sampler Types for the types and the
texture_load / texture_sample operations.
External Linkage
#[linked("name")] — applied to an extern declaration, marks
the function as resolved at SPIR-V link time. The string is the
linkage name the host runtime’s linker matches against an external
SPIR-V module. The Wyn compiler emits a LinkageAttributes import
decoration for the function and trusts the host to supply a body with
a matching Export decoration.
#[linked("sha256_compress")]
extern sha256_compress(state: [8]u32, block: [16]u32) [8]u32
The signature must match the externally-supplied function’s type
exactly. WGSL emission does not support this attribute — #[linked]
is SPIR-V only.
Attribute Examples
Complete Vertex Shader Interface
#[vertex]
entry vertex_main(
#[builtin(vertex_index)] vertex_id: i32,
#[builtin(instance_index)] instance_id: i32,
#[location(0)] position: vec3f32,
#[location(1)] normal: vec3f32
) #[builtin(position)] vec4f32 =
transform_position(position, vertex_id)
Complete Fragment Shader Interface
#[fragment]
entry fragment_main(
#[location(0)] world_pos: vec3f32,
#[location(1)] normal: vec3f32,
#[builtin(front_facing)] is_front: bool
) #[location(0)] vec4f32 =
compute_color(world_pos, normal, is_front)
Complete Compute Shader Interface
#[compute]
entry process_data(
input: []f32,
factor: f32
) []f32 =
map(|x| x * factor, input)