Streaming policy for the progressive loaders (GSplats, Points, Lines, and
the Mesh reveal ladder).
A progressive loader streams an additive LOD ladder coarse→fine. HOW MANY
levels a single updateView pass loads — and when it stops — depends on why
the pass is running. Encoding that decision as pure functions keeps the
geometry loaders' streaming loops identical by construction (they share
this module rather than each re-deriving the rule), and makes the policy
unit-testable in isolation.
The three disciplines:
playback — foreground, under a per-frame budget (a dimension is
playing/scrubbing). Responsiveness dominates, so a cold level is never
worth blocking on. Whether the pass starts EMPTY or restores a cached
prefix, it streams levels that come back CACHE-RESIDENT until the budget
is spent, stopping at the first cold or slow one exactly as refine does.
It used to load LOD 0 and nothing else, on the reasoning that even a
resident level costs ~10-20 ms of dequant+project. That is true, and the
budget deadline is what bounds it — but a level-1 gate is the wrong
instrument, because it assumes LOD 0 is a usable picture. On a node the
viewer SLICES it is not: an additive ladder's rungs are sized against the
WHOLE node, so on a 500-timepoint gsplat leaf LOD 0 is ~42 splats of a
166,443-splat frame and playback rendered an empty screen (#2374, #2376).
Streaming the resident levels costs approximately no network — the coarse
rungs of a sliced ladder are small enough to sit in ONE chunk each, so
they are fetched once and serve every slice — and the worst case is
unchanged at one cold load per pass, since the first cold level still
stops the loop.
Quality is still deepened for later loops by the background prefetch
pass; foreground playback only spends budget remaining in the current
tick.
prefetch — background shadow pass warming the next timepoint. No
first-paint constraint, so it deepens toward the FULL decoded ladder (the
only thing that yields the single-concat fast revisit); it never stops at
a cache miss and is bounded only by the pass budget + abort.
refine — foreground with no budget (a static view, or the refine-on-
pause pass). Stream cache-resident levels and stop at the first cold/slow
one so the frame renders; a later pass picks up the rest.
pinned — a pinned ladder depth is set (ViewState.ladderDepth, the
playback "detail" setting), foreground or shadow. The loader bounds its
loop at the pinned rung count, and neither the deadline nor a cold level
stops it before that bound — a frame is drawn at the pinned depth or the
tick waits. Takes precedence over the other three. Only the refinement
residency allowance still applies.
Streaming policy for the progressive loaders (GSplats, Points, Lines, and the Mesh reveal ladder).
A progressive loader streams an additive LOD ladder coarse→fine. HOW MANY levels a single
updateViewpass loads — and when it stops — depends on why the pass is running. Encoding that decision as pure functions keeps the geometry loaders' streaming loops identical by construction (they share this module rather than each re-deriving the rule), and makes the policy unit-testable in isolation.The three disciplines:
playback— foreground, under a per-frame budget (a dimension is playing/scrubbing). Responsiveness dominates, so a cold level is never worth blocking on. Whether the pass starts EMPTY or restores a cached prefix, it streams levels that come back CACHE-RESIDENT until the budget is spent, stopping at the first cold or slow one exactly asrefinedoes.It used to load LOD 0 and nothing else, on the reasoning that even a resident level costs ~10-20 ms of dequant+project. That is true, and the budget deadline is what bounds it — but a level-1 gate is the wrong instrument, because it assumes LOD 0 is a usable picture. On a node the viewer SLICES it is not: an additive ladder's rungs are sized against the WHOLE node, so on a 500-timepoint gsplat leaf LOD 0 is ~42 splats of a 166,443-splat frame and playback rendered an empty screen (#2374, #2376). Streaming the resident levels costs approximately no network — the coarse rungs of a sliced ladder are small enough to sit in ONE chunk each, so they are fetched once and serve every slice — and the worst case is unchanged at one cold load per pass, since the first cold level still stops the loop.
Quality is still deepened for later loops by the background
prefetchpass; foreground playback only spends budget remaining in the current tick.prefetch— background shadow pass warming the next timepoint. No first-paint constraint, so it deepens toward the FULL decoded ladder (the only thing that yields the single-concat fast revisit); it never stops at a cache miss and is bounded only by the pass budget + abort.refine— foreground with no budget (a static view, or the refine-on- pause pass). Stream cache-resident levels and stop at the first cold/slow one so the frame renders; a later pass picks up the rest.pinned— a pinned ladder depth is set (ViewState.ladderDepth, the playback "detail" setting), foreground or shadow. The loader bounds its loop at the pinned rung count, and neither the deadline nor a cold level stops it before that bound — a frame is drawn at the pinned depth or the tick waits. Takes precedence over the other three. Only the refinement residency allowance still applies.