Help us shape the future of Go! Take the 2026 Go Developer Survey

naga

package module
v0.21.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 9 Imported by: 4

README

naga

Pure Go Shader Compiler
WGSL to SPIR-V, MSL, GLSL, HLSL, and DXIL. Zero CGO.

CI codecov Go Reference Go Report Card License Latest Release Go Version Zero CGO Stars Discussions

Part of the GoGPU ecosystem


Overview

naga is a shader compiler written entirely in Go. It compiles WGSL (WebGPU Shading Language) to multiple backend formats without requiring CGO or external dependencies.

Key Features

Category Capabilities
Input Full WGSL parser (120+ tokens), 48 short type aliases (vec3f, mat4x4f...), abstract constructors
Outputs SPIR-V (checked with spirv-val in CI), MSL, GLSL, HLSL; DXIL — 185 of 199 corpus shaders pass IDxcValidator (experimental)
Compute Storage buffers, workgroups, atomics, barriers, subgroup operations
Ray Tracing Ray query types, acceleration structures, 7 ray query builtins
Compatibility Tested against Rust naga's WGSL snapshot corpus (172 shaders, gfx-rs/wgpu 14328f49): every output is compared, and each known difference is recorded with its reason — see Rust Naga Compatibility
Build Zero CGO, single binary

Features

  • Pure Go — No CGO, no external dependencies
  • WGSL Frontend — Full lexer and parser (120+ tokens), 48 short type aliases (vec3f, mat4x4f, etc.), abstract constructors (vec3(1,2,3))
  • Rust Naga Compatibility — every IR, SPIR-V, MSL, GLSL and HLSL output is compared with Rust naga's on its 172-shader WGSL corpus; known differences are recorded per output with a reason. 29 own test shaders; 929 golden outputs
  • IR — Complete intermediate representation (expressions, statements, types)
  • Compute Shaders — Storage buffers, workgroup memory, @workgroup_size
  • Atomic Operations — atomicAdd, atomicSub, atomicMin, atomicMax, atomicCompareExchangeWeak
  • Barriers — workgroupBarrier, storageBarrier, textureBarrier
  • Type Inference — Automatic type resolution for all expressions, including let bindings
  • Type Deduplication — SPIR-V compliant unique type emission
  • Array Initialization — array(1, 2, 3) shorthand with inferred type and size
  • Texture Sampling — textureSample, textureLoad, textureStore, textureDimensions, textureGather, textureSampleCompare
  • Swizzle Operations — Full vector swizzle support (.xyz, .rgba, .xxyy, etc.)
  • Function Calls — OpFunctionCall support for modular WGSL shaders with helper functions
  • SPIR-V Backend — Vulkan-compatible bytecode generation: integer div/mod safety wrappers, image bounds checking (Restrict/ReadZeroSkipWrite), ray query helpers, loop bounding (on by default), workgroup zero-init polyfill, NonUniform decorations, capability-aware instruction emission
  • MSL Backend — Metal Shading Language output for macOS/iOS, vertex pulling transform, external textures, function-scope workgroup declarations (no host setThreadgroupMemoryLength needed)
  • GLSL Backend — OpenGL Shading Language for OpenGL 3.3+, ES 3.0+, dead code elimination, image bounds checking, version-aware layout(binding=N) emission (SupportsExplicitLocations for GL 4.2+/ES 3.1+), UniformInfo reflection for runtime binding fallback on older GL drivers
  • HLSL Backend — High-Level Shading Language for DirectX 11/12, shader models 5.0–6.7 (FXC and DXC); helpers get one exit where FXC would miscompile an early return
  • DXIL Backend (experimental) — Direct DXIL generation from naga IR (185 of 199 corpus shaders pass IDxcValidator; 99 of 181 DXC roundtrip comparisons match exactly; gg production shaders: every valid entry point passes; GPU readback corpus on D3D12 with Intel and NVIDIA). LLVM 3.7 bitcode with dx.op intrinsics, DXBC container. Vertex, fragment, compute, and mesh shaders (SM 6.0–6.9). CBV/SRV/UAV (read-only storage as SRV, read-write as UAV), atomics (i32/i64/f32 + image), barriers, ray query (35 intrinsics), wave/subgroup ops (13 intrinsics), texture sampling (8 variants), matrix scalarization, pack/unpack, helper functions. Optimization passes: DCE (mark-and-sweep), SROA (struct decomposition), mem2reg (SSA promotion), single-store local promotion, loadInput DCE (per-member backwards reachability), workgroup struct decomposition, function inlining (early-return wrapping), strength reduction (mul→shl, urem→and, sub→add), constant folding. Options.BindingMap for WGSL→DXIL (space, register) remap (wgpu root signature compatibility). Eliminates FXC/DXC dependency. dxil.Compile() API. World's first Pure Go DXIL generator.
  • Type Conversions — Scalar constructors f32(x), u32(y), i32(z) with correct SPIR-V opcodes
  • Bitcast — bitcast<T>(expr) for reinterpreting bit patterns between types
  • Warnings — Unused variable detection with _ prefix exception
  • Validation — Type checking, semantic validation, function call argument type/count verification, @must_use enforcement, const_assert evaluation, @binding/@group pairing, array size validation, swizzle namespace enforcement, mandatory semicolons
  • CLI Tool — nagac command-line compiler

