OpenVDB  4.0.2
LeafBuffer.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2017 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 
31 #ifndef OPENVDB_TREE_LEAFBUFFER_HAS_BEEN_INCLUDED
32 #define OPENVDB_TREE_LEAFBUFFER_HAS_BEEN_INCLUDED
33 
34 #include <openvdb/Types.h>
35 #include <openvdb/io/Compression.h> // for io::readCompressedValues(), etc
36 #include <openvdb/util/NodeMasks.h>
37 #include <tbb/atomic.h>
38 #include <tbb/spin_mutex.h>
39 #include <algorithm> // for std::swap
40 #include <cstddef> // for offsetof()
41 #include <iostream>
42 #include <memory>
43 #include <type_traits>
44 
45 
46 class TestLeaf;
47 
48 namespace openvdb {
50 namespace OPENVDB_VERSION_NAME {
51 namespace tree {
52 
53 namespace {
54 
67 template<typename T>
68 struct LeafBufferFlags
69 {
70  // These structs need to have the same data members as LeafBuffer.
71  struct Atomic { union { T* data; void* ptr; }; tbb::atomic<Index32> i; tbb::spin_mutex mutex; };
72  struct NonAtomic { union { T* data; void* ptr; }; Index32 i; tbb::spin_mutex mutex; };
73 
74 #ifndef __INTEL_COMPILER
75  static constexpr bool IsAtomic = ((sizeof(Atomic) == sizeof(NonAtomic))
77  && (offsetof(Atomic, i) == offsetof(NonAtomic, i)));
78 #else
79  // We can't use offsetof() with ICC, because it requires the arguments
80  // to be POD types. (C++11 requires only that they be standard layout types,
81  // which Atomic and NonAtomic are.)
82  static constexpr bool IsAtomic = (sizeof(Atomic) == sizeof(NonAtomic));
83 #endif
84  static constexpr size_t size = sizeof(Atomic);
87  using type = typename std::conditional<IsAtomic, tbb::atomic<Index32>, Index32>::type;
88 };
89 
90 } // unnamed namespace
91 
92 
95 template<typename T, Index Log2Dim>
97 {
98 public:
99  using ValueType = T;
102  static const Index SIZE = 1 << 3 * Log2Dim;
103 
104 #ifndef OPENVDB_2_ABI_COMPATIBLE
105  struct FileInfo
106  {
107  FileInfo(): bufpos(0) , maskpos(0) {}
108  std::streamoff bufpos;
109  std::streamoff maskpos;
112  };
113 #endif
114 
115 #ifdef OPENVDB_2_ABI_COMPATIBLE
116  LeafBuffer(): mData(new ValueType[SIZE]) {}
119  explicit LeafBuffer(const ValueType& val): mData(new ValueType[SIZE]) { this->fill(val); }
121  LeafBuffer(const LeafBuffer& other): mData(new ValueType[SIZE]) { *this = other; }
123  ~LeafBuffer() { delete[] mData; }
124 
126  bool isOutOfCore() const { return false; }
128  bool empty() const { return (mData == nullptr); }
129 #else
130  inline LeafBuffer(): mData(new ValueType[SIZE]), mOutOfCore(0) {}
133  explicit inline LeafBuffer(const ValueType&);
135  inline LeafBuffer(const LeafBuffer&);
137  LeafBuffer(PartialCreate, const ValueType&): mData(nullptr), mOutOfCore(0) {}
139  inline ~LeafBuffer();
140 
142  bool isOutOfCore() const { return bool(mOutOfCore); }
144  bool empty() const { return !mData || this->isOutOfCore(); }
145 #endif
146  bool allocate() { if (mData == nullptr) mData = new ValueType[SIZE]; return true; }
148 
150  inline void fill(const ValueType&);
151 
153  const ValueType& getValue(Index i) const { return this->at(i); }
155  const ValueType& operator[](Index i) const { return this->at(i); }
157  inline void setValue(Index i, const ValueType&);
158 
160  inline LeafBuffer& operator=(const LeafBuffer&);
161 
164  inline bool operator==(const LeafBuffer&) const;
167  inline bool operator!=(const LeafBuffer& other) const { return !(other == *this); }
168 
170  inline void swap(LeafBuffer&);
171 
173  inline Index memUsage() const;
175  static Index size() { return SIZE; }
176 
180  const ValueType* data() const;
184  ValueType* data();
185 
186 private:
188  inline const ValueType& at(Index i) const;
189 
195  ValueType& operator[](Index i) { return const_cast<ValueType&>(this->at(i)); }
196 
197  bool deallocate();
198 
199 #ifdef OPENVDB_2_ABI_COMPATIBLE
200  void setOutOfCore(bool) {}
201  void loadValues() const {}
202  void doLoad() const {}
203  bool detachFromFile() { return false; }
204 #else
205  inline void setOutOfCore(bool b) { mOutOfCore = b; }
206  // To facilitate inlining in the common case in which the buffer is in-core,
207  // the loading logic is split into a separate function, doLoad().
208  inline void loadValues() const { if (this->isOutOfCore()) this->doLoad(); }
209  inline void doLoad() const;
210  inline bool detachFromFile();
211 #endif
212 
213 
214 #ifdef OPENVDB_2_ABI_COMPATIBLE
215  ValueType* mData;
216 #else
217  using FlagsType = typename LeafBufferFlags<ValueType>::type;
218 
219  union {
221  FileInfo* mFileInfo;
222  };
223  FlagsType mOutOfCore; // interpreted as bool; extra bits reserved for future use
224  tbb::spin_mutex mMutex; // 1 byte
225  //int8_t mReserved[3]; // padding for alignment
226 
227  static const ValueType sZero;
228 #endif
229 
230  friend class ::TestLeaf;
231  // Allow the parent LeafNode to access this buffer's data pointer.
232  template<typename, Index> friend class LeafNode;
233 }; // class LeafBuffer
234 
235 
237 
238 
239 #ifndef OPENVDB_2_ABI_COMPATIBLE
240 
241 template<typename T, Index Log2Dim>
242 const T LeafBuffer<T, Log2Dim>::sZero = zeroVal<T>();
243 
244 
245 template<typename T, Index Log2Dim>
246 inline
248  : mData(new ValueType[SIZE])
249  , mOutOfCore(0)
250 {
251  this->fill(val);
252 }
253 
254 
255 template<typename T, Index Log2Dim>
256 inline
258 {
259  if (this->isOutOfCore()) {
260  this->detachFromFile();
261  } else {
262  this->deallocate();
263  }
264 }
265 
266 
267 template<typename T, Index Log2Dim>
268 inline
270  : mData(nullptr)
271  , mOutOfCore(other.mOutOfCore)
272 {
273  if (other.isOutOfCore()) {
274  mFileInfo = new FileInfo(*other.mFileInfo);
275  } else if (other.mData != nullptr) {
276  this->allocate();
277  ValueType* target = mData;
278  const ValueType* source = other.mData;
279  Index n = SIZE;
280  while (n--) *target++ = *source++;
281  }
282 }
283 
284 #endif // !OPENVDB_2_ABI_COMPATIBLE
285 
286 
287 template<typename T, Index Log2Dim>
288 inline void
290 {
291  assert(i < SIZE);
292 #ifdef OPENVDB_2_ABI_COMPATIBLE
293  mData[i] = val;
294 #else
295  this->loadValues();
296  if (mData) mData[i] = val;
297 #endif
298 }
299 
300 
301 template<typename T, Index Log2Dim>
304 {
305  if (&other != this) {
306 #ifdef OPENVDB_2_ABI_COMPATIBLE
307  if (other.mData != nullptr) {
308  this->allocate();
309  ValueType* target = mData;
310  const ValueType* source = other.mData;
311  Index n = SIZE;
312  while (n--) *target++ = *source++;
313  }
314 #else // ! OPENVDB_2_ABI_COMPATIBLE
315  if (this->isOutOfCore()) {
316  this->detachFromFile();
317  } else {
318  if (other.isOutOfCore()) this->deallocate();
319  }
320  if (other.isOutOfCore()) {
321  mOutOfCore = other.mOutOfCore;
322  mFileInfo = new FileInfo(*other.mFileInfo);
323  } else if (other.mData != nullptr) {
324  this->allocate();
325  ValueType* target = mData;
326  const ValueType* source = other.mData;
327  Index n = SIZE;
328  while (n--) *target++ = *source++;
329  }
330 #endif
331  }
332  return *this;
333 }
334 
335 
336 template<typename T, Index Log2Dim>
337 inline void
339 {
340  this->detachFromFile();
341  if (mData != nullptr) {
342  ValueType* target = mData;
343  Index n = SIZE;
344  while (n--) *target++ = val;
345  }
346 }
347 
348 
349 template<typename T, Index Log2Dim>
350 inline bool
352 {
353  this->loadValues();
354  other.loadValues();
355  const ValueType *target = mData, *source = other.mData;
356  if (!target && !source) return true;
357  if (!target || !source) return false;
358  Index n = SIZE;
359  while (n && math::isExactlyEqual(*target++, *source++)) --n;
360  return n == 0;
361 }
362 
363 
364 template<typename T, Index Log2Dim>
365 inline void
367 {
368  std::swap(mData, other.mData);
369 #ifndef OPENVDB_2_ABI_COMPATIBLE
370  std::swap(mOutOfCore, other.mOutOfCore);
371 #endif
372 }
373 
374 
375 template<typename T, Index Log2Dim>
376 inline Index
378 {
379  size_t n = sizeof(*this);
380 #ifdef OPENVDB_2_ABI_COMPATIBLE
381  if (mData) n += SIZE * sizeof(ValueType);
382 #else
383  if (this->isOutOfCore()) n += sizeof(FileInfo);
384  else if (mData) n += SIZE * sizeof(ValueType);
385 #endif
386  return static_cast<Index>(n);
387 }
388 
389 
390 template<typename T, Index Log2Dim>
391 inline const typename LeafBuffer<T, Log2Dim>::ValueType*
393 {
394 #ifndef OPENVDB_2_ABI_COMPATIBLE
395  this->loadValues();
396  if (mData == nullptr) {
397  LeafBuffer* self = const_cast<LeafBuffer*>(this);
398  // This lock will be contended at most once.
399  tbb::spin_mutex::scoped_lock lock(self->mMutex);
400  if (mData == nullptr) self->mData = new ValueType[SIZE];
401  }
402 #endif
403  return mData;
404 }
405 
406 template<typename T, Index Log2Dim>
407 inline typename LeafBuffer<T, Log2Dim>::ValueType*
409 {
410 #ifndef OPENVDB_2_ABI_COMPATIBLE
411  this->loadValues();
412  if (mData == nullptr) {
413  // This lock will be contended at most once.
414  tbb::spin_mutex::scoped_lock lock(mMutex);
415  if (mData == nullptr) mData = new ValueType[SIZE];
416  }
417 #endif
418  return mData;
419 }
420 
421 
422 template<typename T, Index Log2Dim>
423 inline const typename LeafBuffer<T, Log2Dim>::ValueType&
425 {
426  assert(i < SIZE);
427 #ifdef OPENVDB_2_ABI_COMPATIBLE
428  return mData[i];
429 #else
430  this->loadValues();
431  // We can't use the ternary operator here, otherwise Visual C++ returns
432  // a reference to a temporary.
433  if (mData) return mData[i]; else return sZero;
434 #endif
435 }
436 
437 
438 template<typename T, Index Log2Dim>
439 inline bool
440 LeafBuffer<T, Log2Dim>::deallocate()
441 {
442  if (mData != nullptr && !this->isOutOfCore()) {
443  delete[] mData;
444  mData = nullptr;
445  return true;
446  }
447  return false;
448 }
449 
450 
451 #ifndef OPENVDB_2_ABI_COMPATIBLE
452 
453 template<typename T, Index Log2Dim>
454 inline void
455 LeafBuffer<T, Log2Dim>::doLoad() const
456 {
457  if (!this->isOutOfCore()) return;
458 
459  LeafBuffer<T, Log2Dim>* self = const_cast<LeafBuffer<T, Log2Dim>*>(this);
460 
461  // This lock will be contended at most once, after which this buffer
462  // will no longer be out-of-core.
463  tbb::spin_mutex::scoped_lock lock(self->mMutex);
464  if (!this->isOutOfCore()) return;
465 
466  std::unique_ptr<FileInfo> info(self->mFileInfo);
467  assert(info.get() != nullptr);
468  assert(info->mapping.get() != nullptr);
469  assert(info->meta.get() != nullptr);
470 
472  self->mData = nullptr;
473  self->allocate();
474 
475  SharedPtr<std::streambuf> buf = info->mapping->createBuffer();
476  std::istream is(buf.get());
477 
478  io::setStreamMetadataPtr(is, info->meta, /*transfer=*/true);
479 
480  NodeMaskType mask;
481  is.seekg(info->maskpos);
482  mask.load(is);
483 
484  is.seekg(info->bufpos);
485  io::readCompressedValues(is, self->mData, SIZE, mask, io::getHalfFloat(is));
486 
487  self->setOutOfCore(false);
488 }
489 
490 
491 template<typename T, Index Log2Dim>
492 inline bool
493 LeafBuffer<T, Log2Dim>::detachFromFile()
494 {
495  if (this->isOutOfCore()) {
496  delete mFileInfo;
497  mFileInfo = nullptr;
498  this->setOutOfCore(false);
499  return true;
500  }
501  return false;
502 }
503 
504 #endif // !OPENVDB_2_ABI_COMPATIBLE
505 
506 
508 
509 
510 // Partial specialization for bool ValueType
511 template<Index Log2Dim>
512 class LeafBuffer<bool, Log2Dim>
513 {
514 public:
516  using WordType = typename NodeMaskType::Word;
517  using ValueType = bool;
519 
520  static const Index WORD_COUNT = NodeMaskType::WORD_COUNT;
521  static const Index SIZE = 1 << 3 * Log2Dim;
522 
523  // These static declarations must be on separate lines to avoid VC9 compiler errors.
524  static const bool sOn;
525  static const bool sOff;
526 
528  LeafBuffer(bool on): mData(on) {}
529  LeafBuffer(const NodeMaskType& other): mData(other) {}
530  LeafBuffer(const LeafBuffer& other): mData(other.mData) {}
532  void fill(bool val) { mData.set(val); }
533  LeafBuffer& operator=(const LeafBuffer& b) { if (&b != this) { mData=b.mData; } return *this; }
534 
535  const bool& getValue(Index i) const
536  {
537  assert(i < SIZE);
538  // We can't use the ternary operator here, otherwise Visual C++ returns
539  // a reference to a temporary.
540  if (mData.isOn(i)) return sOn; else return sOff;
541  }
542  const bool& operator[](Index i) const { return this->getValue(i); }
543 
544  bool operator==(const LeafBuffer& other) const { return mData == other.mData; }
545  bool operator!=(const LeafBuffer& other) const { return mData != other.mData; }
546 
547  void setValue(Index i, bool val) { assert(i < SIZE); mData.set(i, val); }
548 
549  void swap(LeafBuffer& other) { if (&other != this) std::swap(mData, other.mData); }
550 
551  Index memUsage() const { return sizeof(*this); }
552  static Index size() { return SIZE; }
553 
556  WordType* data() { return &(mData.template getWord<WordType>(0)); }
559  const WordType* data() const { return const_cast<LeafBuffer*>(this)->data(); }
560 
561 private:
562  // Allow the parent LeafNode to access this buffer's data.
563  template<typename, Index> friend class LeafNode;
564 
565  NodeMaskType mData;
566 }; // class LeafBuffer
567 
568 
573 template<Index Log2Dim> const bool LeafBuffer<bool, Log2Dim>::sOn = true;
574 template<Index Log2Dim> const bool LeafBuffer<bool, Log2Dim>::sOff = false;
575 
576 } // namespace tree
577 } // namespace OPENVDB_VERSION_NAME
578 } // namespace openvdb
579 
580 #endif // OPENVDB_TREE_LEAFBUFFER_HAS_BEEN_INCLUDED
581 
582 // Copyright (c) 2012-2017 DreamWorks Animation LLC
583 // All rights reserved. This software is distributed under the
584 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
void * ptr
Definition: LeafBuffer.h:71
LeafBuffer(bool on)
Definition: LeafBuffer.h:528
std::shared_ptr< T > SharedPtr
Definition: Types.h:130
bool ValueType
Definition: LeafBuffer.h:517
void swap(LeafBuffer &other)
Definition: LeafBuffer.h:549
void setValue(Index i, bool val)
Definition: LeafBuffer.h:547
uint32_t Index32
Definition: Types.h:55
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:391
static Index size()
Definition: LeafBuffer.h:552
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
void fill(bool val)
Definition: LeafBuffer.h:532
OPENVDB_API void setStreamMetadataPtr(std::ios_base &, SharedPtr< StreamMetadata > &, bool transfer=true)
Associate the given stream with (a shared pointer to) an object that stores metadata (file format...
T * data
Definition: LeafBuffer.h:71
static const bool sOn
Definition: LeafBuffer.h:524
tbb::spin_mutex mutex
Definition: LeafBuffer.h:71
static constexpr bool IsAtomic
true if LeafBuffer::mOutOfCore is atomic, false otherwise
Definition: LeafBuffer.h:76
Index32 Index
Definition: Types.h:57
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:505
ValueType * mData
Definition: LeafBuffer.h:220
std::streamoff bufpos
Definition: LeafBuffer.h:108
bool operator==(const LeafBuffer &other) const
Definition: LeafBuffer.h:544
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:61
WordType * data()
Return a pointer to the C-style array of words encoding the bits.
Definition: LeafBuffer.h:556
typename NodeMaskType::Word WordType
Definition: LeafBuffer.h:516
WordType StorageType
Definition: LeafBuffer.h:518
#define OPENVDB_VERSION_NAME
Definition: version.h:43
LeafBuffer & operator=(const LeafBuffer &b)
Definition: LeafBuffer.h:533
LeafBuffer(const NodeMaskType &other)
Definition: LeafBuffer.h:529
static const bool sOff
Definition: LeafBuffer.h:525
bool empty() const
Return true if memory for this buffer has not yet been allocated.
Definition: LeafBuffer.h:144
ValueType StorageType
Definition: LeafBuffer.h:100
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:339
Definition: Exceptions.h:39
Array of fixed size that stores the voxel values of a LeafNode.
Definition: LeafBuffer.h:96
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:487
const WordType * data() const
Return a const pointer to the C-style array of words encoding the bits.
Definition: LeafBuffer.h:559
io::MappedFile::Ptr mapping
Definition: LeafBuffer.h:110
ValueType ValueType
Definition: LeafBuffer.h:99
FileInfo * mFileInfo
Definition: LeafBuffer.h:221
SharedPtr< MappedFile > Ptr
Definition: io.h:152
const bool & getValue(Index i) const
Definition: LeafBuffer.h:535
LeafBuffer(PartialCreate, const ValueType &)
Construct a buffer but don&#39;t allocate memory for the full array of values.
Definition: LeafBuffer.h:137
Index64 Word
Definition: NodeMasks.h:316
bool operator!=(const LeafBuffer &other) const
Return true if the contents of the other buffer are not exactly equal to the contents of this buffer...
Definition: LeafBuffer.h:167
SharedPtr< io::StreamMetadata > meta
Definition: LeafBuffer.h:111
const ValueType & operator[](Index i) const
Return a const reference to the i&#39;th element of this buffer.
Definition: LeafBuffer.h:155
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
Index memUsage() const
Definition: LeafBuffer.h:551
const ValueType & getValue(Index i) const
Return a const reference to the i&#39;th element of this buffer.
Definition: LeafBuffer.h:153
LeafBuffer(const LeafBuffer &other)
Definition: LeafBuffer.h:530
static Index size()
Return the number of values contained in this buffer.
Definition: LeafBuffer.h:175
const bool & operator[](Index i) const
Definition: LeafBuffer.h:542
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
OPENVDB_API bool getHalfFloat(std::ios_base &)
Return true if floating-point values should be quantized to 16 bits when writing to the given stream ...
bool isOutOfCore() const
Return true if this buffer&#39;s values have not yet been read from disk.
Definition: LeafBuffer.h:142
static constexpr size_t size
The size of a LeafBuffer when LeafBuffer::mOutOfCore is atomic.
Definition: LeafBuffer.h:85
bool operator!=(const LeafBuffer &other) const
Definition: LeafBuffer.h:545
FileInfo()
Definition: LeafBuffer.h:107
std::streamoff maskpos
Definition: LeafBuffer.h:109