@@ -68,54 +68,58 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
6868 // / to MaxCachedLeaves. Shared preamble of the cached resolvers, which stage one table
6969 // / entry group per spanned leaf. Must be called by all threads (uses __syncthreads).
7070 // / @param smem_leafIndex Decoded leaf indices in shared memory
71- // / @param firstSpanned Leaf index of slot 0, i.e. the first leaf the block spans
71+ // / @param firstLeaf Leaf index of slot 0, i.e. the first leaf the block spans
7272 // / @param myLeaf This thread's leaf index (UnusedLeafIndex past the last voxel)
7373 template <int MaxCachedLeaves>
7474 __device__
75- static int cachedLeafSpan (const uint32_t *smem_leafIndex, uint32_t firstSpanned , uint32_t myLeaf)
75+ static int cachedLeafSpan (const uint32_t *smem_leafIndex, uint32_t firstLeaf , uint32_t myLeaf)
7676 {
77- __shared__ int sSpannedCount ;
77+ __shared__ int sSpannedLeafCount ;
7878 const int tID = threadIdx .x ;
79- if (tID == 0 ) sSpannedCount = 0 ;
79+ if (tID == 0 ) sSpannedLeafCount = 0 ;
8080 __syncthreads ();
8181 // one atomicMax per distinct leaf: only the first slot of each run contributes
8282 if (myLeaf != UnusedLeafIndex && (tID == 0 || smem_leafIndex[tID-1 ] != myLeaf))
83- atomicMax (&sSpannedCount , int (myLeaf - firstSpanned ) + 1 );
83+ atomicMax (&sSpannedLeafCount , int (myLeaf - firstLeaf ) + 1 );
8484 __syncthreads ();
85- return sSpannedCount < MaxCachedLeaves ? sSpannedCount : MaxCachedLeaves;
85+ return sSpannedLeafCount < MaxCachedLeaves ? sSpannedLeafCount : MaxCachedLeaves;
8686 }
8787
8888 // / @brief Stage the per-spanned-leaf neighbor table shared by the cached resolvers.
8989 // /
90- // / Fills table[slot *N + n ] with the leaf node lying at neighbor position n of the slot-th
91- // / spanned leaf, or nullptr where no such leaf exists ; entry SelfIndex stores the spanned
90+ // / Fills table[leafSlot *N + neighborID ] with the leaf lying at that neighbor position of
91+ // / the leafSlot-th spanned leaf, or nullptr if absent ; entry SelfIndex stores the spanned
9292 // / leaf itself rather than probing for it. Each resolver supplies the shift from a leaf
9393 // / origin to its n-th neighbor's origin, so it keeps whatever indexing its lookup expects.
94- // / The nSpanned x N entries are distributed across ALL threads, so no thread serializes
94+ // / The spannedLeafCount x N entries are distributed across ALL threads, so no thread serializes
9595 // / the probes.
9696 // /
9797 // / Must be called by all threads in the block (ends in __syncthreads).
9898 // /
9999 // / @tparam N Table entries per spanned leaf
100100 // / @tparam SelfIndex Entry index holding the spanned leaf itself (not probed for)
101- // / @tparam OffsetT Device-callable (Coord& origin, int n) shifting a leaf origin to the
102- // / origin of the leaf at entry n
103- // / @param table Flattened [MaxCachedLeaves][N] table of leaf pointers in shared memory
104- // / @param nSpanned Number of spanned leaves (from cachedLeafSpan)
101+ // / @tparam OffsetT Device-callable (Coord& origin, int neighborID) shifting a leaf origin
102+ // / to the origin of the leaf at that neighbor position
103+ // / @param table Flattened [MaxCachedLeaves][N] leaf-pointer table in shared memory
104+ // / @param spannedLeafCount Number of spanned leaves (from cachedLeafSpan)
105+ // / @param firstLeaf Leaf index of the block's first slot
105106 template <int N, int SelfIndex, class BuildT , class LeafT , class OffsetT >
106107 __device__
107108 static void stageLeafTable (const NanoGrid<BuildT> *grid, const LeafT **table,
108- int nSpanned , uint32_t firstSpanned , OffsetT shiftToNeighbor)
109+ int spannedLeafCount , uint32_t firstLeaf , OffsetT shiftToNeighbor)
109110 {
110111 const int tID = threadIdx .x ;
111112 const auto & tree = grid->tree ();
112113 const LeafT* leaf0 = tree.template getFirstNode <0 >();
113- for (int c = tID; c < nSpanned * N; c += blockDim .x ) {
114- const int slot = c / N, n = c % N;
115- if (n == SelfIndex) { table[slot*N + n] = leaf0 + (firstSpanned + slot); continue ; }
116- Coord origin = leaf0[firstSpanned + slot].origin ();
117- shiftToNeighbor (origin, n);
118- table[slot*N + n] = tree.root ().probeLeaf (origin);
114+ for (int entry = tID; entry < spannedLeafCount * N; entry += blockDim .x ) {
115+ const int leafSlot = entry / N, neighborID = entry % N;
116+ if (neighborID == SelfIndex) {// this spanned leaf itself; no probe needed
117+ table[leafSlot*N + neighborID] = leaf0 + (firstLeaf + leafSlot);
118+ continue ;
119+ }
120+ Coord neighborOrigin = leaf0[firstLeaf + leafSlot].origin ();
121+ shiftToNeighbor (neighborOrigin, neighborID);
122+ table[leafSlot*N + neighborID] = tree.root ().probeLeaf (neighborOrigin);
119123 }
120124 __syncthreads ();
121125 }
@@ -376,29 +380,31 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
376380 const auto & tree = grid->tree ();
377381 const LeafT* leaf0 = tree.template getFirstNode <0 >();
378382
379- const uint32_t firstSpanned = smem_leafIndex[0 ];
383+ const uint32_t firstLeaf = smem_leafIndex[0 ];// leaf owning the block's first slot
380384 const uint32_t myLeaf = smem_leafIndex[tID];
381- const int nSpanned = cachedLeafSpan<MaxCachedLeaves>(smem_leafIndex, firstSpanned , myLeaf);
385+ const int spannedLeafCount = cachedLeafSpan<MaxCachedLeaves>(smem_leafIndex, firstLeaf , myLeaf);
382386 // Entry order 0..5 is -x,+x,-y,+y,-z,+z (axis*2 + dir), which the lookup below assumes.
383- stageLeafTable<7 , 6 >(grid, &sFaceLeaves [0 ][0 ], nSpanned, firstSpanned ,
387+ stageLeafTable<7 , 6 >(grid, &sFaceLeaves [0 ][0 ], spannedLeafCount, firstLeaf ,
384388 [](Coord &o, int n) { o[n >> 1 ] += (n & 1 ) ? 8 : -8 ; });
385389
386390 if (myLeaf != UnusedLeafIndex) {
387391 const auto & leaf = leaf0[myLeaf];
388392 const Coord coord = leaf.offsetToGlobalCoord ( smem_voxelOffset[tID] );
389- const uint32_t slot = myLeaf - firstSpanned ;
390- const bool cached = slot < MaxCachedLeaves;
393+ const uint32_t leafSlot = myLeaf - firstLeaf ;
394+ const bool isCached = leafSlot < MaxCachedLeaves;
391395 stencilIndices[13 ] = leaf.getValue ( smem_voxelOffset[tID] );
392396 for (int n = 0 ; n < 6 ; ++n) {
393397 const int axis = n >> 1 , dir = (n & 1 ) ? 1 : -1 ;
394398 Coord neighbor = coord;
395399 neighbor[axis] += dir;
396400 // Standard 27-slot spoke id for this face tap
397401 const int spokeID = 13 + dir * (axis == 0 ? 9 : axis == 1 ? 3 : 1 );
398- if (cached) {
399- const int v = coord[axis] & 7 ;
400- const LeafT* nl = ((v + dir) & ~7 ) ? sFaceLeaves [slot][n] : sFaceLeaves [slot][6 ];
401- stencilIndices[spokeID] = nl ? nl->getValue (LeafT::CoordToOffset (neighbor)) : 0 ;
402+ if (isCached) {
403+ const int voxelOnAxis = coord[axis] & 7 ;// 0..7 within the leaf
404+ // stepping off the leaf on this axis? then use the face neighbor, else self
405+ const LeafT* neighborLeaf = ((voxelOnAxis + dir) & ~7 ) ? sFaceLeaves [leafSlot][n]
406+ : sFaceLeaves [leafSlot][6 ];
407+ stencilIndices[spokeID] = neighborLeaf ? neighborLeaf->getValue (LeafT::CoordToOffset (neighbor)) : 0 ;
402408 } else {
403409 stencilIndices[spokeID] = tree.getValue ( neighbor );
404410 }
@@ -439,30 +445,32 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
439445 const int tID = threadIdx .x ;
440446 const auto & tree = grid->tree ();
441447 const LeafT* leaf0 = tree.template getFirstNode <0 >();
442- const uint32_t firstSpanned = smem_leafIndex[0 ];
448+ const uint32_t firstLeaf = smem_leafIndex[0 ];// leaf owning the block's first slot
443449 const uint32_t myLeaf = smem_leafIndex[tID];
444450
445451 // Stage the spannedLeaves x 27 leaf-neighborhood table across ALL threads
446- const int nSpanned = cachedLeafSpan<MaxCachedLeaves>(smem_leafIndex, firstSpanned , myLeaf);
452+ const int spannedLeafCount = cachedLeafSpan<MaxCachedLeaves>(smem_leafIndex, firstLeaf , myLeaf);
447453 // The full box neighborhood: entry n is the 3x3x3 spoke n.
448- stageLeafTable<27 , 13 >(grid, &sNeighborLeaves [0 ][0 ], nSpanned, firstSpanned ,
454+ stageLeafTable<27 , 13 >(grid, &sNeighborLeaves [0 ][0 ], spannedLeafCount, firstLeaf ,
449455 [](Coord &o, int n) { o = o.offsetBy ((n/9 -1 )*8 , ((n/3 )%3 -1 )*8 , (n%3 -1 )*8 ); });
450456
451457 if (myLeaf == UnusedLeafIndex) return ;
452458 const auto & leaf = leaf0[myLeaf];
453459 const Coord coord = leaf.offsetToGlobalCoord ( smem_voxelOffset[tID] );
454- const uint32_t slot = myLeaf - firstSpanned ;
455- const bool cached = slot < MaxCachedLeaves;
456- const int vi = coord[0 ] & 7 , vj = coord[1 ] & 7 , vk = coord[2 ] & 7 ;
460+ const uint32_t leafSlot = myLeaf - firstLeaf ;
461+ const bool isCached = leafSlot < MaxCachedLeaves;
462+ const int voxelX = coord[0 ] & 7 , voxelY = coord[1 ] & 7 , voxelZ = coord[2 ] & 7 ;
457463 for (int di = -1 ; di <= 1 ; di++)
458464 for (int dj = -1 ; dj <= 1 ; dj++)
459465 for (int dk = -1 ; dk <= 1 ; dk++) {
460466 const int spokeID = ( di + 1 ) * 9 + ( dj + 1 ) * 3 + dk + 1 ;
461467 const Coord neighbor = coord.offsetBy ( di, dj, dk );
462- if (cached) {
463- const int li = ((vi+di)>>3 )+1 , lj = ((vj+dj)>>3 )+1 , lk = ((vk+dk)>>3 )+1 ;
464- const LeafT* nl = sNeighborLeaves [slot][li*9 +lj*3 +lk];
465- op (spokeID, nl ? nl->getValue (LeafT::CoordToOffset (neighbor)) : uint64_t (0 ));
468+ if (isCached) {
469+ // which of the 3x3x3 neighboring leaves this tap falls into
470+ const int leafX = ((voxelX+di)>>3 )+1 , leafY = ((voxelY+dj)>>3 )+1 , leafZ = ((voxelZ+dk)>>3 )+1 ;
471+ const LeafT* neighborLeaf = sNeighborLeaves [leafSlot][leafX*9 + leafY*3 + leafZ];
472+ op (spokeID, neighborLeaf ? neighborLeaf->getValue (LeafT::CoordToOffset (neighbor))
473+ : uint64_t (0 ));
466474 } else {
467475 op (spokeID, tree.getValue ( neighbor ));
468476 }
0 commit comments