OpenVDB  0.104.0
LeafManager.h
Go to the documentation of this file.
1 
2 //
3 // Copyright (c) 2012 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
43 
44 #ifndef OPENVDB_TREE_LEAF_MANAGER_HAS_BEEN_INCLUDED
45 #define OPENVDB_TREE_LEAF_MANAGER_HAS_BEEN_INCLUDED
46 
47 #include <iostream>
48 #include <algorithm> // for std::swap
49 #include <boost/shared_ptr.hpp>
50 #include <boost/static_assert.hpp>
51 #include <boost/bind.hpp>
52 #include <boost/function.hpp>
53 #include <tbb/blocked_range.h>
54 #include <tbb/parallel_for.h>
55 #include <openvdb/Types.h>
56 
57 namespace openvdb {
59 namespace OPENVDB_VERSION_NAME {
60 namespace tree {
61 
73 template<typename TreeT>
75 {
76  public:
77  typedef TreeT TreeType;
78  typedef typename TreeType::LeafNodeType LeafType;
79  typedef typename LeafType::Buffer BufferType;
80  typedef typename tbb::blocked_range<size_t> RangeType;
81 
84  LeafManager(TreeType &tree, size_t auxBuffersPerLeaf=0, bool serial=false):
85  mTree(&tree),
86  mLeafCount(0),
87  mAuxBufferCount(0),
88  mAuxBuffersPerLeaf(auxBuffersPerLeaf),
89  mLeafs(NULL),
90  mAuxBuffers(NULL),
91  mTask(0),
92  mIsMaster(true)
93  {
94  this->rebuild(serial);
95  }
96 
98  LeafManager(const LeafManager& other):
99  mTree(other.mTree),
100  mLeafCount(other.mLeafCount),
101  mAuxBufferCount(other.mAuxBufferCount),
102  mAuxBuffersPerLeaf(other.mAuxBuffersPerLeaf),
103  mLeafs(other.mLeafs),
104  mAuxBuffers(other.mAuxBuffers),
105  mTask(other.mTask),
106  mIsMaster(false)
107  {
108  }
109 
110  virtual ~LeafManager()
111  {
112  if (mIsMaster) {
113  delete [] mLeafs;
114  delete [] mAuxBuffers;
115  }
116  }
117 
122  void rebuild(bool serial=false)
123  {
124  this->initLeafs();
125  this->initAuxBuffers(serial);
126  }
129  void rebuild(size_t auxBuffersPerLeaf, bool serial=false)
130  {
131  mAuxBuffersPerLeaf = auxBuffersPerLeaf;
132  this->rebuild(serial);
133  }
136  void rebuild(TreeType& tree, bool serial=false)
137  {
138  mTree = &tree;
139  this->rebuild(serial);
140  }
143  void rebuild(TreeType& tree, size_t auxBuffersPerLeaf, bool serial=false)
144  {
145  mTree = &tree;
146  mAuxBuffersPerLeaf = auxBuffersPerLeaf;
147  this->rebuild(serial);
148  }
154  void rebuildAuxBuffers(size_t auxBuffersPerLeaf, bool serial=false)
155  {
156  mAuxBuffersPerLeaf = auxBuffersPerLeaf;
157  this->initAuxBuffers(serial);
158  }
160  void removeAuxBuffers() { this->rebuildAuxBuffers(0); }
161 
163  void rebuildLeafs()
164  {
165  this->removeAuxBuffers();
166  this->initLeafs();
167  }
168 
170  size_t auxBufferCount() const { return mAuxBufferCount; }
172  size_t auxBuffersPerLeaf() const { return mAuxBuffersPerLeaf; }
173 
176  size_t leafCount() const { return mLeafCount; }
177 
178  TreeType& tree() { return *mTree; }
179 
183  LeafType& leaf(size_t leafId) { assert(leafId<mLeafCount); return *mLeafs[leafId]; }
184 
193  BufferType& getBuffer(size_t leafId, size_t bufferId)
194  {
195  assert(leafId < mLeafCount);
196  assert(bufferId==0 || bufferId -1 < mAuxBuffersPerLeaf);
197  return bufferId == 0 ? mLeafs[leafId]->buffer() :
198  mAuxBuffers[ leafId*mAuxBuffersPerLeaf + bufferId -1 ];
199  }
200 
202  RangeType getRange(size_t grainsize=1)
203  {
204  return RangeType(0, mLeafCount, grainsize);
205  }
206 
215  bool swapLeafBuffer(size_t bufferId, bool serial = false)
216  {
217  if (bufferId == 0 || bufferId > mAuxBuffersPerLeaf) return false;
218  mTask = boost::bind(&LeafManager::doSwapLeafBuffer, _1, _2, bufferId-1);
219  this->cook(serial ? 0 : 512);
220  return true;//success
221  }
222  bool swapBuffer(size_t bufferId1, size_t bufferId2, bool serial = false)
223  {
224  const size_t b1 = std::min(bufferId1,bufferId2);
225  const size_t b2 = std::max(bufferId1,bufferId2);
226  if (b1==b2 || b2 > mAuxBuffersPerLeaf) return false;
227  if (b1==0) {
228  mTask = boost::bind(&LeafManager::doSwapLeafBuffer, _1, _2, b2-1);
229  } else {
230  mTask = boost::bind(&LeafManager::doSwapAuxBuffer, _1, _2, b1-1, b2-1);
231  }
232  this->cook(serial ? 0 : 512);
233  return true;//success
234  }
235 
244  bool syncAuxBuffer(size_t bufferId, bool serial = false)
245  {
246  if (bufferId==0 || bufferId > mAuxBuffersPerLeaf) return false;
247  mTask = boost::bind(&LeafManager::doSyncAuxBuffer, _1, _2, bufferId - 1);
248  this->cook(serial ? 0 : 64);
249  return true;//success
250  }
251 
255  bool syncAllBuffers(bool serial = false)
256  {
257  switch (mAuxBuffersPerLeaf) {
258  case 0:
259  return false;//nothing to do
260  case 1:
261  mTask = boost::bind(&LeafManager::doSyncAllBuffers1, _1, _2); break;
262  case 2:
263  mTask = boost::bind(&LeafManager::doSyncAllBuffers2, _1, _2); break;
264  default:
265  mTask = boost::bind(&LeafManager::doSyncAllBuffersN, _1, _2);
266  }
267  this->cook(serial ? 0 : 64);
268  return true;//success
269  }
270 
273 
275  void operator()(const RangeType& r) const
276  {
277  if (mTask) mTask(const_cast<LeafManager*>(this), r);
278  else OPENVDB_THROW(ValueError, "task is undefined");
279  }
280 
281  private:
282 
283  void initLeafs()
284  {
285  const size_t leafCount = mTree->leafCount();
286  if (leafCount != mLeafCount) {
287  delete [] mLeafs;
288  mLeafs = (leafCount == 0) ? NULL : new LeafType*[leafCount];
289  mLeafCount = leafCount;
290  }
291  typename TreeType::LeafIter iter = mTree->beginLeaf();
292  for (size_t n = 0; n != leafCount; ++n, ++iter) mLeafs[n] = iter.getLeaf();
293  }
294  void initAuxBuffers(bool serial)
295  {
296  const size_t auxBufferCount = mLeafCount * mAuxBuffersPerLeaf;
297  if (auxBufferCount != mAuxBufferCount) {
298  delete [] mAuxBuffers;
299  mAuxBuffers = (auxBufferCount == 0) ? NULL : new BufferType[auxBufferCount];
300  mAuxBufferCount = auxBufferCount;
301  }
302  this->syncAllBuffers(serial);
303  }
304  void cook(size_t grainsize)
305  {
306  if (grainsize>0) {
307  tbb::parallel_for(this->getRange(grainsize), *this);
308  } else {
309  (*this)(this->getRange());
310  }
311  }
312  void doSwapLeafBuffer(const RangeType& r, size_t auxBufferId)
313  {
314  for (size_t n = r.begin(), m = r.end(), N = mAuxBuffersPerLeaf; n != m; ++n) {
315  mLeafs[n]->swap(mAuxBuffers[ n*N + auxBufferId ]);
316  }
317  }
318  void doSwapAuxBuffer(const RangeType& r, size_t auxBufferId1, size_t auxBufferId2)
319  {
320  for (size_t N = mAuxBuffersPerLeaf, n = N*r.begin(), m = N*r.end(); n != m; n+=N) {
321  mAuxBuffers[n + auxBufferId1].swap(mAuxBuffers[n + auxBufferId2]);
322  }
323  }
324  void doSyncAuxBuffer(const RangeType& r, size_t auxBufferId)
325  {
326  for (size_t n = r.begin(), m = r.end(), N = mAuxBuffersPerLeaf; n != m; ++n) {
327  mAuxBuffers[ n*N + auxBufferId ] = mLeafs[n]->buffer();
328  }
329  }
330  void doSyncAllBuffers1(const RangeType& r)
331  {
332  for (size_t n = r.begin(), m = r.end(); n != m; ++n) mAuxBuffers[n] = mLeafs[n]->buffer();
333  }
334  void doSyncAllBuffers2(const RangeType& r)
335  {
336  for (size_t n = r.begin(), m = r.end(); n != m; ++n) {
337  const BufferType& leafBuffer = mLeafs[n]->buffer();
338  mAuxBuffers[2*n ] = leafBuffer;
339  mAuxBuffers[2*n+1] = leafBuffer;
340  }
341  }
342  void doSyncAllBuffersN(const RangeType& r)
343  {
344  for (size_t n = r.begin(), m = r.end(), N = mAuxBuffersPerLeaf; n != m; ++n) {
345  const BufferType& leafBuffer = mLeafs[n]->buffer();
346  for (size_t i=n*N, j=i+N; i!=j; ++i) mAuxBuffers[i] = leafBuffer;
347  }
348  }
349  typedef typename boost::function<void (LeafManager*, const RangeType&)> FuncType;
350 
351  TreeType* mTree;
352  size_t mLeafCount, mAuxBufferCount, mAuxBuffersPerLeaf;
353  LeafType** mLeafs;//array of LeafNode pointers
354  BufferType* mAuxBuffers;//array of auxiliary buffers
355  FuncType mTask;
356  const bool mIsMaster;
357 };//end of LeafManager class
358 
359 } // namespace tree
360 } // namespace OPENVDB_VERSION_NAME
361 } // namespace openvdb
362 
363 #endif // OPENVDB_TREE_LEAF_MANAGER_HAS_BEEN_INCLUDED
364 
365 // Copyright (c) 2012 DreamWorks Animation LLC
366 // All rights reserved. This software is distributed under the
367 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )