You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up from the review of #167 (issue #154, tracking #160). Line numbers are from main at 2a88a618.
Problem
#167 made the residency budget honest: an unlit chunked volume now holds a 1x1x1 placeholder gradient, and residentBytesForChunkDesc (packages/niivue/src/volume/chunkBudget.ts:101) prices a chunk at 4 bytes per voxel when hasGradient is false. Two other places still assume 8 bytes per voxel and are now out of step with it:
The planner.bytesOf in packages/niivue/src/volume/chunking.ts:1225-1229 costs every brick at 8 bytes per voxel when deciding whether a candidate plan fits budget. For an unlit volume (the default: gradientAmount, gradientOpacity and silhouette all 0) the real residency is half that, so the planner picks a plan with about half the bricks the GPU budget could hold, and the coarser-than-necessary result is exactly what niivue: unlit chunked volumes allocate a full-size dummy gradient #154 set out to avoid. The renderer's working-set cap sees the true bytes, but it can only evict, not refine.
The decoded CPU tier.GPU_BYTES_PER_VOXEL = 8 in packages/niivue/src/volume/decodedChunkCache.ts:65 sizes the decoded tier as 1.5x the shadow of the resident set. With unlit volumes now holding twice as many voxels on the GPU for the same budget, that tier is 0.75x of the real shadow. The module's own note (decodedChunkCache.ts:86-88) explains that a tier smaller than the shadow holds no evicted chunk at all. Concretely, a uint8 volume with a 256 MiB GPU budget: resident voxels go from 32M to 64M, the tier stays at 48 MiB, which is now smaller than the resident set. The tier is sized once when the entry is created (packages/niivue/src/gl/render.ts:926, packages/niivue/src/wgpu/render.ts:1073), so it cannot follow a lighting toggle either way.
Size the decoded tier at 4 bytes per voxel resident. That is the larger and therefore conservative shadow, it is still capped at 384 MiB, and it keeps the tier effective for the common unlit case without any dynamic resizing.
Unit tests: the planner fits twice the bricks at 4 than at 8 for the same budget, and decodedTierBudgetBytes for a uint8 volume at 256 MiB exceeds the resident voxel count.
Follow-up from the review of #167 (issue #154, tracking #160). Line numbers are from
mainat2a88a618.Problem
#167 made the residency budget honest: an unlit chunked volume now holds a 1x1x1 placeholder gradient, and
residentBytesForChunkDesc(packages/niivue/src/volume/chunkBudget.ts:101) prices a chunk at 4 bytes per voxel whenhasGradientis false. Two other places still assume 8 bytes per voxel and are now out of step with it:The planner.
bytesOfinpackages/niivue/src/volume/chunking.ts:1225-1229costs every brick at 8 bytes per voxel when deciding whether a candidate plan fitsbudget. For an unlit volume (the default:gradientAmount,gradientOpacityandsilhouetteall 0) the real residency is half that, so the planner picks a plan with about half the bricks the GPU budget could hold, and the coarser-than-necessary result is exactly what niivue: unlit chunked volumes allocate a full-size dummy gradient #154 set out to avoid. The renderer's working-set cap sees the true bytes, but it can only evict, not refine.The decoded CPU tier.
GPU_BYTES_PER_VOXEL = 8inpackages/niivue/src/volume/decodedChunkCache.ts:65sizes the decoded tier as 1.5x the shadow of the resident set. With unlit volumes now holding twice as many voxels on the GPU for the same budget, that tier is 0.75x of the real shadow. The module's own note (decodedChunkCache.ts:86-88) explains that a tier smaller than the shadow holds no evicted chunk at all. Concretely, a uint8 volume with a 256 MiB GPU budget: resident voxels go from 32M to 64M, the tier stays at 48 MiB, which is now smaller than the resident set. The tier is sized once when the entry is created (packages/niivue/src/gl/render.ts:926,packages/niivue/src/wgpu/render.ts:1073), so it cannot follow a lighting toggle either way.Proposal
bytesPerVoxelinput (4 when the caller knows the volume is unlit, 8 otherwise) and threadneedsGradient()through from both renderers' plan sites, the same way fix(niivue): use a 1x1x1 placeholder gradient for unlit chunked volumes #167 threaded it into the working-set cap.decodedTierBudgetBytesfor a uint8 volume at 256 MiB exceeds the resident voxel count.🤖 Generated with Claude Code
https://claude.ai/code/session_01RxnaB17kqcirGHNyAjPbgG