NanoVDB VBM: Streaming box-stencil - #2262
Draft
swahtz wants to merge 2 commits into
Draft
Conversation
Add VoxelBlockManager::forEachBoxStencil, which visits the 27 taps of the 3x3x3 box stencil and streams (tap, index) to a device-inlined callback in the same deterministic tap order as computeBoxStencil, without materializing the 27-element per-thread index array. Consumers that reduce or accumulate taps (looking each index up in the sidecar) avoid the stack frame and register pressure of the materialized form; callers needing random access to all 27 taps keep computeBoxStencil. Byte-exact with computeBoxStencil (identical output). Eliminating the st[27] index array saves 26 registers + a 216-byte per-thread stack frame (70->44 regs, 216B->0; ptxas -v, sm_120). On a real value-accumulating box filter the streaming path is 1.3-1.9x at 1 sidecar channel, tapering with feature width as the per-tap gather dominates (~1.07x at 16 channels, width 128; ~1.29x at 16 channels, width 512). Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
swahtz
requested review from
Idclip,
apradhana,
danrbailey,
jmlait,
kmuseth and
richhones
as code owners
July 24, 2026 04:25
swahtz
marked this pull request as draft
July 29, 2026 02:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds
VoxelBlockManager::forEachBoxStencilto the NanoVDB VBM — a streaming resolver for the 3×3×3 box stencil. It visits the 27 taps and streams(tap, index)to a device-inlined callback in the same deterministic tap order ascomputeBoxStencil, without materializing the 27-element per-thread index array. Consumers that reduce or accumulate taps (the common case — Laplacians, divergences, sums) fuse the lookup and the arithmetic and avoid the array's register/stack cost.The existing
computeBoxStencilis unchanged for callers that genuinely need random access to all 27 materialized taps.What changed
In an Index-Grid the stencil resolves to indices; a real filter looks each index up in the sidecar (the actual per-voxel data payload) and accumulates:
Same 27 taps, same tap order (
(di+1)*9 + (dj+1)*3 + (dk+1)), so results are identical — but theuint64_t st[27](a 216-byte per-thread array, exactly27 × sizeof(uint64)) is gone. Isolating that overhead (ptxas -v, sm_120), the materialized array costs 26 registers + a 216-byte stack frame (70 → 44 registers, 216 B → 0), which a streaming filter avoids regardless of its arithmetic.That register drop crosses an occupancy tier. On sm_120 (65536 regs/SM, 1536 threads = 48 warps max, allocation granule 8 regs/thread):
— a 1.5× jump in resident warps, which is what the runtime win reflects. (Full occupancy on sm_120 needs ≤40 registers, so streaming lands one 8-register granule short of 100%.)
A/B — real value-accumulating box filter (streaming vs materialized)
A genuine 3×3×3 box filter over an Index-Grid similar to the example usage above: both paths resolve the same 27 tap indices, then gather
Csidecar channels per tap (sidecar[index*C + ch]) and accumulate per channel — so the only difference is the materializedst[27]array. Byte-exact at every (width, C); min of 40, sphere-shell grid (~1.29M active voxels).Benchmarked on an RTX PRO 6000 (sm_120).
The win is largest at narrow feature width and tapers as feature width grows: the sidecar gather (
27 × Cloads, identical for both paths) increasingly dominates the fixed materialization saving. It is also larger at wider blocks (more register/occupancy relief).Validation