Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Module rendering/gpu-byte-budget

    Adaptive GPU-geometry byte budget — the single VRAM budget shared by the GPU buffer pool (pooled-buffer eviction) and the LOD-group registry (resident-level eviction). One authority, not two.

    Browsers deliberately do NOT expose total/available VRAM (it's a fingerprinting vector), so we can't read an "absolute max" and set to it. Auto-sizing takes the lowest estimate from navigator.deviceMemory and the shared non-cache remainder derived from the measured JS heap. An explicit total cache-pool override replaces the heap term in either direction; a mobile device-class fallback supplies that term when the heap is unavailable, and an independent 128 MiB mobile cap remains a peer minimum. The result has a 2 GB ceiling but no lower clamp, with 512 MB used only when no signal exists. As a safety net, the budget is halved on a WebGL context-loss event (a strong OOM signal) so an over-estimate self-corrects instead of repeatedly crashing the context.

    Single-viewer-per-page assumption. The budget lives in module-global state (budgetBytes below), so it is shared by every pool and registry in the page — including the context-loss backoff, which would halve the one shared budget for all of them. This is correct for the supported mode (one viewer per page). Embedding two independent viewers in the same tab would make them fight over (and back off) a single budget; that would require promoting this state onto a per-viewer instance (e.g. owned by SceneLoader / SceneManager) and threading it through the budget getters wired in init/pipeline.ts and scene-loader.ts.

    Per-element cost note (texture storage). A pooled gsplat allocation costs ≈68 B/splat: 64 B in the RGBA32F splat texture (4 texels × 16 B) + 4 B for the aSortedIndex ordering attribute — vs 52 B/splat in the pre-texture interleaved era (≈ +31% VRAM). A pooled points allocation costs ≈52 B/point: 48 B in the RGBA32F point texture (3 texels × 16 B) + 4 B aSortedIndex — vs 32 B/point (36 with scalars) in the interleaved era. EVERY node adds a further 4 B/element for the second ordering buffer the atomic swap needs — ≈72 B/splat, ≈56 B/point — charged from attach whether the node ever depth-sorts or not: materialising that buffer lazily would change the attribute set behind a cached native-WebGPU vertex layout and render the scene black (element-storage.ts). estimateGeometryBytes counts texture and attributes, deduplicating by attribute identity, so eviction pressure reflects the true footprint. The planned RGBA16F narrowing (spec §8) roughly halves the texture share.

    GpuBudgetMemorySignals
    configureGpuByteBudget
    initializeGpuByteBudget
    getGpuByteBudget
    reduceGpuByteBudgetForContextLoss