27#ifndef NANOVDB_VOXELBLOCKMANAGER_H_HAS_BEEN_INCLUDED
28#define NANOVDB_VOXELBLOCKMANAGER_H_HAS_BEEN_INCLUDED
72template <
int N,
int Shift,
typename DataT,
typename MaskT>
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");
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);
97template<
typename BufferT>
100 BufferT mFirstLeafID;
102 uint64_t mBlockCount{0};
103 uint64_t mFirstOffset{0};
104 uint64_t mLastOffset{0};
115 : mFirstLeafID(
std::move(firstLeafID))
116 , mJumpMap(
std::move(jumpMap))
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);
135 : mFirstLeafID(std::move(other.mFirstLeafID))
136 , mJumpMap(std::move(other.mJumpMap))
137 , mBlockCount(other.mBlockCount)
138 , mFirstOffset(other.mFirstOffset)
139 , mLastOffset(other.mLastOffset)
141 other.mBlockCount = 0;
142 other.mFirstOffset = 0;
143 other.mLastOffset = 0;
150 mFirstLeafID.destroy();
153 mFirstLeafID.clear();
162 template<
typename U = BufferT>
165 template<
typename U = BufferT>
168 template<
typename U = BufferT>
171 template<
typename U = BufferT>
173 deviceJumpMap()
const {
return reinterpret_cast<const uint64_t*
>(mJumpMap.data()); }
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()); }
205template <
int Log2BlockW
idth>
209 static_assert(Log2BlockWidth >= 6,
"BlockWidth must be at least 64 (one jumpMap word per block)");
226template <
int Log2BlockW
idth>
256 template <
class BuildT>
260 const uint32_t firstLeafID,
261 const uint64_t *jumpMap,
262 const uint64_t blockFirstOffset,
264 uint16_t *voxelOffset)
269 int nExtraLeaves = 0;
277 const auto &tree = grid->
tree();
278 for (
auto leafID = firstLeafID; leafID <= firstLeafID + nExtraLeaves; leafID++) {
279 const auto &leaf = tree.template getFirstNode<0>()[leafID];
281 const uint64_t leafFirstOffset = leaf.data()->firstOffset();
282 if (leafFirstOffset >= blockFirstOffset +
BlockWidth)
break;
290 uint16_t shifts[513];
294 const uint16_t leafValueCount =
static_cast<uint16_t
>(512u) - shifts[512];
300 uint16_t leafLocalOffsets[512];
301 for (
int i = 0; i < 512; i++) leafLocalOffsets[i] = static_cast<uint16_t>(i);
315 const uint64_t globalStart = std::max(leafFirstOffset, blockFirstOffset);
316 const uint64_t globalEnd = std::min(leafFirstOffset + leafValueCount,
318 const uint64_t jStart = globalStart - leafFirstOffset;
319 const uint64_t pStart = globalStart - blockFirstOffset;
320 const uint64_t count = globalEnd - globalStart;
322 std::fill(leafIndex + pStart, leafIndex + pStart + count, leafID);
323 std::copy(leafLocalOffsets + jStart, leafLocalOffsets + jStart + count,
324 voxelOffset + pStart);
338template<
int Log2BlockW
idth,
typename BufferT>
342 constexpr auto BlockWidth = Base::BlockWidth;
343 constexpr auto JumpMapLength = Base::JumpMapLength;
352 const uint64_t lastOffset = handle.
lastOffset();
356 std::memset(jumpMap, 0, nBlocks * JumpMapLength *
sizeof(uint64_t));
358 const auto &tree = grid->
tree();
359 const auto *firstLeaf = tree.getFirstNode<0>();
360 const uint32_t leafCount = tree.nodeCount(0);
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;
369 if (leafFirstOffset > lastOffset || leafLastOffset < firstOffset)
continue;
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;
377 for (uint64_t b = lastBlock; b > firstBlock; --b)
378 firstLeafID[b] =
static_cast<uint32_t
>(leafIndex);
380 if (leafFirstOffset < firstOffset) {
381 firstLeafID[0] =
static_cast<uint32_t
>(leafIndex);
385 const uint64_t offsetInBlock = (leafFirstOffset - 1) & (BlockWidth - 1);
386 if (!offsetInBlock) {
388 firstLeafID[firstBlock] =
static_cast<uint32_t
>(leafIndex);
391 util::atomicOr(&jumpMap[firstBlock * JumpMapLength + (offsetInBlock >> 6)],
392 uint64_t(1) << (offsetInBlock & 0x3f));
414template<
int Log2BlockW
idth,
typename BufferT = HostBuffer>
415VoxelBlockManagerHandle<BufferT>
418 uint64_t firstOffset = 0,
419 uint64_t lastOffset = 0,
420 uint64_t nBlocks = 0,
421 const BufferT* pool =
nullptr)
424 constexpr auto BlockWidth = Base::BlockWidth;
425 constexpr auto JumpMapLength = Base::JumpMapLength;
427 if (!firstOffset) firstOffset = 1;
431 if (!nBlocks) nBlocks = (lastOffset - firstOffset + BlockWidth) >> Log2BlockWidth;
433 auto firstLeafIDBuf = BufferT::create(nBlocks *
sizeof(uint32_t), pool);
434 auto jumpMapBuf = BufferT::create(nBlocks * JumpMapLength *
sizeof(uint64_t), pool);
437 std::move(firstLeafIDBuf), std::move(jumpMapBuf),
438 nBlocks, firstOffset, lastOffset);
448#if defined(__CUDACC__)
449#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: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
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
#define NANOVDB_RESTRICT
Definition Util.h:96
#define NANOVDB_ASSERT(x)
Definition Util.h:53
static constexpr bool value
Definition HostBuffer.h:164
C++11 implementation of std::enable_if.
Definition Util.h:384