15 #ifndef OPENVDB_TREE_LEAFMANAGER_HAS_BEEN_INCLUDED
16 #define OPENVDB_TREE_LEAFMANAGER_HAS_BEEN_INCLUDED
21 #include <tbb/blocked_range.h>
22 #include <tbb/parallel_for.h>
23 #include <tbb/parallel_reduce.h>
26 #include <type_traits>
42 template<
typename TreeT>
struct TreeTraits<const TreeT> {
53 template<
typename ManagerT>
56 using RangeT =
typename ManagerT::RangeType;
57 using LeafT =
typename ManagerT::LeafType;
58 using BufT =
typename ManagerT::BufferType;
63 for (
size_t n = r.begin(), m = r.end(),
N = bufsPerLeaf;
n != m; ++
n) {
64 leafs[
n]->swap(bufs[
n *
N + auxBufferIdx]);
84 template<
typename TreeT>
124 return mRange.mLeafManager.
getBuffer(mPos, bufferIdx);
127 size_t pos()
const {
return mPos; }
129 bool isValid()
const {
return mPos>=mRange.mBegin && mPos<=mRange.mEnd; }
131 bool test()
const {
return mPos < mRange.mEnd; }
138 return (mPos != other.mPos) || (&mRange != &other.mRange);
151 , mGrainSize(grainSize)
152 , mLeafManager(leafManager)
160 size_t size()
const {
return mEnd - mBegin; }
166 bool empty()
const {
return !(mBegin < mEnd);}
173 , mGrainSize(r.mGrainSize)
174 , mLeafManager(r.mLeafManager)
179 size_t mEnd, mBegin, mGrainSize;
185 size_t middle = r.mBegin + (r.mEnd - r.mBegin) / 2u;
208 , mLeafCount(end-begin)
211 , mLeafPtrs(new
LeafType*[mLeafCount])
212 , mLeafs(mLeafPtrs.
get())
214 size_t n = mLeafCount;
216 while (n--) *target++ = *source++;
225 , mLeafCount(other.mLeafCount)
226 , mAuxBufferCount(other.mAuxBufferCount)
227 , mAuxBuffersPerLeaf(other.mAuxBuffersPerLeaf)
228 , mLeafs(other.mLeafs)
229 , mAuxBuffers(other.mAuxBuffers)
241 this->initLeafArray(serial);
242 this->initAuxBuffers(serial);
270 this->initAuxBuffers(serial);
279 this->initLeafArray(serial);
296 for (
const auto&
leaf: range) { sum +=
leaf.onVoxelCount(); }
334 OPENVDB_ASSERT(bufferIdx == 0 || bufferIdx - 1 < mAuxBuffersPerLeaf);
335 return bufferIdx == 0 ? mLeafs[leafIdx]->buffer()
336 : mAuxBuffers[leafIdx * mAuxBuffersPerLeaf + bufferIdx - 1];
348 return LeafRange(0, mLeafCount, *
this, grainsize);
362 namespace ph = std::placeholders;
363 if (bufferIdx == 0 || bufferIdx > mAuxBuffersPerLeaf || this->
isConstTree())
return false;
364 mTask = std::bind(&LeafManager::doSwapLeafBuffer, ph::_1, ph::_2, bufferIdx - 1);
365 this->cook(serial ? 0 : 512);
372 bool swapBuffer(
size_t bufferIdx1,
size_t bufferIdx2,
bool serial =
false)
374 namespace ph = std::placeholders;
375 const size_t b1 =
std::min(bufferIdx1, bufferIdx2);
376 const size_t b2 =
std::max(bufferIdx1, bufferIdx2);
377 if (b1 == b2 || b2 > mAuxBuffersPerLeaf)
return false;
380 mTask = std::bind(&LeafManager::doSwapLeafBuffer, ph::_1, ph::_2, b2-1);
382 mTask = std::bind(&LeafManager::doSwapAuxBuffer, ph::_1, ph::_2, b1-1, b2-1);
384 this->cook(serial ? 0 : 512);
398 namespace ph = std::placeholders;
399 if (bufferIdx == 0 || bufferIdx > mAuxBuffersPerLeaf)
return false;
400 mTask = std::bind(&LeafManager::doSyncAuxBuffer, ph::_1, ph::_2, bufferIdx - 1);
401 this->cook(serial ? 0 : 64);
410 namespace ph = std::placeholders;
411 switch (mAuxBuffersPerLeaf) {
412 case 0:
return false;
413 case 1: mTask = std::bind(&LeafManager::doSyncAllBuffers1, ph::_1, ph::_2);
break;
414 case 2: mTask = std::bind(&LeafManager::doSyncAllBuffers2, ph::_1, ph::_2);
break;
415 default: mTask = std::bind(&LeafManager::doSyncAllBuffersN, ph::_1, ph::_2);
break;
417 this->cook(serial ? 0 : 64);
483 template<
typename LeafOp>
484 void foreach(
const LeafOp&
op,
bool threaded =
true,
size_t grainSize=1)
532 template<
typename LeafOp>
552 if (offsets ==
nullptr || size < mLeafCount) {
554 offsets =
new size_t[mLeafCount];
558 if ( grainSize > 0 ) {
559 PrefixSum tmp(this->
leafRange( grainSize ), offsets, prefix);
561 for (
size_t i=0; i<mLeafCount; ++i) {
563 prefix += mLeafs[i]->onVoxelCount();
575 if (mTask) mTask(const_cast<LeafManager*>(
this), r);
581 void initLeafArray(
bool serial =
false)
586 using NonConstLeafParentT =
typename NodeChainT::template Get<1>;
589 std::deque<LeafParentT*> leafParents;
591 leafParents.emplace_back(&mTree->root());
594 mTree->getNodes(leafParents);
599 std::vector<Index64> leafCounts;
601 leafCounts.reserve(leafParents.size());
602 for (LeafParentT* leafParent : leafParents) {
603 leafCounts.push_back(leafParent->childCount());
606 leafCounts.resize(leafParents.size());
611 tbb::blocked_range<size_t>(0, leafParents.size(), 64),
612 [&](tbb::blocked_range<size_t>&
range)
614 for (
size_t i = range.begin(); i < range.end(); i++) {
615 leafCounts[i] = leafParents[i]->childCount();
623 for (
size_t i = 1; i < leafCounts.size(); i++) {
624 leafCounts[i] += leafCounts[i-1];
627 const size_t leafCount = leafCounts.empty() ? 0 : leafCounts.back();
631 if (leafCount != mLeafCount) {
633 mLeafPtrs.reset(
new LeafType*[leafCount]);
634 mLeafs = mLeafPtrs.get();
642 if (mLeafCount == 0)
return;
648 for (LeafParentT* leafParent : leafParents) {
649 for (
auto iter = leafParent->beginChildOn(); iter; ++iter) {
650 *leafPtr++ = &iter.getValue();
655 tbb::blocked_range<size_t>(0, leafParents.size()),
656 [&](tbb::blocked_range<size_t>& range)
658 size_t i = range.begin();
660 if (i > 0) leafPtr += leafCounts[i-1];
661 for ( ; i < range.end(); i++) {
662 for (
auto iter = leafParents[i]->beginChildOn(); iter; ++iter) {
663 *leafPtr++ = &iter.getValue();
671 void initAuxBuffers(
bool serial)
674 if (auxBufferCount != mAuxBufferCount) {
675 if (auxBufferCount > 0) {
677 mAuxBuffers = mAuxBufferPtrs.get();
679 mAuxBufferPtrs.reset();
680 mAuxBuffers =
nullptr;
687 void cook(
size_t grainsize)
696 void doSwapLeafBuffer(
const RangeType&
r,
size_t auxBufferIdx)
699 r, auxBufferIdx, mLeafs, mAuxBuffers, mAuxBuffersPerLeaf);
702 void doSwapAuxBuffer(
const RangeType&
r,
size_t auxBufferIdx1,
size_t auxBufferIdx2)
704 for (
size_t N = mAuxBuffersPerLeaf,
n =
N*r.
begin(), m =
N*r.
end();
n != m;
n+=
N) {
705 mAuxBuffers[
n + auxBufferIdx1].swap(mAuxBuffers[
n + auxBufferIdx2]);
709 void doSyncAuxBuffer(
const RangeType& r,
size_t auxBufferIdx)
711 for (
size_t n = r.begin(), m = r.end(),
N = mAuxBuffersPerLeaf;
n != m; ++
n) {
712 mAuxBuffers[
n*
N + auxBufferIdx] = mLeafs[
n]->buffer();
716 void doSyncAllBuffers1(
const RangeType& r)
718 for (
size_t n = r.begin(), m = r.end();
n != m; ++
n) {
719 mAuxBuffers[
n] = mLeafs[
n]->buffer();
723 void doSyncAllBuffers2(
const RangeType& r)
725 for (
size_t n = r.begin(), m = r.end();
n != m; ++
n) {
726 const BufferType& leafBuffer = mLeafs[
n]->buffer();
727 mAuxBuffers[2*
n ] = leafBuffer;
728 mAuxBuffers[2*
n+1] = leafBuffer;
732 void doSyncAllBuffersN(
const RangeType& r)
734 for (
size_t n = r.begin(), m = r.end(),
N = mAuxBuffersPerLeaf;
n != m; ++
n) {
735 const BufferType& leafBuffer = mLeafs[
n]->buffer();
736 for (
size_t i=
n*
N,
j=i+N; i!=
j; ++i) mAuxBuffers[i] = leafBuffer;
742 template<
typename LeafOp>
743 struct LeafTransformer
745 LeafTransformer(
const LeafOp &leafOp) : mLeafOp(leafOp)
748 void run(
const LeafRange &range,
bool threaded)
const
754 for (
typename LeafRange::Iterator it = range.begin(); it; ++it) mLeafOp(*it, it.pos());
756 const LeafOp mLeafOp;
761 template<
typename LeafOp>
764 LeafReducer(LeafOp &leafOp) : mLeafOp(&leafOp)
767 LeafReducer(
const LeafReducer &other,
tbb::split)
768 : mLeafOpPtr(std::make_unique<LeafOp>(*(other.mLeafOp), tbb::
split()))
769 , mLeafOp(mLeafOpPtr.
get())
772 void run(
const LeafRange& range,
bool threaded)
774 threaded ? tbb::parallel_reduce(range, *
this) : (*
this)(range);
778 LeafOp &op = *mLeafOp;
779 for (
typename LeafRange::Iterator it = range.begin(); it; ++it)
op(*it, it.pos());
781 void join(
const LeafReducer& other) { mLeafOp->join(*(other.mLeafOp)); }
782 std::unique_ptr<LeafOp> mLeafOpPtr;
783 LeafOp *mLeafOp =
nullptr;
789 PrefixSum(
const LeafRange& r,
size_t*
offsets,
size_t& prefix)
793 for (
size_t i=0, leafCount = r.size(); i<
leafCount; ++i) {
794 size_t tmp = offsets[i];
799 inline void operator()(
const LeafRange& r)
const {
800 for (
typename LeafRange::Iterator i = r.begin(); i; ++i) {
801 mOffsets[i.pos()] = i->onVoxelCount();
807 using FuncType =
typename std::function<void (LeafManager*, const RangeType&)>;
810 size_t mLeafCount, mAuxBufferCount, mAuxBuffersPerLeaf;
811 std::unique_ptr<LeafType*[]> mLeafPtrs;
813 std::unique_ptr<NonConstBufferType[]> mAuxBufferPtrs;
815 FuncType mTask =
nullptr;
820 template<
typename TreeT>
839 #endif // OPENVDB_TREE_LEAFMANAGER_HAS_BEEN_INCLUDED
void rebuild(TreeType &tree, bool serial=false)
Repopulate the leaf array and delete and reallocate auxiliary buffers.
void rebuild(TreeType &tree, size_t auxBuffersPerLeaf, bool serial=false)
Repopulate the leaf array and delete and reallocate auxiliary buffers.
LeafManager(TreeType &tree, size_t auxBuffersPerLeaf=0, bool serial=false)
Constructor from a tree reference and an auxiliary buffer count.
void reduce(LeafOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to each leaf node in the LeafManager. Unlike foreach (defined above) this method performs a reduction on all the leaf nodes.
SYS_FORCE_INLINE const_iterator begin() const
typename TreeType::ValueType ValueType
LeafRange(size_t begin, size_t end, const LeafManager &leafManager, size_t grainSize=1)
typename ManagerT::LeafType LeafT
typename CopyConstness< TreeType, NonConstBufferType >::Type BufferType
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
static void doSwapLeafBuffer(const RangeT &r, size_t auxBufferIdx, LeafT **leafs, BufT *bufs, size_t bufsPerLeaf)
LeafType * operator->() const
Return a pointer to the leaf node to which this iterator is pointing.
const LeafManager & leafManager() const
Iterator & operator=(const Iterator &)=default
GLsizei const GLfloat * value
const TreeType & tree() const
Return a const reference to tree associated with this manager.
TreeType & tree()
Return a reference to the tree associated with this manager.
bool operator!=(const Iterator &other) const
typename ManagerT::BufferType BufT
RootNodeType & root()
Return a reference to the root node associated with this manager.
#define OPENVDB_USE_VERSION_NAMESPACE
bool is_divisible() const
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
void operator()(const RangeType &r) const
Used internally by tbb::parallel_for() - never call it directly!
**But if you need a or simply need to know when the task has note that the like this
const RootNodeType & root() const
Return a const reference to root node associated with this manager.
void rebuildAuxBuffers(size_t auxBuffersPerLeaf, bool serial=false)
Change the number of auxiliary buffers.
tbb::blocked_range< size_t > RangeType
GLuint GLsizei const GLuint const GLintptr * offsets
bool isValid() const
Return true if the position of this iterator is in a valid range.
#define OPENVDB_ASSERT(X)
SYS_FORCE_INLINE const_iterator end() const
size_t leafCount() const
Return the number of leaf nodes.
typename TreeType::LeafNodeType NonConstLeafType
typename SubtreeT::template Append< HeadT > Type
void rebuildLeafArray(bool serial=false)
Remove the auxiliary buffers and rebuild the leaf array.
Iterator(const LeafRange &range, size_t pos)
typename LeafType::Buffer NonConstBufferType
typename ManagerT::LeafType LeafT
LeafType & operator*() const
Return a reference to the leaf node to which this iterator is pointing.
BufferType & buffer(size_t bufferIdx)
Return the nth buffer for the leaf node to which this iterator is pointing, where n = bufferIdx and n...
typename TreeType::RootNodeType RootNodeType
typename std::remove_const< ToType >::type Type
LeafManager(TreeType &tree, LeafType **begin, LeafType **end, size_t auxBuffersPerLeaf=0, bool serial=false)
Construct directly from an existing array of leafnodes.
GLsizei GLsizei GLchar * source
OIIO_UTIL_API void parallel_for(int32_t begin, int32_t end, function_view< void(int32_t)> task, paropt opt=0)
bool empty() const
Return true if this iterator is exhausted.
size_t getPrefixSum(size_t *&offsets, size_t &size, size_t grainSize=1) const
Generate a linear array of prefix sums of offsets into the active voxels in the leafs. So offsets[n]+m is the offset to the mth active voxel in the nth leaf node (useful for user-managed value buffers, e.g. in tools/LevelSetAdvect.h).
typename TreeT::LeafIter LeafIterType
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
typename leafmgr::TreeTraits< TreeType >::LeafIterType LeafIterType
auto get(const UT_ARTIterator< T > &it) -> decltype(it.key())
typename ManagerT::BufferType BufT
size_t pos() const
Return the index into the leaf array of the current leaf node.
RangeType getRange(size_t grainsize=1) const
Return a tbb::blocked_range of leaf array indices.
LeafManager(const LeafManager &other)
bool swapLeafBuffer(size_t bufferIdx, bool serial=false)
Swap each leaf node's buffer with the nth corresponding auxiliary buffer, where n = bufferIdx...
GA_API const UT_StringHolder transform
bool isConstTree() const
Return true if the tree associated with this manager is immutable.
bool syncAuxBuffer(size_t bufferIdx, bool serial=false)
Sync up the specified auxiliary buffer with the corresponding leaf node buffer.
The root node of an OpenVDB tree.
size_t auxBufferCount() const
Return the total number of allocated auxiliary buffers.
typename ManagerT::RangeType RangeT
static const bool IsConstTree
typename TreeT::LeafCIter LeafIterType
size_t auxBuffersPerLeaf() const
Return the number of auxiliary buffers per leaf node.
LeafRange(LeafRange &r, tbb::split)
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GA_API const UT_StringHolder N
static const bool IsConstTree
void rebuild(size_t auxBuffersPerLeaf, bool serial=false)
Repopulate the leaf array and delete and reallocate auxiliary buffers.
typename ManagerT::RangeType RangeT
Useful traits for Tree types.
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Iterator & operator++()
Advance to the next leaf node.
void OIIO_UTIL_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
void rebuild(bool serial=false)
(Re)initialize by resizing (if necessary) and repopulating the leaf array and by deleting existing au...
bool operator==(const Iterator &other) const
typename CopyConstness< TreeType, NonConstLeafType >::Type LeafType
static void doSwapLeafBuffer(const RangeT &, size_t, LeafT **, BufT *, size_t)
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Index64 activeLeafVoxelCount() const
Return the number of active voxels in the leaf nodes.
const LeafRange & leafRange() const
void removeAuxBuffers()
Remove the auxiliary buffers, but don't rebuild the leaf array.
bool swapBuffer(size_t bufferIdx1, size_t bufferIdx2, bool serial=false)
Swap any two buffers for each leaf node.
#define OPENVDB_THROW(exception, message)
BufferType & getBuffer(size_t leafIdx, size_t bufferIdx) const
Return the leaf or auxiliary buffer for the leaf node at index leafIdx. If bufferIdx is zero...
bool test() const
Return true if this iterator is not yet exhausted.
bool syncAllBuffers(bool serial=false)
Sync up all auxiliary buffers with their corresponding leaf node buffers.
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.