Skip to main content

Crate iridia

Crate iridia 

Source
Expand description

Compiled Direct3D shaders as naga modules, so they can be validated, inspected and written as WGSL, SPIR-V or whatever else a naga backend writes.

This is the crate every bytecode reader of the iridia workspace lifts into. A Program is a naga::Module with what a module cannot say: an Interface (inputs and outputs by semantic name with their D3D register and lanes kept in provenance, constant buffers with explicit layouts, textures, samplers and buffers), the clip-space and texture-origin Conventions it was written for, which of Direct3D’s numeric behaviours its body spells out (D3dModes) and where it came from (Provenance). The readers are separate crates: iridia-dxbc (Shader Model 4 and 5), iridia-dxil (Shader Model 6), iridia-d3d9 (raw Shader Model 2 and 3 tokens) and iridia-mojo (the GLSL MojoShader writes from Shader Model 2 and 3).

§Example

Lift a compiled pixel shader, check it and write WGSL (iridia-dxbc is a development dependency of this crate; a program of your own depends on it directly):

let container = include_bytes!("../../iridia-dxbc/tests/fixtures/modes.dxbc");
let program = iridia_dxbc::lift(container)?;

assert_eq!(program.stage, iridia::Stage::Pixel);
assert_eq!(program.provenance.target, "ps_5_0");
// the constant buffer `C` of the HLSL source, named by the container's reflection
assert_eq!(program.interface.resources[0].provenance.name, "C");

program.validate().expect("a lifted program validates");
let wgsl = iridia::emit::wgsl(&program)?;
assert!(wgsl.contains("@fragment"));

§What is here

  • Program, its validate (naga’s validation, then the interface against the entry point and the resources against the module’s globals) and text (a stable text form, for diffs);
  • emit: WGSL writers, and emit::wgsl_for, WGSL as one pipeline binds it;
  • build::Builder, the typed builder over naga’s IR the readers lift with, and build::structure, which turns a control flow graph into structured control flow;
  • d3d: Direct3D’s enum numbers and packing rules mapped into the iridia_interface vocabulary, shared by the DXBC and DXIL readers;
  • Refusal: what every reader returns for bytecode it cannot lift, naming where and why;
  • gate: the version check a reader’s tests use so that a changed output comes with a bumped version number;
  • analyses of a lifted program, none of which runs it: flow (what each output lane is made of), matrix (how a constant buffer holds a matrix), output_stores and output_uses (what the entry point stores into its outputs and what a discard or blend shows a lane is used for), and Program::constant_reads (which constant words it reads);
  • rt: the calls a ray tracing program makes in place of the pipeline’s operations.

Running a program on the CPU is the iridia-exec crate.

The vocabulary types are those of iridia_interface, re-exported here.

Re-exports§

pub use bound::BoundSizes;

Modules§

blend
Layers a program lays over one another, read from its value graph (Values) with no game in it: a lane that is a chain of interpolations, each towards a layer’s value by a weight (Over), and any scalar value as the float operations it is made of (Scalar), down to the nodes the caller says what they are of (an input lane, a texel, a constant word).
bound
The size a constant buffer is bound with.
build
A typed builder over naga’s IR for lifters. Every value it hands out carries its scalar kind and width, so a lifter never asks naga’s typifier and a bitcast or splat is explicit where it is needed. Nothing here knows a bytecode; behaviour holds D3D’s results spelled out as operations.
d3d
D3D’s enum numbers and packing rules, mapped into the vocabulary (iridia_interface). The DXBC and DXIL readers share them: both state signatures and constant buffers in D3D’s terms. Nothing here is evaluation; a number the table does not map is refused with its name (an Err the reader reports), never guessed.
emit
Writers: a Program as source text for another API. A writer that cannot express a program refuses it with the reason; it never approximates.
flow
What a program’s outputs are made of: a dataflow query over the lifted module, with no game in it.
gate
The version gate of a lifter. A lifter’s LIFTER_VERSION and the program representation’s crate::PROGRAM_VERSION are what a cache keyed by a bytecode’s hash trusts to know that a program it holds is stale, so a change to what a lifter makes of a bytecode must come with a bump. The gate makes that checkable: a lifter’s tests lift its committed fixtures, table hashes each outcome (the program’s stable text form, or the refusal) under the versions the lifter has, the table is committed, and check fails when the outcomes changed and the versions did not (bump the one that names the change), or the versions changed and the committed table is not that version’s.
matrix
How a program holds a matrix in a constant buffer: the arrangement of its lines, read from what the program does.
output_stores
What a program’s entry point stores into its outputs, lane by lane, read from its lifted module: for each output the interface declares, the local variable the entry point’s result takes it from, and the stores into that variable’s lanes, in every branch. OutputStores gives a colour target’s lanes (SV_Target<n>) and the constant rows an output is made of, and tests how a stored value is made (x * 0.5 + 0.5, floor(x) / 256, a square root, the constant 0), seeing through the bit casts the lifters write every output word with and the loads of a local variable assigned once. Nothing here is read from a program’s name or a local’s name; what the lanes mean is for the caller to say.
output_uses
What a pixel program’s own discards and its targets’ stated blend show its output lanes are used for (output_uses), and what its discards compare a constant word with (discard_compares, alpha_tests). These are observations of the program and its state; what they make a lane or a word stand for is the caller’s to decide. Nothing is read from a program’s or a target’s name.
rt
The ray tracing pipeline’s operations. WGSL has no ray tracing pipeline and naga’s has no ReportHit, IgnoreHit, CallShader or hit-group indices, so a ray tracing program (see crate::stage_functions) does what the pipeline does for it by calling functions of its own module that have no body: the call is the operation, the arguments its operands, and a consumer that traces rays reads the calls. A stub’s body is empty (a function that returns a value returns false), so nothing that runs the module as written runs the pipeline.
specialise
Conservative material specialisation. Only explicitly supplied uniform words are constants. The original program remains unchanged; unsupported control flow is refused rather than guessed.

