Expand description
A CPU reference executor for iridia::Programs: run a lifted shader on explicit inputs, whatever bytecode it came
from, and read back exactly what it wrote. It is for checking a translation, not for rendering: it is bounded,
deterministic and slow.
Executable::new checks a program and compiles it once into a flat form (typed operations on four-lane word
registers, pointers folded to word offsets, dead operations dropped). Executable::bind flattens the buffers a
program reads once for many runs, and a Runner executes the program for one invocation, a 2 x 2 quad, or several
invocations in lockstep (masked where they diverge, each with its own steps and budget), asking its Backend for
everything outside the program: texture samples, loads and queries, and the effects of writes to unordered-access
views. ProgramShader puts a vertex or pixel program behind PixelShader, in the register vocabulary of the D3D
bytecode it came from. The other stages have their own drivers: mesh, geometry, tessellation and
tessellator (a model of the fixed-function tessellator), Pipeline (a ray tracing pipeline over a Scene),
draw (a small software rasterizer over vertex and pixel programs) and probe.
What a run does follows the program’s iridia::D3dModes: a program that says its body spells out D3D’s integer
division, conversions and min/max runs as written, and one that expects denormals flushed to zero has every
32-bit float operation flush its operands and result (sign kept). Anything the program does that the module cannot
make valid (an index past the end of a local array, an integer division by zero in the module) is an error of the
run, never a silent value. Every run has a step budget (STEP_LIMIT).
Sampling belongs to the caller: texture samples are answered by a Sampler callback (a closure answers 2D
samples), because a scalar execution cannot infer derivatives, filtering or addressing, and the caller states them.
evaluate() runs a pixel shader over a grid of UVs and evaluate_periodic over a tiling block.
§Example
Lift a pixel shader and run it once. Its constant buffer holds f = (0.25, 2, 4, 8) and u = (7, 2, 0, 0); the
HLSL computes min(f.x, f.y), max(f.x, f.y) into target 0 and u.x / u.y, u.x % u.y into target 1:
use iridia_exec::{PixelShader, ProgramShader, Sample};
let program = iridia_dxbc::lift(include_bytes!("../../iridia-dxbc/tests/fixtures/modes.dxbc"))?;
let shader = ProgramShader::new(program)?;
let bits = |v: [f32; 4]| v.map(f32::to_bits);
let constants = [bits([0.25, 2.0, 4.0, 8.0]), [7, 2, 0, 0], [0; 4]];
let inputs = vec![[0u32; 4]; shader.input_count()]; // SV_Position, which the program never reads
let run = shader.execute(&inputs, &[(0, &constants)], &mut |_: Sample| Err("no textures".into()))?;
assert_eq!(f32::from_bits(run.outputs[0][0]), 0.25); // min(f.x, f.y)
assert_eq!(f32::from_bits(run.outputs[0][1]), 2.0); // max(f.x, f.y)
assert_eq!(&run.outputs[1][..2], &[3, 1]); // 7 / 2, 7 % 2Re-exports§
pub use evaluate::Evaluation;pub use evaluate::Field;pub use evaluate::Grid;pub use evaluate::Input;pub use evaluate::Invocation;pub use evaluate::Lane;pub use evaluate::Layout;pub use evaluate::Raw;pub use evaluate::evaluate;pub use evaluate::evaluate_raw;pub use evaluate::evaluate_raw_with;pub use evaluate::evaluate_with;pub use texture::Filtering;pub use texture::SampledTexture;pub use texture::SamplerUse;pub use texture::Unstated;pub use views::Absent;pub use views::Image;pub use views::View;pub use views::Views;
Modules§
- draw
- A draw on the CPU, as Direct3D draws an indexed triangle list: the vertex program for each vertex, each triangle clipped, mapped through the viewport and rasterized, the pixel program for each pixel it covers, the depth test, and the render targets written. It is for re-running a draw recorded from a running game on the programs the record names, so its pixels can be set against the ones the game wrote.
- evaluate
- Evaluate a pixel shader over a UV grid, to bake a procedural material to textures. The caller states everything the program reads (constant layout and values, a texture per sampled slot, a value per used input) and which output registers it wants; the evaluator has no game names and no policy, and refuses what it is not given.
- geometry
- A geometry program on the CPU: what the input assembler does before it and what a draw does around it, since WGSL
has no geometry stage.
Topologyassembles a draw’s vertices into the primitives the program reads (with the adjacent vertices of the*Adjacencytopologies),GeometryShader::drawruns the program for every primitive and every one of its instances and returns the strips it emitted, andStrip::primitivesassembles a strip’s vertices into the points, lines and triangles they make. - mesh
- A mesh program on the CPU: a thread group that writes one meshlet.
MeshShader::drawruns the thread groups of a dispatch one after another and returns the meshlet each wrote: its vertices (one register per output varying, as a geometry program’s emitted vertices are,MeshShader::outputsnames them) and its primitives (the indices of their vertices). What the rasterizer does with them is the pipeline’s. - probe
- One vertex of a vertex program, run to see what it does with chosen constants: the clip position a probe reads to learn what a constant is (a matrix the program places the vertex with, a table it reads the instance through).
- ray_
flags - A ray’s flags, as DXR numbers them (and naga’s
RayFlagafter them). - tessellation
- A tessellated patch on the CPU: the hull program for each output control point and for the patch’s constants, the
fixed-function tessellator (
super::tessellator) over the factors the hull program wrote, and the domain program for each point it made. WGSL has no tessellation stages, so this is how to draw a patch from lifted programs. - tessellator
- The Direct3D 11 fixed-function tessellator: from the tessellation factors of a patch, the points of its domain and how they connect.
- texture
- A 2D texture as the executor samples it (
SampledTexture, anImage): its stored levels, the colour transfer applied before filtering, the addressing (with a border’s colour), level-of-detail bias and level range its binding’s sampler states (SamplerUse), and the filtering a caller states (Filtering). - value
- A node of a program’s value graph (
iridia::flow::Values) evaluated from the words of the leaves it reads, with the executor’s own operations: what a run of the program computes for that lane where it is given the same leaves, bit for bit. The caller answers the leaves (an input lane, a supplied value, a global’s word, a texel, a query) or leaves them unknown; a node that needs an unknown leaf is unknown, naming it. A select whose condition is unknown is known where both its values are and are the same bits. - views
- Resource views bound by slot (
Views), answering a program’s requests. Where nothing is bound or an address falls outside a view, they answer as their policy states (Absent): as Direct3D answers (Absent::Zero, the rules below), or by refusing, naming the slot or address (Absent::Refuse: an evaluation runs on no value it was not given). The rules are the D3D11.3 functional specification’s, stated here once:
Structs§
- Atomic
Add - An atomic add (
imm_atomic_iadd) to the 32-bit word of an unordered-access view ataddress: a structured view’s element and byte offset in its first two lanes, a typed view’s x, y (and z) otherwise (0 where the view has fewer). - Bound
- The buffers a program reads, ready for runs: built once per program and reused for every pixel.
- Built
- A scene with its hierarchies.
- Call
Shader CallShader: run the callable programindexof the shader table on the words of a parameter structure.- Dispatch
Stats - What a dispatch did.
- Dispatched
- What a compute run did.
- Element
- A resource of the program’s interface and, for an array of them (
binding_array), the element the program’s index picked (0 for a resource that is not an array). An index past a bounded array’s length is an error that stops the evaluation (D3D12 leaves it undefined, so there is no answer to compare); the length of an unbounded array is the caller’s to check. - Error
- An evaluation or binding error, located in the implementation’s own terms (a DXBC word, a DXIL value).
- Executable
- A program compiled once into a flat form: typed operations on four-lane word registers, static pointer arithmetic
folded, bitcasts aliased, dead operations removed. Running it is
Runner’s. - Execution
- What one evaluation wrote.
- Geometry
- One geometry of a bottom level: triangles, or (when
boxesis not empty) procedural primitives, each an axis-aligned box the program intersects itself. - Image
Atomic - An atomic operation on one texel of a single-channel 32-bit unordered-access texture. Its result is the word as it was
before; the program reads it when its
Statement::ImageAtomichas a result. - Image
Load - A texel load (
ld,ld_ms, a typed unordered-access load). - Image
Query - A
resinfo-style query. - Image
Sample - A sample of any texture: 1D, 2D, 3D, cube, arrayed, with an offset, a gather or a comparison.
- Image
Store - A write to an unordered-access texture.
- Instance
- An instance of a bottom level in the top level.
- Instance
Flags - What an instance does besides place its bottom level.
- Load
- A load request (
ld): one texel by its integer address, without a sampler. - Output
- What one invocation produced.
- Pipeline
- A ray tracing pipeline: the programs of a library, its hit groups and the application’s shader table.
- Pipeline
Resources - What a dispatch binds besides the programs: the constant buffers of the root signature, by register and space, and the acceleration structure all the programs trace into.
- Program
Shader - A pixel program with the register view the D3D readers’ callers use.
- Report
Hit ReportHit: an intersection program reports a hit attof kindhit_kind, with the words of its attributes.- Resources
- What a run reads besides its inputs: constant buffers (rows of four lanes) and buffers (32-bit words), by resource.
- Runner
- Runs an
Executablefor a 2 x 2 quad in lockstep (N= 4: lanes 0 and 1 the top row, 2 and 3 the bottom), as a GPU does: lanes that diverge are masked, a screen derivative is a difference inside the quad, a lane that is discarded goes on as a helper. Any otherNruns that many invocations of their own (N= 1, one), in lockstep and masked where they diverge, each as it would run alone: its own steps and budget, a discard ending it, the derivatives of its inputs the ones the caller gives for every lane. A runner is reused for any number of runs. - Sample
- A sample request of a 2D texture (or a 2D array’s layer).
- Scene
- The bottom levels and the top level of an acceleration structure.
- Scratch
- The registers and local memory of a
Runner, kept from one run of a program to the next so that the literals are written once and nothing is allocated per pixel. - Shader
Table - The application’s shader table: the program each index selects, by the export name the library gives it.
- Store
- A store request (
store_uav_typed,store_structured). - Trace
Ray TraceRay: a ray shot into an acceleration structure. The payload is the words of the program’s payload structure, which the programs the ray runs read and write; the caller leaves it as the ray’s last program did.- Wide
- Up to 1024 lanes. A lane past them is in no set, and inserting it or removing it changes none.
Enums§
- Decision
- What a ray tracing program decided about the hit it was offered, besides its payload.
- Dim
- A texture’s shape as a request states it.
- Image
Atomic Op - What an atomic operation on a texel does with the word it holds and the program’s value.
- Image
Lod - How a request picks its level of detail. Gradients are three components wide: a 1D or 2D texture leaves the rest 0.
- Lod
- How a sample request picks its level of detail.
- Query
Kind - Which property of a texture a query reads.
Constants§
- STEP_
LIMIT - The most operations and loop turns one invocation may execute: a program that does not end is refused.
Traits§
- Backend
- Everything an evaluation asks of its caller: texture sampling, loads, queries, and the effects of unordered-access writes. A request the caller cannot answer is an error that stops the evaluation. Reads of buffers need no call: the buffers are bound before the run.
- Mask
- A set of the lanes of a run.
- Pixel
Shader - A checked pixel shader that can be evaluated.
- Sampler
- Answers sample, load, store and structured-buffer requests; an error stops the evaluation. A closure answers samples only.
Functions§
- evaluate_
periodic - Evaluate
shaderas a texture that tiles with periodcells(K, at least 2) cells oftexelspixels each (module documentation): each requested target is (K * texels)^2 values in row-major order, orNonewhen the program does not write it. The evaluation grid, (K + 1) * texels pixels per axis, is at most 4096.textures,inputsandtargetsare ascrate::evaluate()takes them; the grid’s U and V (crate::Lane::U,V) run one per cell. The instruction and sample counts are the grid’s. - evaluate_
periodic_ with evaluate_periodicwith the grid evaluated onthreadsthreads (crate::evaluate_with): the same bake on any count.
Type Aliases§
- Constants
- The rows of constant buffers, by (register, space).