OpenVDB  12.1.0
GridHandle.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 
4 /*!
5  \file nanovdb/GridHandle.h
6 
7  \author Ken Museth
8 
9  \date January 8, 2020
10 
11  \brief Defines GridHandle, which manages a host, and possibly a device,
12  memory buffer containing one or more NanoVDB grids.
13 */
14 
15 #ifndef NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED
16 #define NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED
17 
18 #include <fstream> // for std::ifstream
19 #include <iostream> // for std::cerr/cout
20 #include <vector>
21 #include <initializer_list>
22 
23 #include <nanovdb/NanoVDB.h>// for toGridType
24 #include <nanovdb/HostBuffer.h>
25 #include <nanovdb/tools/GridChecksum.h>// for updateGridCount
26 
27 namespace nanovdb {
28 
29 // --------------------------> GridHandle <------------------------------------
30 
32 
33 /// @brief This class serves to manage a buffer containing one or more NanoVDB Grids.
34 ///
35 /// @note It is important to note that this class does NOT depend on OpenVDB.
36 template<typename BufferT = HostBuffer>
38 {
39  std::vector<GridHandleMetaData> mMetaData;
40  BufferT mBuffer;
41 
42  template <typename T>
43  static T* no_const(const T* ptr) { return const_cast<T*>(ptr); }
44 
45 public:
46  using BufferType = BufferT;
47 
48  /// @brief Move constructor from a dual host-device buffer
49  /// @param buffer buffer containing one or more NanoGrids that will be moved into this GridHandle
50  /// @throw Will throw and error with the buffer does not contain a valid NanoGrid!
51  /// @note The implementation of this template specialization is in nanovdb/cuda/GridHandle.cuh since it requires CUDA
52  template<typename T = BufferT, typename util::enable_if<BufferTraits<T>::hasDeviceDual, int>::type = 0>
53  GridHandle(T&& buffer);
54 
55  /// @brief Move constructor from a host buffer
56  /// @param buffer buffer containing one or more NanoGrids that will be moved into this GridHandle
57  /// @throw Will throw and error with the buffer does not contain a valid NanoGrid!
58  template<typename T = BufferT, typename util::disable_if<BufferTraits<T>::hasDeviceDual, int>::type = 0>
59  GridHandle(T&& buffer);
60 
61  /// @brief Constructs an empty GridHandle
62  GridHandle() = default;
63 
64  /// @brief Disallow copy-construction
65  GridHandle(const GridHandle&) = delete;
66 
67  /// @brief Move copy-constructor
68  GridHandle(GridHandle&& other) noexcept {
69  mBuffer = std::move(other.mBuffer);
70  mMetaData = std::move(other.mMetaData);
71  }
72 
73  /// @brief clear this GridHandle to an empty handle
74  void reset() {
75  mBuffer.clear();
76  mMetaData.clear();
77  }
78 
79  /// @brief Disallow copy assignment operation
80  GridHandle& operator=(const GridHandle&) = delete;
81 
82  /// @brief Move copy assignment operation
83  GridHandle& operator=(GridHandle&& other) noexcept {
84  mBuffer = std::move(other.mBuffer);
85  mMetaData = std::move(other.mMetaData);
86  return *this;
87  }
88 
89  /// @brief Performs a deep copy of the GridHandle, possibly templated on a different buffer type
90  /// @tparam OtherBufferT Buffer type of the deep copy
91  /// @param buffer optional buffer used for allocation
92  /// @return A new handle of the specified buffer type that contains a deep copy of the current handle
93  template <typename OtherBufferT = HostBuffer>
94  GridHandle<OtherBufferT> copy(const OtherBufferT& buffer = OtherBufferT()) const;
95 
96  /// @brief Return a reference to the buffer
97  BufferT& buffer() { return mBuffer; }
98 
99  /// @brief Return a const reference to the buffer
100  const BufferT& buffer() const { return mBuffer; }
101 
102  /// @brief Returns a non-const pointer to the data.
103  /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized
104  void* data() { return mBuffer.data(); }
105 
106  /// @brief Returns a const pointer to the data.
107  /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized
108  const void* data() const { return mBuffer.data(); }
109 
110  template<typename U = BufferT>
111  typename util::enable_if<BufferTraits<U>::hasDeviceDual, const void*>::type
112  deviceData() const { return mBuffer.deviceData(); }
113  template<typename U = BufferT>
114  typename util::enable_if<BufferTraits<U>::hasDeviceDual, const void*>::type
115  deviceData(int device) const { return mBuffer.deviceData(device); }
116  template<typename U = BufferT>
118  deviceData() { return mBuffer.deviceData(); }
119  template<typename U = BufferT>
121  deviceData(int device) { return mBuffer.deviceData(device); }
122 
123  //@{
124  /// @brief Returns the size in bytes of the raw memory buffer managed by this GridHandle.
125  [[deprecated("Use GridHandle::bufferSize instead.")]] uint64_t size() const { return mBuffer.size(); }
126  uint64_t bufferSize() const { return mBuffer.size(); }
127  //@}
128 
129  //@{
130  /// @brief Return true if this handle is empty, i.e. has no allocated memory
131  bool empty() const { return mBuffer.size() == 0; }
132  bool isEmpty() const { return mBuffer.size() == 0; }
133  //@}
134 
135  /// @brief Return true if this handle is not empty, i.e. contains at least one grid
136  operator bool() const { return !this->empty(); }
137 
138  /// @brief Returns a const host pointer to the @a n'th NanoVDB grid encoded in this GridHandle.
139  /// @tparam ValueT Value type of the grid point to be returned
140  /// @param n Index of the (host) grid pointer to be returned
141  /// @warning Note that the return pointer can be NULL if the GridHandle no host grid, @a n is invalid
142  /// or if the template parameter does not match the specified grid!
143  template<typename ValueT>
144  const NanoGrid<ValueT>* grid(uint32_t n = 0) const;
145 
146  /// @brief Returns a host pointer to the @a n'th NanoVDB grid encoded in this GridHandle.
147  /// @tparam ValueT Value type of the grid point to be returned
148  /// @param n Index of the (host) grid pointer to be returned
149  /// @warning Note that the return pointer can be NULL if the GridHandle no host grid, @a n is invalid
150  /// or if the template parameter does not match the specified grid!
151  template<typename ValueT>
152  NanoGrid<ValueT>* grid(uint32_t n = 0) {return const_cast<NanoGrid<ValueT>*>(static_cast<const GridHandle*>(this)->template grid<ValueT>(n));}
153 
154  /// @brief Return a const pointer to the @a n'th grid encoded in this GridHandle on the device, e.g. GPU
155  /// @tparam ValueT Value type of the grid point to be returned
156  /// @param n Index of the (device) grid pointer to be returned
157  /// @warning Note that the return pointer can be NULL if the GridHandle has no device grid, @a n is invalid,
158  /// or if the template parameter does not match the specified grid.
159  template<typename ValueT, typename U = BufferT>
161  deviceGrid(uint32_t n=0) const;
162 
163  /// @brief Return a const pointer to the @a n'th grid encoded in this GridHandle on the device, e.g. GPU
164  /// @tparam ValueT Value type of the grid point to be returned
165  /// @param n Index of the grid pointer to be returned
166  /// @param verbose if non-zero error messages will be printed in case something failed
167  /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized, @a n is invalid,
168  /// or if the template parameter does not match the specified grid.
169  template<typename ValueT, typename U = BufferT>
170  typename util::enable_if<BufferTraits<U>::hasDeviceDual, NanoGrid<ValueT>*>::type
171  deviceGrid(uint32_t n=0){return const_cast<NanoGrid<ValueT>*>(static_cast<const GridHandle*>(this)->template deviceGrid<ValueT>(n));}
172 
173  /// @brief Upload the grid to the device, e.g. from CPU to GPU
174  /// @note This method is only available if the buffer supports devices
175  template<typename U = BufferT>
176  typename util::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
177  deviceUpload(void* stream, bool sync = true) { mBuffer.deviceUpload(stream, sync); }
178 
179  /// @brief Upload the host buffer to a specific device buffer. It device buffer doesn't exist it's created first
180  /// @param device Device to upload host data to
181  /// @param stream cuda stream
182  /// @param sync if false the memory copy is asynchronous
183  template<typename U = BufferT>
184  typename util::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
185  deviceUpload(int device = 0, void* stream = nullptr, bool sync = true) { mBuffer.deviceUpload(device, stream, sync); }
186 
187  /// @brief Download the grid to from the device, e.g. from GPU to CPU
188  /// @note This method is only available if the buffer supports devices
189  template<typename U = BufferT>
190  typename util::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
191  deviceDownload(void* stream, bool sync = true) { mBuffer.deviceDownload(stream, sync); }
192 
193  template<typename U = BufferT>
194  typename util::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
195  deviceDownload(int device = 0, void* stream = nullptr, bool sync = true) { mBuffer.deviceDownload(device, stream, sync); }
196 
197  /// @brief Check if the buffer is this handle has any padding, i.e. if the buffer is larger than the combined size of all its grids
198  /// @return true is the combined size of all grid is smaller than the buffer size
199  bool isPadded() const {return mMetaData.empty() ? false : mMetaData.back().offset + mMetaData.back().size != mBuffer.size();}
200 
201  /// @brief Return the total number of grids contained in this buffer
202  uint32_t gridCount() const {return static_cast<uint32_t>(mMetaData.size());}
203 
204  /// @brief Return the grid size of the @a n'th grid in this GridHandle
205  /// @param n index of the grid (assumed to be less than gridCount())
206  /// @return Return the byte size of the specified grid
207  uint64_t gridSize(uint32_t n = 0) const {return mMetaData[n].size; }
208 
209  /// @brief compute the total sum of memory footprints of all the grids in this buffer
210  /// @return the number of bytes occupied by all grids associated with this buffer
211  uint64_t totalGridSize() const {
212  uint64_t sum = 0;
213  for (auto &m : mMetaData) sum += m.size;
214  NANOVDB_ASSERT(sum <= mBuffer.size());
215  return sum;
216  }
217 
218  /// @brief compute the size of unused storage in this buffer
219  /// @return the number of unused bytes in this buffer.
220  uint64_t freeSize() const {return mBuffer.size() - this->totalGridSize();}
221 
222  /// @brief Test if this buffer has any unused storage left, i.e. memory not occupied by grids
223  /// @return true if there is no extra storage left in this buffer, i.e. empty or fully occupied with grids
224  bool isFull() const { return this->totalGridSize() == mBuffer.size(); }
225 
226  /// @brief Return the GridType of the @a n'th grid in this GridHandle
227  /// @param n index of the grid (assumed to be less than gridCount())
228  /// @return Return the GridType of the specified grid
229  GridType gridType(uint32_t n = 0) const {return mMetaData[n].gridType; }
230 
231  /// @brief Access to the GridData of the n'th grid in the current handle
232  /// @param n zero-based ID of the grid
233  /// @return Const pointer to the n'th GridData in the current handle
234  const GridData* gridData(uint32_t n = 0) const;
235 
236  /// @brief Returns a const point to the @a n'th grid meta data
237  /// @param n zero-based ID of the grid
238  /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized
239  const GridMetaData* gridMetaData(uint32_t n = 0) const;
240 
241  /// @brief Write a specific grid in this buffer to an output stream
242  /// @param os output stream that the buffer will be written to
243  /// @param n zero-based index of the grid to be written to stream
244  void write(std::ostream& os, uint32_t n) const {
245  if (const GridData* data = this->gridData(n)) {
246  os.write((const char*)data, data->mGridSize);
247  } else {
248  throw std::runtime_error("GridHandle does not contain a #" + std::to_string(n) + " grid");
249  }
250  }
251 
252  /// @brief Write the entire grid buffer to an output stream
253  /// @param os output stream that the buffer will be written to
254  void write(std::ostream& os) const {
255  for (uint32_t n=0; n<this->gridCount(); ++n) this->write(os, n);
256  }
257 
258  /// @brief Write this entire grid buffer to a file
259  /// @param fileName string name of the output file
260  void write(const std::string &fileName) const {
261  std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
262  if (!os.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for output");
263  this->write(os);
264  }
265 
266  /// @brief Write a specific grid to file
267  /// @param fileName string name of the output file
268  /// @param n zero-based index of the grid to be written to file
269  void write(const std::string &fileName, uint32_t n) const {
270  std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
271  if (!os.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for output");
272  this->write(os, n);
273  }
274 
275  /// @brief Read an entire raw grid buffer from an input stream
276  /// @param is input stream containing a raw grid buffer
277  /// @param pool optional pool from which to allocate the new grid buffer
278  /// @throw Will throw a std::logic_error if the stream does not contain a valid raw grid
279  void read(std::istream& is, const BufferT& pool = BufferT());
280 
281  /// @brief Read a specific grid from an input stream containing a raw grid buffer
282  /// @param is input stream containing a raw grid buffer
283  /// @param n zero-based index of the grid to be read
284  /// @param pool optional pool from which to allocate the new grid buffer
285  /// @throw Will throw a std::logic_error if the stream does not contain a valid raw grid
286  void read(std::istream& is, uint32_t n, const BufferT& pool = BufferT());
287 
288  /// @brief Read a specific grid from an input stream containing a raw grid buffer
289  /// @param is input stream containing a raw grid buffer
290  /// @param gridName string name of the grid to be read
291  /// @param pool optional pool from which to allocate the new grid buffer
292  /// @throw Will throw a std::logic_error if the stream does not contain a valid raw grid with the specified name
293  void read(std::istream& is, const std::string &gridName, const BufferT& pool = BufferT());
294 
295  /// @brief Read a raw grid buffer from a file
296  /// @param filename string name of the input file containing a raw grid buffer
297  /// @param pool optional pool from which to allocate the new grid buffer
298  void read(const std::string &fileName, const BufferT& pool = BufferT()) {
299  std::ifstream is(fileName, std::ios::in | std::ios::binary);
300  if (!is.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for input");
301  this->read(is, pool);
302  }
303 
304  /// @brief Read a specific grid from a file containing a raw grid buffer
305  /// @param filename string name of the input file containing a raw grid buffer
306  /// @param n zero-based index of the grid to be read
307  /// @param pool optional pool from which to allocate the new grid buffer
308  /// @throw Will throw a std::ios_base::failure if the file does not exist and a
309  /// std::logic_error if the files does not contain a valid raw grid
310  void read(const std::string &fileName, uint32_t n, const BufferT& pool = BufferT()) {
311  std::ifstream is(fileName, std::ios::in | std::ios::binary);
312  if (!is.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for input");
313  this->read(is, n, pool);
314  }
315 
316  /// @brief Read a specific grid from a file containing a raw grid buffer
317  /// @param filename string name of the input file containing a raw grid buffer
318  /// @param gridName string name of the grid to be read
319  /// @param pool optional pool from which to allocate the new grid buffer
320  /// @throw Will throw a std::ios_base::failure if the file does not exist and a
321  /// std::logic_error if the files does not contain a valid raw grid withe the specified name
322  void read(const std::string &fileName, const std::string &gridName, const BufferT& pool = BufferT()) {
323  std::ifstream is(fileName, std::ios::in | std::ios::binary);
324  if (!is.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for input");
325  this->read(is, gridName, pool);
326  }
327 }; // GridHandle
328 
329 // --------------------------> Implementation of private methods in GridHandle <------------------------------------
330 
331 template<typename BufferT>
332 inline const GridData* GridHandle<BufferT>::gridData(uint32_t n) const
333 {
334  const void *data = this->data();
335  if (data == nullptr || n >= mMetaData.size()) return nullptr;
336  return util::PtrAdd<GridData>(data, mMetaData[n].offset);
337 }// const GridData* GridHandle<BufferT>::gridData(uint32_t n) const
338 
339 template<typename BufferT>
340 inline const GridMetaData* GridHandle<BufferT>::gridMetaData(uint32_t n) const
341 {
342  const auto *data = this->data();
343  if (data == nullptr || n >= mMetaData.size()) return nullptr;
344  return util::PtrAdd<GridMetaData>(data, mMetaData[n].offset);
345 }// const GridMetaData* GridHandle<BufferT>::gridMetaData(uint32_t n) const
346 
348 {
349  uint64_t offset = 0;
350  for (auto *p=meta, *q=p+data->mGridCount; p!=q; ++p) {
351  *p = {offset, data->mGridSize, data->mGridType};
352  offset += p->size;
353  data = util::PtrAdd<GridData>(data, p->size);
354  }
355 }// void cpyGridHandleMeta(const GridData *data, GridHandleMetaData *meta)
356 
357 // template specialization of move constructor from a host buffer
358 template<typename BufferT>
359 template<typename T, typename util::disable_if<BufferTraits<T>::hasDeviceDual, int>::type>
361 {
362  static_assert(util::is_same<T,BufferT>::value, "Expected U==BufferT");
363  mBuffer = std::move(buffer);
364  if (auto *data = reinterpret_cast<const GridData*>(mBuffer.data())) {
365  if (!data->isValid()) throw std::runtime_error("GridHandle was constructed with an invalid host buffer");
366  mMetaData.resize(data->mGridCount);
367  cpyGridHandleMeta(data, mMetaData.data());
368  }
369 }// GridHandle<BufferT>::GridHandle(T&& buffer)
370 
371 template<typename BufferT>
372 template <typename OtherBufferT>
373 inline GridHandle<OtherBufferT> GridHandle<BufferT>::copy(const OtherBufferT& other) const
374 {
375  if (mBuffer.isEmpty()) return GridHandle<OtherBufferT>();// return an empty handle
376  auto buffer = OtherBufferT::create(mBuffer.size(), &other);
377  std::memcpy(buffer.data(), mBuffer.data(), mBuffer.size());// deep copy of buffer
378  return GridHandle<OtherBufferT>(std::move(buffer));
379 }// GridHandle<OtherBufferT> GridHandle<BufferT>::copy(const OtherBufferT& other) const
380 
381 template<typename BufferT>
382 template<typename ValueT>
383 inline const NanoGrid<ValueT>* GridHandle<BufferT>::grid(uint32_t n) const
384 {
385  const void *data = mBuffer.data();
386  if (data == nullptr || n >= mMetaData.size() || mMetaData[n].gridType != toGridType<ValueT>()) return nullptr;
387  return util::PtrAdd<NanoGrid<ValueT>>(data, mMetaData[n].offset);
388 }// const NanoGrid<ValueT>* GridHandle<BufferT>::grid(uint32_t n) const
389 
390 template<typename BufferT>
391 template<typename ValueT, typename U>
392 inline typename util::enable_if<BufferTraits<U>::hasDeviceDual, const NanoGrid<ValueT>*>::type
394 {
395  const void *data = mBuffer.deviceData();
396  if (data == nullptr || n >= mMetaData.size() || mMetaData[n].gridType != toGridType<ValueT>()) return nullptr;
397  return util::PtrAdd<NanoGrid<ValueT>>(data, mMetaData[n].offset);
398 }// GridHandle<BufferT>::deviceGrid(uint32_t n) cons
399 
400 template<typename BufferT>
401 void GridHandle<BufferT>::read(std::istream& is, const BufferT& pool)
402 {
403  GridData data;
404  is.read((char*)&data, sizeof(GridData));
405  if (data.isValid()) {
406  uint64_t size = data.mGridSize, sum = 0u;
407  while(data.mGridIndex + 1u < data.mGridCount) {// loop over remaining raw grids in stream
408  is.seekg(data.mGridSize - sizeof(GridData), std::ios::cur);// skip grid
409  is.read((char*)&data, sizeof(GridData));
410  sum += data.mGridSize;
411  }
412  auto buffer = BufferT::create(size + sum, &pool);
413  is.seekg(-int64_t(sum + sizeof(GridData)), std::ios::cur);// rewind to start
414  is.read((char*)(buffer.data()), buffer.size());
415  *this = GridHandle(std::move(buffer));
416  } else {
417  is.seekg(-sizeof(GridData), std::ios::cur);// rewind
418  throw std::logic_error("This stream does not contain a valid raw grid buffer");
419  }
420 }// void GridHandle<BufferT>::read(std::istream& is, const BufferT& pool)
421 
422 template<typename BufferT>
423 void GridHandle<BufferT>::read(std::istream& is, uint32_t n, const BufferT& pool)
424 {
425  GridData data;
426  is.read((char*)&data, sizeof(GridData));
427  if (data.isValid()) {
428  if (n>=data.mGridCount) throw std::runtime_error("stream does not contain a #" + std::to_string(n) + " grid");
429  while(data.mGridIndex != n) {
430  is.seekg(data.mGridSize - sizeof(GridData), std::ios::cur);// skip grid
431  is.read((char*)&data, sizeof(GridData));
432  }
433  auto buffer = BufferT::create(data.mGridSize, &pool);
434  is.seekg(-sizeof(GridData), std::ios::cur);// rewind
435  is.read((char*)(buffer.data()), data.mGridSize);
436  tools::updateGridCount((GridData*)buffer.data(), 0u, 1u);
437  *this = GridHandle(std::move(buffer));
438  } else {
439  is.seekg(-sizeof(GridData), std::ios::cur);// rewind sizeof(GridData) bytes to undo initial read
440  throw std::logic_error("This file does not contain a valid raw buffer");
441  }
442 }// void GridHandle<BufferT>::read(std::istream& is, uint32_t n, const BufferT& pool)
443 
444 template<typename BufferT>
445 void GridHandle<BufferT>::read(std::istream& is, const std::string &gridName, const BufferT& pool)
446 {
447  static const std::streamsize byteSize = sizeof(GridData);
448  GridData data;
449  is.read((char*)&data, byteSize);
450  is.seekg(-byteSize, std::ios::cur);// rewind
451  if (data.isValid()) {
452  uint32_t n = 0;
453  while(data.mGridName != gridName && n++ < data.mGridCount) {
454  is.seekg(data.mGridSize, std::ios::cur);// skip grid
455  is.read((char*)&data, byteSize);// read sizeof(GridData) bytes
456  is.seekg(-byteSize, std::ios::cur);// rewind
457  }
458  if (n>data.mGridCount) throw std::runtime_error("No raw grid named \""+gridName+"\"");
459  auto buffer = BufferT::create(data.mGridSize, &pool);
460  is.read((char*)(buffer.data()), data.mGridSize);
461  tools::updateGridCount((GridData*)buffer.data(), 0u, 1u);
462  *this = GridHandle(std::move(buffer));
463  } else {
464  throw std::logic_error("This file does not contain a valid raw buffer");
465  }
466 }// void GridHandle<BufferT>::read(std::istream& is, const std::string &gridName n, const BufferT& pool)
467 
468 // --------------------------> free-standing functions <------------------------------------
469 
470 /// @brief Split all grids in a single GridHandle into a vector of multiple GridHandles each with a single grid
471 /// @tparam BufferT Type of the input and output grid buffers
472 /// @param handle GridHandle with grids that will be slip into individual GridHandles
473 /// @param pool optional pool used for allocation of output GridHandle
474 /// @return Vector of GridHandles each containing a single grid
475 template<typename BufferT, template <class, class...> class VectorT = std::vector>
476 inline VectorT<GridHandle<BufferT>>
477 splitGrids(const GridHandle<BufferT> &handle, const BufferT* other = nullptr)
478 {
479  using HandleT = GridHandle<BufferT>;
480  const void *ptr = handle.data();
481  if (ptr == nullptr) return VectorT<HandleT>();
482  VectorT<HandleT> handles(handle.gridCount());
483  for (auto &h : handles) {
484  const GridData *src = reinterpret_cast<const GridData*>(ptr);
485  NANOVDB_ASSERT(src->isValid());
486  auto buffer = BufferT::create(src->mGridSize, other);
487  GridData *dst = reinterpret_cast<GridData*>(buffer.data());
488  std::memcpy(dst, src, src->mGridSize);
489  tools::updateGridCount(dst, 0u, 1u);
490  h = HandleT(std::move(buffer));
491  ptr = util::PtrAdd(ptr, src->mGridSize);
492  }
493  return std::move(handles);
494 }// splitGrids
495 
496 /// @brief Combines (or merges) multiple GridHandles into a single GridHandle containing all grids
497 /// @tparam BufferT Type of the input and output grid buffers
498 /// @param handles Vector of GridHandles to be combined
499 /// @param pool optional pool used for allocation of output GridHandle
500 /// @return single GridHandle containing all input grids
501 template<typename BufferT, template <class, class...> class VectorT>
502 inline GridHandle<BufferT>
503 mergeGrids(const VectorT<GridHandle<BufferT>> &handles, const BufferT* pool = nullptr)
504 {
505  uint64_t size = 0u;
506  uint32_t counter = 0u, gridCount = 0u;
507  for (auto &h : handles) {
508  gridCount += h.gridCount();
509  for (uint32_t n=0; n<h.gridCount(); ++n) size += h.gridSize(n);
510  }
511  auto buffer = BufferT::create(size, pool);
512  void *dst = buffer.data();
513  for (auto &h : handles) {
514  const void *src = h.data();
515  for (uint32_t n=0; n<h.gridCount(); ++n) {
516  std::memcpy(dst, src, h.gridSize(n));
517  GridData *data = reinterpret_cast<GridData*>(dst);
518  NANOVDB_ASSERT(data->isValid());
519  tools::updateGridCount(data, counter++, gridCount);
520  dst = util::PtrAdd(dst, data->mGridSize);
521  src = util::PtrAdd(src, data->mGridSize);
522  }
523  }
524  return GridHandle<BufferT>(std::move(buffer));
525 }// mergeGrids
526 
527 } // namespace nanovdb
528 
529 #if defined(__CUDACC__)
530 #include <nanovdb/cuda/GridHandle.cuh>
531 #endif// defined(__CUDACC__)
532 
533 #endif // NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED
C++11 implementation of std::enable_if.
Definition: Util.h:335
uint64_t size() const
Returns the size in bytes of the raw memory buffer managed by this GridHandle.
Definition: GridHandle.h:125
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2099
uint64_t freeSize() const
compute the size of unused storage in this buffer
Definition: GridHandle.h:220
void write(const std::string &fileName, uint32_t n) const
Write a specific grid to file.
Definition: GridHandle.h:269
char mGridName[MaxNameSize]
Definition: NanoVDB.h:1904
HostBuffer - a buffer that contains a shared or private bump pool to either externally or internally ...
NanoGrid< ValueT > * grid(uint32_t n=0)
Returns a host pointer to the n&#39;th NanoVDB grid encoded in this GridHandle.
Definition: GridHandle.h:152
uint64_t mGridSize
Definition: NanoVDB.h:1903
void reset()
clear this GridHandle to an empty handle
Definition: GridHandle.h:74
uint32_t mGridCount
Definition: NanoVDB.h:1902
__hostdev__ bool isValid() const
return true if the magic number and the version are both valid
Definition: NanoVDB.h:1952
util::enable_if< BufferTraits< U >::hasDeviceDual, const void * >::type deviceData(int device) const
Definition: GridHandle.h:115
#define __hostdev__
Definition: Util.h:73
util::enable_if< BufferTraits< U >::hasDeviceDual, void * >::type deviceData()
Definition: GridHandle.h:118
This class serves to manage a buffer containing one or more NanoVDB Grids.
Definition: GridHandle.h:37
GridHandle< OtherBufferT > copy(const OtherBufferT &buffer=OtherBufferT()) const
Performs a deep copy of the GridHandle, possibly templated on a different buffer type.
Definition: GridHandle.h:373
BufferT & buffer()
Return a reference to the buffer.
Definition: GridHandle.h:97
Implements a light-weight self-contained VDB data-structure in a single file! In other words...
util::enable_if< BufferTraits< U >::hasDeviceDual, NanoGrid< ValueT > * >::type deviceGrid(uint32_t n=0)
Return a const pointer to the n&#39;th grid encoded in this GridHandle on the device, e...
Definition: GridHandle.h:171
Definition: GridHandle.h:27
GridType mGridType
Definition: NanoVDB.h:1909
void read(std::istream &is, const BufferT &pool=BufferT())
Read an entire raw grid buffer from an input stream.
Definition: GridHandle.h:401
bool empty() const
Return true if this handle is empty, i.e. has no allocated memory.
Definition: GridHandle.h:131
VectorT< GridHandle< BufferT > > splitGrids(const GridHandle< BufferT > &handle, const BufferT *other=nullptr)
Split all grids in a single GridHandle into a vector of multiple GridHandles each with a single grid...
Definition: GridHandle.h:477
GridType gridType(uint32_t n=0) const
Return the GridType of the n&#39;th grid in this GridHandle.
Definition: GridHandle.h:229
GridHandle()=default
Constructs an empty GridHandle.
bool isPadded() const
Check if the buffer is this handle has any padding, i.e. if the buffer is larger than the combined si...
Definition: GridHandle.h:199
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceDownload(void *stream, bool sync=true)
Download the grid to from the device, e.g. from GPU to CPU.
Definition: GridHandle.h:191
void read(const std::string &fileName, const std::string &gridName, const BufferT &pool=BufferT())
Read a specific grid from a file containing a raw grid buffer.
Definition: GridHandle.h:322
uint32_t gridCount() const
Return the total number of grids contained in this buffer.
Definition: GridHandle.h:202
void read(const std::string &fileName, const BufferT &pool=BufferT())
Read a raw grid buffer from a file.
Definition: GridHandle.h:298
const NanoGrid< ValueT > * grid(uint32_t n=0) const
Returns a const host pointer to the n&#39;th NanoVDB grid encoded in this GridHandle. ...
Definition: GridHandle.h:383
void write(std::ostream &os) const
Write the entire grid buffer to an output stream.
Definition: GridHandle.h:254
uint64_t bufferSize() const
Returns the size in bytes of the raw memory buffer managed by this GridHandle.
Definition: GridHandle.h:126
bool empty(const char *str)
tests if a c-string str is empty, that is its first value is &#39;\0&#39;
Definition: Util.h:144
GridHandle< BufferT > mergeGrids(const VectorT< GridHandle< BufferT >> &handles, const BufferT *pool=nullptr)
Combines (or merges) multiple GridHandles into a single GridHandle containing all grids...
Definition: GridHandle.h:503
uint64_t gridSize(uint32_t n=0) const
Return the grid size of the n&#39;th grid in this GridHandle.
Definition: GridHandle.h:207
OutGridT const XformOp bool bool
Definition: ValueTransformer.h:609
util::enable_if< BufferTraits< U >::hasDeviceDual, void * >::type deviceData(int device)
Definition: GridHandle.h:121
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceUpload(void *stream, bool sync=true)
Upload the grid to the device, e.g. from CPU to GPU.
Definition: GridHandle.h:177
bool isFull() const
Test if this buffer has any unused storage left, i.e. memory not occupied by grids.
Definition: GridHandle.h:224
util::enable_if< BufferTraits< U >::hasDeviceDual, const void * >::type deviceData() const
Definition: GridHandle.h:112
void read(const std::string &fileName, uint32_t n, const BufferT &pool=BufferT())
Read a specific grid from a file containing a raw grid buffer.
Definition: GridHandle.h:310
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceUpload(int device=0, void *stream=nullptr, bool sync=true)
Upload the host buffer to a specific device buffer. It device buffer doesn&#39;t exist it&#39;s created first...
Definition: GridHandle.h:185
uint32_t mGridIndex
Definition: NanoVDB.h:1901
void write(const std::string &fileName) const
Write this entire grid buffer to a file.
Definition: GridHandle.h:260
BufferT BufferType
Definition: GridHandle.h:46
const BufferT & buffer() const
Return a const reference to the buffer.
Definition: GridHandle.h:100
bool isEmpty() const
Return true if this handle is empty, i.e. has no allocated memory.
Definition: GridHandle.h:132
#define NANOVDB_ASSERT(x)
Definition: Util.h:50
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:220
util::enable_if< BufferTraits< U >::hasDeviceDual, const NanoGrid< ValueT > * >::type deviceGrid(uint32_t n=0) const
Return a const pointer to the n&#39;th grid encoded in this GridHandle on the device, e...
Definition: GridHandle.h:393
static DstT * PtrAdd(void *p, int64_t offset)
Adds a byte offset to a non-const pointer to produce another non-const pointer.
Definition: Util.h:478
const GridData * gridData(uint32_t n=0) const
Access to the GridData of the n&#39;th grid in the current handle.
Definition: GridHandle.h:332
GridHandle & operator=(GridHandle &&other) noexcept
Move copy assignment operation.
Definition: GridHandle.h:83
void write(std::ostream &os, uint32_t n) const
Write a specific grid in this buffer to an output stream.
Definition: GridHandle.h:244
C++11 implementation of std::is_same.
Definition: Util.h:314
Definition: GridHandle.h:31
Struct with all the member data of the Grid (useful during serialization of an openvdb grid) ...
Definition: NanoVDB.h:1894
const void * data() const
Returns a const pointer to the data.
Definition: GridHandle.h:108
const GridMetaData * gridMetaData(uint32_t n=0) const
Returns a const point to the n&#39;th grid meta data.
Definition: GridHandle.h:340
uint64_t totalGridSize() const
compute the total sum of memory footprints of all the grids in this buffer
Definition: GridHandle.h:211
GridType gridType
Definition: GridHandle.h:31
This is a convenient class that allows for access to grid meta-data that are independent of the value...
Definition: NanoVDB.h:5459
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceDownload(int device=0, void *stream=nullptr, bool sync=true)
Definition: GridHandle.h:195
uint64_t offset
Definition: GridHandle.h:31
uint64_t size
Definition: GridHandle.h:31
GridHandle(GridHandle &&other) noexcept
Move copy-constructor.
Definition: GridHandle.h:68
__hostdev__ void cpyGridHandleMeta(const GridData *data, GridHandleMetaData *meta)
Definition: GridHandle.h:347
void * data()
Returns a non-const pointer to the data.
Definition: GridHandle.h:104