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