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);
67template<
typename BufferT>
71 return BufferT::create(bytes, pool);
75 if (!pool)
throw std::runtime_error(
"GridHandle: a host-accessible buffer over a non-default-constructible "
76 "resource requires a pool buffer to take the resource from");
90 if (bytes == 0)
return;
91 throw std::runtime_error(
"GridHandle::adopt: the metadata describes no grids but the buffer is not empty");
94 for (
size_t i = 0; i < meta.size(); ++i) {
95 auto where = [&] {
return " (grid " + std::to_string(i) +
" of " + std::to_string(meta.size()) +
")"; };
96 if (meta[i].offset != offset)
97 throw std::runtime_error(
"GridHandle::adopt: grids must be contiguous from offset zero" + where());
99 throw std::runtime_error(
"GridHandle::adopt: grid offset is not a multiple of NANOVDB_DATA_ALIGNMENT" + where());
100 if (meta[i].size <
sizeof(
GridData))
101 throw std::runtime_error(
"GridHandle::adopt: grid size is smaller than a grid header" + where());
102 if (meta[i].size > bytes - offset)
103 throw std::runtime_error(
"GridHandle::adopt: grid exceeds the buffer" + where());
105 throw std::runtime_error(
"GridHandle::adopt: invalid grid type" + where());
106 offset += meta[i].size;
120 throw std::runtime_error(
"GridHandle: grid chain exceeds the host buffer (truncated or corrupt grid data)");
121 if (!head->
isValid())
throw std::runtime_error(
"GridHandle was constructed with an invalid host buffer");
123 if (count == 0)
throw std::runtime_error(
"GridHandle: host buffer contains no grids");
124 if (uint64_t(count) > bytes /
sizeof(
GridData))
125 throw std::runtime_error(
"GridHandle: grid chain exceeds the host buffer (truncated or corrupt grid data)");
128 for (uint32_t i = 0; i < count; ++i) {
129 auto where = [&] {
return " (grid " + std::to_string(i) +
" of " + std::to_string(count) +
")"; };
130 if (offset +
sizeof(
GridData) > bytes)
131 throw std::runtime_error(
"GridHandle: grid chain exceeds the host buffer (truncated or corrupt grid data)" + where());
138 throw std::runtime_error(
"GridHandle was constructed with an invalid host buffer" + where());
140 throw std::runtime_error(
"GridHandle: inconsistent grid index/count in the host buffer's grid chain" + where());
142 throw std::runtime_error(
"GridHandle: grid size field exceeds the host buffer (truncated or corrupt grid data)" + where());
151template<
typename BufferT,
typename =
void>
153template<
typename BufferT>
155{
static constexpr bool value =
true; };
162template<
typename BufferT = HostBuffer>
167 "GridHandle requires byte-addressed single-space storage, e.g. cuda::Buffer<std::byte, R>");
169 "BufferTraits::hasDeviceDual was removed in NanoVDB 14.0 together with the dual-space buffers: "
170 "hold device grids in a single-space buffer such as cuda::Buffer<std::byte> and set "
171 "BufferTraits::hasDeviceSingle for a custom one");
173 std::vector<GridHandleMetaData> mMetaData;
176 template <
typename T>
177 static T* no_const(
const T* ptr) {
return const_cast<T*
>(ptr); }
182 template<
typename ValueT>
185 if (base ==
nullptr || n >= mMetaData.size() || mMetaData[n].gridType !=
toGridType<ValueT>())
return nullptr;
190 : mMetaData(std::move(meta))
191 , mBuffer(std::move(
buffer)) {}
194 void parseSingleBuffer();
213 static GridHandle
adopt(BufferT&&
buffer, std::vector<GridHandleMetaData> meta)
222 const std::vector<GridHandleMetaData>&
metaData()
const {
return mMetaData; }
234 this->parseSingleBuffer();
236 if (
auto *
data =
reinterpret_cast<const GridData*
>(mBuffer.data())) {
255 : mMetaData(std::move(other.mMetaData))
256 , mBuffer(std::move(other.mBuffer)) {}
261 else mBuffer.clear();
270 mBuffer = std::move(other.mBuffer);
271 mMetaData = std::move(other.mMetaData);
284 template <
typename OtherBufferT = HostBuffer>
293 template <
typename OtherBufferT = HostBuffer>
300 const BufferT&
buffer()
const {
return mBuffer; }
306 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
307 void*
data() {
return mBuffer.data(); }
308 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
309 const void*
data()
const {
return mBuffer.data(); }
314 template<
typename U = BufferT>
317 template<
typename U = BufferT>
329 bool empty()
const {
return mBuffer.size() == 0; }
330 bool isEmpty()
const {
return mBuffer.size() == 0; }
334 operator bool()
const {
return !this->
empty(); }
341 template<typename ValueT, typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
349 template<typename ValueT, typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
356 template<
typename ValueT,
typename U = BufferT>
358 deviceGrid(uint32_t n=0)
const {
return this->
template gridAt<ValueT>(mBuffer.data(), n); }
359 template<
typename ValueT,
typename U = BufferT>
366 bool isPadded()
const {
return mMetaData.empty() ? false : mMetaData.back().offset + mMetaData.back().size != mBuffer.size();}
369 uint32_t
gridCount()
const {
return static_cast<uint32_t
>(mMetaData.size());}
374 uint64_t
gridSize(uint32_t n = 0)
const {
return mMetaData[n].size; }
380 for (
auto &m : mMetaData) sum += m.size;
401 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
407 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type = 0>
413 void write(std::ostream& os, uint32_t n)
const {
415 "GridHandle::write requires host-accessible grids: cuda::copyTo a host-readable handle first");
417 os.write((
const char*)
data,
data->mGridSize);
419 throw std::runtime_error(
"GridHandle does not contain a #" + std::to_string(n) +
" grid");
425 void write(std::ostream& os)
const {
427 "GridHandle::write requires host-accessible grids: cuda::copyTo a host-readable handle first");
434 void write(
const std::string &fileName)
const {
435 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
436 if (!os.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for output");
443 void write(
const std::string &fileName, uint32_t n)
const {
444 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
445 if (!os.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for output");
453 void read(std::istream& is,
const BufferT& pool = BufferT());
460 void read(std::istream& is, uint32_t n,
const BufferT& pool = BufferT());
467 void read(std::istream& is,
const std::string &gridName,
const BufferT& pool = BufferT());
472 void read(
const std::string &fileName,
const BufferT& pool = BufferT()) {
473 std::ifstream is(fileName, std::ios::in | std::ios::binary);
474 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
475 this->
read(is, pool);
484 void read(
const std::string &fileName, uint32_t n,
const BufferT& pool = BufferT()) {
485 std::ifstream is(fileName, std::ios::in | std::ios::binary);
486 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
487 this->
read(is, n, pool);
496 void read(
const std::string &fileName,
const std::string &gridName,
const BufferT& pool = BufferT()) {
497 std::ifstream is(fileName, std::ios::in | std::ios::binary);
498 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
499 this->
read(is, gridName, pool);
512 template<
typename DstBufferT,
typename SrcBufferT>
516 throw std::runtime_error(
"GridHandle: a copied buffer must match the size of its source");
525template<
typename BufferT>
526template<typename U, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type>
529 const void *
data = this->data();
530 if (
data ==
nullptr || n >= mMetaData.size())
return nullptr;
534template<
typename BufferT>
535template<typename U, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type>
539 if (
data ==
nullptr || n >= mMetaData.size())
return nullptr;
543template<
typename BufferT>
544template <
typename OtherBufferT>
548 "GridHandle::copy(pool) cannot honor a pool argument for a single-space device buffer, "
549 "whose copy allocates through the source buffer's resource: use the no-argument copy() "
550 "for a same-space deep copy, or cuda::copyTo (cuda/HandleStorage.h) to cross address spaces");
551 if (mBuffer.size() == 0)
return GridHandle<OtherBufferT>();
553 std::memcpy(
buffer.data(), mBuffer.data(), mBuffer.size());
554 return GridHandle<OtherBufferT>(std::move(
buffer));
557template<
typename BufferT>
558template <
typename OtherBufferT>
563 "GridHandle::copy is same-space only: a single-space device handle copies to its own "
564 "buffer type; use cuda::copyTo (cuda/HandleStorage.h) to move grids across address spaces");
569 return GridHandle(mBuffer.copy(), mMetaData);
572 "GridHandle::copy() without arguments default-constructs the target pool buffer: "
573 "pass a prototype to copy(other) for a buffer over a non-default-constructible resource");
574 return this->
copy(OtherBufferT());
578template<
typename BufferT>
579template<typename ValueT, typename U, typename util::disable_if<BufferIsDeviceOnly<U>::value,
int>::type>
582 return this->
template gridAt<ValueT>(mBuffer.data(), n);
585template<
typename BufferT>
589 "GridHandle::read requires a host-accessible buffer: read into a host-readable handle, then cuda::copyTo");
590 const std::streampos start = is.tellg();
593 if (
data.isValid()) {
594 uint64_t size =
data.mGridSize, sum = 0u;
595 while(
data.mGridIndex + 1u <
data.mGridCount) {
596 is.seekg(
data.mGridSize -
sizeof(
GridData), std::ios::cur);
598 sum +=
data.mGridSize;
603 *
this = GridHandle(std::move(
buffer));
605 is.seekg(-
sizeof(
GridData), std::ios::cur);
606 throw std::logic_error(
"This stream does not contain a valid raw grid buffer");
610template<
typename BufferT>
614 "GridHandle::read requires a host-accessible buffer: read into a host-readable handle, then cuda::copyTo");
617 if (
data.isValid()) {
618 if (n>=
data.mGridCount)
throw std::runtime_error(
"stream does not contain a #" + std::to_string(n) +
" grid");
619 while(
data.mGridIndex != n) {
620 is.seekg(
data.mGridSize -
sizeof(
GridData), std::ios::cur);
624 is.seekg(-
sizeof(
GridData), std::ios::cur);
625 is.read((
char*)(
buffer.data()),
data.mGridSize);
627 *
this = GridHandle(std::move(
buffer));
629 is.seekg(-
sizeof(
GridData), std::ios::cur);
630 throw std::logic_error(
"This file does not contain a valid raw buffer");
634template<
typename BufferT>
638 "GridHandle::read requires a host-accessible buffer: read into a host-readable handle, then cuda::copyTo");
639 static const std::streamsize byteSize =
sizeof(
GridData);
641 is.read((
char*)&
data, byteSize);
642 is.seekg(-byteSize, std::ios::cur);
643 if (
data.isValid()) {
645 while(
data.mGridName != gridName && n++ <
data.mGridCount) {
646 is.seekg(
data.mGridSize, std::ios::cur);
647 is.read((
char*)&
data, byteSize);
648 is.seekg(-byteSize, std::ios::cur);
650 if (n>
data.mGridCount)
throw std::runtime_error(
"No raw grid named \""+gridName+
"\"");
652 is.read((
char*)(
buffer.data()),
data.mGridSize);
654 *
this = GridHandle(std::move(
buffer));
656 throw std::logic_error(
"This file does not contain a valid raw buffer");
674template<
typename BufferT,
template <
class,
class...>
class VectorT = std::vector>
675inline VectorT<GridHandle<BufferT>>
679 "splitGrids copies grids on the host: use cuda::splitGridHandles for a device handle");
681 VectorT<HandleT> handles;
682 if (handle.
data() ==
nullptr)
return handles;
684 for (uint32_t n = 0; n < handle.
gridCount(); ++n) {
685 const uint64_t size = handle.
gridSize(n);
689 throw std::runtime_error(
"splitGrids: grid header size disagrees with the handle's metadata (grid " + std::to_string(n) +
")");
692 std::memcpy(dst, src, size);
694 handles.push_back(HandleT(std::move(buffer)));
711template<
typename BufferT,
template <
class,
class...>
class VectorT>
712inline GridHandle<BufferT>
716 "mergeGrids copies grids on the host: use cuda::mergeGridHandles for device handles");
718 uint32_t counter = 0u, gridCount = 0u;
719 for (
auto &h : handles) {
720 gridCount += h.gridCount();
721 for (uint32_t n=0; n<h.gridCount(); ++n) {
722 if (h.gridData(n)->mGridSize != h.gridSize(n))
723 throw std::runtime_error(
"mergeGrids: grid header size disagrees with its handle's metadata (grid " + std::to_string(n) +
")");
724 size += h.gridSize(n);
728 void *dst = buffer.data();
729 for (
auto &h : handles) {
730 for (uint32_t n=0; n<h.gridCount(); ++n) {
731 std::memcpy(dst, h.gridData(n), h.gridSize(n));
746#if defined(__CUDACC__) && !defined(NANOVDB_CUDA_HANDLESTORAGE_DEFERS_GRIDHANDLE_CUH) \
747 && !defined(NANOVDB_TOOLS_CUDA_GRIDCHECKSUM_DEFERS_GRIDHANDLE_CUH)
748#include <nanovdb/cuda/GridHandle.cuh>
Computes a pair of uint32_t checksums, of a Grid, by means of 32 bit Cyclic Redundancy Check (CRC32)
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,...
#define NANOVDB_DATA_ALIGNMENT
Definition NanoVDB.h:133
This class serves to manage a buffer containing one or more NanoVDB Grids.
Definition GridHandle.h:164
uint64_t freeSize() const
compute the size of unused storage in this buffer
Definition GridHandle.h:387
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:358
GridHandle & operator=(const GridHandle &)=delete
Disallow copy assignment operation.
GridHandle(BufferT &&buffer)
Move constructor from a host or single-space device buffer.
Definition GridHandle.h:230
uint64_t totalGridSize() const
compute the total sum of memory footprints of all the grids in this buffer
Definition GridHandle.h:378
BufferT & buffer()
Return a reference to the buffer.
Definition GridHandle.h:297
void write(std::ostream &os) const
Write the entire grid buffer to an output stream.
Definition GridHandle.h:425
GridHandle(const GridHandle &)=delete
Disallow copy-construction.
GridHandle & operator=(GridHandle &&other) noexcept
Move copy assignment operation.
Definition GridHandle.h:269
GridHandle(U &&)=delete
Reject anything other than a BufferT rvalue, e.g. a size or a different buffer type that would otherw...
uint64_t bufferSize() const
Returns the size in bytes of the raw memory buffer managed by this GridHandle.
Definition GridHandle.h:324
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:496
bool empty() const
Return true if this handle is empty, i.e. has no allocated memory.
Definition GridHandle.h:329
util::enable_if< BufferHasDeviceSingle< U >::value, void * >::type deviceData()
Definition GridHandle.h:319
const void * data() const
Definition GridHandle.h:309
const GridData * gridData(uint32_t n=0) const
Access to the GridData of the n'th grid in the current handle.
Definition GridHandle.h:527
const std::vector< GridHandleMetaData > & metaData() const
The layout of the grids in this handle's buffer: offset, size and grid type of each....
Definition GridHandle.h:222
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:316
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:580
const BufferT & buffer() const
Return a const reference to the buffer.
Definition GridHandle.h:300
GridHandle(GridHandle &&other) noexcept
Move copy-constructor.
Definition GridHandle.h:254
uint64_t gridSize(uint32_t n=0) const
Return the grid size of the n'th grid in this GridHandle.
Definition GridHandle.h:374
GridType gridType(uint32_t n=0) const
Return the GridType of the n'th grid in this GridHandle.
Definition GridHandle.h:396
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:484
void write(const std::string &fileName) const
Write this entire grid buffer to a file.
Definition GridHandle.h:434
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:366
static GridHandle adopt(BufferT &&buffer, std::vector< GridHandleMetaData > meta)
Constructs a handle over buffer from metadata the caller already knows to describe its contents,...
Definition GridHandle.h:213
NanoGrid< ValueT > * grid(uint32_t n=0)
Returns a host pointer to the n'th NanoVDB grid encoded in this GridHandle.
Definition GridHandle.h:350
const GridMetaData * gridMetaData(uint32_t n=0) const
Returns a const point to the n'th grid meta data.
Definition GridHandle.h:536
util::enable_if< BufferHasDeviceSingle< U >::value, NanoGrid< ValueT > * >::type deviceGrid(uint32_t n=0)
Definition GridHandle.h:361
BufferT BufferType
Definition GridHandle.h:199
GridHandle< OtherBufferT > copy() const
Deep copy without a pool argument. The single-space path allocates through the source buffer's resour...
Definition GridHandle.h:559
uint32_t gridCount() const
Return the total number of grids contained in this buffer.
Definition GridHandle.h:369
bool isEmpty() const
Definition GridHandle.h:330
void reset()
clear this GridHandle to an empty handle
Definition GridHandle.h:259
bool isFull() const
Test if this buffer has any unused storage left, i.e. memory not occupied by grids.
Definition GridHandle.h:391
void * data()
Returns a pointer to the host data; not available for a single-space device buffer,...
Definition GridHandle.h:307
void read(const std::string &fileName, const BufferT &pool=BufferT())
Read a raw grid buffer from a file.
Definition GridHandle.h:472
void write(const std::string &fileName, uint32_t n) const
Write a specific grid to file.
Definition GridHandle.h:443
void read(std::istream &is, const BufferT &pool=BufferT())
Read an entire raw grid buffer from an input stream.
Definition GridHandle.h:586
void write(std::ostream &os, uint32_t n) const
Write a specific grid in this buffer to an output stream.
Definition GridHandle.h:413
GridHandle< OtherBufferT > copy(const OtherBufferT &buffer) const
Performs a deep copy of the GridHandle, possibly templated on a different buffer type.
Definition GridHandle.h:545
GridHandle()=default
Constructs an empty GridHandle.
Definition VoxToNanoVDB.h:15
void validateGridLayout(const std::vector< GridHandleMetaData > &meta, uint64_t bytes)
Checks that meta describes grids laid out back to back from offset zero inside bytes of storage,...
Definition GridHandle.h:87
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:117
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:555
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:34
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:713
GridType toGridType()
Maps from a templated build type to a GridType enum.
Definition NanoVDB.h:848
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:4699
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:676
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:223
@ End
Definition NanoVDB.h:250
#define NANOVDB_ASSERT(x)
Definition Util.h:53
static constexpr bool value
Definition HostBuffer.h:146
static constexpr bool value
Definition HostBuffer.h:164
static constexpr bool value
Definition HostBuffer.h:111
static constexpr bool value
Definition HostBuffer.h:120
static constexpr bool value
Definition HostBuffer.h:137
static constexpr bool value
Definition HostBuffer.h:155
static constexpr bool value
Definition HostBuffer.h:131
Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
Definition NanoVDB.h:1952
GridType mGridType
Definition NanoVDB.h:1966
bool isValid() const
return true if the magic number and the version are both valid
Definition NanoVDB.h:2009
uint64_t mGridSize
Definition NanoVDB.h:1960
uint32_t mGridCount
Definition NanoVDB.h:1959
uint32_t mGridIndex
Definition NanoVDB.h:1958
static constexpr bool value
Definition GridHandle.h:155
Detects a BufferTraits specialization that still declares the hasDeviceDual member removed in NanoVDB...
Definition GridHandle.h:152
static constexpr bool value
Definition GridHandle.h:152
Wraps a byte-for-byte copy of a handle's buffer in a handle with that handle's layout....
Definition GridHandle.h:511
static GridHandle< DstBufferT > make(DstBufferT &&buffer, const GridHandle< SrcBufferT > &src)
Definition GridHandle.h:513
C++11 implementation of std::enable_if.
Definition Util.h:384
static constexpr bool value
Definition Util.h:359