Structs§

BufferLayout
A constant buffer’s contents.
Constant
One named constant of a buffer.
Conventions
The pipeline rules a program was written for, declared where it meets the pipeline (the vertex stage’s clip position, the pixel stage’s fragment position and texture coordinates) and applied once at that boundary by whoever runs it on another API’s rules; the body itself is never rewritten for them.
D3dBinding
A D3D bind point: class, register index and register space.
D3dModes
Which of D3D’s behaviours the body spells out. The IR’s own results for these differ between the APIs that lower to it (WGSL defines integer division by zero as the dividend, SPIR-V leaves it undefined), so a D3D lifter writes D3D’s answer as plain operations and says it did: a consumer that finds a flag unset knows the body takes the IR’s answer there, and a writer never has to guess.
D3dSignature
Where a D3D signature element sits: its register (four 32-bit lanes each) and the lanes of it the element occupies, as a mask (bit k is lane k, x first), and the signature’s read/write mask as stored.
DomainFacts
What a domain program states about its patch: the same domain as the hull program that feeds it, how many control points it reads, and the patch-constant varyings it reads (inputs of the interface are its control points’).
EntryIo
The entry point’s arguments (one per input varying) and result members (one per output varying, the clip distances being one together), in interface order. A varying nothing reads or writes (used false) that no binding exists for is left out: the interface lists every element of the container’s signature, the module carries what it can.
FnItem
One argument or result member of a stage function.
FunctionSig
A function of a program that has no entry point: its name, arguments and result members (a structure Out when there are any).
GeometryFacts
What a geometry program states: the primitive it reads, what its emitted vertices make, the most vertices an invocation emits and how many invocations run for a primitive.
HitGroup
A hit group of a ray tracing library: the programs it runs, named by the library’s exports (none where the group has no such program).
HullFacts
What a hull program states about its patch beyond its varyings. The patch-constant varyings are its outputs per patch (SV_TessFactor, SV_InsideTessFactor, whatever the domain program reads); outputs of the interface are its control points’.
InstructionCount
How many instructions a program has, in the unit that says how they were counted.
Interface
What a program exposes: its stage, the varyings it takes and gives, and the resources it binds.
Interpolation
A pixel input’s interpolation: the mode and the sampling location.
IoItem
One argument or result member.
Label
A varying’s name in its source: the semantic name and its index (DXBC TEXCOORD and 5, SPIR-V Location and 3, GLSL vUv and 0). Labels are not interpreted: games put anything in TEXCOORDn, and what a label means is the consumer’s business. Stages match by label.
Member
A structure’s member: its offset is from the start of the structure.
MeshFacts
What a mesh program states: what its primitives are and the most vertices and primitives it writes. Its thread group size is the entry point’s, as a compute program’s is.
Program
A shader program: the module, and what the module cannot say.
ProgramGraph
What a binding takes from a lifted program: its value graph, the interface the graph names resources by (a program lifted again may number them otherwise than a stored interface), and the constant words its results are made of.
Provenance
Where a program came from.
RayTracingFacts
What a ray tracing program’s library states: the program’s own export name (as the subobjects name it) and every subobject of the library, in the order it stores them. A pipeline is built from a library’s programs and these.
Refusal
A program a lifter did not lift, or a container it could not read: the bytecode, where in it and the reason, by name. The reason is stated whole, numbers included; Refusal::group is the key to count refusals by.
Resource
One bound resource.
ResourceId
Names a resource within one super::Interface; the reader numbers them in its source’s order.
ResourceProvenance
The source’s own name and address for a resource; one field per API that has a notion of it.
Value
A scalar type and a width of 1 to 4 lanes.
Varying
One interface variable: a value passed between stages (or between a stage and the pipeline), one per label. D3D packs several into one register; they are separate here, with the register and lanes kept in provenance.
VaryingProvenance
The source’s own address of a varying; one field per API that has a notion of it.
WordsRead
The words of each constant buffer a program’s results are made of: every word some output lane, discard condition or write (Values::writes) of the value graph reaches back to, at the word’s place in the buffer (row r, lane l is word 4r + l). A buffer read at an index computed at run time may be read at any word. A word a computation reads and nothing uses is not read. The reads are what the program may use, not what it must: a word multiplied by zero at run time still counts.

