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 byHandle<T>. Iterating yields(Handle, &T)pairs in insertion order.UniqueArena<T>— likeArena<T>but deduplicates onHash + Eq. Used forTypeso twovec3<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 theserializefeature).
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:
- Add the variant in
naga/src/ir/mod.rs. - Update
naga/src/proc/typifier.rs(if it produces a value) andnaga/src/proc/constant_evaluator.rs(if it can be evaluated at compile time). - Update validation in
naga/src/valid/.expression.rs,function.rs,analyzer.rsare the usual places. - Update each frontend that should produce the variant (
naga/src/front/{wgsl,glsl,spv}/). - Update each backend that should consume it (
naga/src/back/{spv,msl,hlsl,glsl,wgsl,dot}/). - Add snapshot test inputs under
naga/tests/in/and run the snapshot harness; commit the regenerated outputs innaga/tests/out/. - 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.