Installation

go get github.com/gogpu/naga

Requirements: Go 1.25+


Usage

As Library

package main

import (
    "fmt"
    "log"

    "github.com/gogpu/naga"
)

func main() {
    source := `
@vertex
fn main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {
    return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}
`
    // Simple compilation
    spirv, err := naga.Compile(source)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Generated %d bytes of SPIR-V\n", len(spirv))
}

With Options

The zero value of every options struct is the safe one: SPIR-V 1.0, bounds checks on (Restrict), loops bounded, workgroup memory zeroed, every binding required, no optional capability. Ask for more explicitly:

opts := naga.CompileOptions{
    SPIRV:        spirv.Options{Version: spirv.Version1_3}, // subgroup operations need 1.3
    Capabilities: valid.CapShaderFloat16,                   // the device's features
}
spirvBytes, err := naga.CompileWithOptions(source, opts)

A backend never raises the target version a shader needs: it refuses with an error that names the feature and the version (errors.Is(err, backend.ErrUnsupported)).

CLI Tool

# Install
go install github.com/gogpu/naga/cmd/nagac@latest

# Compile shader
nagac shader.wgsl -o shader.spv

# With debug info
nagac -debug shader.wgsl -o shader.spv

# Show version
nagac -version

Development Tools

# SPIR-V disassembler (debugging shader compilation)
go install github.com/gogpu/naga/cmd/spvdis@latest
spvdis shader.spv

# DXIL validator — Pure Go wrapper around Microsoft IDxcValidator (Windows)
# First Pure Go integration with dxil.dll, zero CGO. Runs a three-layer
# defensive pre-check (DXBC structural + LLVM bitcode metadata walker)
# before handing blobs to IDxcValidator::Validate.
go install github.com/gogpu/naga/cmd/dxilval@latest
dxilval shader.dxil                       # validate a single container
dxilval --wgsl shader.wgsl                # compile through naga, then validate
dxilval --corpus snapshot/testdata/rust/in/wgsl/  # walk a directory, typed-error summary

# Texture shader compile tool (testing)
go install github.com/gogpu/naga/cmd/texture_compile@latest
texture_compile shader.wgsl

Parse, Validate, Write Any Backend

The same steps as Rust naga: parse WGSL to IR, validate it with the device's capabilities, then hand the module to any backend. Every backend has the one contract Compile(*ir.Module, Options) (output, TranslationInfo, error).

module, _, err := wgsl.Parse(source, wgsl.ParseOptions{})
if err != nil {
    var pe *wgsl.ParseError
    if errors.As(err, &pe) {
        fmt.Println(pe.Format(source, "shader.wgsl")) // labelled source lines, as Rust naga prints them
    }
    return err
}
info, err := valid.Validate(module, valid.Options{Capabilities: valid.CapShaderFloat16})
if err != nil {
    return err // a valid.Errors: every problem, errors.As finds each *valid.Error
}
_ = info // per entry point: the globals it uses and how (bind group layouts, workgroup size limits)

spirvBytes, _, err := spirv.Compile(module, spirv.Options{})                            // Vulkan
mslCode, _, err := msl.Compile(module, msl.Options{})                                   // Metal
glslCode, _, err := glsl.Compile(module, glsl.Options{LangVersion: glsl.Version450})    // OpenGL; one entry point
hlslCode, _, err := hlsl.Compile(module, hlsl.Options{})                                // Direct3D through FXC/DXC
dxilBytes, _, err := dxil.Compile(module, dxil.Options{})                               // Direct3D 12, no compiler

GLSL and DXIL write one entry point: select it with Options.EntryPoint = &backend.EntryPointSelector{Stage, Name} when the module has several.

Pipeline Constants

override declarations get their values per pipeline. Parse and validate once, then process the module for each pipeline before any backend, as wgpu does:

pipelineModule, pipelineInfo, err := naga.ProcessOverrides(module, info, naga.OverrideOptions{
    Constants:  naga.PipelineConstants{"gain": 1.5, "13": 64}, // name, or @id
    EntryPoint: &backend.EntryPointSelector{Stage: ir.StageCompute, Name: "main"},
})
// errors.Is(err, naga.ErrOverrideMissingValue), *naga.PipelineConstantError, ...

code, _, err := msl.Compile(pipelineModule, msl.Options{})

naga.Compile applies the overrides' defaults. A backend given a module that still uses overrides returns an error wrapping ir.ErrUnresolvedOverride.


Architecture

