Harbor

branch main
showing the latest snapshot on main
language.md 5.8 KB · Markdown
gpu/shader/docs/language.md 0644 Raw

Luma Language Reference

Scalar Types

TypeDescription
boolBoolean (true/false)
intSigned 32-bit integer
uintUnsigned 32-bit integer
float32-bit floating point
half16-bit floating point

Vector Types

Vectors of 2-4 components: vec2, vec3, vec4 (float), ivec2-ivec4 (int), uvec2-uvec4 (uint), bvec2-bvec4 (bool).

Constructors:

let v = vec3(1.0, 2.0, 3.0)
let v2 = vec4(v, 1.0)         -- expand vec3 to vec4

Swizzling (xyzw, rgba, stpq):

let xy = v.xy        -- vec2
let zzz = v.zzz      -- vec3
let r = color.r       -- float

Matrix Types

Square: mat2, mat3, mat4. Non-square: mat2x3, mat3x4, etc.

Matrix-vector multiplication uses *:

let clip = view_proj * model * vec4(pos, 1.0)

Array Types

Fixed-size arrays: [N]T.

@group(0) @binding(0)
buffer lights: [16]Light

-- Access by index
let first = lights[0]

Sampler Types

sampler2D represents a combined texture/sampler. During compilation, it is automatically split into separate texture and sampler bindings for backends that require it.

@group(1) @binding(0)
uniform tex: sampler2D

-- In shader body:
let color = sample(tex, uv)
let mipped = sample_level(tex, uv, 2.0)

Structs

struct MyStruct
    field1: vec3
    field2: float
end

Attributes on Fields

struct VertexInput
    @location(0) position: vec3
    @location(1) normal: vec3
    @builtin(vertex_index) vid: uint
end

Varying Structs

@varying structs are shared between vertex output and fragment input. Fragment inputs automatically skip @builtin fields.

@varying
struct Interpolated
    @builtin(position) position: vec4
    @location(0) uv: vec2
end

Functions

function helper(a: vec3, b: vec3) -> float
    return dot(a, b)
end

Functions cannot be recursive. All functions are inlined or statically dispatched.

Entry Points

Workflow stages

vertex main
    in position: vec3 @location(0)
    in uv: vec2 @location(1)
    out clip: vec4 @builtin(position)
    out uv: vec2
do
    clip = vec4(position, 1.0)
    out.uv = uv
end

fragment shade
    in uv: vec2
    out color: vec4
do
    return vec4(uv, 0.0, 1.0)
end

compute simulate @workgroup_size(64, 1, 1)
do
    let i = work.global_id.x
    -- write storage buffers/resources
end

return expr is only fragment single-output top-level sugar. Vertex stages use explicit out assignments. Compute stages do not return and cannot declare out slots.

Workflow output assignments can appear in control flow if every non-discard path definitely assigns every output before stage exit. Overwrites are allowed.

Compatibility entry syntax

The older annotation syntax remains supported:

@entry(vertex)
function main(input: VertexInput) -> VertexOutput
    -- ...
end

@entry(fragment)
function main(@location(0) uv: vec2) -> (color: vec4)
    return vec4(uv, 0.0, 1.0)
end

Variables

let x = 1.0               -- immutable, type inferred
let y: float = 2.0        -- explicit type

Assignment requires mutable variables (loop variables, shared memory, buffer elements):

for i = 0, 10 do
    shared_data[i] = float(i)
end

Constants

const PI = 3.14159
const MAX_LIGHTS: int = 16

Specialization Constants

@spec(0) const TILE_SIZE: int = 8
@spec(1) const USE_NORMAL_MAP: bool = true

Bindings

Uniform Buffers

group frame = 0
    @binding(0) uniform camera: CameraData
end

Storage Buffers

group sim = 0
    @binding(1) buffer particles: ParticleBuffer
end

Textures

group material = 1
    @binding(0) texture diffuse: sampler2D
end

Auto-numbering

@group defaults to 0. @binding auto-increments within each group:

uniform a: TypeA       -- group=0, binding=0
uniform b: TypeB       -- group=0, binding=1
@group(1)
uniform c: sampler2D   -- group=1, binding=0 (texture), binding=1 (sampler)

group material = 1
    texture c: sampler2D
end

Shared Memory

Workgroup-shared memory for compute shaders:

shared tile: [64]float

compute main @workgroup_size(64, 1, 1)
do
    let idx = work.local_index
    tile[idx] = float(idx)
    barrier()
    -- all threads can now read tile
end

Control Flow

If/Elseif/Else

if x > 0.0 then
    -- ...
elseif x < 0.0 then
    -- ...
else
    -- ...
end

For Loop

for i = 0, 10 do          -- i goes from 0 to 9
    -- ...
end

for i = 0, 100, 2 do      -- step of 2
    -- ...
end

While Loop

while dist > 0.001 do
    -- ...
end

Operators

CategoryOperators
Arithmetic+, -, *, /, %
Comparison==, ~=, <, >, <=, >=
Logicaland, or, not
Unary- (negate), not

Preprocessor

#include "common.luma"

Include paths are resolved relative to the source file and any --include-dir paths.

Built-in Variables

Vertex

NameTypeDescription
positionvec4Clip-space position (output)
vertex_indexuintVertex index (input)
instance_indexuintInstance index (input)

Fragment

NameTypeDescription
positionvec4Fragment coord (input)
front_facingboolFront-facing (input)
frag_depthfloatDepth override (output)

Compute

NameTypeDescription
global_invocation_iduvec3Global thread ID
local_invocation_iduvec3Local thread ID
workgroup_iduvec3Workgroup ID
num_workgroupsuvec3Total workgroups
local_invocation_indexuintFlattened local index