Skip to content

Stages

A stage block groups declarations and functions that belong to a single shader stage.

Syntax

axsl
@stage vertex {
    // in/out interface blocks, uniforms, buffers, structs, functions
}

The @stage decorator accepts a stage name as a suffix (@stage vertex, @stage fragment, etc.) or followed by a keyword (@stage vertex { ... }). Both forms are equivalent.

Supported Stages

Stage NameOutput ExtensionPurpose
vertex.vert.glslVertex processing
fragment.frag.glslFragment/pixel shading
geometry.geom.glslGeometry processing (optional)
compute.comp.glslCompute shaders

Stage-Local Declarations

Inside a @stage block, the following constructs are available:

Input Interface Block (Inline)

axsl
in Attributes {
    @location(0) vec3 a_pos;
    @location(1) vec2 a_uv;
} a;

Output Interface Block (Inline)

axsl
out FragOut {
    vec4 color;
} o;

Interface Reference

Reference a global interface definition:

axsl
out Varyings v;  // references global 'interface Varyings'
in Varyings v;   // in a different stage

See the Interface System guide for details.

Stage-Local Uniform

axsl
@binding(1) uniform mat4 u_model;

Stage-Local Buffer (SSBO)

axsl
@std430 @binding(0) buffer InstanceBuffer {
    mat4 models[];
} instance;

Uniform with Default Value

axsl
uniform float near_plane = -10.0;
uniform bool flag = false;

Stage-Local Struct

axsl
struct LocalData {
    vec3 color;
    float intensity;
};

Stage-Local Function

axsl
vec3 compute_lighting(vec3 normal) {
    // ...
}

Complete Vertex Stage Example

axsl
@stage vertex {
    // Input attributes
    in Attributes {
        @location(0) vec3 a_pos;
        @location(1) vec2 a_uv;
        @location(2) vec3 a_normal;
    } a;

    // Output (references global interface)
    out Varyings v;

    // Uniforms
    @binding(0) uniform mat4 u_mvp;
    @binding(1) uniform mat4 u_model;

    // Main function
    void main() {
        v.v_uv = a.a_uv;
        v.v_normal = mat3(u_model) * a.a_normal;
        gl_Position = u_mvp * vec4(a.a_pos, 1.0);
    }
}

Complete Fragment Stage Example

axsl
@stage fragment {
    // Input (references global interface)
    in Varyings v;

    // Output
    out vec4 o_color;

    // Uniforms
    @binding(2) uniform sampler2D u_texture;
    @binding(3) uniform vec3 u_light_dir;

    // Stage-local function
    float diffuse(vec3 normal, vec3 light_dir) {
        return max(dot(normal, light_dir), 0.0);
    }

    // Main function
    void main() {
        vec3 normal = normalize(v.v_normal);
        float lighting = diffuse(normal, u_light_dir);
        vec4 tex_color = texture(u_texture, v.v_uv);
        o_color = tex_color * lighting;
    }
}

Compute Stage Example

axsl
@stage compute {
    // Local work group size
    layout(local_size_x = 16, local_size_y = 16) in;

    // Input/output buffers
    @std430 @binding(0) buffer InputBuffer {
        float data[];
    } input_buf;

    @std430 @binding(1) buffer OutputBuffer {
        float data[];
    } output_buf;

    void main() {
        uint idx = gl_GlobalInvocationID.x +
                   gl_GlobalInvocationID.y * gl_NumWorkGroups.x * 16;
        output_buf.data[idx] = input_buf.data[idx] * 2.0;
    }
}

Stage Order

Stages can appear in any order in the source file:

axsl
@stage fragment { ... }
@stage vertex { ... }     // fragment before vertex is fine

The compiler will emit separate files for each stage regardless of order.

Optional Stages

You don't need to define all stages. Only define the stages you actually use:

axsl
@version 450;

// Only vertex and fragment, no geometry or compute
@stage vertex { ... }
@stage fragment { ... }

This will emit only .vert.glsl and .frag.glsl.