naga/
├── naga.go, overrides.go, compact.go   # Compile, CompileWithOptions, ProcessOverrides, Compact
├── wgsl/        # WGSL frontend: Parse → *ir.Module (lexer, parser, lowerer in wgsl/internal)
├── ir/          # the IR data model (Rust naga's naga::ir): Module, types, expressions, statements, Layouter
├── valid/       # validation (Rust naga's valid): Validate, Options, ModuleInfo, Capabilities
├── backend/     # what every backend shares: bounds-check policies, entry point selector, shader model, errors
├── spirv/       # SPIR-V backend (Vulkan)
├── msl/         # Metal Shading Language backend
├── glsl/        # GLSL backend (OpenGL 3.3+, OpenGL ES 3.0+)
├── hlsl/        # HLSL backend (Direct3D through FXC or DXC)
├── dxil/        # DXIL backend (Direct3D 12 without a shader compiler)
│   └── internal/  # bitcode writer, DXIL module, DXBC container, IR → DXIL emitter, optimization passes
├── internal/    # shared implementation: typifier, constant evaluator, override processing, IR passes
├── testdata/    # GPU readback corpus (read by gogpu/wgpu) and vendored third-party shaders
├── snapshot/    # golden tests against Rust naga's outputs, DXC roundtrip, spirv-val and IDxcValidator
└── cmd/
    ├── nagac/            # CLI compiler
    ├── spvdis/           # SPIR-V disassembler
    ├── dxilval/          # DXIL validation through dxil.dll (Windows)
    └── texture_compile/  # texture shader testing

Each package's implementation lives in its internal/ directory; the package itself is the public API that pkg.go.dev shows.

Supported WGSL Features

Types

  • Scalars: f16, f32, f64, i32, u32, i64, u64, bool
  • Vectors: vec2<T>, vec3<T>, vec4<T> (and short aliases: vec2f, vec3i, vec4u, etc.)
  • Matrices: mat2x2<f32> ... mat4x4<f32> (and short aliases: mat2x2f, mat4x4f, etc.)
  • Arrays: array<T, N>, array<T> (runtime-sized, storage buffers)
  • Structs: struct { ... } (with constructor syntax: StructName(field1, field2))
  • Atomics: atomic<u32>, atomic<i32>
  • Textures: texture_2d<f32>, texture_3d<f32>, texture_cube<f32>, texture_depth_2d_array
  • Samplers: sampler, sampler_comparison
  • Binding arrays: binding_array<T, N>
  • Ray tracing: acceleration_structure, ray_query
  • Abstract constructors: vec3(1,2,3), mat2x2(...), array(...) (without explicit template parameters)
  • Type aliases: alias FVec3 = vec3<f32>;

Shader Stages

  • @vertex — Vertex shaders with @builtin(position) output
  • @fragment — Fragment shaders with @location(N) outputs
  • @compute — Compute shaders with @workgroup_size(X, Y, Z)

Bindings

  • @builtin(position), @builtin(vertex_index), @builtin(instance_index)
  • @builtin(global_invocation_id) — Compute shader invocation ID
  • @location(N) — Vertex attributes and fragment outputs
  • @group(G) @binding(B) — Resource bindings

Address Spaces

  • var<uniform> — Uniform buffer
  • var<storage, read> — Read-only storage buffer
  • var<storage, read_write> — Read-write storage buffer
  • var<workgroup> — Workgroup shared memory

Statements

  • Variable declarations: var, let, const
  • Override declarations: @id(N) override name: type = default;
  • Compile-time assertions: const_assert expr;
  • Control flow: if, else, for, while, loop, switch, case, default
  • Loop control: break, continue, break if (continuing blocks)
  • Functions: return, discard
  • Assignment: =, +=, -=, *=, /=

Built-in Functions (100+)

  • Math: abs, min, max, clamp, saturate, sign, fma, modf, frexp, ldexp, quantizeToF16
  • Trigonometric: sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh, asinh, acosh, atanh
  • Angle: radians, degrees
  • Exponential: exp, exp2, log, log2, pow, sqrt, inverseSqrt
  • Decomposition: ceil, floor, round, fract, trunc
  • Geometric: dot, cross, length, distance, normalize, faceForward, reflect, refract, outerProduct
  • Interpolation: mix, step, smoothstep
  • Matrix: transpose, determinant, inverse
  • Relational: all, any, isnan, isinf
  • Bit: countTrailingZeros, countLeadingZeros, countOneBits, reverseBits, extractBits, insertBits, firstTrailingBit, firstLeadingBit
  • Packing: pack4x8snorm, pack4x8unorm, pack2x16snorm, pack2x16unorm, pack2x16float, pack4xI8, pack4xU8, pack4xI8Clamp, pack4xU8Clamp, unpack4x8snorm, unpack4x8unorm, unpack2x16snorm, unpack2x16unorm, unpack2x16float, unpack4xI8, unpack4xU8
  • Selection: select
  • Derivatives: dpdx, dpdy, fwidth, dpdxCoarse, dpdyCoarse, fwidthCoarse, dpdxFine, dpdyFine, fwidthFine
  • Atomic: atomicAdd, atomicSub, atomicMin, atomicMax, atomicAnd, atomicOr, atomicXor, atomicExchange, atomicCompareExchangeWeak
  • Barriers: workgroupBarrier, storageBarrier, textureBarrier, subgroupBarrier
  • Subgroup: subgroupBallot, subgroupAll, subgroupAny, subgroupAdd/Mul/Min/Max/And/Or/Xor, subgroupBroadcast/First, subgroupShuffle/XOR/Up/Down, quadSwap/Broadcast (need enable subgroups;, as the WGSL spec requires)
  • Directives: enable for f16, clip_distances, dual_source_blending, subgroups, primitive_index, draw_index and wgpu's extensions; a feature used without its enable is an error
  • Ray Query: rayQueryInitialize, rayQueryProceed, rayQueryGetCommittedIntersection, rayQueryGetCandidateIntersection, rayQueryTerminate
  • Uniform Load: workgroupUniformLoad
  • Array: arrayLength

