Open-Source Wikis

/

wgpu

/

Crates

/

Naga IR

gfx-rs/wgpu

Naga IR

Naga's internal shader representation lives under naga/src/ir/. Every front-end produces it and every back-end consumes it.

Top-level shape

A shader is a naga::Module:

pub struct Module {
    pub types: UniqueArena<Type>,
    pub special_types: SpecialTypes,
    pub constants: Arena<Constant>,
    pub overrides: Arena<Override>,
    pub global_variables: Arena<GlobalVariable>,
    pub global_expressions: Arena<Expression>,
    pub functions: Arena<Function>,
    pub entry_points: Vec<EntryPoint>,
    pub doc_comments: Option<Box<DocComments>>,
    pub diagnostic_filters: Arena<DiagnosticFilter>,
    pub diagnostic_filter_leaf: Option<Handle<DiagnosticFilter>>,
}

(Exact shape varies; see naga/src/ir/mod.rs for the current definition.)

Everything is in arenas. References are Handle<T> — a NonZeroU32 index into the arena, with no lifetime.

Arenas

naga/src/arena.rs defines:

  • Arena<T> — append-only, ordered, indexable by Handle<T>. Iterating yields (Handle, &T) pairs in insertion order.
  • UniqueArena<T> — like Arena<T> but deduplicates on Hash + Eq. Used for Type so two vec3<f32> declarations are the same handle.
  • Range<T> — range of consecutive handles, used to refer to "the expressions emitted by this expression."
  • Handle<T>NonZeroU32, Copy + Eq + Hash. Free of lifetimes, so the IR is freely cloneable and serializable (with the serialize feature).

Why arenas: graph-shaped data (functions referencing types referencing other types) is awkward in safe Rust with & references. Arenas turn the graph into a flat array; Handle<T> replaces &T. Mutability is handled by mutating the arena and re-emitting handles.

Module subtrees

Concept Type File
Type Type, TypeInner naga/src/ir/mod.rs
Constant Constant naga/src/ir/mod.rs
Override Override naga/src/ir/mod.rs
Global variable GlobalVariable naga/src/ir/mod.rs
Function Function, LocalVariable, FunctionArgument naga/src/ir/mod.rs
Statement Statement naga/src/ir/mod.rs
Expression Expression naga/src/ir/mod.rs
Entry point EntryPoint, ShaderStage naga/src/ir/mod.rs
Diagnostic filter DiagnosticFilter naga/src/diagnostic_filter.rs

Statements vs expressions

Naga distinguishes side-effecting statements from value-producing expressions. A function body is a list of Statements; expressions live in their own arena and statements refer to them by handle.

Important consequence: an Expression in the arena doesn't necessarily appear at any particular point in the function body. Backends and the validator use Function::body to determine where expressions are emitted (made available); see naga/src/proc/emitter.rs.

Type system

Type is the most-shared item, hence the UniqueArena. Notable variants of TypeInner:

  • Scalar — bool, i32, u32, f32, f64, abstractInt, abstractFloat.
  • Vector { size, scalar }.
  • Matrix { columns, rows, scalar }.
  • Atomic { scalar }.
  • Pointer { base, space }.
  • ValuePointer { ... } (used during validation).
  • Array { base, size, stride }.
  • Struct { members, span }.
  • Image { dim, arrayed, class }.
  • Sampler { comparison }.
  • AccelerationStructure, RayQuery (ray tracing).
  • BindingArray { base, size }.

The naga/src/proc/typifier.rs file (~36 KB) computes the type of every expression based on context. The validator (naga/src/valid/expression.rs) re-derives types and checks them.

SpecialTypes

Module::special_types is a small map that records "the canonical handle for this conceptual type" — useful when the validator needs a fresh handle for vec3<u32> (for example for ray-tracing intrinsic results). Frontends and processing passes register special types on demand.

Spans

Each item in the IR can have a Span (naga/src/span.rs) recording its source position. Frontends populate spans; backends typically ignore them; the validator surfaces them in diagnostics. WithSpan<T> is the common error wrapper.

Doc comments

Module::doc_comments carries WGSL doc comments (/// ... style on items). Backends may emit them into target source.

Mutating the IR

Naga's IR is add-only in normal use. To delete or rewrite, build a new module:

  • naga/src/compact/ is the canonical pass that copies a module while dropping unreachable items. Run it after parsing user code or before lowering to a backend.
  • For ad-hoc transformations, walk the source module and emit handles into a new one. Avoid in-place mutation; the borrow-checker patterns in AGENTS.md's notes on the constant evaluator apply broadly.

Adding an IR variant

When adding a new Statement, Expression, or Type variant:

  1. Add the variant in naga/src/ir/mod.rs.
  2. Update naga/src/proc/typifier.rs (if it produces a value) and naga/src/proc/constant_evaluator.rs (if it can be evaluated at compile time).
  3. Update validation in naga/src/valid/. expression.rs, function.rs, analyzer.rs are the usual places.
  4. Update each frontend that should produce the variant (naga/src/front/{wgsl,glsl,spv}/).
  5. Update each backend that should consume it (naga/src/back/{spv,msl,hlsl,glsl,wgsl,dot}/).
  6. Add snapshot test inputs under naga/tests/in/ and run the snapshot harness; commit the regenerated outputs in naga/tests/out/.
  7. Validate the regenerated outputs with cd naga && cargo xtask validate <backend>.

The "butterfly" pattern in docs/testing.md keeps you from having to author one input per backend.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Naga IR – wgpu wiki | Factory