Enums§

Access
What a program may do to a storage resource.
BufferKind
How a buffer’s elements are addressed.
ClipDepth
Which way clip space’s depth runs.
ConstantType
The type of one constant, with the layout it has in its buffer written out: vectors are tightly packed lanes, every matrix line and array element sits at a stated stride, whatever packing rules (D3D, std140, std430, DX9 registers) put it there.
D3dClass
The register class of a D3D binding: b, t, s or u.
GsInput
The primitive a geometry program reads.
GsOutput
What a geometry program’s emitted vertices make.
HitGroupKind
What a hit group runs for the geometry it is bound to.
InstructionUnit
The source’s counting unit. DXBC counts decoded instructions including control flow, excluding declarations; DXIL counts LLVM instructions in the functions the lifter reads. Neither is an executed instruction count or an IR expression count.
InterpMode
How a varying is interpolated across a primitive.
InterpSampling
Where in a pixel a varying is sampled.
IoType
The type of an entry point argument or result member.
ItemList
What a FnItem carries.
Majorness
Whether consecutive lines of a matrix are its rows or its columns.
MeshTopology
What a mesh program’s primitives are.
Origin
Which way a vertical axis runs.
Partitioning
How the tessellator spaces the vertices it adds along an edge.
Problem
One rule a program broke.
ProgramError
What can go wrong building, checking or writing a program.
ResourceKind
What a resource is.
SampleType
What a texture returns when it is read.
ScalarType
The scalar type of a value or constant.
ShaderFormat
How a shader program’s bytes are encoded. Only the encoding lives here; reading one is the job of the crate that knows it (iridia-dxbc, iridia-dxil, iridia-d3d9, iridia-mojo), and the program’s meaning is lifted from it on demand.
Stage
The pipeline stage a program runs in.
StageFacts
Facts about a program a stage’s varyings and resources do not carry.
StorageTarget
What a storage resource is.
Subobject
A state object subobject of a ray tracing library, as the library declares it.
SystemValue
The system values, one vocabulary for every API: what the pipeline itself supplies to or takes from a stage.
TessDomain
The shape a tessellator gives a patch.
TessTopology
What the tessellator emits.
TextureDim
The dimensionality of a texture or image. Whether it is an array or multisampled is separate.
Unit
What an offset in a Refusal or an crate::Origin counts, in the source’s own terms.

Constants§

PROGRAM_VERSION
The version of the program representation: bumped when what a program means changes (a convention, a mode, how the module carries the interface). Each lifter’s tests hash what it makes of its fixtures under this and its own version (iridia::gate), so a change that moves them without a bump of one of the two fails.
WEBGPU_BASELINE
WebGPU’s default limits: invocations per workgroup, size along x, y and z, and bytes of workgroup memory.

Functions§

compute_limit_notes
Notes for a module whose compute entry point exceeds WEBGPU_BASELINE: empty when it fits.
entry_io
The entry point’s arguments and result members for interface. Err says why the module cannot carry it (a system value no stage binding exists for).
interface_notes
Notes for an interface that carries something WebGPU has no built-in for.
mesh_vertex_io
The members of a mesh program’s vertex type, one for each output varying, bound as a vertex program’s outputs are.
source_hash
The hash of the bytes a lifter was given (sha256: and 64 hexadecimal digits), which a program keeps as its source’s identity in crate::Provenance::source_hash: the lifter computes it, the caller does not state it.
stage_functions
The functions a program of a stage naga has no entry point for is made of; None for a stage that is an entry point. The arguments carry no bindings: they are named after the varying they carry, as an entry point’s are.