Skip to content

Commit d084783

Browse files
committed
NanoVDB CUDA: assert the one-thread-per-slot contract in the stencil resolvers
Every stencil resolver resolves the taps of the decoded slot with its own thread index (smem_leafIndex[tID]), so the block must be launched with blockDim.x == BlockWidth. That requirement was neither documented nor checked: a smaller block silently skipped the slots past blockDim.x, and a larger one read smem_leafIndex past the end of a BlockWidth-sized array and could then index an out-of-range leaf. Add NANOVDB_ASSERT(blockDim.x == BlockWidth) to the five resolvers and state the contract on the class, noting that decodeInverseMaps is deliberately more permissive - it strides over the slots, so it fills the maps correctly for any blockDim.x. Debug-build only. Verified that a deliberate blockDim.x = BlockWidth/2 launch now trips the assertion, that the correct launch still passes the VoxelBlockManager_ValueOnIndex unit-test path (250047 comparisons, zero mismatches), and that all VBM goldens still pass. Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
1 parent 76b32d3 commit d084783

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

nanovdb/nanovdb/tools/cuda/VoxelBlockManager.cuh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
6363
// Independently, compute<Name> materializes the taps into a 27-slot array while
6464
// forEach<Name> streams (tap, index) to a device-inlined callback, which avoids the
6565
// per-thread array entirely for consumers that can take the taps in order.
66+
//
67+
// Every resolver resolves the taps of ONE decoded slot per thread - the slot with the
68+
// thread's own index - so the block must be launched with blockDim.x == BlockWidth.
69+
// (decodeInverseMaps itself is more permissive: it strides over the slots, so it fills
70+
// the maps correctly for any blockDim.x.)
6671

6772
/// @brief Number of distinct, consecutive leaves the block's decoded slots span, clamped
6873
/// to MaxCachedLeaves. Shared preamble of the cached resolvers, which stage one table
@@ -221,6 +226,7 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
221226
{
222227
// Verify that the nodes can be accessed linearly
223228
NANOVDB_ASSERT(grid->isSequential());
229+
NANOVDB_ASSERT(blockDim.x == BlockWidth);// one thread per decoded slot
224230

225231
int tID = threadIdx.x;
226232
const auto& tree = grid->tree();
@@ -260,6 +266,7 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
260266
OpT op)
261267
{
262268
NANOVDB_ASSERT(grid->isSequential());
269+
NANOVDB_ASSERT(blockDim.x == BlockWidth);// one thread per decoded slot
263270
const int tID = threadIdx.x;
264271
const auto& tree = grid->tree();
265272
if (smem_leafIndex[tID] == UnusedLeafIndex) return;
@@ -330,6 +337,7 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
330337
{
331338
// Verify that the nodes can be accessed linearly
332339
NANOVDB_ASSERT(grid->isSequential());
340+
NANOVDB_ASSERT(blockDim.x == BlockWidth);// one thread per decoded slot
333341

334342
int tID = threadIdx.x;
335343
const auto& tree = grid->tree();
@@ -370,6 +378,7 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
370378
uint64_t *stencilIndices)
371379
{
372380
NANOVDB_ASSERT(grid->isSequential());
381+
NANOVDB_ASSERT(blockDim.x == BlockWidth);// one thread per decoded slot
373382

374383
using LeafT = typename NanoTree<BuildT>::LeafNodeType;
375384
constexpr int MaxCachedLeaves = 16;
@@ -437,6 +446,7 @@ struct VoxelBlockManager : nanovdb::tools::VoxelBlockManagerBase<Log2BlockWidth>
437446
OpT op)
438447
{
439448
NANOVDB_ASSERT(grid->isSequential());
449+
NANOVDB_ASSERT(blockDim.x == BlockWidth);// one thread per decoded slot
440450

441451
using LeafT = typename NanoTree<BuildT>::LeafNodeType;
442452
constexpr int MaxCachedLeaves = 16;

0 commit comments

Comments
 (0)