OpenVDB: nanovdb/GridHandle.h Source File

OpenVDB 12.1.0

Loading...
Searching...
No Matches
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
31 struct GridHandleMetaData {uint64_t offset, size; GridType gridType;};
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.
36template<typename BufferT = HostBuffer>
37 class GridHandle
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
45public:
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>
117 typename util::enable_if<BufferTraits<U>::hasDeviceDual, void*>::type
118 deviceData() { return mBuffer.deviceData(); }
119 template<typename U = BufferT>
120 typename util::enable_if<BufferTraits<U>::hasDeviceDual, void*>::type
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>
160 typename util::enable_if<BufferTraits<U>::hasDeviceDual, const NanoGrid<ValueT>*>::type
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
331template<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
339template<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
347 inline __hostdev__ void cpyGridHandleMeta(const GridData *data, GridHandleMetaData *meta)
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
358template<typename BufferT>
359template<typename T, typename util::disable_if<BufferTraits<T>::hasDeviceDual, int>::type>
360 GridHandle<BufferT>::GridHandle(T&& buffer)
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
371template<typename BufferT>
372template <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
381template<typename BufferT>
382template<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
390template<typename BufferT>
391template<typename ValueT, typename U>
392inline typename util::enable_if<BufferTraits<U>::hasDeviceDual, const NanoGrid<ValueT>*>::type
393GridHandle<BufferT>::deviceGrid(uint32_t n) const
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
400template<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
422template<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
444template<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
475template<typename BufferT, template <class, class...> class VectorT = std::vector>
476inline VectorT<GridHandle<BufferT>>
477splitGrids(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
501template<typename BufferT, template <class, class...> class VectorT>
502inline GridHandle<BufferT>
503mergeGrids(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
HostBuffer.h
HostBuffer - a buffer that contains a shared or private bump pool to either externally or internally ...
NanoVDB.h
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
nanovdb::GridHandle
This class serves to manage a buffer containing one or more NanoVDB Grids.
Definition GridHandle.h:38
nanovdb::GridHandle::data
void * data()
Returns a non-const pointer to the data.
Definition GridHandle.h:104
nanovdb::GridHandle::freeSize
uint64_t freeSize() const
compute the size of unused storage in this buffer
Definition GridHandle.h:220
nanovdb::GridHandle::operator=
GridHandle & operator=(const GridHandle &)=delete
Disallow copy assignment operation.
nanovdb::GridHandle::totalGridSize
uint64_t totalGridSize() const
compute the total sum of memory footprints of all the grids in this buffer
Definition GridHandle.h:211
nanovdb::GridHandle::deviceDownload
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceDownload(int device=0, void *stream=nullptr, bool sync=true)
Definition GridHandle.h:195
nanovdb::GridHandle::deviceData
util::enable_if< BufferTraits< U >::hasDeviceDual, constvoid * >::type deviceData(int device) const
Definition GridHandle.h:115
nanovdb::GridHandle::grid
NanoGrid< ValueT > * grid(uint32_t n=0)
Returns a host pointer to the n'th NanoVDB grid encoded in this GridHandle.
Definition GridHandle.h:152
nanovdb::GridHandle::deviceUpload
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
nanovdb::GridHandle::buffer
BufferT & buffer()
Return a reference to the buffer.
Definition GridHandle.h:97
nanovdb::GridHandle::gridData
const GridData * gridData(uint32_t n=0) const
Access to the GridData of the n'th grid in the current handle.
Definition GridHandle.h:332
nanovdb::GridHandle::data
const void * data() const
Returns a const pointer to the data.
Definition GridHandle.h:108
nanovdb::GridHandle::write
void write(std::ostream &os) const
Write the entire grid buffer to an output stream.
Definition GridHandle.h:254
nanovdb::GridHandle::GridHandle
GridHandle(const GridHandle &)=delete
Disallow copy-construction.
nanovdb::GridHandle::operator=
GridHandle & operator=(GridHandle &&other) noexcept
Move copy assignment operation.
Definition GridHandle.h:83
nanovdb::GridHandle::grid
const NanoGrid< ValueT > * grid(uint32_t n=0) const
Returns a const host pointer to the n'th NanoVDB grid encoded in this GridHandle.
Definition GridHandle.h:383
nanovdb::GridHandle::bufferSize
uint64_t bufferSize() const
Definition GridHandle.h:126
nanovdb::GridHandle::read
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
nanovdb::GridHandle::empty
bool empty() const
Return true if this handle is empty, i.e. has no allocated memory.
Definition GridHandle.h:131
nanovdb::GridHandle::deviceGrid
util::enable_if< BufferTraits< U >::hasDeviceDual, constNanoGrid< ValueT > * >::type deviceGrid(uint32_t n=0) const
Return a const pointer to the n'th grid encoded in this GridHandle on the device, e....
Definition GridHandle.h:393
nanovdb::GridHandle::size
uint64_t size() const
Returns the size in bytes of the raw memory buffer managed by this GridHandle.
Definition GridHandle.h:125
nanovdb::GridHandle::deviceGrid
util::enable_if< BufferTraits< U >::hasDeviceDual, NanoGrid< ValueT > * >::type deviceGrid(uint32_t n=0)
Return a const pointer to the n'th grid encoded in this GridHandle on the device, e....
Definition GridHandle.h:171
nanovdb::GridHandle::buffer
const BufferT & buffer() const
Return a const reference to the buffer.
Definition GridHandle.h:100
nanovdb::GridHandle::GridHandle
GridHandle(GridHandle &&other) noexcept
Move copy-constructor.
Definition GridHandle.h:68
nanovdb::GridHandle::deviceData
util::enable_if< BufferTraits< U >::hasDeviceDual, constvoid * >::type deviceData() const
Definition GridHandle.h:112
nanovdb::GridHandle::gridMetaData
const GridMetaData * gridMetaData(uint32_t n=0) const
Returns a const point to the n'th grid meta data.
Definition GridHandle.h:340
nanovdb::GridHandle::gridSize
uint64_t gridSize(uint32_t n=0) const
Return the grid size of the n'th grid in this GridHandle.
Definition GridHandle.h:207
nanovdb::GridHandle::gridType
GridType gridType(uint32_t n=0) const
Return the GridType of the n'th grid in this GridHandle.
Definition GridHandle.h:229
nanovdb::GridHandle::deviceData
util::enable_if< BufferTraits< U >::hasDeviceDual, void * >::type deviceData(int device)
Definition GridHandle.h:121
nanovdb::GridHandle::read
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
nanovdb::GridHandle::write
void write(const std::string &fileName) const
Write this entire grid buffer to a file.
Definition GridHandle.h:260
nanovdb::GridHandle::isPadded
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
nanovdb::GridHandle::BufferType
BufferT BufferType
Definition GridHandle.h:46
nanovdb::GridHandle::copy
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
nanovdb::GridHandle::gridCount
uint32_t gridCount() const
Return the total number of grids contained in this buffer.
Definition GridHandle.h:202
nanovdb::GridHandle::isEmpty
bool isEmpty() const
Definition GridHandle.h:132
nanovdb::GridHandle::reset
void reset()
clear this GridHandle to an empty handle
Definition GridHandle.h:74
nanovdb::GridHandle::isFull
bool isFull() const
Test if this buffer has any unused storage left, i.e. memory not occupied by grids.
Definition GridHandle.h:224
nanovdb::GridHandle::GridHandle
GridHandle(T &&buffer)
Move constructor from a dual host-device buffer.
Definition GridHandle.h:360
nanovdb::GridHandle::deviceData
util::enable_if< BufferTraits< U >::hasDeviceDual, void * >::type deviceData()
Definition GridHandle.h:118
nanovdb::GridHandle::read
void read(const std::string &fileName, const BufferT &pool=BufferT())
Read a raw grid buffer from a file.
Definition GridHandle.h:298
nanovdb::GridHandle::deviceUpload
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't exist it's created first...
Definition GridHandle.h:185
nanovdb::GridHandle::write
void write(const std::string &fileName, uint32_t n) const
Write a specific grid to file.
Definition GridHandle.h:269
nanovdb::GridHandle::read
void read(std::istream &is, const BufferT &pool=BufferT())
Read an entire raw grid buffer from an input stream.
Definition GridHandle.h:401
nanovdb::GridHandle::write
void write(std::ostream &os, uint32_t n) const
Write a specific grid in this buffer to an output stream.
Definition GridHandle.h:244
nanovdb::GridHandle::GridHandle
GridHandle()=default
Constructs an empty GridHandle.
nanovdb::GridHandle::deviceDownload
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
nanovdb::GridMetaData
This is a convenient class that allows for access to grid meta-data that are independent of the value...
Definition NanoVDB.h:5460
nanovdb::util::PtrAdd
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
nanovdb
Definition GridHandle.h:27
nanovdb::cpyGridHandleMeta
void cpyGridHandleMeta(const GridData *data, GridHandleMetaData *meta)
Definition GridHandle.h:347
nanovdb::mergeGrids
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
nanovdb::NanoGrid
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:4614
nanovdb::toGridType
__hostdev__ GridType toGridType()
Maps from a templated build type to a GridType enum.
Definition NanoVDB.h:807
nanovdb::splitGrids
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
nanovdb::GridType
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:220
__hostdev__
#define __hostdev__
Definition Util.h:73
NANOVDB_ASSERT
#define NANOVDB_ASSERT(x)
Definition Util.h:50
nanovdb::GridData
Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
Definition NanoVDB.h:1895
nanovdb::GridData::mGridType
GridType mGridType
Definition NanoVDB.h:1909
nanovdb::GridData::mGridSize
uint64_t mGridSize
Definition NanoVDB.h:1903
nanovdb::GridData::isValid
__hostdev__ bool isValid() const
return true if the magic number and the version are both valid
Definition NanoVDB.h:1952
nanovdb::GridData::mGridCount
uint32_t mGridCount
Definition NanoVDB.h:1902
nanovdb::GridHandleMetaData
Definition GridHandle.h:31
nanovdb::GridHandleMetaData::offset
uint64_t offset
Definition GridHandle.h:31
nanovdb::GridHandleMetaData::gridType
GridType gridType
Definition GridHandle.h:31
nanovdb::GridHandleMetaData::size
uint64_t size
Definition GridHandle.h:31
nanovdb::util::enable_if
C++11 implementation of std::enable_if.
Definition Util.h:335
nanovdb::util::is_same::value
static constexpr bool value
Definition Util.h:316