Byte-tracking containers for the GPU buffer pool's two kinds of residency.
GPUBufferPool.getResidentBytes() is the single source of truth for the
VRAM budget and is queried by the LOD registry every frame and by the
byte-eviction pass on every acquire/release. It used to walk every active
and pooled buffer on each call; these containers keep the totals
INCREMENTALLY instead, so the query is O(1) (B9b, #2944).
They are drop-in Map subclasses so every existing reader (adapters,
evictor, stats, tests) keeps working unchanged. The contract that keeps the
totals exact:
ActiveBufferMap: every set / delete / clear adjusts the total.
Replacing a key subtracts the bytes charged to the previous entry.
FreeBucketMap: the bytes charged to each bucket are remembered, and
set(bucket, array) / delete(bucket) / clear() RESYNC that bucket
(subtract what it was charged, charge what it now holds). So an in-place
array mutation (push / splice) is exact as soon as it is followed by
a set or delete of that bucket. pushBuffer / takeAt /
removeBuffer do both in one call and are what the pool uses.
Bytes are charged with estimateGeometryBytes, cached per geometry, and the
exact amount charged is what is later subtracted — so the totals cannot
drift even if a geometry's cached size were invalidated while resident (no
production code does that: pooled geometries have a fixed capacity).
Byte-tracking containers for the GPU buffer pool's two kinds of residency.
GPUBufferPool.getResidentBytes()is the single source of truth for the VRAM budget and is queried by the LOD registry every frame and by the byte-eviction pass on every acquire/release. It used to walk every active and pooled buffer on each call; these containers keep the totals INCREMENTALLY instead, so the query is O(1) (B9b, #2944).They are drop-in
Mapsubclasses so every existing reader (adapters, evictor, stats, tests) keeps working unchanged. The contract that keeps the totals exact:ActiveBufferMap: everyset/delete/clearadjusts the total. Replacing a key subtracts the bytes charged to the previous entry.FreeBucketMap: the bytes charged to each bucket are remembered, andset(bucket, array)/delete(bucket)/clear()RESYNC that bucket (subtract what it was charged, charge what it now holds). So an in-place array mutation (push/splice) is exact as soon as it is followed by asetordeleteof that bucket.pushBuffer/takeAt/removeBufferdo both in one call and are what the pool uses.Bytes are charged with
estimateGeometryBytes, cached per geometry, and the exact amount charged is what is later subtracted — so the totals cannot drift even if a geometry's cached size were invalidated while resident (no production code does that: pooled geometries have a fixed capacity).