Status

Current Version: See CHANGELOG.md for release history.

Backend Status Target Platform
SPIR-V ✅ Stable, spirv-val in CI Vulkan
MSL ✅ Stable Metal (macOS/iOS)
GLSL ✅ Stable, version-aware binding OpenGL 3.3+, ES 3.0+
HLSL ✅ Stable DirectX 11/12
DXIL 185/199 IDxcValidator (Rust naga and own corpus), 99/181 DXC golden DirectX 12 (SM 6.0-6.9, experimental)

See ROADMAP.md for detailed development plans.

Test Coverage

Coverage per package and per commit is on Codecov. Tests verify output (exact strings, spirv-val, IDxcValidator, DXC roundtrip), negative cases with Rust naga's error texts, and GPU readback values; every fix ships with a test that failed before it.

Architecture

All backends follow the DXIL internal package pattern — implementation in internal/codegen/, thin public API with real types (not aliases). Zero panics in error paths.


References

Rust Naga Compatibility

naga is tested against the WGSL snapshot corpus of Rust naga: 172 shaders with their test parameters and reference outputs, vendored from gfx-rs/wgpu at commit 14328f49 (snapshot/testdata/rust/, with a manifest of every file). Every output Rust's snapshot driver writes — IR, SPIR-V, MSL, GLSL, HLSL — is compared with ours. An output that does not match is a test failure unless it is recorded in snapshot/rust_deviations_test.go with its reason and a fingerprint of the difference; most records name the upstream commits not ported yet, and some are bugs being fixed. SPIR-V is still compared by instruction counts rather than exactly. Shaders using features we do not support yet (cooperative matrices, debugPrintf, 16-bit integers, ray tracing pipelines) are listed with their expected error. In addition, 28 own test shaders and 936 golden outputs guard against unintended changes.


Ecosystem

naga is the shader compiler for the GoGPU ecosystem.

Project Description
gogpu/gogpu GPU framework with windowing and input
gogpu/wgpu Pure Go WebGPU implementation
gogpu/naga Shader compiler (this repo)
gogpu/gg 2D graphics library
gogpu/ui GUI toolkit (22 widgets, M3/Fluent/Cupertino)

Documentation


Contributing

We welcome contributions! Areas where help is needed:

  • Additional WGSL features
  • Test cases from real shaders
  • Backend optimizations
  • Documentation improvements

Star History

Star History Chart

License

MIT License — see LICENSE for details.


naga — Shaders in Pure Go

Documentation

Overview

Package naga provides a Pure Go shader compiler.

naga compiles WGSL (WebGPU Shading Language) source code to multiple output formats:

  • SPIR-V — Binary format for Vulkan
  • MSL — Metal Shading Language for macOS/iOS
  • GLSL — OpenGL Shading Language for OpenGL 3.3+, ES 3.0+
  • HLSL — High Level Shading Language for DirectX
  • DXIL — DirectX Intermediate Language for Direct3D 12

This package is the one-call path from WGSL to SPIR-V, plus pipeline constants (ProcessOverrides) and module compaction (Compact). Each language has its own package: a frontend's Parse (wgsl.Parse) gives an IR module, valid.Validate checks it, and a backend's Compile (spirv, msl, glsl, hlsl, dxil) writes it.

Example usage (SPIR-V):

source := `
@vertex
fn main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {
    return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}
`
spirv, err := naga.Compile(source)
if err != nil {
    log.Fatal(err)
}

For MSL output:

module, _, err := wgsl.Parse(source, wgsl.ParseOptions{})
...
if _, err := valid.Validate(module, valid.Options{}); err != nil { ... }
mslCode, info, err := msl.Compile(module, msl.Options{})

Concurrency

Every exported function is safe for concurrent use. ProcessOverrides never modifies its input module; its result may share unmodified parts of it. Compact is the one function that modifies the module it is given, in place: no other goroutine may use that module while it runs.

Example (Backends)

Parse, validate with the device's capabilities, then write any backend.

package main

import (
	"errors"
	"fmt"

	"github.com/gogpu/naga"
	"github.com/gogpu/naga/dxil"
	"github.com/gogpu/naga/glsl"
	"github.com/gogpu/naga/hlsl"
	"github.com/gogpu/naga/msl"
	"github.com/gogpu/naga/spirv"
	"github.com/gogpu/naga/valid"
	"github.com/gogpu/naga/wgsl"
)

