Language Basics

GPULang is designed to be familiar to developers coming from C/C++ and modern shader languages, while introducing improvements that make GPU programming more accessible and expressive.

Key Principles

Cross-Platform

Write once, compile to multiple targets including SPIR-V, DXIL, and more.

Program Assembly

Assemble programs in the shader, allowing for link time validation and trivial runtime pipeline setup.

Type Inference

GPULang supports basic type inference, reducing verbosity while maintaining clarity.

Data Types

GPULang provides a comprehensive set of data types optimized for GPU computation.

Scalar Types

Loading types from syntax definition...

Vector Types

GPULang supports vector types from 2 to 4 components:

Loading vector types...

Matrix Types

Matrices are specified as type x rows x columns:

Loading matrix types...

Texture Types

Various texture types for different dimensionalities and use cases. Texture types containing the Sampled word is a combined texture and sampler and can't be used with for example textureLoad.

Loading texture types...

Special Types

Additional specialized types for specific GPU operations:

Loading special types...

Variables and Constants

Variable Declaration

Variables can be declared with explicit types or using type inference:

// Explicit type declaration
var position : f32x3 = f32x3(0.0f, 1.0f, 0.0f);
var count : i32 = 42;

// Type inferred from right hand side
var color = f32x4(1.0f, 0.5f, 0.2f, 1.0f);  // inferred as f32x4
var isVisible = true;                         // inferred as bool

Constants

Constants are declared using the const keyword:

// Constants
const PI = 3.14159f;
const MAX_LIGHTS = 8;
const DEFAULT_COLOR = f32x4(1.0f, 1.0f, 1.0f, 1.0f);

Type Aliasing

Type aliases can be created using the alias keyword:

alias Vec3 as f32x3;
alias RGBA as f32x4;

Uniform Variables

Uniform variables are declared using the uniform keyword. Uniform variables denote an externally provided resource:

// Uniform declarations
uniform ViewConstants : *View;
uniform DiffuseTexture : *texture2D;

Functions

Function Declaration

Functions are declared with return type trailing the parameter list:

// Function with multiple parameters
calculateLighting(position : f32x3, normal : f32x3, lightPos : f32x3) f32x4
{
    const lightDir = normalize(lightPos - position);
    const intensity = max(dot(normal, lightDir), 0.0f);
    return f32x4(f32x3(intensity), 1.0f);
}

Entry Points

Shader entry points are declared using the entry_point keyword:

// Vertex shader entry point
entry_point
VertexMain(
    binding(0) in position : f32x3,
    binding(1) in normal : f32x3,
    out worldPos : f32x4,
    out worldNormal : f32x3
) void
{
    worldPos = ViewMatrix * f32x4(position, 1.0f);
    worldNormal = normalize((ViewMatrix * f32x4(normal, 0.0f)).xyz);
    vertexExportCoordinates(worldPos);
}

Shader Attributes

Functions tagged with entry_point can be provided shader attributes. They will activate based on their program binding point, allowing for the same shader to change its execution mode.

// Compute shader attributes
threads(i32x3(8, 8, 1))
entry_point csMain() void {...}

// Pixel shader attributes
pixel_origin("center")
entry_point psMain() void {...}

Shader Type Switches

GPULang provides a set of built-in booleans to test what execution mode the shader is executing in:

var pixel : i32x2;

// GPULang will determine this branch at compile time
if (gplIsPixelShader)
{
    // Pixel shader specific code
    pixel = pixelGetCoordinates().xy;
}
else if (gplIsComputeShader)
{
    // Compute shader specific code
    pixel = computeGetGlobalThreadIndices().xy;
}

Generate

The generate statement allows for conditional code generation

// Generate a set of functions
generate
<
    if (!declared<BlurSize>)
    <
        const BlurSize = 5;
    >
    if (!declared<InputComponents>)
    {
        alias MemType as f32x4;
    }
    workgroup SharedMemory : MemType[BlurSize];
>

Control Flow

Branching

// If-else statements
if (alpha < 0.5f) 
{
    discard;
}
else if (alpha < 0.8f)
{
    color.rgb *= 0.5f;
}
else
{
    color.rgb *= 1.2f;
}

Loops

// For loop
var totalColor = f32x3(0.0f);
for (var i : i32 = 0; i < MAX_LIGHTS; i++)
{
    totalColor += calculateLight(position, lights[i]);
}

// While loop
var samples : i32 = 0;
while (samples < MAX_SAMPLES && quality > threshold)
{
    // Sampling logic
    samples++;
}

Switch

C-like Switch-case is supported in GPULang:

switch (shaderType);
case ShaderTypes.PBR:
{
    // PBR shader logic
}
case ShaderTypes.Diffuse:
{
    // Diffuse shader logic
}

Uniform Value Loops Work in progress

Uniformely looping over threads sharing the same value is built-in to GPULang:

const cellIndex = ...;
for_uniform(cellIndex)
{
    // Access cell value uniformly for all threads sharing cellIndex
    const cellValue = uniformData[cellIndex];
    // Perform operations with cellValue
}

Structures

Structure Definition

// Material structure
struct Material
{
    Albedo : f32x3;
    Roughness : f32;
    Metallic : f32;
    Normal : f32x3;
};

// Light structure
struct Light
{
    Position : f32x3;
    Tint : f32x3;
    Intensity : f32;
    Range : f32;
};

Using Structures

// Create and use structures
Material mat;
mat.Albedo = f32x3(0.8f, 0.6f, 0.4f);
mat.Roughness = 0.3f;
mat.Metallic = 0.0f;

// Structure as function parameter
calculatePBR(material : Material, light : Light, viewDir : f32x3) f32x3
{
    // PBR calculation logic
    return material.Albedo * light.Tint;
}

Shader Programs

Program Definition

Shader programs combine multiple shader stages:

// Render state definition
render_state MyRenderState
{
    Cull = CullFace.Back;
    DepthTest = true;
    DepthWrite = true;
    Blend = false;
};

// Program combining shaders
program StandardShading
{
    VertexShader = VertexMain;
    PixelShader = PixelMain;
    RenderState = MyRenderState;
};

Compute Shaders

// Compute shader entry point
threads(i32x3(8, 8, 1))
entry_point
ComputeMain() void
{
    const id = computeGetGlobalThreadIndices().xy;
    
    // Compute logic here
    outputTexture[id] = inputTexture[id] * 2.0f;
}

// Program combining shaders
program Compute
{
    ComputeShader = ComputeMain;
};

Advanced Features

Annotations

GPULang supports annotations for additional metadata which can be retrieved at runtime:

// Annotations for program variants
@Features("Static") 
program VariantShader
{
    VertexShader = VertexMain;
    PixelShader = PixelMain;
};

struct ShaderParams
{
    @Edit("Slider") BaseColor : f32x3;
};
uniform Params : *ShaderParams;

Sampler States

// Sampler state definition
sampler_state LinearSampler
{
    Filter = FilterMode.Linear;
    AddressU = AddressMode.Clamp;
    AddressV = AddressMode.Clamp;
    Border = Color.Black;
};