The committedData mesh stamp — typed accessors for the memoized-concat
no-op contract — plus its sibling elementIdMap stamp.
The progressive loaders MEMOIZE their LOD concatenation: an update whose
view state is unchanged and that loaded no new LODs returns the SAME
object reference as the previous update. The commit pipeline stamps that
reference onto the mesh (mesh.userData.committedData) whenever geometry
actually reaches the GPU, so a handler seeing
getCommittedData(mesh) === data knows the GPU already holds this exact
data and can skip the expensive process (nD→3D projection) and upload
steps entirely.
The stamp is load-bearing in BOTH directions:
PRESENCE + identity is the no-op fast-path key (above).
ABSENCE signals LOD demotion: the demoted level's geometry returned to
the evictable pool (and may since belong to another node), so consumers
like the depth-sort coordinator treat a missing stamp as "this mesh's
geometry no longer holds the commit's data".
Presence therefore tests !== undefined, and clearing DELETES the
property (never assigns undefined) — the stamp would otherwise keep the
loader-returned source arrays reachable. (For Mesh this is no longer the
ONLY such reference: rendering/mesh-geometry.ts's own currency stamps —
meshColorsSource / meshNormalSource / meshAScalarSource — also pin
the last committed colour/normal/scalar arrays on the geometry's
userData, independent of this stamp.)
The elementIdMap sibling stamp. Picking needs to translate the
STORAGE SLOT its shaders report (a position in the buffer now on the GPU)
into the ON-DISK element index the per-element label CSR is keyed by. That
map is a property of the committed buffers, not of any loader payload, so
it lives here as a second mesh-level stamp rather than riding on the data
object — a loaded payload can be a SliceCache-owned snapshot whose byte size
was measured at store time, and commit-time mutation of it would both
falsify that accounting and break the cache's never-mutated invariant.
Contract:
indexed by STORAGE slot; the value is the on-disk element index,
written in LOCKSTEP with committedData so it always describes the
buffers currently on the GPU (and cleared with it whenever those buffers
are actually released — see clearCommittedData vs
invalidateCommittedDataStamp),
OPTIONAL: absent ⇒ the identity holds, the slot IS the on-disk index.
Lives in types/ (the bottom layer) so both rendering/ (depth-sort
coordinator, picking) and data/ (commit pipeline, scene loader) share one
definition without violating layer direction.
The
committedDatamesh stamp — typed accessors for the memoized-concat no-op contract — plus its siblingelementIdMapstamp.The progressive loaders MEMOIZE their LOD concatenation: an update whose view state is unchanged and that loaded no new LODs returns the SAME object reference as the previous update. The commit pipeline stamps that reference onto the mesh (
mesh.userData.committedData) whenever geometry actually reaches the GPU, so a handler seeinggetCommittedData(mesh) === dataknows the GPU already holds this exact data and can skip the expensive process (nD→3D projection) and upload steps entirely.The stamp is load-bearing in BOTH directions:
!== undefined, and clearing DELETES the property (never assignsundefined) — the stamp would otherwise keep the loader-returned source arrays reachable. (For Mesh this is no longer the ONLY such reference:rendering/mesh-geometry.ts's own currency stamps —meshColorsSource/meshNormalSource/meshAScalarSource— also pin the last committed colour/normal/scalar arrays on the geometry'suserData, independent of this stamp.)The
elementIdMapsibling stamp. Picking needs to translate the STORAGE SLOT its shaders report (a position in the buffer now on the GPU) into the ON-DISK element index the per-element label CSR is keyed by. That map is a property of the committed buffers, not of any loader payload, so it lives here as a second mesh-level stamp rather than riding on the data object — a loaded payload can be a SliceCache-owned snapshot whose byte size was measured at store time, and commit-time mutation of it would both falsify that accounting and break the cache's never-mutated invariant. Contract:committedDataso it always describes the buffers currently on the GPU (and cleared with it whenever those buffers are actually released — seeclearCommittedDatavsinvalidateCommittedDataStamp),Lives in
types/(the bottom layer) so bothrendering/(depth-sort coordinator, picking) anddata/(commit pipeline, scene loader) share one definition without violating layer direction.