const exampleShader = `
override gain: f32 = 1.0;

@group(0) @binding(0) var<storage, read_write> data: array<f32>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    data[id.x] = data[id.x] * gain;
}
`

func main() {
	module, _, err := wgsl.Parse(exampleShader, wgsl.ParseOptions{})
	if err != nil {
		var pe *wgsl.ParseError
		if errors.As(err, &pe) {
			fmt.Println(pe.Format(exampleShader, "shader.wgsl"))
		}
		return
	}
	info, err := valid.Validate(module, valid.Options{Capabilities: valid.CapShaderFloat16})
	if err != nil {
		fmt.Println(err)
		return
	}

	// Backends take a module without overrides: give them their values first.
	module, _, err = naga.ProcessOverrides(module, info, naga.OverrideOptions{})
	if err != nil {
		fmt.Println(err)
		return
	}

	_, _, errSPIRV := spirv.Compile(module, spirv.Options{})
	_, _, errMSL := msl.Compile(module, msl.Options{})
	_, _, errGLSL := glsl.Compile(module, glsl.Options{LangVersion: glsl.Version450})
	_, _, errHLSL := hlsl.Compile(module, hlsl.Options{})
	_, _, errDXIL := dxil.Compile(module, dxil.Options{})
	fmt.Println(errors.Join(errSPIRV, errMSL, errGLSL, errHLSL, errDXIL))
}
Output:
<nil>

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrOverrideNotFound: a key names no override of the module.
	ErrOverrideNotFound = overrides.ErrNotFound
	// ErrOverrideMissingValue: an override an entry point uses has no value
	// and no default.
	ErrOverrideMissingValue = overrides.ErrMissingValue
	// ErrOverrideValueNotFinite: NaN or an infinity for a numeric override.
	ErrOverrideValueNotFinite = overrides.ErrValueNotFinite
	// ErrOverrideValueOutOfRange: the value does not fit the override's type.
	ErrOverrideValueOutOfRange = overrides.ErrValueOutOfRange
	// ErrNegativeWorkgroupSize: a workgroup size given by an override is not
	// positive.
	ErrNegativeWorkgroupSize = overrides.ErrNegativeWorkgroupSize
	// ErrNegativeMeshOutputMax: a mesh output limit given by an override is
	// negative.
	ErrNegativeMeshOutputMax = overrides.ErrNegativeMeshOutputMax
)

Pipeline-constant errors.

Functions

func Compact added in v0.21.0

func Compact(module *ir.Module, keep KeepUnused)

Compact removes the objects module does not use and renumbers the handles of what is left, as Rust naga's compact::compact does. module must be valid.

With either keep value it removes the function expressions nothing refers to, the constants, overrides and global expressions nothing uses (named constants of a concrete type always stay), the abstract types and the anonymous types nothing refers to any more. With KeepUnusedNo it first removes the global variables and functions no entry point reaches, and the named overrides nothing uses. Entry points, special types and named types always stay; Rust also removes an unused named type under KeepUnused::No.

Compact modifies module in place: nothing else may read or write module while it runs, and handles taken from module before the call are not valid after it. Calls on different modules may run concurrently.

func Compile

func Compile(source string) ([]byte, error)

Compile compiles WGSL source code to SPIR-V binary using default options.

Example

Compile WGSL to SPIR-V with the safe defaults.

package main

import (
	"fmt"

	"github.com/gogpu/naga"
)

const exampleShader = `
override gain: f32 = 1.0;

@group(0) @binding(0) var<storage, read_write> data: array<f32>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    data[id.x] = data[id.x] * gain;
}
`

func main() {
	spirvBytes, err := naga.Compile(exampleShader)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(len(spirvBytes) > 0)
}
Output:
true

func CompileWithOptions

func CompileWithOptions(source string, opts CompileOptions) ([]byte, error)

CompileWithOptions compiles WGSL source code to SPIR-V binary with custom options.

The compilation pipeline is:

  1. Parse WGSL to IR (wgsl.Parse); a *wgsl.ParseError is returned wrapped, with its line and column
  2. Validate IR (if enabled)
  3. Replace overrides by their defaults (ProcessOverrides with no pipeline constants), as Rust naga's CLI does; an override without a default is an error. For pipeline constants use wgsl.Parse, ProcessOverrides and a backend.
  4. Generate SPIR-V binary

func ProcessOverrides added in v0.20.1

func ProcessOverrides(module *ir.Module, info valid.ModuleInfo, opts OverrideOptions) (*ir.Module, valid.ModuleInfo, error)

ProcessOverrides returns module with every override expression replaced by a constant holding its pipeline value or default, every expression that becomes constant evaluated, and workgroup sizes given by overrides resolved — Rust naga's back::pipeline_constants::process_overrides. Call it before a backend; naga.Compile calls it with the defaults.

module is never modified, and ProcessOverrides may be called concurrently on the same module. The result may be module itself when there is nothing to do (no overrides, and no EntryPoint or at most one entry point); treat it as read-only. Handles in the result are not stable relative to module.

