HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LeafBuffer.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
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 //
29 ///////////////////////////////////////////////////////////////////////////
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/spin_mutex.h>
38 #include <algorithm> // for std::swap
39 #include <iostream>
40 #include <type_traits>
41 
42 
43 class TestLeaf;
44 
45 namespace openvdb {
47 namespace OPENVDB_VERSION_NAME {
48 namespace tree {
49 
50 /// @brief Array of fixed size @f$2^{3 \times {\rm Log2Dim}}@f$ that stores
51 /// the voxel values of a LeafNode
52 template<typename T, Index Log2Dim>
54 {
55 public:
56  using ValueType = T;
58  static const Index SIZE = 1 << 3 * Log2Dim;
59 
60 #ifndef OPENVDB_2_ABI_COMPATIBLE
61  struct FileInfo
62  {
63  FileInfo(): bufpos(0) , maskpos(0) {}
64  std::streamoff bufpos;
65  std::streamoff maskpos;
68  };
69 #endif
70 
71 #ifdef OPENVDB_2_ABI_COMPATIBLE
72  /// Default constructor
73  LeafBuffer(): mData(new ValueType[SIZE]) {}
74  /// Construct a buffer populated with the specified value.
75  explicit LeafBuffer(const ValueType& val): mData(new ValueType[SIZE]) { this->fill(val); }
76  /// Copy constructor
77  LeafBuffer(const LeafBuffer& other): mData(new ValueType[SIZE]) { *this = other; }
78  /// Destructor
79  ~LeafBuffer() { delete[] mData; }
80 
81  /// Return @c true if this buffer's values have not yet been read from disk.
82  bool isOutOfCore() const { return false; }
83  /// Return @c true if memory for this buffer has not yet been allocated.
84  bool empty() const { return (mData == nullptr); }
85 #else
86  /// Default constructor
87  inline LeafBuffer(): mData(new ValueType[SIZE]), mOutOfCore(0) {}
88  /// Construct a buffer populated with the specified value.
89  explicit inline LeafBuffer(const ValueType&);
90  /// Copy constructor
91  inline LeafBuffer(const LeafBuffer&);
92  /// Construct a buffer but don't allocate memory for the full array of values.
93  LeafBuffer(PartialCreate, const ValueType&): mData(nullptr), mOutOfCore(0) {}
94  /// Destructor
95  inline ~LeafBuffer();
96 
97  /// Return @c true if this buffer's values have not yet been read from disk.
98  bool isOutOfCore() const { return bool(mOutOfCore); }
99  /// Return @c true if memory for this buffer has not yet been allocated.
100  bool empty() const { return !mData || this->isOutOfCore(); }
101 #endif
102  /// Allocate memory for this buffer if it has not already been allocated.
103  bool allocate() { if (mData == nullptr) mData = new ValueType[SIZE]; return true; }
104 
105  /// Populate this buffer with a constant value.
106  inline void fill(const ValueType&);
107 
108  /// Return a const reference to the i'th element of this buffer.
109  const ValueType& getValue(Index i) const { return this->at(i); }
110  /// Return a const reference to the i'th element of this buffer.
111  const ValueType& operator[](Index i) const { return this->at(i); }
112  /// Set the i'th value of this buffer to the specified value.
113  inline void setValue(Index i, const ValueType&);
114 
115  /// Copy the other buffer's values into this buffer.
116  inline LeafBuffer& operator=(const LeafBuffer&);
117 
118  /// @brief Return @c true if the contents of the other buffer
119  /// exactly equal the contents of this buffer.
120  inline bool operator==(const LeafBuffer&) const;
121  /// @brief Return @c true if the contents of the other buffer
122  /// are not exactly equal to the contents of this buffer.
123  inline bool operator!=(const LeafBuffer& other) const { return !(other == *this); }
124 
125  /// Exchange this buffer's values with the other buffer's values.
126  inline void swap(LeafBuffer&);
127 
128  /// Return the memory footprint of this buffer in bytes.
129  inline Index memUsage() const;
130  /// Return the number of values contained in this buffer.
131  static Index size() { return SIZE; }
132 
133  /// @brief Return a const pointer to the array of voxel values.
134  /// @details This method guarantees that the buffer is allocated and loaded.
135  /// @warning This method should only be used by experts seeking low-level optimizations.
136  const ValueType* data() const;
137  /// @brief Return a pointer to the array of voxel values.
138  /// @details This method guarantees that the buffer is allocated and loaded.
139  /// @warning This method should only be used by experts seeking low-level optimizations.
140  ValueType* data();
141 
142 private:
143  /// If this buffer is empty, return zero, otherwise return the value at index @ i.
144  inline const ValueType& at(Index i) const;
145 
146  /// @brief Return a non-const reference to the value at index @a i.
147  /// @details This method is private since it makes assumptions about the
148  /// buffer's memory layout. LeafBuffers associated with custom leaf node types
149  /// (e.g., a bool buffer implemented as a bitmask) might not be able to
150  /// return non-const references to their values.
151  ValueType& operator[](Index i) { return const_cast<ValueType&>(this->at(i)); }
152 
153  bool deallocate();
154 
155 #ifdef OPENVDB_2_ABI_COMPATIBLE
156  void setOutOfCore(bool) {}
157  void loadValues() const {}
158  void doLoad() const {}
159  bool detachFromFile() { return false; }
160 #else
161  inline void setOutOfCore(bool b) { mOutOfCore = b; }
162  // To facilitate inlining in the common case in which the buffer is in-core,
163  // the loading logic is split into a separate function, doLoad().
164  inline void loadValues() const { if (this->isOutOfCore()) this->doLoad(); }
165  inline void doLoad() const;
166  inline bool detachFromFile();
167 #endif
168 
169 
170 #ifdef OPENVDB_2_ABI_COMPATIBLE
171  ValueType* mData;
172 #else
173  union {
175  FileInfo* mFileInfo;
176  };
177  Index32 mOutOfCore; // currently interpreted as bool; extra bits reserved for future use
178  tbb::spin_mutex mMutex; // 1 byte
179  //int8_t mReserved[3]; // padding for alignment
180 
181  static const ValueType sZero;
182 #endif
183 
184  friend class ::TestLeaf;
185  // Allow the parent LeafNode to access this buffer's data pointer.
186  template<typename, Index> friend class LeafNode;
187 
188 }; // class LeafBuffer
189 
190 
191 ////////////////////////////////////////
192 
193 
194 #ifndef OPENVDB_2_ABI_COMPATIBLE
195 template<typename T, Index Log2Dim>
196 const T LeafBuffer<T, Log2Dim>::sZero = zeroVal<T>();
197 #endif
198 
199 
200 #ifndef OPENVDB_2_ABI_COMPATIBLE
201 
202 template<typename T, Index Log2Dim>
203 inline
205  : mData(new ValueType[SIZE])
206  , mOutOfCore(0)
207 {
208  this->fill(val);
209 }
210 
211 
212 template<typename T, Index Log2Dim>
213 inline
215 {
216  if (this->isOutOfCore()) {
217  this->detachFromFile();
218  } else {
219  this->deallocate();
220  }
221 }
222 
223 
224 template<typename T, Index Log2Dim>
225 inline
227  : mData(nullptr)
228  , mOutOfCore(other.mOutOfCore)
229 {
230  if (other.isOutOfCore()) {
231  mFileInfo = new FileInfo(*other.mFileInfo);
232  } else if (other.mData != nullptr) {
233  this->allocate();
235  const ValueType* source = other.mData;
236  Index n = SIZE;
237  while (n--) *target++ = *source++;
238  }
239 }
240 
241 
242 template<typename T, Index Log2Dim>
243 inline void
245 {
246  assert(i < SIZE);
247 #ifdef OPENVDB_2_ABI_COMPATIBLE
248  mData[i] = val;
249 #else
250  this->loadValues();
251  if (mData) mData[i] = val;
252 #endif
253 }
254 
255 
256 template<typename T, Index Log2Dim>
259 {
260  if (&other != this) {
261 #ifdef OPENVDB_2_ABI_COMPATIBLE
262  if (other.mData != nullptr) {
263  this->allocate();
264  ValueType* target = mData;
265  const ValueType* source = other.mData;
266  Index n = SIZE;
267  while (n--) *target++ = *source++;
268  }
269 #else // ! OPENVDB_2_ABI_COMPATIBLE
270  if (this->isOutOfCore()) {
271  this->detachFromFile();
272  } else {
273  if (other.isOutOfCore()) this->deallocate();
274  }
275  if (other.isOutOfCore()) {
276  mOutOfCore = other.mOutOfCore;
277  mFileInfo = new FileInfo(*other.mFileInfo);
278  } else if (other.mData != nullptr) {
279  this->allocate();
280  ValueType* target = mData;
281  const ValueType* source = other.mData;
282  Index n = SIZE;
283  while (n--) *target++ = *source++;
284  }
285 #endif
286  }
287  return *this;
288 }
289 
290 
291 template<typename T, Index Log2Dim>
292 inline void
294 {
295  this->detachFromFile();
296  if (mData != nullptr) {
297  ValueType* target = mData;
298  Index n = SIZE;
299  while (n--) *target++ = val;
300  }
301 }
302 
303 
304 template<typename T, Index Log2Dim>
305 inline bool
307 {
308  this->loadValues();
309  other.loadValues();
310  const ValueType *target = mData, *source = other.mData;
311  if (!target && !source) return true;
312  if (!target || !source) return false;
313  Index n = SIZE;
314  while (n && math::isExactlyEqual(*target++, *source++)) --n;
315  return n == 0;
316 }
317 
318 
319 template<typename T, Index Log2Dim>
320 inline void
322 {
323  std::swap(mData, other.mData);
324 #ifndef OPENVDB_2_ABI_COMPATIBLE
325  std::swap(mOutOfCore, other.mOutOfCore);
326 #endif
327 }
328 
329 
330 template<typename T, Index Log2Dim>
331 inline Index
333 {
334  size_t n = sizeof(*this);
335 #ifdef OPENVDB_2_ABI_COMPATIBLE
336  if (mData) n += SIZE * sizeof(ValueType);
337 #else
338  if (this->isOutOfCore()) n += sizeof(FileInfo);
339  else if (mData) n += SIZE * sizeof(ValueType);
340 #endif
341  return static_cast<Index>(n);
342 }
343 
344 
345 template<typename T, Index Log2Dim>
346 inline const typename LeafBuffer<T, Log2Dim>::ValueType*
348 {
349 #ifndef OPENVDB_2_ABI_COMPATIBLE
350  this->loadValues();
351  if (mData == nullptr) {
352  LeafBuffer* self = const_cast<LeafBuffer*>(this);
353  // This lock will be contended at most once.
354  tbb::spin_mutex::scoped_lock lock(self->mMutex);
355  if (mData == nullptr) self->mData = new ValueType[SIZE];
356  }
357 #endif
358  return mData;
359 }
360 
361 template<typename T, Index Log2Dim>
362 inline typename LeafBuffer<T, Log2Dim>::ValueType*
364 {
365 #ifndef OPENVDB_2_ABI_COMPATIBLE
366  this->loadValues();
367  if (mData == nullptr) {
368  // This lock will be contended at most once.
369  tbb::spin_mutex::scoped_lock lock(mMutex);
370  if (mData == nullptr) mData = new ValueType[SIZE];
371  }
372 #endif
373  return mData;
374 }
375 
376 
377 template<typename T, Index Log2Dim>
378 inline const typename LeafBuffer<T, Log2Dim>::ValueType&
380 {
381  assert(i < SIZE);
382 #ifdef OPENVDB_2_ABI_COMPATIBLE
383  return mData[i];
384 #else
385  this->loadValues();
386  // We can't use the ternary operator here, otherwise Visual C++ returns
387  // a reference to a temporary.
388  if (mData) return mData[i]; else return sZero;
389 #endif
390 }
391 
392 
393 template<typename T, Index Log2Dim>
394 inline bool
395 LeafBuffer<T, Log2Dim>::deallocate()
396 {
397  if (mData != nullptr && !this->isOutOfCore()) {
398  delete[] mData;
399  mData = nullptr;
400  return true;
401  }
402  return false;
403 }
404 
405 
406 template<typename T, Index Log2Dim>
407 inline void
408 LeafBuffer<T, Log2Dim>::doLoad() const
409 {
410  if (!this->isOutOfCore()) return;
411 
412  LeafBuffer<T, Log2Dim>* self = const_cast<LeafBuffer<T, Log2Dim>*>(this);
413 
414  // This lock will be contended at most once, after which this buffer
415  // will no longer be out-of-core.
416  tbb::spin_mutex::scoped_lock lock(self->mMutex);
417  if (!this->isOutOfCore()) return;
418 
419  std::unique_ptr<FileInfo> info(self->mFileInfo);
420  assert(info.get() != nullptr);
421  assert(info->mapping.get() != nullptr);
422  assert(info->meta.get() != nullptr);
423 
424  /// @todo For now, we have to clear the mData pointer in order for allocate() to take effect.
425  self->mData = nullptr;
426  self->allocate();
427 
428  SharedPtr<std::streambuf> buf = info->mapping->createBuffer();
429  std::istream is(buf.get());
430 
431  io::setStreamMetadataPtr(is, info->meta, /*transfer=*/true);
432 
433  NodeMaskType mask;
434  is.seekg(info->maskpos);
435  mask.load(is);
436 
437  is.seekg(info->bufpos);
438  io::readCompressedValues(is, self->mData, SIZE, mask, io::getHalfFloat(is));
439 
440  self->setOutOfCore(false);
441 }
442 
443 
444 template<typename T, Index Log2Dim>
445 inline bool
446 LeafBuffer<T, Log2Dim>::detachFromFile()
447 {
448  if (this->isOutOfCore()) {
449  delete mFileInfo;
450  mFileInfo = nullptr;
451  this->setOutOfCore(false);
452  return true;
453  }
454  return false;
455 }
456 
457 #endif // OPENVDB_2_ABI_COMPATIBLE
458 
459 
460 ////////////////////////////////////////
461 
462 
463 // Partial specialization for bool ValueType
464 template<Index Log2Dim>
465 class LeafBuffer<bool, Log2Dim>
466 {
467 public:
469  using WordType = typename NodeMaskType::Word;
470 
471  static const Index WORD_COUNT = NodeMaskType::WORD_COUNT;
472  static const Index SIZE = 1 << 3 * Log2Dim;
473 
474  // These static declarations must be on separate lines to avoid VC9 compiler errors.
475  static const bool sOn;
476  static const bool sOff;
477 
479  LeafBuffer(bool on): mData(on) {}
480  LeafBuffer(const NodeMaskType& other): mData(other) {}
481  LeafBuffer(const LeafBuffer& other): mData(other.mData) {}
483  void fill(bool val) { mData.set(val); }
484  LeafBuffer& operator=(const LeafBuffer& b) { if (&b != this) { mData=b.mData; } return *this; }
485 
486  const bool& getValue(Index i) const
487  {
488  assert(i < SIZE);
489  // We can't use the ternary operator here, otherwise Visual C++ returns
490  // a reference to a temporary.
491  if (mData.isOn(i)) return sOn; else return sOff;
492  }
493  const bool& operator[](Index i) const { return this->getValue(i); }
494 
495  bool operator==(const LeafBuffer& other) const { return mData == other.mData; }
496  bool operator!=(const LeafBuffer& other) const { return mData != other.mData; }
497 
498  void setValue(Index i, bool val) { assert(i < SIZE); mData.set(i, val); }
499 
500  void swap(LeafBuffer& other) { if (&other != this) std::swap(mData, other.mData); }
501 
502  Index memUsage() const { return sizeof(*this); }
503  static Index size() { return SIZE; }
504 
505  /// @brief Return a pointer to the C-style array of words encoding the bits.
506  /// @warning This method should only be used by experts seeking low-level optimizations.
507  WordType* data() { return &(mData.template getWord<WordType>(0)); }
508  /// @brief Return a const pointer to the C-style array of words encoding the bits.
509  /// @warning This method should only be used by experts seeking low-level optimizations.
510  const WordType* data() const { return const_cast<LeafBuffer*>(this)->data(); }
511 
512 private:
513  // Allow the parent LeafNode to access this buffer's data.
514  template<typename, Index> friend class LeafNode;
515 
517 }; // class LeafBuffer
518 
519 
520 /// @internal For consistency with other nodes and with iterators, methods like
521 /// LeafNode::getValue() return a reference to a value. Since it's not possible
522 /// to return a reference to a bit in a node mask, we return a reference to one
523 /// of the following static values instead.
524 template<Index Log2Dim> const bool LeafBuffer<bool, Log2Dim>::sOn = true;
525 template<Index Log2Dim> const bool LeafBuffer<bool, Log2Dim>::sOff = false;
526 
527 } // namespace tree
528 } // namespace OPENVDB_VERSION_NAME
529 } // namespace openvdb
530 
531 #endif // OPENVDB_TREE_LEAFBUFFER_HAS_BEEN_INCLUDED
532 
533 // Copyright (c) 2012-2017 DreamWorks Animation LLC
534 // All rights reserved. This software is distributed under the
535 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
LeafBuffer & operator=(const LeafBuffer &)
Copy the other buffer's values into this buffer.
Definition: LeafBuffer.h:258
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:407
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1561
LeafBuffer(PartialCreate, const ValueType &)
Construct a buffer but don't allocate memory for the full array of values.
Definition: LeafBuffer.h:93
GLint GLuint mask
Definition: glcorearb.h:123
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 ...
SharedPtr< MappedFile > Ptr
Definition: io.h:152
bool operator==(const LeafBuffer &) const
Return true if the contents of the other buffer exactly equal the contents of this buffer...
Definition: LeafBuffer.h:306
bool empty() const
Return true if memory for this buffer has not yet been allocated.
Definition: LeafBuffer.h:100
png_uint_32 i
Definition: png.h:2877
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:505
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:339
std::shared_ptr< T > SharedPtr
Definition: Types.h:130
GLdouble n
Definition: glcorearb.h:2007
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:302
#define OPENVDB_VERSION_NAME
Definition: version.h:43
void swap(LeafBuffer &)
Exchange this buffer's values with the other buffer's values.
Definition: LeafBuffer.h:321
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:60
bool allocate()
Allocate memory for this buffer if it has not already been allocated.
Definition: LeafBuffer.h:103
static Index size()
Return the number of values contained in this buffer.
Definition: LeafBuffer.h:131
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:802
const ValueType & getValue(Index i) const
Return a const reference to the i'th element of this buffer.
Definition: LeafBuffer.h:109
GLenum target
Definition: glcorearb.h:1666
Index memUsage() const
Return the memory footprint of this buffer in bytes.
Definition: LeafBuffer.h:332
WordType * data()
Return a pointer to the C-style array of words encoding the bits.
Definition: LeafBuffer.h:507
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1221
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2539
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...
const ValueType * data() const
Return a const pointer to the array of voxel values.
Definition: LeafBuffer.h:347
const ValueType & operator[](Index i) const
Return a const reference to the i'th element of this buffer.
Definition: LeafBuffer.h:111
void fill(const ValueType &)
Populate this buffer with a constant value.
Definition: LeafBuffer.h:293
bool isOutOfCore() const
Return true if this buffer's values have not yet been read from disk.
Definition: LeafBuffer.h:98
Array of fixed size that stores the voxel values of a LeafNode.
Definition: LeafBuffer.h:53
GLuint GLfloat * val
Definition: glcorearb.h:1607
#define SIZE
Definition: simple.C:40
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
void setValue(Index i, const ValueType &)
Set the i'th value of this buffer to the specified value.
Definition: LeafBuffer.h:244
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:123
const WordType * data() const
Return a const pointer to the C-style array of words encoding the bits.
Definition: LeafBuffer.h:510