indicatrix-dispatch
Sample-range and work-item scheduling for indicatrix render lanes.
indicatrix-dispatch is the scheduler a render coordinator runs: several backends
("lanes" — a joined remote worker, the coordinator's own CPU/GPU, anything
implementing WorkerLane) contribute disjoint absolute sample ranges to one
image, and their per-chunk radiance sums are merged into one buffer with an exact
sample count. It holds no networking, no GUI and no GPU code; it depends only on
indicatrix-net (for SceneState) and glam, so both the worker binary and the
desktop app can link it.
Why merging by plain addition is sound
A path sample is identified by (global_pixel_index, absolute_sample_index) and
nothing else, on every backend. Any set of backends tracing disjoint sample
ranges of the same scene at the same resolution therefore merges by per-pixel
addition, divided by the total count. Disjointness is the whole correctness
guarantee, and SampleCursor provides it by construction.
Main types
SampleCursor— the atomic claim point handing out disjoint sample ranges.WorkerLane,ChunkResult,SampleRange— what a lane is, what it is asked to trace and what it returns.RateModel,ChunkPolicy— per-lane throughput calibration and chunk sizing (ChunkPolicy::fixedfor a timing-independent partition).LanePool/PoolConfig— N lanes against one cursor for one image epoch, with failure reclaim, backoff, retirement, cancellation andPoolEvents.Merger— the deterministic merge of chunk sums (see below).ItemQueue— whole-item distribution (catalogue batches) over N lanes.CancelToken— a cloneable cancellation flag.
Determinism
Chunks finish in whatever order the lanes finish them. Merger does not add them on
arrival; it folds them in ascending first_sample order, parking early arrivals
until the chunk at the frontier comes in. For a given partition of the range into
chunks, the merged buffer is therefore bit-identical no matter which lane traced which
chunk or in which order they finished. The partition itself depends on measured rates
unless ChunkPolicy::fixed is used (and no lane fails); different backends are never
bit-identical to each other anyway (GPU fma fusion).
Who uses it
apps/indicatrix-worker's coordinator (serve) — fans a viewer's render or final-image request out as aLanePooljob over joined workers plus its own lane, and emits theMerger's result.apps/indicatrix-cut— its live render loop's sample cursor (bridge::sample_cursor) is this crate'sSampleCursor.
Testing
cargo test -p indicatrix-dispatch
Every test lives inline next to its module (sample_cursor, rate, merge,
item_queue, pool); the pool tests drive fake lanes, so no network or GPU is
needed.