A module produced by the WGSL frontend with no overrides (len(Overrides) == 0) has no override expressions, override workgroup sizes or override-sized arrays and needs no processing, but call ProcessOverrides anyway when Constants is not empty: a key that names no override is an error (ErrOverrideNotFound).

With EntryPoint, globals the entry point does not use are removed. A backend that numbers resources by their position in the module (MSL without msl.Options.PerEntryPointMap) can then give them other slots.

The result keeps the overrides arena, with each initializer evaluated, and override-sized arrays stay pending (ir.ArraySize.Resolve sizes them; backends do), as in Rust. With EntryPoint the selected entry point is EntryPoints[0]. Processing a processed module again with other constants is not supported: process the module from the frontend for every pipeline.

The caller MUST have validated module first, with valid.Validate and the device's own valid.Options, and info is that validation's ModuleInfo: capabilities are gated there and nowhere else. When there is nothing to do, module and info are returned as they are, unvalidated. Otherwise the processed module is validated again, as Rust's revalidate does after substitution (validate_resolved_overrides): with every capability allowed, so it re-checks the structure but cannot catch a capability the device lacks. Its new valid.ModuleInfo is returned. A backend never validates.

Errors: a *PipelineConstantError for a constant (errors.Is with ErrOverrideNotFound, ErrOverrideMissingValue, ErrOverrideValueNotFinite, ErrOverrideValueOutOfRange); backend.ErrEntryPointNotFound; ErrNegativeWorkgroupSize; ErrNegativeMeshOutputMax; an evaluation error of an expression that becomes constant (for example a division by zero after substitution); or an invalid processed module. Keys are checked in sorted order, so the same input reports the same key.

Example

Give overrides their values per pipeline, then compile.

package main

import (
	"fmt"

	"github.com/gogpu/naga"
	"github.com/gogpu/naga/backend"
	"github.com/gogpu/naga/ir"
	"github.com/gogpu/naga/msl"
	"github.com/gogpu/naga/valid"
	"github.com/gogpu/naga/wgsl"
)

const exampleShader = `
override gain: f32 = 1.0;

@group(0) @binding(0) var<storage, read_write> data: array<f32>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    data[id.x] = data[id.x] * gain;
}
`

