16#ifndef NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED
17#define NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED
25#include <initializer_list>
52template<
typename BufferT>
56 return BufferT(pool.stream(), pool.resource(), bytes, {});
58 return BufferT(pool.resource(), bytes, {});
60 return BufferT::create(bytes, &pool);
74 throw std::runtime_error(
"GridHandle: grid chain exceeds the host buffer (truncated or corrupt grid data)");
75 if (!head->
isValid())
throw std::runtime_error(
"GridHandle was constructed with an invalid host buffer");
77 if (count == 0)
throw std::runtime_error(
"GridHandle: host buffer contains no grids");
78 if (uint64_t(count) > bytes /
sizeof(
GridData))
79 throw std::runtime_error(
"GridHandle: grid chain exceeds the host buffer (truncated or corrupt grid data)");
82 for (uint32_t i = 0; i < count; ++i) {
83 auto where = [&] {
return " (grid " + std::to_string(i) +
" of " + std::to_string(count) +
")"; };
84 if (offset +
sizeof(
GridData) > bytes)
85 throw std::runtime_error(
"GridHandle: grid chain exceeds the host buffer (truncated or corrupt grid data)" + where());
92 throw std::runtime_error(
"GridHandle was constructed with an invalid host buffer" + where());
94 throw std::runtime_error(
"GridHandle: inconsistent grid index/count in the host buffer's grid chain" + where());
96 throw std::runtime_error(
"GridHandle: grid size field exceeds the host buffer (truncated or corrupt grid data)" + where());
107template<
typename BufferT = HostBuffer>
111 "a buffer cannot be both dual-space and single-space");
114 "GridHandle requires byte-addressed single-space storage, e.g. cuda::Buffer<std::byte, R>");
116 std::vector<GridHandleMetaData> mMetaData;
119 template <
typename T>
120 static T* no_const(
const T* ptr) {
return const_cast<T*
>(ptr); }
125 template<
typename ValueT>
128 if (base ==
nullptr || n >= mMetaData.size() || mMetaData[n].gridType !=
toGridType<ValueT>())
return nullptr;
136 : mMetaData(std::move(meta))
137 , mBuffer(std::move(
buffer)) {}
148 template<typename T = BufferT, typename util::enable_if<BufferTraits<T>::hasDeviceDual,
int>::type = 0>
162 template<typename T = BufferT, typename util::enable_if<BufferHasDeviceSingle<T>::value,
int>::type = 0,
typename =
void>
173 : mMetaData(std::move(other.mMetaData))
174 , mBuffer(std::move(other.mBuffer)) {}
179 else mBuffer.clear();
188 mBuffer = std::move(other.mBuffer);
189 mMetaData = std::move(other.mMetaData);
202 template <
typename OtherBufferT = HostBuffer>
211 template <
typename OtherBufferT = HostBuffer>
218 const BufferT&
buffer()
const {
return mBuffer; }
224 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
225 void*
data() {
return mBuffer.data(); }
226 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
227 const void*
data()
const {
return mBuffer.data(); }
230 template<
typename U = BufferT>
233 template<
typename U = BufferT>
235 deviceData(
int device)
const {
return mBuffer.deviceData(device); }
236 template<
typename U = BufferT>
239 template<
typename U = BufferT>
241 deviceData(
int device) {
return mBuffer.deviceData(device); }
245 template<
typename U = BufferT>
248 template<
typename U = BufferT>
255 [[deprecated(
"Use GridHandle::bufferSize instead.")]] uint64_t
size()
const {
return mBuffer.size(); }
261 bool empty()
const {
return mBuffer.size() == 0; }
262 bool isEmpty()
const {
return mBuffer.size() == 0; }
266 operator bool()
const {
return !this->
empty(); }
273 template<typename ValueT, typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
281 template<typename ValueT, typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
289 template<
typename ValueT,
typename U = BufferT>
298 template<
typename ValueT,
typename U = BufferT>
306 template<
typename ValueT,
typename U = BufferT>
308 deviceGrid(uint32_t n=0)
const {
return this->
template gridAt<ValueT>(mBuffer.data(), n); }
309 template<
typename ValueT,
typename U = BufferT>
316 template<
typename U = BufferT>
318 deviceUpload(
void* stream,
bool sync =
true) { mBuffer.deviceUpload(stream, sync); }
324 template<
typename U = BufferT>
326 deviceUpload(
int device = 0,
void* stream =
nullptr,
bool sync =
true) { mBuffer.deviceUpload(device, stream, sync); }
330 template<
typename U = BufferT>
332 deviceDownload(
void* stream,
bool sync =
true) { mBuffer.deviceDownload(stream, sync); }
334 template<
typename U = BufferT>
336 deviceDownload(
int device = 0,
void* stream =
nullptr,
bool sync =
true) { mBuffer.deviceDownload(device, stream, sync); }
340 bool isPadded()
const {
return mMetaData.empty() ? false : mMetaData.back().offset + mMetaData.back().size != mBuffer.size();}
343 uint32_t
gridCount()
const {
return static_cast<uint32_t
>(mMetaData.size());}
348 uint64_t
gridSize(uint32_t n = 0)
const {
return mMetaData[n].size; }
354 for (
auto &m : mMetaData) sum += m.size;
375 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
381 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
387 void write(std::ostream& os, uint32_t n)
const {
389 "GridHandle::write requires host-accessible grids: cuda::copyTo a host-readable handle first");
391 os.write((
const char*)
data,
data->mGridSize);
393 throw std::runtime_error(
"GridHandle does not contain a #" + std::to_string(n) +
" grid");
399 void write(std::ostream& os)
const {
401 "GridHandle::write requires host-accessible grids: cuda::copyTo a host-readable handle first");
408 void write(
const std::string &fileName)
const {
409 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
410 if (!os.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for output");
417 void write(
const std::string &fileName, uint32_t n)
const {
418 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
419 if (!os.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for output");
427 void read(std::istream& is,
const BufferT& pool = BufferT());
434 void read(std::istream& is, uint32_t n,
const BufferT& pool = BufferT());
441 void read(std::istream& is,
const std::string &gridName,
const BufferT& pool = BufferT());
446 void read(
const std::string &fileName,
const BufferT& pool = BufferT()) {
447 std::ifstream is(fileName, std::ios::in | std::ios::binary);
448 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
449 this->
read(is, pool);
458 void read(
const std::string &fileName, uint32_t n,
const BufferT& pool = BufferT()) {
459 std::ifstream is(fileName, std::ios::in | std::ios::binary);
460 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
461 this->
read(is, n, pool);
470 void read(
const std::string &fileName,
const std::string &gridName,
const BufferT& pool = BufferT()) {
471 std::ifstream is(fileName, std::ios::in | std::ios::binary);
472 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
473 this->
read(is, gridName, pool);
479template<
typename BufferT>
480template<typename U, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type>
483 const void *
data = this->data();
484 if (
data ==
nullptr || n >= mMetaData.size())
return nullptr;
488template<
typename BufferT>
489template<typename U, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type>
493 if (
data ==
nullptr || n >= mMetaData.size())
return nullptr;
498template<
typename BufferT>
504 if (
auto *
data =
reinterpret_cast<const GridData*
>(mBuffer.data())) {
505 detail::parseHostGridChain(data, mBuffer.size(), mMetaData);
509template<
typename BufferT>
510template <
typename OtherBufferT>
514 "GridHandle::copy(pool) cannot honor a pool argument for a single-space device buffer, "
515 "whose copy allocates through the source buffer's resource: use the no-argument copy() "
516 "for a same-space deep copy, or cuda::copyTo (cuda/HandleStorage.h) to cross address spaces");
517 if (mBuffer.size() == 0)
return GridHandle<OtherBufferT>();
519 std::memcpy(
buffer.data(), mBuffer.data(), mBuffer.size());
520 return GridHandle<OtherBufferT>(std::move(
buffer));
523template<
typename BufferT>
524template <
typename OtherBufferT>
529 "GridHandle::copy is same-space only: a single-space device handle copies to its own "
530 "buffer type; use cuda::copyTo (cuda/HandleStorage.h) to move grids across address spaces");
535 return GridHandle(mBuffer.copy(), mMetaData);
538 "GridHandle::copy() without arguments default-constructs the target pool buffer: "
539 "pass a prototype to copy(other) for a buffer over a non-default-constructible resource");
540 return this->
copy(OtherBufferT());
544template<
typename BufferT>
545template<typename ValueT, typename U, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type>
548 return this->
template gridAt<ValueT>(mBuffer.data(), n);
551template<
typename BufferT>
552template<
typename ValueT,
typename U>
556 return this->
template gridAt<ValueT>(mBuffer.deviceData(), n);
559template<
typename BufferT>
563 "GridHandle::read requires a host-accessible buffer: read into a host-readable handle, then cuda::copyTo");
564 const std::streampos start = is.tellg();
567 if (
data.isValid()) {
568 uint64_t
size =
data.mGridSize, sum = 0u;
569 while(
data.mGridIndex + 1u <
data.mGridCount) {
570 is.seekg(
data.mGridSize -
sizeof(
GridData), std::ios::cur);
572 sum +=
data.mGridSize;
577 *
this = GridHandle(std::move(
buffer));
579 is.seekg(-
sizeof(
GridData), std::ios::cur);
580 throw std::logic_error(
"This stream does not contain a valid raw grid buffer");
584template<
typename BufferT>
588 "GridHandle::read requires a host-accessible buffer: read into a host-readable handle, then cuda::copyTo");
591 if (
data.isValid()) {
592 if (n>=
data.mGridCount)
throw std::runtime_error(
"stream does not contain a #" + std::to_string(n) +
" grid");
593 while(
data.mGridIndex != n) {
594 is.seekg(
data.mGridSize -
sizeof(
GridData), std::ios::cur);
598 is.seekg(-
sizeof(
GridData), std::ios::cur);
599 is.read((
char*)(
buffer.data()),
data.mGridSize);
601 *
this = GridHandle(std::move(
buffer));
603 is.seekg(-
sizeof(
GridData), std::ios::cur);
604 throw std::logic_error(
"This file does not contain a valid raw buffer");
608template<
typename BufferT>
612 "GridHandle::read requires a host-accessible buffer: read into a host-readable handle, then cuda::copyTo");
613 static const std::streamsize byteSize =
sizeof(
GridData);
615 is.read((
char*)&
data, byteSize);
616 is.seekg(-byteSize, std::ios::cur);
617 if (
data.isValid()) {
619 while(
data.mGridName != gridName && n++ <
data.mGridCount) {
620 is.seekg(
data.mGridSize, std::ios::cur);
621 is.read((
char*)&
data, byteSize);
622 is.seekg(-byteSize, std::ios::cur);
624 if (n>
data.mGridCount)
throw std::runtime_error(
"No raw grid named \""+gridName+
"\"");
626 is.read((
char*)(
buffer.data()),
data.mGridSize);
628 *
this = GridHandle(std::move(
buffer));
630 throw std::logic_error(
"This file does not contain a valid raw buffer");
641template<
typename BufferT,
template <
class,
class...>
class VectorT = std::vector>
642inline VectorT<GridHandle<BufferT>>
646 "splitGrids requires a buffer type providing create(): cuda::copyTo a HostBuffer handle first");
648 "splitGrids requires a buffer type providing create(): copy the handle to a HostBuffer first");
650 const void *ptr = handle.
data();
651 if (ptr ==
nullptr)
return VectorT<HandleT>();
652 VectorT<HandleT> handles(handle.
gridCount());
653 for (
auto &h : handles) {
656 auto buffer = BufferT::create(src->
mGridSize, other);
660 h = HandleT(std::move(buffer));
671template<
typename BufferT,
template <
class,
class...>
class VectorT>
672inline GridHandle<BufferT>
676 "mergeGrids requires a buffer type providing create(): cuda::copyTo HostBuffer handles first");
678 "mergeGrids requires a buffer type providing create(): copy the handles to HostBuffer first");
680 uint32_t counter = 0u, gridCount = 0u;
681 for (
auto &h : handles) {
682 gridCount += h.gridCount();
683 for (uint32_t n=0; n<h.gridCount(); ++n) size += h.gridSize(n);
685 auto buffer = BufferT::create(size, pool);
686 void *dst = buffer.data();
687 for (
auto &h : handles) {
688 const void *src = h.data();
689 for (uint32_t n=0; n<h.gridCount(); ++n) {
690 std::memcpy(dst, src, h.gridSize(n));
703#if defined(__CUDACC__)
704#include <nanovdb/cuda/GridHandle.cuh>
HostBuffer - a buffer that contains a shared or private bump pool to either externally or internally ...
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
This class serves to manage a buffer containing one or more NanoVDB Grids.
Definition GridHandle.h:109
uint64_t freeSize() const
compute the size of unused storage in this buffer
Definition GridHandle.h:361
util::enable_if< BufferHasDeviceSingle< U >::value, constNanoGrid< ValueT > * >::type deviceGrid(uint32_t n=0) const
Return a pointer to the n'th grid of a single-space device buffer.
Definition GridHandle.h:308
GridHandle & operator=(const GridHandle &)=delete
Disallow copy assignment operation.
uint64_t totalGridSize() const
compute the total sum of memory footprints of all the grids in this buffer
Definition GridHandle.h:352
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceDownload(int device=0, void *stream=nullptr, bool sync=true)
Definition GridHandle.h:336
util::enable_if< BufferTraits< U >::hasDeviceDual, constvoid * >::type deviceData(int device) const
Definition GridHandle.h:235
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:318
BufferT & buffer()
Return a reference to the buffer.
Definition GridHandle.h:215
void write(std::ostream &os) const
Write the entire grid buffer to an output stream.
Definition GridHandle.h:399
GridHandle(const GridHandle &)=delete
Disallow copy-construction.
GridHandle & operator=(GridHandle &&other) noexcept
Move copy assignment operation.
Definition GridHandle.h:187
uint64_t bufferSize() const
Definition GridHandle.h:256
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:470
bool empty() const
Return true if this handle is empty, i.e. has no allocated memory.
Definition GridHandle.h:261
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:554
util::enable_if< BufferHasDeviceSingle< U >::value, void * >::type deviceData()
Definition GridHandle.h:250
const void * data() const
Definition GridHandle.h:227
const GridData * gridData(uint32_t n=0) const
Access to the GridData of the n'th grid in the current handle.
Definition GridHandle.h:481
util::enable_if< BufferHasDeviceSingle< U >::value, constvoid * >::type deviceData() const
For a single-space buffer the device data is the buffer itself.
Definition GridHandle.h:247
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:546
uint64_t size() const
Returns the size in bytes of the raw memory buffer managed by this GridHandle.
Definition GridHandle.h:255
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:300
const BufferT & buffer() const
Return a const reference to the buffer.
Definition GridHandle.h:218
GridHandle(GridHandle &&other) noexcept
Move copy-constructor.
Definition GridHandle.h:172
util::enable_if< BufferTraits< U >::hasDeviceDual, constvoid * >::type deviceData() const
Definition GridHandle.h:232
uint64_t gridSize(uint32_t n=0) const
Return the grid size of the n'th grid in this GridHandle.
Definition GridHandle.h:348
GridType gridType(uint32_t n=0) const
Return the GridType of the n'th grid in this GridHandle.
Definition GridHandle.h:370
GridHandle(T &&buffer)
Move constructor from a single-space device buffer: the grid metadata is read through the device on t...
util::enable_if< BufferTraits< U >::hasDeviceDual, void * >::type deviceData(int device)
Definition GridHandle.h:241
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:458
void write(const std::string &fileName) const
Write this entire grid buffer to a file.
Definition GridHandle.h:408
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:340
NanoGrid< ValueT > * grid(uint32_t n=0)
Returns a host pointer to the n'th NanoVDB grid encoded in this GridHandle.
Definition GridHandle.h:282
const GridMetaData * gridMetaData(uint32_t n=0) const
Returns a const point to the n'th grid meta data.
Definition GridHandle.h:490
util::enable_if< BufferHasDeviceSingle< U >::value, NanoGrid< ValueT > * >::type deviceGrid(uint32_t n=0)
Definition GridHandle.h:311
BufferT BufferType
Definition GridHandle.h:142
GridHandle< OtherBufferT > copy() const
Deep copy without a pool argument. The single-space path allocates through the source buffer's resour...
Definition GridHandle.h:525
uint32_t gridCount() const
Return the total number of grids contained in this buffer.
Definition GridHandle.h:343
bool isEmpty() const
Definition GridHandle.h:262
void reset()
clear this GridHandle to an empty handle
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:365
GridHandle(T &&buffer)
Move constructor from a host buffer.
util::enable_if< BufferTraits< U >::hasDeviceDual, void * >::type deviceData()
Definition GridHandle.h:238
void * data()
Returns a pointer to the host data; not available for a single-space device buffer,...
Definition GridHandle.h:225
void read(const std::string &fileName, const BufferT &pool=BufferT())
Read a raw grid buffer from a file.
Definition GridHandle.h:446
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:326
void write(const std::string &fileName, uint32_t n) const
Write a specific grid to file.
Definition GridHandle.h:417
void read(std::istream &is, const BufferT &pool=BufferT())
Read an entire raw grid buffer from an input stream.
Definition GridHandle.h:560
void write(std::ostream &os, uint32_t n) const
Write a specific grid in this buffer to an output stream.
Definition GridHandle.h:387
GridHandle< OtherBufferT > copy(const OtherBufferT &buffer) const
Performs a deep copy of the GridHandle, possibly templated on a different buffer type.
Definition GridHandle.h:511
GridHandle()=default
Constructs an empty GridHandle.
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:332
Definition VoxToNanoVDB.h:15
Definition GridHandle.h:37
BufferT createHostStorage(uint64_t bytes, const BufferT &pool)
Allocates bytes of host-readable storage for a GridHandle: through BufferT::create for buffers that p...
Definition GridHandle.h:53
void parseHostGridChain(const GridData *head, uint64_t bytes, std::vector< GridHandleMetaData > &meta)
Validates the grid chain in bytes of host-readable memory headed by head and fills meta with one entr...
Definition GridHandle.h:71
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:524
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:31
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:673
GridType toGridType()
Maps from a templated build type to a GridType enum.
Definition NanoVDB.h:851
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:4742
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:643
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:219
#define NANOVDB_ASSERT(x)
Definition Util.h:53
static constexpr bool value
Definition HostBuffer.h:147
static constexpr bool value
Definition HostBuffer.h:165
static constexpr bool value
Definition HostBuffer.h:112
static constexpr bool value
Definition HostBuffer.h:121
static constexpr bool value
Definition HostBuffer.h:138
static constexpr bool value
Definition HostBuffer.h:156
static constexpr bool value
Definition HostBuffer.h:132
static constexpr bool hasDeviceDual
Definition HostBuffer.h:102
Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
Definition NanoVDB.h:1977
GridType mGridType
Definition NanoVDB.h:1991
bool isValid() const
return true if the magic number and the version are both valid
Definition NanoVDB.h:2034
uint64_t mGridSize
Definition NanoVDB.h:1985
uint32_t mGridCount
Definition NanoVDB.h:1984
uint32_t mGridIndex
Definition NanoVDB.h:1983
The one gateway for constructing a GridHandle from a buffer plus metadata that is already known to be...
Definition HandleStorage.h:146
C++11 implementation of std::enable_if.
Definition Util.h:353
static constexpr bool value
Definition Util.h:328