27#ifndef NANOVDB_VOXELBLOCKMANAGER_H_HAS_BEEN_INCLUDED
28#define NANOVDB_VOXELBLOCKMANAGER_H_HAS_BEEN_INCLUDED
69template <
int N,
int Shift,
typename DataT,
typename MaskT>
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");
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);
94template<
typename BufferT>
99 uint64_t mBlockCount{0};
100 uint64_t mFirstOffset{0};
101 uint64_t mLastOffset{0};
112 : mFirstLeafID(
std::move(firstLeafID))
113 , mJumpMap(
std::move(jumpMap))
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);
132 : mFirstLeafID(std::move(other.mFirstLeafID))
133 , mJumpMap(std::move(other.mJumpMap))
134 , mBlockCount(other.mBlockCount)
135 , mFirstOffset(other.mFirstOffset)
136 , mLastOffset(other.mLastOffset)
138 other.mBlockCount = 0;
139 other.mFirstOffset = 0;
140 other.mLastOffset = 0;
147 mFirstLeafID.destroy();
150 mFirstLeafID.clear();
159 template<
typename U = BufferT>
166 template<
typename U = BufferT>
173 template<
typename U = BufferT>
180 template<
typename U = BufferT>
182 deviceJumpMap()
const {
return static_cast<const uint64_t*
>(mJumpMap.deviceData()); }
187 template<
typename U = BufferT>
190 template<
typename U = BufferT>
193 template<
typename U = BufferT>
196 template<
typename U = BufferT>
198 deviceJumpMap()
const {
return reinterpret_cast<const uint64_t*
>(mJumpMap.data()); }
214 const uint32_t*
hostFirstLeafID()
const {
return static_cast<const uint32_t*
>(mFirstLeafID.data()); }
217 uint64_t*
hostJumpMap() {
return static_cast<uint64_t*
>(mJumpMap.data()); }
220 const uint64_t*
hostJumpMap()
const {
return static_cast<const uint64_t*
>(mJumpMap.data()); }
229template <
int Log2BlockW
idth>
233 static_assert(Log2BlockWidth >= 6,
"BlockWidth must be at least 64 (one jumpMap word per block)");
250template <
int Log2BlockW
idth>
280 template <
class BuildT>
284 const uint32_t firstLeafID,
285 const uint64_t *jumpMap,
286 const uint64_t blockFirstOffset,
288 uint16_t *voxelOffset)
293 int nExtraLeaves = 0;
301 const auto &tree = grid->
tree();
302 for (
auto leafID = firstLeafID; leafID <= firstLeafID + nExtraLeaves; leafID++) {
303 const auto &leaf = tree.template getFirstNode<0>()[leafID];
305 const uint64_t leafFirstOffset = leaf.data()->firstOffset();
306 if (leafFirstOffset >= blockFirstOffset +
BlockWidth)
break;
314 uint16_t shifts[513];
318 const uint16_t leafValueCount =
static_cast<uint16_t
>(512u) - shifts[512];
324 uint16_t leafLocalOffsets[512];
325 for (
int i = 0; i < 512; i++) leafLocalOffsets[i] = static_cast<uint16_t>(i);
339 const uint64_t globalStart = std::max(leafFirstOffset, blockFirstOffset);
340 const uint64_t globalEnd = std::min(leafFirstOffset + leafValueCount,
342 const uint64_t jStart = globalStart - leafFirstOffset;
343 const uint64_t pStart = globalStart - blockFirstOffset;
344 const uint64_t count = globalEnd - globalStart;
346 std::fill(leafIndex + pStart, leafIndex + pStart + count, leafID);
347 std::copy(leafLocalOffsets + jStart, leafLocalOffsets + jStart + count,
348 voxelOffset + pStart);
362template<
int Log2BlockW
idth,
typename BufferT>
366 constexpr auto BlockWidth = Base::BlockWidth;
367 constexpr auto JumpMapLength = Base::JumpMapLength;
376 const uint64_t lastOffset = handle.
lastOffset();
380 std::memset(jumpMap, 0, nBlocks * JumpMapLength *
sizeof(uint64_t));
382 const auto &tree = grid->
tree();
383 const auto *firstLeaf = tree.getFirstNode<0>();
384 const uint32_t leafCount = tree.nodeCount(0);
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;
393 if (leafFirstOffset > lastOffset || leafLastOffset < firstOffset)
continue;
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;
401 for (uint64_t b = lastBlock; b > firstBlock; --b)
402 firstLeafID[b] =
static_cast<uint32_t
>(leafIndex);
404 if (leafFirstOffset < firstOffset) {
405 firstLeafID[0] =
static_cast<uint32_t
>(leafIndex);
409 const uint64_t offsetInBlock = (leafFirstOffset - 1) & (BlockWidth - 1);
410 if (!offsetInBlock) {
412 firstLeafID[firstBlock] =
static_cast<uint32_t
>(leafIndex);
415 util::atomicOr(&jumpMap[firstBlock * JumpMapLength + (offsetInBlock >> 6)],
416 uint64_t(1) << (offsetInBlock & 0x3f));
438template<
int Log2BlockW
idth,
typename BufferT = HostBuffer>
439VoxelBlockManagerHandle<BufferT>
442 uint64_t firstOffset = 0,
443 uint64_t lastOffset = 0,
444 uint64_t nBlocks = 0,
445 const BufferT* pool =
nullptr)
448 constexpr auto BlockWidth = Base::BlockWidth;
449 constexpr auto JumpMapLength = Base::JumpMapLength;
451 if (!firstOffset) firstOffset = 1;
455 if (!nBlocks) nBlocks = (lastOffset - firstOffset + BlockWidth) >> Log2BlockWidth;
457 auto firstLeafIDBuf = BufferT::create(nBlocks *
sizeof(uint32_t), pool);
458 auto jumpMapBuf = BufferT::create(nBlocks * JumpMapLength *
sizeof(uint64_t), pool);
461 std::move(firstLeafIDBuf), std::move(jumpMapBuf),
462 nBlocks, firstOffset, lastOffset);
472#if defined(__CUDACC__)
473#include <nanovdb/tools/cuda/VoxelBlockManager.cuh>
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
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
#define NANOVDB_RESTRICT
Definition Util.h:96
#define NANOVDB_ASSERT(x)
Definition Util.h:53
static constexpr bool value
Definition HostBuffer.h:165
C++11 implementation of std::enable_if.
Definition Util.h:353