func main() {
	module, _, err := wgsl.Parse(exampleShader, wgsl.ParseOptions{})
	if err != nil {
		fmt.Println(err)
		return
	}
	info, err := valid.Validate(module, valid.Options{})
	if err != nil {
		fmt.Println(err)
		return
	}
	pipelineModule, _, err := naga.ProcessOverrides(module, info, naga.OverrideOptions{
		Constants:  naga.PipelineConstants{"gain": 1.5},
		EntryPoint: &backend.EntryPointSelector{Stage: ir.StageCompute, Name: "main"},
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	code, _, err := msl.Compile(pipelineModule, msl.Options{})
	fmt.Println(err == nil && len(code) > 0)
}
Output:
true

Types

type CompileOptions

type CompileOptions struct {
	// SPIRV is the SPIR-V backend's options, all of them. Its zero value is
	// the safe set: SPIR-V 1.0, Restrict bounds checks, bounded loops,
	// workgroup memory zeroed, every binding required. A shader that needs
	// a newer SPIR-V version (subgroup operations need 1.3) is an error
	// until SPIRV.Version gives one; the backend never raises it.
	SPIRV spirv.Options

	// Capabilities is what the IR validator allows beyond core WebGPU: the
	// zero value rejects every optional feature (f64, i64, u64, f16,
	// subgroups, 64-bit and f32 atomics, ray queries, mesh shaders, binding
	// arrays, ...), as Rust naga's default does. Enable one with its
	// valid.Cap* constant, for example [valid.CapShaderFloat16] or
	// [valid.CapSubgroup], or [valid.CapAll] to permit everything. The
	// subgroup stages and operations are derived from it as
	// [valid.Options] documents.
	Capabilities valid.Capabilities

	// SkipValidation compiles the module without validating it first. The
	// zero value validates, as Rust naga's CLI does. A module with overrides
	// is still validated after they are replaced, with every capability (as
	// ProcessOverrides always does); one without is not validated at all.
	SkipValidation bool
}

CompileOptions configures shader compilation.

func DefaultOptions

func DefaultOptions() CompileOptions

DefaultOptions returns the zero CompileOptions, the safe defaults.

type KeepUnused added in v0.21.0

type KeepUnused bool

KeepUnused selects whether Compact keeps the functions, global variables and named overrides nothing uses, as Rust naga's compact::KeepUnused.

const (
	// KeepUnusedNo removes every function and global variable no entry point
	// reaches and every override nothing uses (Rust KeepUnused::No), as
	// pipeline-constant processing needs: an override no entry point uses
	// needs no value.
	KeepUnusedNo KeepUnused = false
	// KeepUnusedYes keeps every function, global variable and named override
	// (Rust KeepUnused::Yes), as after lowering.
	KeepUnusedYes KeepUnused = true
)

type OverrideOptions added in v0.20.1

type OverrideOptions struct {
	// Constants are the pipeline-constant values.
	Constants PipelineConstants
	// EntryPoint, if not nil, keeps only that entry point; only overrides it
	// uses need a value.
	EntryPoint *backend.EntryPointSelector
}

OverrideOptions configure ProcessOverrides. The zero value processes every entry point with no pipeline constants: every override takes its default.

type PipelineConstantError added in v0.20.1

type PipelineConstantError struct {
	Key string // the pipeline-constant key, or the override's identifier string
	Err error
}

PipelineConstantError is an error about one pipeline constant or override (Rust naga's PipelineConstantError). Err is one of the ErrOverride* sentinels; Error is Rust's message.

func (*PipelineConstantError) Error added in v0.20.1

func (e *PipelineConstantError) Error() string

func (*PipelineConstantError) Unwrap added in v0.20.1

func (e *PipelineConstantError) Unwrap() error

Unwrap returns Err, for errors.Is.

type PipelineConstants added in v0.20.1

type PipelineConstants map[string]float64

PipelineConstants are the values of pipeline-overridable constants (WebGPU GPUProgrammableStage.constants). A key is an override's @id as a decimal string, or its name if it has no @id; keys are compared exactly, as WGSL identifiers.

Directories

Path Synopsis
Package backend holds the types that every naga backend shares: the bounds-check policies, the workgroup zero-initialization mode, the entry-point selector, the frag_depth clamp, the DirectX shader model and the error categories a caller can branch on with errors.Is.
Package backend holds the types that every naga backend shares: the bounds-check policies, the workgroup zero-initialization mode, the entry-point selector, the frag_depth clamp, the DirectX shader model and the error categories a caller can branch on with errors.Is.
cmd
dxilval command
Command dxilval validates DXIL containers using Microsoft's IDxcValidator.
Command dxilval validates DXIL containers using Microsoft's IDxcValidator.
dxilval/internal/run
Package run implements the dxilval CLI logic.
Package run implements the dxilval CLI logic.
nagac command
Command nagac is the naga shader compiler CLI.
Command nagac is the naga shader compiler CLI.
spvdis command
spvdis - SPIR-V disassembler Generates valid .spvasm text format
spvdis - SPIR-V disassembler Generates valid .spvasm text format
texture_compile command
Package dxil implements a DXIL (DirectX Intermediate Language) backend for the naga shader compiler.
Package dxil implements a DXIL (DirectX Intermediate Language) backend for the naga shader compiler.
internal/bitcode
Package bitcode implements a bit-level writer for LLVM 3.7 bitcode format.
Package bitcode implements a bit-level writer for LLVM 3.7 bitcode format.
internal/container
Package container implements the DXBC container format used to wrap DXIL shader bitcode.
Package container implements the DXBC container format used to wrap DXIL shader bitcode.
internal/emit
Package emit implements naga IR to DXIL module lowering.
Package emit implements naga IR to DXIL module lowering.
internal/module
Package module provides an in-memory representation of a DXIL module.
Package module provides an in-memory representation of a DXIL module.
internal/passes/dce
Package dce implements dead code elimination for DXIL shader functions.
Package dce implements dead code elimination for DXIL shader functions.
internal/passes/mem2reg
Package mem2reg promotes function-scope local variables of scalar type to SSA values, eliminating the corresponding alloca / load / store triples that the DXIL emitter would otherwise produce.
Package mem2reg promotes function-scope local variables of scalar type to SSA values, eliminating the corresponding alloca / load / store triples that the DXIL emitter would otherwise produce.
internal/passes/sroa
Package sroa implements Scalar Replacement of Aggregates for DXIL emit.
Package sroa implements Scalar Replacement of Aggregates for DXIL emit.
internal/viewid
Package viewid computes input→output dataflow dependencies for graphics entry points, producing the data that populates DXIL's `dx.viewIdState` metadata (ComputeViewIdState.cpp format) and the PSV0 dependency table (PSVDependencyTable layout).
Package viewid computes input→output dataflow dependencies for graphics entry points, producing the data that populates DXIL's `dx.viewIdState` metadata (ComputeViewIdState.cpp format) and the PSV0 dependency table (PSVDependencyTable layout).
Package glsl provides a GLSL (OpenGL Shading Language) backend for naga.
Package glsl provides a GLSL (OpenGL Shading Language) backend for naga.
Package hlsl provides HLSL (High-Level Shading Language) code generation from the naga intermediate representation.
Package hlsl provides HLSL (High-Level Shading Language) code generation from the naga intermediate representation.
internal/codegen
Package hlsl implements HLSL expression generation for all IR expression types.
Package hlsl implements HLSL expression generation for all IR expression types.
internal
cmd/corpussync command
Command corpussync maintains the Rust naga test corpus vendored under snapshot/testdata (ADR-006).
Command corpussync maintains the Rust naga test corpus vendored under snapshot/testdata (ADR-006).
consteval
Package consteval evaluates WGSL const-expressions: the shader-creation-time evaluation that the WGSL specification requires for const declarations and that naga also applies to constant operands in function bodies.
Package consteval evaluates WGSL const-expressions: the shader-creation-time evaluation that the WGSL specification requires for const declarations and that naga also applies to constant operands in function bodies.
d3d
Package d3d holds cross-backend constants and helpers shared between naga's text backends (HLSL) and binary backends (DXIL) that both target the D3D ecosystem.
Package d3d holds cross-backend constants and helpers shared between naga's text backends (HLSL) and binary backends (DXIL) that both target the D3D ecosystem.
dxcvalidator
Package dxcvalidator wraps Microsoft's IDxcValidator (dxil.dll) so naga can run real DXIL validation against generated containers from Pure Go.
Package dxcvalidator wraps Microsoft's IDxcValidator (dxil.dll) so naga can run real DXIL validation against generated containers from Pure Go.
dxcvalidator/bitcheck
Package bitcheck implements a minimal LLVM 3.7 bitstream reader that walks a DXIL container far enough to verify the `!dx.entryPoints` named metadata is well-formed — specifically that every entry-point tuple has a non-null function reference in operand 0.
Package bitcheck implements a minimal LLVM 3.7 bitstream reader that walks a DXIL container far enough to verify the `!dx.entryPoints` named metadata is well-formed — specifically that every entry-point tuple has a non-null function reference in operand 0.
entrypoint
Package entrypoint selects the entry point a backend writes, the meaning of every backend's Options.EntryPoint (backend.EntryPointSelector).
Package entrypoint selects the entry point a backend writes, the meaning of every backend's Options.EntryPoint (backend.EntryPointSelector).
irutil
Package irutil holds the IR helpers and passes that naga's own frontends, backends and pipeline-constant processing share and that are not part of the public ir package: ir keeps the data model, validation, type resolution and the few helpers a frontend or backend outside naga needs (ADR-010 B7).
Package irutil holds the IR helpers and passes that naga's own frontends, backends and pipeline-constant processing share and that are not part of the public ir package: ir keeps the data model, validation, type resolution and the few helpers a frontend or backend outside naga needs (ADR-010 B7).
overrides
Package overrides replaces pipeline-overridable constants by their values: a port of Rust naga's back::pipeline_constants::process_overrides on the shared constant evaluator (ADR-008).
Package overrides replaces pipeline-overridable constants by their values: a port of Rust naga's back::pipeline_constants::process_overrides on the shared constant evaluator (ADR-008).
readback
Package readback reads the GPU readback corpus under testdata/readback: small compute shaders with the values a GPU must write when it runs them.
Package readback reads the GPU readback corpus under testdata/readback: small compute shaders with the values a GPU must write when it runs them.
registry
Package registry provides type deduplication for the naga IR.
Package registry provides type deduplication for the naga IR.
ssa
Package ssa holds the two expression kinds the DXIL backend adds to a function when it promotes local variables to SSA values: Alias and Phi.
Package ssa holds the two expression kinds the DXIL backend adds to a function when it promotes local variables to SSA values: Alias and Phi.
testcorpus
Package testcorpus records and verifies the provenance of the test corpus under snapshot/testdata (ADR-006).
Package testcorpus records and verifies the provenance of the test corpus under snapshot/testdata (ADR-006).
testtools
Package testtools gives tests one policy for external tools (spirv-val, spirv-dis, dxc, ...), in the spirit of Go's internal/testenv.
Package testtools gives tests one policy for external tools (spirv-val, spirv-dis, dxc, ...), in the spirit of Go's internal/testenv.
textutil
Package textutil provides shared text writing utilities for naga codegen backends.
Package textutil provides shared text writing utilities for naga codegen backends.
typifier
Package typifier types the expressions of an IR function: Rust naga's Typifier (front/mod.rs) with the rules of proc::ResolveContext::resolve (proc/typifier.rs).
Package typifier types the expressions of an IR function: Rust naga's Typifier (front/mod.rs) with the rules of proc::ResolveContext::resolve (proc/typifier.rs).
unsupported
Package unsupported builds the backends' refusals: errors that wrap backend.ErrUnsupported while keeping their message as written.
Package unsupported builds the backends' refusals: errors that wrap backend.ErrUnsupported while keeping their message as written.
Package ir defines the intermediate representation for naga.
Package ir defines the intermediate representation for naga.
msl
Package msl implements Metal Shading Language (MSL) code generation for naga.
Package msl implements Metal Shading Language (MSL) code generation for naga.
Package spirv provides SPIR-V code generation from naga IR.
Package spirv provides SPIR-V code generation from naga IR.
internal/codegen
Package codegen implements SPIR-V code generation from naga IR.
Package codegen implements SPIR-V code generation from naga IR.
Package valid validates an IR module: Rust naga's valid module.
Package valid validates an IR module: Rust naga's valid module.
Package wgsl is the WGSL (WebGPU Shading Language) frontend: Parse turns WGSL source into an IR module, as Rust naga's front::wgsl.
Package wgsl is the WGSL (WebGPU Shading Language) frontend: Parse turns WGSL source into an IR module, as Rust naga's front::wgsl.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL