OpenVDB 14.0.0
Loading...
Searching...
No Matches
VoxelBlockManager.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5 \file nanovdb/tools/VoxelBlockManager.h
6
7 \author Efty Sifakis
8
9 \date July 24, 2025
10
11 \brief VoxelBlockManager: acceleration structure for voxel-sequential,
12 SIMT/SIMD-parallel access over the active voxels of an OnIndexGrid,
13 independent of occupancy.
14
15 \details Provides:
16 - VoxelBlockManagerHandle: manages the raw metadata buffers (firstLeafID
17 array and jumpMap) on host or device.
18 - buildVoxelBlockManager: constructs the VBM metadata from a NanoGrid.
19 - VoxelBlockManager: host-side decode of the inverse maps (sequential
20 active-voxel index -> leaf ID + intra-leaf voxel offset) for a single
21 voxel block, intended to be called once per block from a parallel loop.
22 - nanovdb::util::shuffleDownMask: generic masked shuffle-down primitive
23 used by the decode; a candidate for a future nanovdb/util/Algo.h.
24*/
25
26
27#ifndef NANOVDB_VOXELBLOCKMANAGER_H_HAS_BEEN_INCLUDED
28#define NANOVDB_VOXELBLOCKMANAGER_H_HAS_BEEN_INCLUDED
29
30#include <nanovdb/NanoVDB.h>
31#include <nanovdb/HostBuffer.h>
33
35
36#include <algorithm>
37#include <cstddef> // for std::byte
38#include <cstring>
39#include <type_traits> // for std::is_unsigned_v
40#include <utility> // for std::move, std::exchange
41
42namespace nanovdb {
43
44namespace util {
45
46/// @brief One pass of masked conditional shuffle-down on a stream of values.
47///
48/// For each position j in [0, N - Shift), conditionally replaces data[j] with
49/// data[j+Shift] based on the predicate (masks[j+Shift] & maskBits) != 0:
50///
51/// m = ~DataT{0} if (masks[j+Shift] & maskBits) != 0 (all-ones blend mask)
52/// m = DataT{0} otherwise (all-zeros blend mask)
53/// data[j] = (data[j+Shift] & m) | (data[j] & ~m)
54///
55/// Positions j in [N - Shift, N) are left unchanged (the trailing portion of
56/// the stream that cannot receive a shifted element).
57///
58/// In-place safe: j < j+Shift guarantees every source element is read before
59/// its slot is overwritten, including under SIMD vectorization.
60///
61/// The name follows the CUDA __shfl_down_sync convention: "shuffle down" denotes
62/// a conditional fixed-distance gather from higher-indexed positions, as opposed
63/// to an arbitrary permutation.
64///
65/// @tparam N Length of the data and masks arrays.
66/// @tparam Shift Number of positions to shift; must satisfy 0 < Shift < N.
67/// @tparam DataT Element type of the data array (any unsigned integer type).
68/// @tparam MaskT Element type of the masks array (any unsigned integer type).
69/// @param data Buffer of N DataT values, updated in-place.
70/// @param masks Read-only predicate table of N MaskT values.
71/// @param maskBits Bitmask ANDed with masks[j+Shift] to form the predicate.
72template <int N, int Shift, typename DataT, typename MaskT>
73inline void shuffleDownMask(DataT* NANOVDB_RESTRICT data,
74 const MaskT* NANOVDB_RESTRICT masks,
75 MaskT maskBits)
76{
77 static_assert(Shift > 0 && Shift < N, "Shift must satisfy 0 < Shift < N");
78 static_assert(std::is_unsigned_v<DataT>, "DataT must be an unsigned integer type");
79 static_assert(std::is_unsigned_v<MaskT>, "MaskT must be an unsigned integer type");
80 #pragma omp simd
81 for (int j = 0; j < N - Shift; j++) {
82 const DataT m = (masks[j + Shift] & maskBits) != 0 ? ~DataT{0} : DataT{0};
83 data[j] = (data[j + Shift] & m) | (data[j] & ~m);
84 }
85}
86
87} // namespace util
88
89namespace tools {
90
91/// @brief Move-only owner of the two raw metadata buffers that back a VoxelBlockManager:
92/// the per-block firstLeafID array (uint32_t[blockCount]) and the per-block
93/// jumpMap array (uint64_t[blockCount * JumpMapLength]).
94/// @tparam BufferT Buffer type that owns a contiguous allocation. Must satisfy the
95/// NanoVDB BufferTraits concept: provide data() and destroy() or clear(); a
96/// single-space device buffer (e.g. cuda::Buffer<std::byte>) holds device memory.
97template<typename BufferT>
99{
100 BufferT mFirstLeafID;
101 BufferT mJumpMap;
102 uint64_t mBlockCount{0};
103 uint64_t mFirstOffset{0};
104 uint64_t mLastOffset{0};
105
106public:
107 /// @brief Constructor from metadata buffers (used by buildVoxelBlockManager)
108 /// @param firstLeafID Allocated buffer holding the firstLeafID array
109 /// @param jumpMap Allocated buffer holding the jumpMap array
110 /// @param blockCount Number of voxel blocks (allocated capacity of the buffers)
111 /// @param firstOffset Sequential index of the first voxel covered by this VBM
112 /// @param lastOffset Sequential index of the last voxel covered by this VBM
113 VoxelBlockManagerHandle(BufferT&& firstLeafID, BufferT&& jumpMap,
114 uint64_t blockCount, uint64_t firstOffset, uint64_t lastOffset)
115 : mFirstLeafID(std::move(firstLeafID))
116 , mJumpMap(std::move(jumpMap))
117 , mBlockCount(blockCount)
118 , mFirstOffset(firstOffset)
119 , mLastOffset(lastOffset) {}
120
124
126 mFirstLeafID = std::move(other.mFirstLeafID);
127 mJumpMap = std::move(other.mJumpMap);
128 mBlockCount = std::exchange(other.mBlockCount, 0);
129 mFirstOffset = std::exchange(other.mFirstOffset, 0);
130 mLastOffset = std::exchange(other.mLastOffset, 0);
131 return *this;
132 }
133
135 : mFirstLeafID(std::move(other.mFirstLeafID))
136 , mJumpMap(std::move(other.mJumpMap))
137 , mBlockCount(other.mBlockCount)
138 , mFirstOffset(other.mFirstOffset)
139 , mLastOffset(other.mLastOffset)
140 {
141 other.mBlockCount = 0;
142 other.mFirstOffset = 0;
143 other.mLastOffset = 0;
144 }
145
147 /// @brief clear the buffer
148 void reset() {
149 if constexpr (BufferHasDestroy<BufferT>::value) {
150 mFirstLeafID.destroy();
151 mJumpMap.destroy();
152 } else {
153 mFirstLeafID.clear();
154 mJumpMap.clear();
155 }
156 mBlockCount = 0;
157 }
158
159 //@{
160 /// @brief For a single-space buffer the device data is the buffer itself.
161 /// @warning Note that the return pointer can be NULL if the VoxelBlockManagerHandle was not initialized
162 template<typename U = BufferT>
163 typename util::enable_if<BufferHasDeviceSingle<U>::value, uint32_t*>::type
164 deviceFirstLeafID() { return reinterpret_cast<uint32_t*>(mFirstLeafID.data()); }
165 template<typename U = BufferT>
166 typename util::enable_if<BufferHasDeviceSingle<U>::value, const uint32_t*>::type
167 deviceFirstLeafID() const { return reinterpret_cast<const uint32_t*>(mFirstLeafID.data()); }
168 template<typename U = BufferT>
169 typename util::enable_if<BufferHasDeviceSingle<U>::value, uint64_t*>::type
170 deviceJumpMap() { return reinterpret_cast<uint64_t*>(mJumpMap.data()); }
171 template<typename U = BufferT>
172 typename util::enable_if<BufferHasDeviceSingle<U>::value, const uint64_t*>::type
173 deviceJumpMap() const { return reinterpret_cast<const uint64_t*>(mJumpMap.data()); }
174 //@}
175
176 /// @brief Returns the number of voxel blocks in the VoxelBlockManager
177 uint64_t blockCount() const { return mBlockCount; }
178
179 /// @brief Returns the first voxel index (linear offset) associated with this VoxelBlockManager
180 uint64_t firstOffset() const { return mFirstOffset; }
181
182 /// @brief Returns the last voxel index (linear offset) associated with this VoxelBlockManager
183 uint64_t lastOffset() const { return mLastOffset; }
184
185 //@{
186 /// @brief Returns pointers to the host-side firstLeafID and jumpMap data; not
187 /// available for a single-space device buffer, which has no host-readable bytes.
188 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value, int>::type = 0>
189 uint32_t* hostFirstLeafID() { return reinterpret_cast<uint32_t*>(mFirstLeafID.data()); }
190 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value, int>::type = 0>
191 const uint32_t* hostFirstLeafID() const { return reinterpret_cast<const uint32_t*>(mFirstLeafID.data()); }
192 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value, int>::type = 0>
193 uint64_t* hostJumpMap() { return reinterpret_cast<uint64_t*>(mJumpMap.data()); }
194 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value, int>::type = 0>
195 const uint64_t* hostJumpMap() const { return reinterpret_cast<const uint64_t*>(mJumpMap.data()); }
196 //@}
197
198}; // VoxelBlockManagerHandle
199
200// --------------------------> VoxelBlockManagerBase <----------------------------------------
201
202/// @brief Compile-time geometry parameters and output sentinels shared by the CPU
203/// and CUDA VoxelBlockManager decode structs.
204/// @tparam Log2BlockWidth Log2 of the number of active voxels per VBM block
205template <int Log2BlockWidth>
207{
208 static constexpr int BlockWidth = 1 << Log2BlockWidth;
209 static_assert(Log2BlockWidth >= 6, "BlockWidth must be at least 64 (one jumpMap word per block)");
210 static constexpr int JumpMapLength = BlockWidth / 64; ///< number of uint64_t words per block in the jumpMap
211
212 /// Sentinel written to leafIndex slots with no active voxel in this block
213 static constexpr uint32_t UnusedLeafIndex = ~uint32_t{0};
214 /// Sentinel written to voxelOffset slots with no active voxel in this block
215 static constexpr uint16_t UnusedVoxelOffset = ~uint16_t{0};
216}; // VoxelBlockManagerBase
217
218// --------------------------> VoxelBlockManager (CPU) <--------------------------------------
219
220/// @brief CPU counterpart of tools::cuda::VoxelBlockManager. Provides host-side
221/// decode of the inverse maps (sequential index -> leaf + voxel offset)
222/// for a single voxel block. The implementation is single-threaded per block
223/// and SIMD-accelerated (via util::shuffleDownMask and util::buildMaskPrefixSums);
224/// the caller is responsible for parallelism across blocks (e.g. OpenMP or
225/// nanovdb::util::forEach).
226template <int Log2BlockWidth>
228{
230 using Base::BlockWidth;
234
235 /// @brief Decode the inverse maps for a single voxel block on the host.
236 ///
237 /// Given the VBM metadata for one block (firstLeafID and the block's slice of
238 /// the jumpMap) and the block's base sequential offset, fills leafIndex[] and
239 /// voxelOffset[] so that for each position p in [0, BlockWidth):
240 /// - leafIndex[p] = index of the leaf node containing sequential voxel
241 /// (blockFirstOffset + p), or UnusedLeafIndex if that
242 /// index is beyond the last active voxel.
243 /// - voxelOffset[p] = local (0..511) offset of that voxel within its leaf,
244 /// or UnusedVoxelOffset.
245 ///
246 /// The CPU analogue of the CUDA decodeInverseMaps. Single-threaded per block;
247 /// SIMD is used internally. The caller is responsible for parallelism across blocks.
248 ///
249 /// @tparam BuildT Build type of the grid (must be an index type)
250 /// @param grid Host-accessible OnIndex grid
251 /// @param firstLeafID Index of the first leaf overlapping this block
252 /// @param jumpMap Pointer to the JumpMapLength words for this block
253 /// @param blockFirstOffset Sequential index of the first voxel in this block
254 /// @param leafIndex Output array of length BlockWidth
255 /// @param voxelOffset Output array of length BlockWidth
256 template <class BuildT>
257 static typename util::enable_if<BuildTraits<BuildT>::is_index, void>::type
259 const NanoGrid<BuildT> *grid,
260 const uint32_t firstLeafID,
261 const uint64_t *jumpMap,
262 const uint64_t blockFirstOffset,
263 uint32_t *leafIndex,
264 uint16_t *voxelOffset)
265 {
267
268 // Count how many additional leaves follow firstLeafID in this block
269 int nExtraLeaves = 0;
270 for (int i = 0; i < JumpMapLength; i++)
271 nExtraLeaves += util::countOn(jumpMap[i]);
272
273 // Initialize outputs to sentinel values
274 std::fill(leafIndex, leafIndex + BlockWidth, UnusedLeafIndex);
275 std::fill(voxelOffset, voxelOffset + BlockWidth, UnusedVoxelOffset);
276
277 const auto &tree = grid->tree();
278 for (auto leafID = firstLeafID; leafID <= firstLeafID + nExtraLeaves; leafID++) {
279 const auto &leaf = tree.template getFirstNode<0>()[leafID];
280
281 const uint64_t leafFirstOffset = leaf.data()->firstOffset();
282 if (leafFirstOffset >= blockFirstOffset + BlockWidth) break;
283
284 // Compute shifts[i] = number of inactive voxels at positions 0..i-1, i.e. the
285 // exclusive prefix count of 0-bits over the inverted mask. Using the 513-entry
286 // exclusive layout (shifts[0]=0, buildMaskPrefixSums<true> writes inclusive
287 // 0-bit counts into shifts[1..512]):
288 // shifts[i] = exclusive 0-bit prefix at i (used by shuffleDownMask passes)
289 // shifts[512] = total inactive voxel count = 512 - leafValueCount
290 uint16_t shifts[513];
291 shifts[0] = 0;
292 util::buildMaskPrefixSums<true>(leaf.valueMask(), leaf.data()->mPrefixSum, shifts + 1);
293
294 const uint16_t leafValueCount = static_cast<uint16_t>(512u) - shifts[512];
295
296 // Build leafLocalOffsets via 9 in-place shfl_down passes.
297 // buf is initialized with the identity (buf[i] = i) and updated in-place
298 // each pass. NANOVDB_RESTRICT on both buf and shifts discharges the aliasing
299 // concern and allows the vectorizer to emit SIMD blend instructions.
300 uint16_t leafLocalOffsets[512];
301 for (int i = 0; i < 512; i++) leafLocalOffsets[i] = static_cast<uint16_t>(i);
302 util::shuffleDownMask<512, 1>(leafLocalOffsets, shifts, uint16_t{ 1});
303 util::shuffleDownMask<512, 2>(leafLocalOffsets, shifts, uint16_t{ 2});
304 util::shuffleDownMask<512, 4>(leafLocalOffsets, shifts, uint16_t{ 4});
305 util::shuffleDownMask<512, 8>(leafLocalOffsets, shifts, uint16_t{ 8});
306 util::shuffleDownMask<512, 16>(leafLocalOffsets, shifts, uint16_t{ 16});
307 util::shuffleDownMask<512, 32>(leafLocalOffsets, shifts, uint16_t{ 32});
308 util::shuffleDownMask<512, 64>(leafLocalOffsets, shifts, uint16_t{ 64});
309 util::shuffleDownMask<512, 128>(leafLocalOffsets, shifts, uint16_t{128});
310 util::shuffleDownMask<512, 256>(leafLocalOffsets, shifts, uint16_t{256});
311
312 // Intersect this leaf's active range with the block's range.
313 // Active voxels span [leafFirstOffset, leafFirstOffset+leafValueCount) globally.
314 // Block output slots span [blockFirstOffset, blockFirstOffset+BlockWidth).
315 const uint64_t globalStart = std::max(leafFirstOffset, blockFirstOffset);
316 const uint64_t globalEnd = std::min(leafFirstOffset + leafValueCount,
317 blockFirstOffset + BlockWidth);
318 const uint64_t jStart = globalStart - leafFirstOffset; // first dense index in leaf
319 const uint64_t pStart = globalStart - blockFirstOffset; // first output slot in block
320 const uint64_t count = globalEnd - globalStart;
321
322 std::fill(leafIndex + pStart, leafIndex + pStart + count, leafID);
323 std::copy(leafLocalOffsets + jStart, leafLocalOffsets + jStart + count,
324 voxelOffset + pStart);
325 }
326 }
327}; // VoxelBlockManager
328
329// --------------------------> buildVoxelBlockManager (CPU) <---------------------------------
330
331/// @brief Rebuild a VoxelBlockManager in-place using a pre-allocated handle.
332/// Zeros the jumpMap and recomputes both metadata arrays. No memory allocation.
333/// @tparam Log2BlockWidth Log2 of the number of active voxels per VBM block
334/// @tparam BufferT Buffer type of the handle (must provide host-accessible data())
335/// @param grid Host-accessible ValueOnIndex grid (must satisfy isSequential())
336/// @param handle Pre-allocated handle whose blockCount/firstOffset/lastOffset are
337/// already set to match the grid
338template<int Log2BlockWidth, typename BufferT>
340{
342 constexpr auto BlockWidth = Base::BlockWidth;
343 constexpr auto JumpMapLength = Base::JumpMapLength;
344
346 if (!handle.blockCount()) return;
347
348 uint32_t *firstLeafID = handle.hostFirstLeafID();
349 uint64_t *jumpMap = handle.hostJumpMap();
350 const uint64_t nBlocks = handle.blockCount();
351 const uint64_t firstOffset = handle.firstOffset();
352 const uint64_t lastOffset = handle.lastOffset();
353
354 NANOVDB_ASSERT(!((firstOffset - 1) & (BlockWidth - 1))); // firstOffset == 1 (mod BlockWidth)
355
356 std::memset(jumpMap, 0, nBlocks * JumpMapLength * sizeof(uint64_t));
357
358 const auto &tree = grid->tree();
359 const auto *firstLeaf = tree.getFirstNode<0>();
360 const uint32_t leafCount = tree.nodeCount(0);
361
362 util::forEach(0, leafCount, 1, [&](const util::Range1D& range) {
363 for (auto leafIndex = range.begin(); leafIndex < range.end(); ++leafIndex) {
364 const auto& leaf = firstLeaf[leafIndex];
365 const uint64_t leafFirstOffset = leaf.data()->firstOffset();
366 const uint64_t leafValueCount = leaf.data()->valueCount();
367 const uint64_t leafLastOffset = leafFirstOffset + leafValueCount - 1;
368
369 if (leafFirstOffset > lastOffset || leafLastOffset < firstOffset) continue;
370
371 const uint64_t lastBlock = std::min<uint64_t>(
372 (leafLastOffset - firstOffset) >> Log2BlockWidth, nBlocks - 1);
373 const uint64_t firstBlock = (leafFirstOffset < firstOffset) ? 0 :
374 (leafFirstOffset - firstOffset) >> Log2BlockWidth;
375
376 // For blocks after firstBlock, this leaf is the first leaf of each
377 for (uint64_t b = lastBlock; b > firstBlock; --b)
378 firstLeafID[b] = static_cast<uint32_t>(leafIndex);
379
380 if (leafFirstOffset < firstOffset) {
381 firstLeafID[0] = static_cast<uint32_t>(leafIndex);
382 continue;
383 }
384
385 const uint64_t offsetInBlock = (leafFirstOffset - 1) & (BlockWidth - 1);
386 if (!offsetInBlock) {
387 // Leaf starts exactly at a block boundary: register in firstLeafID
388 firstLeafID[firstBlock] = static_cast<uint32_t>(leafIndex);
389 } else {
390 // Leaf starts in the interior of a block: mark in jumpMap with atomic OR
391 util::atomicOr(&jumpMap[firstBlock * JumpMapLength + (offsetInBlock >> 6)],
392 uint64_t(1) << (offsetInBlock & 0x3f));
393 }
394 }
395 });
396}
397
398/// @brief Allocate buffers and build a VoxelBlockManager on the host from a
399/// ValueOnIndex grid. Uses nanovdb::util::forEach to process lower internal
400/// nodes in parallel.
401/// @tparam Log2BlockWidth Log2 of the number of active voxels per VBM block
402/// @tparam BufferT Buffer type for the returned handle (default: HostBuffer)
403/// @param grid Host-accessible ValueOnIndex grid (must satisfy isSequential())
404/// @param firstOffset First active-voxel offset covered by this VBM; must satisfy
405/// firstOffset == 1 (mod BlockWidth). Pass 0 (default) to use 1,
406/// which covers the full grid from the first active voxel.
407/// @param lastOffset Last active-voxel offset covered by this VBM. Pass 0 (default)
408/// to use grid->activeVoxelCount(), covering the full grid.
409/// @param nBlocks Allocated capacity in blocks; must be >=
410/// ceil((lastOffset - firstOffset + 1) / BlockWidth). Pass 0
411/// (default) to use the minimum required capacity.
412/// @param pool Optional pool buffer for allocation (passed to BufferT::create)
413/// @return A fully constructed VoxelBlockManagerHandle
414template<int Log2BlockWidth, typename BufferT = HostBuffer>
415VoxelBlockManagerHandle<BufferT>
417 const NanoGrid<ValueOnIndex>* grid,
418 uint64_t firstOffset = 0,
419 uint64_t lastOffset = 0,
420 uint64_t nBlocks = 0,
421 const BufferT* pool = nullptr)
422{
424 constexpr auto BlockWidth = Base::BlockWidth;
425 constexpr auto JumpMapLength = Base::JumpMapLength;
426
427 if (!firstOffset) firstOffset = 1;
428 if (!lastOffset) lastOffset = grid->activeVoxelCount();
429 if (lastOffset < firstOffset) return VoxelBlockManagerHandle<BufferT>{};
430 NANOVDB_ASSERT(!((firstOffset - 1) & (BlockWidth - 1))); // firstOffset == 1 (mod BlockWidth)
431 if (!nBlocks) nBlocks = (lastOffset - firstOffset + BlockWidth) >> Log2BlockWidth;
432
433 auto firstLeafIDBuf = BufferT::create(nBlocks * sizeof(uint32_t), pool);
434 auto jumpMapBuf = BufferT::create(nBlocks * JumpMapLength * sizeof(uint64_t), pool);
435
437 std::move(firstLeafIDBuf), std::move(jumpMapBuf),
438 nBlocks, firstOffset, lastOffset);
439
441 return handle;
442}
443
444} // namespace tools
445
446} // namespace nanovdb
447
448#if defined(__CUDACC__)
449#include <nanovdb/tools/cuda/VoxelBlockManager.cuh>
450#endif// defined(__CUDACC__)
451
452#endif // NANOVDB_VOXELBLOCKMANAGER_H_HAS_BEEN_INCLUDED
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
HostBuffer - a buffer that contains a shared or private bump pool to either externally or internally ...
Bit-parallel inclusive prefix-sum over a NanoVDB Mask<3>.
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
bool isSequential() const
return true if the specified node type is laid out breadth-first in memory and has a fixed size....
Definition NanoVDB.h:2306
uint64_t activeVoxelCount() const
Computes a AABB of active values in world space.
Definition NanoVDB.h:2281
const TreeT & tree() const
Return a const reference to the tree.
Definition NanoVDB.h:2211
Move-only owner of the two raw metadata buffers that back a VoxelBlockManager: the per-block firstLea...
Definition VoxelBlockManager.h:99
uint64_t lastOffset() const
Returns the last voxel index (linear offset) associated with this VoxelBlockManager.
Definition VoxelBlockManager.h:183
VoxelBlockManagerHandle(VoxelBlockManagerHandle &&other) noexcept
Definition VoxelBlockManager.h:134
const uint32_t * hostFirstLeafID() const
Definition VoxelBlockManager.h:191
uint64_t * hostJumpMap()
Definition VoxelBlockManager.h:193
VoxelBlockManagerHandle & operator=(const VoxelBlockManagerHandle &)=delete
VoxelBlockManagerHandle(const VoxelBlockManagerHandle &)=delete
util::enable_if< BufferHasDeviceSingle< U >::value, uint32_t * >::type deviceFirstLeafID()
For a single-space buffer the device data is the buffer itself.
Definition VoxelBlockManager.h:164
VoxelBlockManagerHandle(BufferT &&firstLeafID, BufferT &&jumpMap, uint64_t blockCount, uint64_t firstOffset, uint64_t lastOffset)
Constructor from metadata buffers (used by buildVoxelBlockManager)
Definition VoxelBlockManager.h:113
uint32_t * hostFirstLeafID()
Returns pointers to the host-side firstLeafID and jumpMap data; not available for a single-space devi...
Definition VoxelBlockManager.h:189
const uint64_t * hostJumpMap() const
Definition VoxelBlockManager.h:195
util::enable_if< BufferHasDeviceSingle< U >::value, constuint64_t * >::type deviceJumpMap() const
Definition VoxelBlockManager.h:173
util::enable_if< BufferHasDeviceSingle< U >::value, uint64_t * >::type deviceJumpMap()
Definition VoxelBlockManager.h:170
util::enable_if< BufferHasDeviceSingle< U >::value, constuint32_t * >::type deviceFirstLeafID() const
Definition VoxelBlockManager.h:167
uint64_t firstOffset() const
Returns the first voxel index (linear offset) associated with this VoxelBlockManager.
Definition VoxelBlockManager.h:180
~VoxelBlockManagerHandle()
Definition VoxelBlockManager.h:146
void reset()
clear the buffer
Definition VoxelBlockManager.h:148
uint64_t blockCount() const
Returns the number of voxel blocks in the VoxelBlockManager.
Definition VoxelBlockManager.h:177
VoxelBlockManagerHandle & operator=(VoxelBlockManagerHandle &&other) noexcept
Definition VoxelBlockManager.h:125
void buildVoxelBlockManager(const NanoGrid< ValueOnIndex > *grid, VoxelBlockManagerHandle< BufferT > &handle)
Rebuild a VoxelBlockManager in-place using a pre-allocated handle. Zeros the jumpMap and recomputes b...
Definition VoxelBlockManager.h:339
Definition GridChecksum.h:86
void buildMaskPrefixSums(const Mask< 3 > &mask, uint64_t prefixSum, uint16_t offsets[512])
Compute the 512-entry inclusive prefix-sum table for a NanoVDB Mask<3> leaf, optionally over the inve...
Definition MaskPrefixSum.h:100
uint32_t countOn(uint64_t v)
Definition Util.h:699
void shuffleDownMask(DataT *NANOVDB_RESTRICT data, const MaskT *NANOVDB_RESTRICT masks, MaskT maskBits)
One pass of masked conditional shuffle-down on a stream of values.
Definition VoxelBlockManager.h:73
uint64_t atomicOr(uint64_t *target, uint64_t mask)
Atomically ORs mask into the 64-bit word at target (relaxed ordering). Returns the old value....
Definition Util.h:724
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition ForEach.h:42
Range< 1, size_t > Range1D
Definition Range.h:33
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:34
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:4699
Definition Coord.h:590
#define NANOVDB_RESTRICT
Definition Util.h:96
#define NANOVDB_ASSERT(x)
Definition Util.h:53
static constexpr bool value
Definition HostBuffer.h:164
Compile-time geometry parameters and output sentinels shared by the CPU and CUDA VoxelBlockManager de...
Definition VoxelBlockManager.h:207
static constexpr int BlockWidth
Definition VoxelBlockManager.h:208
static constexpr uint32_t UnusedLeafIndex
Sentinel written to leafIndex slots with no active voxel in this block.
Definition VoxelBlockManager.h:213
static constexpr int JumpMapLength
number of uint64_t words per block in the jumpMap
Definition VoxelBlockManager.h:210
static constexpr uint16_t UnusedVoxelOffset
Sentinel written to voxelOffset slots with no active voxel in this block.
Definition VoxelBlockManager.h:215
CPU counterpart of tools::cuda::VoxelBlockManager. Provides host-side decode of the inverse maps (seq...
Definition VoxelBlockManager.h:228
static constexpr int BlockWidth
Definition VoxelBlockManager.h:208
static util::enable_if< BuildTraits< BuildT >::is_index, void >::type decodeInverseMaps(const NanoGrid< BuildT > *grid, const uint32_t firstLeafID, const uint64_t *jumpMap, const uint64_t blockFirstOffset, uint32_t *leafIndex, uint16_t *voxelOffset)
Decode the inverse maps for a single voxel block on the host.
Definition VoxelBlockManager.h:258
VoxelBlockManagerBase< Log2BlockWidth > Base
Definition VoxelBlockManager.h:229
static constexpr uint32_t UnusedLeafIndex
Sentinel written to leafIndex slots with no active voxel in this block.
Definition VoxelBlockManager.h:213
static constexpr int JumpMapLength
number of uint64_t words per block in the jumpMap
Definition VoxelBlockManager.h:210
static constexpr uint16_t UnusedVoxelOffset
Sentinel written to voxelOffset slots with no active voxel in this block.
Definition VoxelBlockManager.h:215
C++11 implementation of std::enable_if.
Definition Util.h:384