iridia-exec-ir
Runs a program of iridia's shader IR on the CPU, one invocation or a pixel program's 2 x 2 quad, by the IR's own definition of each operation: the reference the passes and lowerings are checked against.
Part of iridia, which turns compiled shaders into programs other tools can read and write. The design is docs/design/ir.md. This crate does no I/O.
What it runs
run(program, bound)takes the program and aBound: each input slot's lanes, each constant buffer's rows, each pipeline state resource's value, and a sampler the caller answers eachSamplewith (the texture and sampler ids, the coordinate's lanes, the level of detail). It gives aRun: each output slot's lanes as last stored (a lane never stored is zero, a slot never storedNone) and whether the invocation was killed.run_quad(program, bounds)runs a pixel program's quad, aBoundper lane (lanes 0 and 1 the top row). A derivative is a difference between lanes: the right lane's less the left's along x, the lower's less the upper's along y, of the top row or left column when coarse (and forFineness::Any, asiridia-exectakes it), of the lane's own when fine. An implicit-LOD sample is asked with the quad's coarse derivatives of its coordinate (Lod::Grad,Lod::GradBias). A demoted lane (a discard) goes on as a helper the others still read. The lanes run one after another with no threads, each until it meets a derivative or implicit-LOD sample whose operands are not all known, then again knowing them; lanes that do not meet it at the same operation and loop iteration are refused as divergent, and so is a run of more thanMEETING_LIMITmeetings.needs_quad(program)says whether a program's results depend on its quad.- Both body forms: every construct of a
Regionsbody, and the blocks of aCfgone (block parameters copied in parallel). A run of more thanSTEP_LIMITloop iterations or block executions is refused. - The arithmetic is the reference
iridia-execuses: IEEE 754f32for the basic operations, the transcendental functions (exp2,log2,sin,cos,sqrt,inverseSqrt,pow) inf64rounded once, a dot product summed left to right with each step rounded. Denormals are kept. Each operation's enum decides the rest: a zero-wins multiply, a NaN rule ofminandmax, ties away from zero.
Example
use ;
let entry = parse
.unwrap;
let varying = ;
let program = Program ;
validate.unwrap;
let mut sampler = ;
let inputs = ;
let mut bound = Bound ;
let run = run.unwrap;
// zero wins: 0 * inf is +0, not NaN; the lanes past the output's width are zero
assert_eq!;
assert!;
Guarantees and limits
- This subset runs 32-bit scalars and vectors, constant buffer reads, pipeline state, samples, derivatives in a quad, demotion and kill; anything else (memory other than variables and constant buffers, other widths) is refused by name, not approximated.
- A program whose float environment leaves denormals open runs by
Bound::denormals; one that states a rule runs by it. runruns one invocation, which has no derivatives: it refuses a derivative, and an implicit level of detail isLod::Auto, for the caller's sampler to decide.- A quad's sampler may be asked a request again, once per pass that reaches it, and must answer it the same way each time.
Tests
cargo test -p iridia-exec-ir needs no game files: tests/fixtures.rs runs programs in IR text on inputs whose results are worked by hand from the operations' definitions (the NaN and rounding rules, zero-wins multiplication, saturating conversion, lane masks, a loop, a kill; a quad's coarse and fine derivatives, a derivative in a loop, a divergent quad refused, an implicit-LOD sample's footprint) and checks the text parser's refusals.
Licence
GPL-3.0-or-later.