Skip to content

Overview

AXSLC is the Astralix Shader Language Compiler. It compiles .axsl source files - a custom shader language - into separate per-stage GLSL files targeting OpenGL 4.5 (#version 450 core).

Motivation

The primary motivation is to write vertex, fragment, geometry, and compute shaders in a single unified source file, sharing global declarations (structs, constants, uniforms, interface definitions) without duplication. AXSLC handles splitting the program into per-stage GLSL outputs and performs per-stage dead-code elimination on uniforms.

What AXSLC is not

AXSLC does not perform type checking. Type correctness is fully delegated to the downstream GLSL compiler (the OpenGL driver). AXSLC validates identifier resolution (undefined variables, unresolved symbols) but makes no attempt to infer or verify types.

Source File Extension

.axsl - Astralix Shader Language.

Output Files

For each stage present in the source, AXSLC writes a separate .glsl file. Stage-to-extension mapping:

StageOutput extension
vertex.vert.glsl
fragment.frag.glsl
geometry.geom.glsl
compute.comp.glsl

Compilation Pipeline

AXSLC processes shaders through four distinct phases:

  1. Tokenizer - Lexical analysis, converts source text to token stream
  2. Parser - Syntax analysis using Pratt parsing, builds flat AST
  3. Linker - Resolves @include files, validates identifiers, tracks uniform usage per stage
  4. Emitter - Generates GLSL code for each stage with dead code elimination

Key Features

Unified Source Files

Write all shader stages in one file with shared global declarations. No more copy-pasting struct definitions between vertex and fragment shaders.

Example:

axsl
@version 450;

// Shared global struct - defined once
struct Material {
    vec3 color;
    float roughness;
};

uniform Material u_material;

interface Varyings {
    vec2 v_uv;
    vec3 v_normal;
};

@stage vertex {
    in vec3 a_position;
    out Varyings v;

    void main() {
        v.v_uv = a_position.xy;
        v.v_normal = a_position;
        gl_Position = vec4(a_position, 1.0);
    }
}

@stage fragment {
    in Varyings v;
    out vec4 fragColor;

    void main() {
        // u_material only emitted in fragment stage (dead code elimination)
        fragColor = vec4(u_material.color, 1.0);
    }
}

Dead Code Elimination

Global uniforms are only emitted in stages that actually reference them, preventing unused uniform warnings and reducing shader binary size.

Interface System

Define interface blocks once globally and reference them by name in stages. The compiler automatically expands and matches them between stages.

Include System

Use @include "path/to/file.axsl" to merge global declarations from other files, enabling modular shader libraries.

Annotations

Control GLSL layout qualifiers with annotations:

  • @location(N) - Interface field location
  • @binding(N) - Uniform/buffer binding point
  • @std430 / @std140 - Memory layout for buffers

Clean Output

Generates readable, properly formatted GLSL code with appropriate layout qualifiers and annotations.

Fast Compilation

No type checking means compilation is extremely fast. Type errors are caught by the downstream GLSL compiler where they belong.

Command Line Usage

bash
axslc [options] <input.axsl>

Options:

  • -o, --output <prefix> - Output file prefix (default: out)
  • -I, --include-path <path> - Override base directory for includes
  • -v, --verbose - Print compilation status
  • -h, --help - Print usage
  • --version - Print version

Output naming: <prefix>.vert.glsl, <prefix>.frag.glsl, etc.

Public API

For programmatic use, AXSLC provides a simple C++ API:

cpp
#include "compiler.h"

Compiler compiler;
CompileResult result = compiler.compile(source, "shader.axsl", "./");

if (!result.errors.empty()) {
    // Handle errors
}

// result.stages is a map of StageKind → GLSL code
for (const auto& [stage, code] : result.stages) {
    // Write or use the generated GLSL
}

Limitations

AXSLC does not validate:

  • Type errors or mismatches
  • Missing main function
  • Interface block mismatches between stages
  • Circular includes (may cause infinite loop)

All type-level validation is delegated to the downstream GLSL compiler.