cumulative byte counters across all types.
Number of pooled buffers whose eviction was deferred past the
current evictUnused() call because the per-call batch cap
(evictBatchSize, default 5) was hit. Diagnostic only — these
buffers will be picked up on the next frame's eviction sweep.
Useful for spotting "user paused for 5 min then resumed and the
eviction queue is stretching across many frames" scenarios.
Of evictions, how many were forced by the BYTE budget rather than by LRU
recycling — the subset that means the pool went over its VRAM budget and
had to shed pooled geometry to get back under it.
Split out because evictions conflates two unrelated events. Routine LRU
recycling of released pooled buffers happens constantly on any nD scene as
slices change and says nothing about capacity; a byte-budget eviction says
the pool could not hold what it was holding, so what stayed resident is a
property of this machine and this run rather than of the store, and a
capture taken against it is not comparable (#2508). A consumer that refused
on evictions would refuse every normal nD capture. That distinction is
the whole reason this counter exists.
WHAT IT DOES AND DOES NOT PROVE. The byte pass disposes POOLED
(already-released) buffers only — active in-use buffers are never
candidates (byte-budget-evictor.ts) — so a nonzero count is not by itself
evidence that anything left the screen. It does cover the case where
committed detail is thrown away, because the LOD registry demotes cold
ACTIVE levels to pooled and this pass then reclaims them; a demoted level
that would otherwise have been re-adopted is gone.
KNOWN BLIND SPOT: it stays 0 when ACTIVE bytes alone exceed the budget with
nothing pooled to shed. The pooled-disposal target floors at 0, there is
nothing to dispose, and the pass reports no evictions — so this is not a
"the pool could not hold the scene" detector. Compare activeBytes against
the budget for that question.
KNOWN BENIGN TRIGGER: a node growing through a capacity tier under a binding
budget. The growth releases the superseded SMALLER buffer to the pool and the
byte pass immediately reclaims it, so the counter moves while nothing
rendered was lost. Measured with new GPUBufferPool(20, 300, 5, () => 480_000), acquirePointsGeometry('n1', 100) then
acquirePointsGeometry('n1', 5000): byteBudgetEvictions: 1,
activeBuffers: 1, pooledBuffers: 0. It only arises once active + pooled
is ALREADY over budget (453 KB + 67 KB against 480 KB there; the same pair
under a 10 MB budget evicts nothing), i.e. on a scene at the ceiling — which
is the population this signal exists for. capture-readiness.ts refuses on
it anyway, and argues that asymmetry at poolEvictionReason.
Per-pooled-type breakdown. Record<PooledGeometryType, …> for the same reason as
type above, and matching its already-keyed sibling
GPUPoolStats.byType in types/data-monitor-types.ts — the two were a keyed
record and a hand-written triple describing the same thing.
Overall pool statistics with per-type breakdown.