OpenVDB: nanovdb/util/IndexGridBuilder.h Source File

OpenVDB 10.0.1

Loading...
Searching...
No Matches
IndexGridBuilder.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: MPL-2.0
3
4/*!
5 \file IndexGridBuilder.h
6
7 \author Ken Museth
8
9 \date July 8, 2022
10
11 \brief Generates a NanoVDB IndexGrid from any existing NanoVDB grid.
12
13 \note An IndexGrid encodes index offsets to external value arrays
14*/
15
16#ifndef NANOVDB_INDEXGRIDBUILDER_H_HAS_BEEN_INCLUDED
17#define NANOVDB_INDEXGRIDBUILDER_H_HAS_BEEN_INCLUDED
18
19#include "GridHandle.h"
20#include "NodeManager.h"
21#include "Range.h"
22#include "ForEach.h"
23
24#include <map>
25#include <limits>
26#include <iostream>
27#include <sstream> // for stringstream
28#include <vector>
29#include <cstring> // for memcpy
30
31namespace nanovdb {
32
33/// @brief Allows for the construction of NanoVDB grids without any dependency
34template <typename SrcValueT>
35 class IndexGridBuilder
36{
37 using SrcNode0 = NanoLeaf< SrcValueT>;
38 using SrcNode1 = NanoLower<SrcValueT>;
39 using SrcNode2 = NanoUpper<SrcValueT>;
40 using SrcData0 = typename SrcNode0::DataType;
41 using SrcData1 = typename SrcNode1::DataType;
42 using SrcData2 = typename SrcNode2::DataType;
43 using SrcRootT = NanoRoot<SrcValueT>;
44 using SrcTreeT = NanoTree<SrcValueT>;
45 using SrcGridT = NanoGrid<SrcValueT>;
46
47 using DstNode0 = NanoLeaf< ValueIndex>;
48 using DstNode1 = NanoLower<ValueIndex>;
49 using DstNode2 = NanoUpper<ValueIndex>;
50 using DstData0 = NanoLeaf< ValueIndex>::DataType;
51 using DstData1 = NanoLower<ValueIndex>::DataType;
52 using DstData2 = NanoUpper<ValueIndex>::DataType;
53 using DstRootT = NanoRoot<ValueIndex>;
54 using DstTreeT = NanoTree<ValueIndex>;
55 using DstGridT = NanoGrid<ValueIndex>;
56
57 NodeManagerHandle<> mSrcMgrHandle;
58 NodeManager<SrcValueT> *mSrcMgr;
59 std::vector<uint64_t> mValIdx2, mValIdx1, mValIdx0;// store id of first value in node
60 uint8_t* mBufferPtr;// pointer to the beginning of the buffer
61 uint64_t mBufferOffsets[9];//grid, tree, root, upper, lower, leafs, meta, data, buffer size
62 uint64_t mValueCount;
63 const bool mIsSparse, mIncludeStats;// include inactive values and stats
64
65 DstNode0* getLeaf( int i=0) const {return PtrAdd<DstNode0>(mBufferPtr, mBufferOffsets[5]) + i;}
66 DstNode1* getLower(int i=0) const {return PtrAdd<DstNode1>(mBufferPtr, mBufferOffsets[4]) + i;}
67 DstNode2* getUpper(int i=0) const {return PtrAdd<DstNode2>(mBufferPtr, mBufferOffsets[3]) + i;}
68 DstRootT* getRoot() const {return PtrAdd<DstRootT>(mBufferPtr, mBufferOffsets[2]);}
69 DstTreeT* getTree() const {return PtrAdd<DstTreeT>(mBufferPtr, mBufferOffsets[1]);}
70 DstGridT* getGrid() const {return PtrAdd<DstGridT>(mBufferPtr, mBufferOffsets[0]);}
71
72 // Count the number of values (possibly only active)
73 void countValues();
74
75 // Below are private methods use to serialize nodes into NanoVDB
76 template<typename BufferT>
77 GridHandle<BufferT> initHandle(uint32_t channels, const BufferT& buffer);
78
79 void processLeafs();
80
81 void processLower();
82
83 void processUpper();
84
85 void processRoot();
86
87 void processTree();
88
89 void processGrid(const std::string& name, uint32_t channels);
90
91 void processChannels(uint32_t channels);
92
93public:
94
95 /// @brief Constructor based on a source grid
96 ///
97 /// @param srcGrid Source grid used to generate the IndexGrid
98 /// @param includeInactive Include inactive values or only active values
99 /// @param includeStats Include min/max/avg/std per node or not
100 ///
101 /// @note For minimum memory consumption set the two boolean options to false
102 IndexGridBuilder(const SrcGridT& srcGrid, bool includeInactive = true, bool includeStats = true)
103 : mSrcMgrHandle(createNodeManager(srcGrid))
104 , mSrcMgr(mSrcMgrHandle.template mgr<SrcValueT>())
105 , mValueCount(0)
106 , mIsSparse(!includeInactive)
107 , mIncludeStats(includeStats)
108 {}
109
110 /// @brief Return an instance of a GridHandle (invoking move semantics)
111 template<typename BufferT = HostBuffer>
112 GridHandle<BufferT> getHandle(const std::string& name = "", uint32_t channels = 0u, const BufferT& buffer = BufferT());
113
114 /// @brief return the total number of values located in the source grid.
115 ///
116 /// @note This is minimum number of elements required for the external array that the IndexGrid
117 /// points to.
118 uint64_t getValueCount() const { return mValueCount; }
119
120 /// @brief return a buffer with all the values in the source grid
121 template<typename BufferT = HostBuffer>
122 BufferT getValues(uint32_t channels = 1u, const BufferT &buffer = BufferT());
123
124 /// @brief copy values from the source grid into the provided array and returns number of values copied
125 uint64_t copyValues(SrcValueT *buffer, size_t maxValueCount = -1);
126}; // IndexGridBuilder
127
128//================================================================================================
129
130template<typename SrcValueT>
131template<typename BufferT>
132 GridHandle<BufferT> IndexGridBuilder<SrcValueT>::
133 getHandle(const std::string &name, uint32_t channels, const BufferT &buffer)
134{
135 this->countValues();
136
137 auto handle = this->template initHandle<BufferT>(channels, buffer);// initialize the arrays of nodes
138
139 this->processLeafs();
140
141 this->processLower();
142
143 this->processUpper();
144
145 this->processRoot();
146
147 this->processTree();
148
149 this->processGrid(name, channels);
150
151 this->processChannels(channels);
152
153 return handle;
154} // IndexGridBuilder::getHandle
155
156//================================================================================================
157
158template<typename SrcValueT>
159void IndexGridBuilder<SrcValueT>::countValues()
160{
161 const uint64_t stats = mIncludeStats ? 4u : 0u;
162
163 uint64_t valueCount = 1u + stats;//background, [minimum, maximum, average, and deviation]
164
165 // root values
166 if (mIsSparse) {
167 for (auto it = mSrcMgr->root().beginValueOn(); it; ++it) ++valueCount;
168 } else {
169 for (auto it = mSrcMgr->root().beginValue(); it; ++it) ++valueCount;
170 }
171
172 // tile values in upper internal nodes
173 mValIdx2.resize(mSrcMgr->nodeCount(2) + 1);
174 if (mIsSparse) {
175 forEach(1, mValIdx2.size(), 8, [&](const Range1D& r){
176 for (auto i = r.begin(); i!=r.end(); ++i) {
177 mValIdx2[i] = stats + mSrcMgr->upper(i-1).data()->mValueMask.countOn();
178 }
179 });
180 } else {
181 forEach(1, mValIdx2.size(), 8, [&](const Range1D& r){
182 const uint64_t n = 32768u + stats;
183 for (auto i = r.begin(); i!=r.end(); ++i) {
184 mValIdx2[i] = n - mSrcMgr->upper(i-1).data()->mChildMask.countOn();
185 }
186 });
187 }
188 mValIdx2[0] = valueCount;
189 for (size_t i=1; i<mValIdx2.size(); ++i) mValIdx2[i] += mValIdx2[i-1];// pre-fixed sum
190 valueCount = mValIdx2.back();
191
192 // tile values in lower internal nodes
193 mValIdx1.resize(mSrcMgr->nodeCount(1) + 1);
194 if (mIsSparse) {
195 forEach(1, mValIdx1.size(), 8, [&](const Range1D& r){
196 for (auto i = r.begin(); i!=r.end(); ++i) {
197 mValIdx1[i] = stats + mSrcMgr->lower(i-1).data()->mValueMask.countOn();
198 }
199 });
200 } else {
201 forEach(1, mValIdx1.size(), 8, [&](const Range1D& r){
202 const uint64_t n = 4096u + stats;
203 for (auto i = r.begin(); i!=r.end(); ++i) {
204 mValIdx1[i] = n - mSrcMgr->lower(i-1).data()->mChildMask.countOn();
205 }
206 });
207 }
208 mValIdx1[0] = valueCount;
209 for (size_t i=1; i<mValIdx1.size(); ++i) mValIdx1[i] += mValIdx1[i-1];// pre-fixed sum
210 valueCount = mValIdx1.back();
211
212 // voxel values in leaf nodes
213 mValIdx0.clear();
214 mValIdx0.resize(mSrcMgr->nodeCount(0) + 1, 512u + stats);
215 if (mIsSparse) {
216 forEach(1, mValIdx0.size(), 8, [&](const Range1D& r) {
217 for (auto i = r.begin(); i != r.end(); ++i) {
218 mValIdx0[i] = stats + mSrcMgr->leaf(i-1).data()->mValueMask.countOn();
219 }
220 });
221 }
222 mValIdx0[0] = valueCount;
223 for (size_t i=1; i<mValIdx0.size(); ++i) mValIdx0[i] += mValIdx0[i-1];// pre-fixed sum
224
225 mValueCount = mValIdx0.back();
226}// countValues
227
228
229//================================================================================================
230template<typename SrcValueT>
231uint64_t IndexGridBuilder<SrcValueT>::copyValues(SrcValueT *buffer, size_t maxValueCount)
232{
233 assert(mBufferPtr);
234 if (maxValueCount < mValueCount) return 0;
235
236 // Value array always starts with these entries
237 buffer[0] = mSrcMgr->root().background();
238 if (mIncludeStats) {
239 buffer[1] = mSrcMgr->root().minimum();
240 buffer[2] = mSrcMgr->root().maximum();
241 buffer[3] = mSrcMgr->root().average();
242 buffer[4] = mSrcMgr->root().stdDeviation();
243 }
244 {// copy root tile values
245 auto *srcData = mSrcMgr->root().data();
246 SrcValueT *v = buffer + (mIncludeStats ? 5u : 1u);
247 for (uint32_t tileID = 0; tileID < srcData->mTableSize; ++tileID) {
248 auto *srcTile = srcData->tile(tileID);
249 if (srcTile->isChild() ||(mIsSparse&&!srcTile->state)) continue;
250 NANOVDB_ASSERT(v - buffer < mValueCount);
251 *v++ = srcTile->value;
252 }
253 }
254
255 {// upper nodes
256 auto kernel = [&](const Range1D& r) {
257 DstData2 *dstData = this->getUpper(r.begin())->data();
258 for (auto i = r.begin(); i != r.end(); ++i, ++dstData) {
259 SrcValueT *v = buffer + mValIdx2[i];
260 const SrcNode2 &srcNode = mSrcMgr->upper(i);
261 if (mIncludeStats) {
262 *v++ = srcNode.minimum();
263 *v++ = srcNode.maximum();
264 *v++ = srcNode.average();
265 *v++ = srcNode.stdDeviation();
266 }
267 if (mIsSparse) {
268 for (auto it = srcNode.beginValueOn(); it; ++it) {
269 NANOVDB_ASSERT(v - buffer < mValueCount);
270 *v++ = *it;
271 }
272 } else {
273 auto *srcData = srcNode.data();
274 for (uint32_t j = 0; j != 32768; ++j) {
275 if (srcData->mChildMask.isOn(j)) continue;
276 NANOVDB_ASSERT(v - buffer < mValueCount);
277 *v++ = srcData->getValue(j);
278 }
279 }
280 }
281 };
282 forEach(0, mSrcMgr->nodeCount(2), 1, kernel);
283 }
284
285 {// lower nodes
286 auto kernel = [&](const Range1D& r) {
287 DstData1 *dstData = this->getLower(r.begin())->data();
288 for (auto i = r.begin(); i != r.end(); ++i, ++dstData) {
289 SrcValueT *v = buffer + mValIdx1[i];
290 const SrcNode1 &srcNode = mSrcMgr->lower(i);
291 if (mIncludeStats) {
292 *v++ = srcNode.minimum();
293 *v++ = srcNode.maximum();
294 *v++ = srcNode.average();
295 *v++ = srcNode.stdDeviation();
296 }
297 if (mIsSparse) {
298 for (auto it = srcNode.beginValueOn(); it; ++it) {
299 NANOVDB_ASSERT(v - buffer < mValueCount);
300 *v++ = *it;
301 }
302 } else {
303 auto *srcData = srcNode.data();
304 for (uint32_t j = 0; j != 4096; ++j) {
305 if (srcData->mChildMask.isOn(j)) continue;
306 NANOVDB_ASSERT(v - buffer < mValueCount);
307 *v++ = srcData->getValue(j);
308 }
309 }
310 }
311 };
312 forEach(0, mSrcMgr->nodeCount(1), 4, kernel);
313 }
314 {// leaf nodes
315 auto kernel = [&](const Range1D& r) {
316 DstData0 *dstLeaf = this->getLeaf(r.begin())->data();
317 for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
318 SrcValueT *v = buffer + mValIdx0[i];// bug!?
319 const SrcNode0 &srcLeaf = mSrcMgr->leaf(i);
320 if (mIncludeStats) {
321 *v++ = srcLeaf.minimum();
322 *v++ = srcLeaf.maximum();
323 *v++ = srcLeaf.average();
324 *v++ = srcLeaf.stdDeviation();
325 }
326 if (mIsSparse) {
327 for (auto it = srcLeaf.beginValueOn(); it; ++it) {
328 NANOVDB_ASSERT(v - buffer < mValueCount);
329 *v++ = *it;
330 }
331 } else {
332 const SrcData0 *srcData = srcLeaf.data();
333 for (uint32_t j = 0; j != 512; ++j) {
334 NANOVDB_ASSERT(v - buffer < mValueCount);
335 *v++ = srcData->getValue(j);
336 }
337 }
338 }
339 };
340 forEach(0, mSrcMgr->nodeCount(0), 8, kernel);
341 }
342 return mValueCount;
343} // IndexGridBuilder::copyValues
344
345template<typename SrcValueT>
346template<typename BufferT>
347BufferT IndexGridBuilder<SrcValueT>::getValues(uint32_t channels, const BufferT &buffer)
348{
349 assert(channels > 0);
350 auto values = BufferT::create(channels*sizeof(SrcValueT)*mValueCount, &buffer);
351 SrcValueT *p = reinterpret_cast<SrcValueT*>(values.data());
352 if (!this->copyValues(p, mValueCount)) {
353 throw std::runtime_error("getValues: insufficient channels");
354 }
355 for (uint32_t i=1; i<channels; ++i) {
356 nanovdb::forEach(0,mValueCount,1024,[&](const nanovdb::Range1D &r){
357 SrcValueT *dst=p+i*mValueCount+r.begin(), *end=dst+r.size(), *src=dst-mValueCount;
358 while(dst!=end) *dst++ = *src++;
359 });
360 }
361 return values;
362} // IndexGridBuilder::getValues
363
364//================================================================================================
365
366template<typename SrcValueT>
367template<typename BufferT>
368 GridHandle<BufferT> IndexGridBuilder<SrcValueT>::
369 initHandle(uint32_t channels, const BufferT& buffer)
370{
371 const SrcTreeT &srcTree = mSrcMgr->tree();
372 mBufferOffsets[0] = 0;// grid is always stored at the start of the buffer!
373 mBufferOffsets[1] = DstGridT::memUsage(); // tree
374 mBufferOffsets[2] = mBufferOffsets[1] + DstTreeT::memUsage(); // root
375 mBufferOffsets[3] = mBufferOffsets[2] + DstRootT::memUsage(srcTree.root().tileCount());// upper internal nodes
376 mBufferOffsets[4] = mBufferOffsets[3] + srcTree.nodeCount(2)*sizeof(DstData2); // lower internal nodes
377 mBufferOffsets[5] = mBufferOffsets[4] + srcTree.nodeCount(1)*sizeof(DstData1); // leaf nodes
378 mBufferOffsets[6] = mBufferOffsets[5] + srcTree.nodeCount(0)*sizeof(DstData0); // meta data
379 mBufferOffsets[7] = mBufferOffsets[6] + GridBlindMetaData::memUsage(channels); // channel values
380 mBufferOffsets[8] = mBufferOffsets[7] + channels*mValueCount*sizeof(SrcValueT);// total size
381#if 0
382 std::cerr << "grid starts at " << mBufferOffsets[0] <<" byte" << std::endl;
383 std::cerr << "tree starts at " << mBufferOffsets[1] <<" byte" << std::endl;
384 std::cerr << "root starts at " << mBufferOffsets[2] <<" byte" << std::endl;
385 std::cerr << "node starts at " << mBufferOffsets[3] <<" byte" << " #" << srcTree.nodeCount(2) << std::endl;
386 std::cerr << "node starts at " << mBufferOffsets[4] <<" byte" << " #" << srcTree.nodeCount(1) << std::endl;
387 std::cerr << "leaf starts at " << mBufferOffsets[5] <<" byte" << " #" << srcTree.nodeCount(0) << std::endl;
388 std::cerr << "meta starts at " << mBufferOffsets[6] <<" byte" << std::endl;
389 std::cerr << "data starts at " << mBufferOffsets[7] <<" byte" << std::endl;
390 std::cerr << "buffer ends at " << mBufferOffsets[8] <<" byte" << std::endl;
391 std::cerr << "creating buffer of size " << (mBufferOffsets[8]>>20) << "MB" << std::endl;
392#endif
393 GridHandle<BufferT> handle(BufferT::create(mBufferOffsets[8], &buffer));
394 mBufferPtr = handle.data();
395
396 return handle;
397} // IndexGridBuilder::initHandle
398
399//================================================================================================
400
401template<typename SrcValueT>
402void IndexGridBuilder<SrcValueT>::processGrid(const std::string& name, uint32_t channels)
403{
404 auto *srcData = mSrcMgr->grid().data();
405 auto *dstData = this->getGrid()->data();
406
407 dstData->mMagic = NANOVDB_MAGIC_NUMBER;
408 dstData->mChecksum = 0u;
409 dstData->mVersion = Version();
410 dstData->mFlags = static_cast<uint32_t>(GridFlags::IsBreadthFirst);
411 dstData->mGridIndex = 0;
412 dstData->mGridCount = 1;
413 dstData->mGridSize = mBufferOffsets[8];
414 std::memset(dstData->mGridName, '\0', GridData::MaxNameSize);//overwrite mGridName
415 strncpy(dstData->mGridName, name.c_str(), GridData::MaxNameSize-1);
416 dstData->mMap = srcData->mMap;
417 dstData->mWorldBBox = srcData->mWorldBBox;
418 dstData->mVoxelSize = srcData->mVoxelSize;
419 dstData->mGridClass = GridClass::IndexGrid;
420 dstData->mGridType = mapToGridType<ValueIndex>();
421 dstData->mBlindMetadataOffset = mBufferOffsets[6];
422 dstData->mBlindMetadataCount = channels;
423 dstData->mData0 = 0u;
424 dstData->mData1 = mValueCount;// encode the total number of values being indexed
425 dstData->mData2 = 0u;
426
427 if (name.length() >= GridData::MaxNameSize) {// currently we don't support long grid names
428 std::stringstream ss;
429 ss << "Grid name \"" << name << "\" is more then " << GridData::MaxNameSize << " characters";
430 throw std::runtime_error(ss.str());
431 }
432} // IndexGridBuilder::processGrid
433
434//================================================================================================
435
436template<typename SrcValueT>
437void IndexGridBuilder<SrcValueT>::processTree()
438{
439 auto *srcData = mSrcMgr->tree().data();
440 auto *dstData = this->getTree()->data();
441 for (int i=0; i<4; ++i) dstData->mNodeOffset[i] = mBufferOffsets[5-i] - mBufferOffsets[1];// byte offset from tree to first leaf, lower, upper and root node
442 for (int i=0; i<3; ++i) {
443 dstData->mNodeCount[i] = srcData->mNodeCount[i];// total number of nodes of type: leaf, lower internal, upper internal
444 dstData->mTileCount[i] = srcData->mTileCount[i];// total number of active tile values at the lower internal, upper internal and root node levels
445 }
446 dstData->mVoxelCount = srcData->mVoxelCount;// total number of active voxels in the root and all its child nodes
447} // IndexGridBuilder::processTree
448
449//================================================================================================
450
451template<typename SrcValueT>
452void IndexGridBuilder<SrcValueT>::processRoot()
453{
454 auto *srcData = mSrcMgr->root().data();
455 auto *dstData = this->getRoot()->data();
456
457 if (dstData->padding()>0) std::memset(dstData, 0, DstRootT::memUsage(mSrcMgr->root().tileCount()));
458 dstData->mBBox = srcData->mBBox;
459 dstData->mTableSize = srcData->mTableSize;
460 dstData->mBackground = 0u;
461 uint64_t valueCount = 1u;// the first entry is always the background value
462 if (mIncludeStats) {
463 valueCount += 4u;
464 dstData->mMinimum = 1u;
465 dstData->mMaximum = 2u;
466 dstData->mAverage = 3u;
467 dstData->mStdDevi = 4u;
468 } else if (dstData->padding()==0) {
469 dstData->mMinimum = 0u;
470 dstData->mMaximum = 0u;
471 dstData->mAverage = 0u;
472 dstData->mStdDevi = 0u;
473 }
474 //uint64_t valueCount = 5u;// this is always the first available index
475 for (uint32_t tileID = 0, childID = 0; tileID < dstData->mTableSize; ++tileID) {
476 auto *srcTile = srcData->tile(tileID);
477 auto *dstTile = dstData->tile(tileID);
478 dstTile->key = srcTile->key;
479 if (srcTile->isChild()) {
480 dstTile->child = childID * sizeof(DstNode2) + mBufferOffsets[3] - mBufferOffsets[2];
481 dstTile->state = false;
482 dstTile->value = std::numeric_limits<uint64_t>::max();
483 ++childID;
484 } else {
485 dstTile->child = 0;
486 dstTile->state = srcTile->state;
487 if (!(mIsSparse && !dstTile->state)) dstTile->value = valueCount++;
488 }
489 }
490} // IndexGridBuilder::processRoot
491
492//================================================================================================
493
494template<typename SrcValueT>
495void IndexGridBuilder<SrcValueT>::processUpper()
496{
497 static_assert(DstData2::padding()==0u, "Expected upper internal nodes to have no padding");
498 auto kernel = [&](const Range1D& r) {
499 const bool activeOnly = mIsSparse;
500 const bool hasStats = mIncludeStats;
501 auto *dstData1 = this->getLower()->data();// fixed size
502 auto *dstData2 = this->getUpper(r.begin())->data();// fixed size
503 for (auto i = r.begin(); i != r.end(); ++i, ++dstData2) {
504 SrcData2 *srcData2 = mSrcMgr->upper(i).data();// might vary in size due to compression
505 dstData2->mBBox = srcData2->mBBox;
506 dstData2->mFlags = srcData2->mFlags;
507 srcData2->mFlags = i;// encode node ID
508 dstData2->mChildMask = srcData2->mChildMask;
509 dstData2->mValueMask = srcData2->mValueMask;
510 uint64_t n = mValIdx2[i];
511 if (mIncludeStats) {
512 dstData2->mMinimum = n++;
513 dstData2->mMaximum = n++;
514 dstData2->mAverage = n++;
515 dstData2->mStdDevi = n++;
516 } else {
517 dstData2->mMinimum = 0u;
518 dstData2->mMaximum = 0u;
519 dstData2->mAverage = 0u;
520 dstData2->mStdDevi = 0u;
521 }
522 for (uint32_t j = 0; j != 32768; ++j) {
523 if (dstData2->isChild(j)) {
524 SrcData1 *srcChild = srcData2->getChild(j)->data();
525 DstData1 *dstChild = dstData1 + srcChild->mFlags;
526 dstData2->setChild(j, dstChild);
527 srcChild->mFlags = dstChild->mFlags;// restore
528 } else {
529 const bool test = activeOnly && !srcData2->mValueMask.isOn(j);
530 dstData2->setValue(j, test ? 0 : n++);
531 }
532 }
533
534 }
535 };
536 forEach(0, mSrcMgr->nodeCount(2), 1, kernel);
537} // IndexGridBuilder::processUpper
538
539//================================================================================================
540
541template<typename SrcValueT>
542void IndexGridBuilder<SrcValueT>::processLower()
543{
544 static_assert(DstData1::padding()==0u, "Expected lower internal nodes to have no padding");
545 auto kernel = [&](const Range1D& r) {
546 const bool activeOnly = mIsSparse;
547 DstData0 *dstData0 = this->getLeaf()->data();// first dst leaf node
548 DstData1 *dstData1 = this->getLower(r.begin())->data();// fixed size
549 for (auto i = r.begin(); i != r.end(); ++i, ++dstData1) {
550 SrcData1 *srcData1 = mSrcMgr->lower(i).data();// might vary in size due to compression
551 dstData1->mBBox = srcData1->mBBox;
552 dstData1->mFlags = srcData1->mFlags;
553 srcData1->mFlags = i;// encode node ID
554 dstData1->mChildMask = srcData1->mChildMask;
555 dstData1->mValueMask = srcData1->mValueMask;
556 uint64_t n = mValIdx1[i];
557 if (mIncludeStats) {
558 dstData1->mMinimum = n++;
559 dstData1->mMaximum = n++;
560 dstData1->mAverage = n++;
561 dstData1->mStdDevi = n++;
562 } else {
563 dstData1->mMinimum = 0u;
564 dstData1->mMaximum = 0u;
565 dstData1->mAverage = 0u;
566 dstData1->mStdDevi = 0u;
567 }
568 for (uint32_t j = 0; j != 4096; ++j) {
569 if (dstData1->isChild(j)) {
570 SrcData0 *srcChild = srcData1->getChild(j)->data();
571 DstData0 *dstChild = dstData0 + srcChild->mBBoxMin[0];
572 dstData1->setChild(j, dstChild);
573 srcChild->mBBoxMin[0] = dstChild->mBBoxMin[0];// restore
574 } else {
575 const bool test = activeOnly && !srcData1->mValueMask.isOn(j);
576 dstData1->setValue(j, test ? 0 : n++);
577 }
578 }
579 }
580 };
581 forEach(0, mSrcMgr->nodeCount(1), 4, kernel);
582} // IndexGridBuilder::processLower
583
584//================================================================================================
585
586template<typename SrcValueT>
587void IndexGridBuilder<SrcValueT>::processLeafs()
588{
589 static_assert(DstData0::padding()==0u, "Expected leaf nodes to have no padding");
590
591 auto kernel = [&](const Range1D& r) {
592 DstData0 *dstData0 = this->getLeaf(r.begin())->data();// fixed size
593 const uint8_t flags = mIsSparse ? 16u : 0u;// 4th bit indicates sparseness
594 for (auto i = r.begin(); i != r.end(); ++i, ++dstData0) {
595 SrcData0 *srcData0 = mSrcMgr->leaf(i).data();// might vary in size due to compression
596 dstData0->mBBoxMin = srcData0->mBBoxMin;
597 srcData0->mBBoxMin[0] = int(i);// encode node ID
598 dstData0->mBBoxDif[0] = srcData0->mBBoxDif[0];
599 dstData0->mBBoxDif[1] = srcData0->mBBoxDif[1];
600 dstData0->mBBoxDif[2] = srcData0->mBBoxDif[2];
601 dstData0->mFlags = flags | (srcData0->mFlags & 2u);// 2nd bit indicates a bbox
602 dstData0->mValueMask = srcData0->mValueMask;
603
604 if (mIncludeStats) {
605 dstData0->mStatsOff = mValIdx0[i];// first 4 entries are leaf stats
606 dstData0->mValueOff = mValIdx0[i] + 4u;
607 } else {
608 dstData0->mStatsOff = 0u;// set to background which indicates no stats!
609 dstData0->mValueOff = mValIdx0[i];
610 }
611 }
612 };
613 forEach(0, mSrcMgr->nodeCount(0), 8, kernel);
614} // IndexGridBuilder::processLeafs
615
616//================================================================================================
617
618template<typename SrcValueT>
619void IndexGridBuilder<SrcValueT>::processChannels(uint32_t channels)
620{
621 for (uint32_t i=0; i<channels; ++i) {
622 auto *metaData = PtrAdd<GridBlindMetaData>(mBufferPtr, mBufferOffsets[6]) + i;
623 auto *blindData = PtrAdd<SrcValueT>(mBufferPtr, mBufferOffsets[7]) + i*mValueCount;
624 metaData->setBlindData(blindData);
625 metaData->mElementCount = mValueCount;
626 metaData->mFlags = 0;
627 metaData->mSemantic = GridBlindDataSemantic::Unknown;
628 metaData->mDataClass = GridBlindDataClass::ChannelArray;
629 metaData->mDataType = mapToGridType<SrcValueT>();
630 std::memset(metaData->mName, '\0', GridBlindMetaData::MaxNameSize);
631 std::stringstream ss;
632 ss << toStr(metaData->mDataType) << "_channel_" << i;
633 strncpy(metaData->mName, ss.str().c_str(), GridBlindMetaData::MaxNameSize-1);
634 if (i) {// deep copy from previous channel
635#if 0
636 this->copyValues(blindData, mValueCount);
637 //std::memcpy(blindData, blindData-mValueCount, mValueCount*sizeof(SrcValueT));
638#else
639 nanovdb::forEach(0,mValueCount,1024,[&](const nanovdb::Range1D &r){
640 SrcValueT *dst=blindData+r.begin(), *end=dst+r.size(), *src=dst-mValueCount;
641 while(dst!=end) *dst++ = *src++;
642 });
643#endif
644 } else {
645 this->copyValues(blindData, mValueCount);
646 }
647 }
648}
649
650} // namespace nanovdb
651
652#endif // NANOVDB_INDEXGRIDBUILDER_H_HAS_BEEN_INCLUDED
ForEach.h
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
GridHandle.h
Defines two classes, a GridRegister the defines the value type (e.g. Double, Float etc) of a NanoVDB ...
NANOVDB_ASSERT
#define NANOVDB_ASSERT(x)
Definition: NanoVDB.h:173
NANOVDB_MAGIC_NUMBER
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:121
Range.h
Custom Range class that is compatible with the tbb::blocked_range classes.
nanovdb::GridHandle
This class serves to manage a raw memory buffer of a NanoVDB Grid.
Definition: GridHandle.h:71
nanovdb::Grid
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2556
nanovdb::Grid::data
DataType * data()
Definition: NanoVDB.h:2575
nanovdb::IndexGridBuilder
Allows for the construction of NanoVDB grids without any dependency.
Definition: IndexGridBuilder.h:36
nanovdb::IndexGridBuilder::getValueCount
uint64_t getValueCount() const
return the total number of values located in the source grid.
Definition: IndexGridBuilder.h:118
nanovdb::IndexGridBuilder::IndexGridBuilder
IndexGridBuilder(const SrcGridT &srcGrid, bool includeInactive=true, bool includeStats=true)
Constructor based on a source grid.
Definition: IndexGridBuilder.h:102
nanovdb::IndexGridBuilder::getValues
BufferT getValues(uint32_t channels=1u, const BufferT &buffer=BufferT())
return a buffer with all the values in the source grid
Definition: IndexGridBuilder.h:347
nanovdb::IndexGridBuilder::getHandle
GridHandle< BufferT > getHandle(const std::string &name="", uint32_t channels=0u, const BufferT &buffer=BufferT())
Return an instance of a GridHandle (invoking move semantics)
Definition: IndexGridBuilder.h:133
nanovdb::IndexGridBuilder::copyValues
uint64_t copyValues(SrcValueT *buffer, size_t maxValueCount=-1)
copy values from the source grid into the provided array and returns number of values copied
Definition: IndexGridBuilder.h:231
nanovdb::InternalNode
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:3521
nanovdb::InternalNode::DataType
InternalData< ChildT, Log2Dim > DataType
Definition: NanoVDB.h:3523
nanovdb::InternalNode::average
const FloatType & average() const
Return a const reference to the average of all the active values encoded in this internal node and an...
Definition: NanoVDB.h:3623
nanovdb::InternalNode::data
DataType * data()
Definition: NanoVDB.h:3597
nanovdb::InternalNode::stdDeviation
const FloatType & stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this internal ...
Definition: NanoVDB.h:3629
nanovdb::InternalNode::maximum
const ValueType & maximum() const
Return a const reference to the maximum active value encoded in this internal node and any of its chi...
Definition: NanoVDB.h:3620
nanovdb::InternalNode::minimum
const ValueType & minimum() const
Return a const reference to the minimum active value encoded in this internal node and any of its chi...
Definition: NanoVDB.h:3617
nanovdb::InternalNode::beginValueOn
ValueOnIterator beginValueOn() const
Definition: NanoVDB.h:3589
nanovdb::LeafNode
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:4252
nanovdb::LeafNode::DataType
LeafData< BuildT, CoordT, MaskT, Log2Dim > DataType
Definition: NanoVDB.h:4261
nanovdb::LeafNode::data
DataType * data()
Definition: NanoVDB.h:4334
nanovdb::LeafNode::maximum
ValueType maximum() const
Return a const reference to the maximum active value encoded in this leaf node.
Definition: NanoVDB.h:4345
nanovdb::LeafNode::average
FloatType average() const
Return a const reference to the average of all the active values encoded in this leaf node.
Definition: NanoVDB.h:4348
nanovdb::LeafNode::minimum
ValueType minimum() const
Return a const reference to the minimum active value encoded in this leaf node.
Definition: NanoVDB.h:4342
nanovdb::LeafNode::beginValueOn
ValueOnIterator beginValueOn() const
Definition: NanoVDB.h:4285
nanovdb::LeafNode::stdDeviation
FloatType stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this leaf node...
Definition: NanoVDB.h:4354
nanovdb::NodeManagerHandle
NodeManagerHandle manages the memory of a NodeManager.
Definition: NodeManager.h:55
nanovdb::NodeManager
NodeManager allows for sequential access to nodes.
Definition: NodeManager.h:189
nanovdb::NodeManager::nodeCount
uint64_t nodeCount(int level) const
Return the number of tree nodes at the specified level.
Definition: NodeManager.h:244
nanovdb::NodeManager::upper
const Node2 & upper(uint32_t i) const
Return the i'th upper internal node with respect to breadth-first ordering.
Definition: NodeManager.h:283
nanovdb::NodeManager::leaf
const Node0 & leaf(uint32_t i) const
Return the i'th leaf node with respect to breadth-first ordering.
Definition: NodeManager.h:275
nanovdb::NodeManager::grid
GridT & grid()
Return a reference to the grid.
Definition: NodeManager.h:231
nanovdb::NodeManager::root
RootT & root()
Return a reference to the root.
Definition: NodeManager.h:239
nanovdb::NodeManager::tree
TreeT & tree()
Return a reference to the tree.
Definition: NodeManager.h:235
nanovdb::NodeManager::lower
const Node1 & lower(uint32_t i) const
Return the i'th lower internal node with respect to breadth-first ordering.
Definition: NodeManager.h:279
nanovdb::Range
Definition: Range.h:28
nanovdb::RootNode
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:3074
nanovdb::Tree
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2799
nanovdb
Definition: NanoVDB.h:208
nanovdb::toStr
const char * toStr(GridType gridType)
Retuns a c-string used to describe a GridType.
Definition: NanoVDB.h:267
nanovdb::forEach
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
nanovdb::createNodeManager
NodeManagerHandle< BufferT > createNodeManager(const NanoGrid< BuildT > &grid, const BufferT &buffer=BufferT())
brief Construct a NodeManager and return its handle
Definition: NodeManager.h:289
nanovdb::Range1D
Range< 1, size_t > Range1D
Definition: Range.h:30
NodeManager.h
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
nanovdb::GridData::mMagic
uint64_t mMagic
Definition: NanoVDB.h:2434
nanovdb::InternalData
Struct with all the member data of the InternalNode (useful during serialization of an openvdb Intern...
Definition: NanoVDB.h:3418
nanovdb::LeafData
Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode)
Definition: NanoVDB.h:3810