OpenVDB 13.1.0
Loading...
Searching...
No Matches
NodeManager.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/NodeManager.h
6
7 \author Ken Museth
8
9 \date February 12, 2021
10
11 \brief This class allows for sequential access to nodes
12 in a NanoVDB tree on both the host and device.
13
14 \details The ordering of the sequential access to nodes is always breadth-first!
15*/
16
17#include <nanovdb/NanoVDB.h>// for NanoGrid etc
18#include <nanovdb/HostBuffer.h>// for HostBuffer
19
20#ifndef NANOVDB_NODEMANAGER_H_HAS_BEEN_INCLUDED
21#define NANOVDB_NODEMANAGER_H_HAS_BEEN_INCLUDED
22
23namespace nanovdb {
24
25/// @brief NodeManager allows for sequential access to nodes
26template <typename BuildT>
27class NodeManager;
28
29/// @brief NodeManagerHandle manages the memory of a NodeManager
30template<typename BufferT = HostBuffer>
31class NodeManagerHandle;
32
33/// @brief brief Construct a NodeManager and return its handle
34///
35/// @param grid grid whose nodes will be accessed sequentially
36/// @param buffer buffer from which to allocate the output handle
37///
38/// @note This is the only way to create a NodeManager since it's using
39/// managed memory pointed to by a NodeManagerHandle.
40template <typename BuildT, typename BufferT = HostBuffer>
41NodeManagerHandle<BufferT> createNodeManager(const NanoGrid<BuildT> &grid,
42 const BufferT& buffer = BufferT());
43
45{// 40B = 5*8B
46 __hostdev__ NodeManagerData(void *grid) : mPadding{0}, mGrid(grid), mPtr{0,0,0}{}
47 union {int64_t mPadding; uint8_t mLinear;};// 8B of which 1B is used for a binary flag
48 void *mGrid;// 8B pointer to either host or device grid
49 union {int64_t *mPtr[3], mOff[3];};// 24B, use mOff if mLinear!=0
50};
51
52/// @brief This class serves to manage a raw memory buffer of a NanoVDB NodeManager or LeafManager.
53template<typename BufferT>
55{
58 "NodeManagerHandle requires byte-addressed single-space storage, e.g. cuda::Buffer<std::byte, R>");
59
60 GridType mGridType{GridType::Unknown};
61 BufferT mBuffer;
62
63 template<typename BuildT, typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value, int>::type = 0>
64 const NodeManager<BuildT>* getMgr() const {
65 return mGridType == toGridType<BuildT>() ? (const NodeManager<BuildT>*)mBuffer.data() : nullptr;
66 }
67
68 template<typename BuildT, typename U = BufferT>
70 getDeviceMgr() const {
71 return mGridType == toGridType<BuildT>() ? (const NodeManager<BuildT>*)mBuffer.deviceData() : nullptr;
72 }
73
74 template <typename T>
75 static T* no_const(const T* ptr) { return const_cast<T*>(ptr); }
76
77public:
78 /// @brief Move constructor from a buffer
79 NodeManagerHandle(GridType gridType, BufferT&& buffer)
80 : mGridType(gridType)
81 , mBuffer(std::move(buffer)) {}// member-initialized, so a non-default-constructible buffer works
82 /// @brief Empty ctor
83 NodeManagerHandle() = default;
84 /// @brief Disallow copy-construction
86 /// @brief Disallow copy assignment operation
88 /// @brief Move copy assignment operation
90 mGridType = other.mGridType;
91 mBuffer = std::move(other.mBuffer);
92 other.mGridType = GridType::Unknown;
93 return *this;
94 }
95 /// @brief Move copy-constructor
97 : mGridType(other.mGridType)
98 , mBuffer(std::move(other.mBuffer))
99 {
100 other.mGridType = GridType::Unknown;
101 }
102 /// @brief Default destructor
104 /// @brief Release the buffer's storage
105 void reset() {
106 if constexpr (BufferHasDestroy<BufferT>::value) mBuffer.destroy();
107 else mBuffer.clear();
108 }
109
110 /// @brief Return a reference to the buffer
111 BufferT& buffer() { return mBuffer; }
112
113 /// @brief Return a const reference to the buffer
114 const BufferT& buffer() const { return mBuffer; }
115
116 //@{
117 /// @brief Returns a pointer to the host data; not available for a
118 /// single-space device buffer, which has no host-readable bytes.
119 /// @warning Note that the return pointer can be NULL if the NodeManagerHandle was not initialized
120 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value, int>::type = 0>
121 void* data() { return mBuffer.data(); }
122 template<typename U = BufferT, typename util::disable_if<BufferIsDeviceOnly<U>::value, int>::type = 0>
123 const void* data() const { return mBuffer.data(); }
124 //@}
125
126 /// @brief Returns the size in bytes of the raw memory buffer managed by this NodeManagerHandle's allocator.
127 uint64_t size() const { return mBuffer.size(); }
128
129 /// @brief Returns a const pointer to the NodeManager encoded in this NodeManagerHandle.
130 ///
131 /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid!
132 template<typename BuildT>
133 const NodeManager<BuildT>* mgr() const { return this->template getMgr<BuildT>(); }
134
135 /// @brief Returns a pointer to the NodeManager encoded in this NodeManagerHandle.
136 ///
137 /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid!
138 template<typename BuildT>
139 NodeManager<BuildT>* mgr() { return no_const(this->template getMgr<BuildT>()); }
140
141 /// @brief Return a const pointer to the NodeManager encoded in this NodeManagerHandle on the device, e.g. GPU
142 ///
143 /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid!
144 template<typename BuildT, typename U = BufferT>
146 deviceMgr() const { return this->template getDeviceMgr<BuildT>(); }
147
148 /// @brief Return a const pointer to the NodeManager encoded in this NodeManagerHandle on the device, e.g. GPU
149 ///
150 /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid!
151 template<typename BuildT, typename U = BufferT>
153 deviceMgr() { return no_const(this->template getDeviceMgr<BuildT>()); }
154
155 //@{
156 /// @brief Return a pointer to the NodeManager of a single-space device buffer
157 /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid!
158 template<typename BuildT, typename U = BufferT>
160 deviceMgr() const {
161 return mGridType == toGridType<BuildT>() ? (const NodeManager<BuildT>*)mBuffer.data() : nullptr;
162 }
163 template<typename BuildT, typename U = BufferT>
165 deviceMgr() { return no_const(static_cast<const NodeManagerHandle*>(this)->template deviceMgr<BuildT>()); }
166 //@}
167
168 /// @brief Upload the NodeManager to the device, e.g. from CPU to GPU
169 ///
170 /// @note This method is only available if the buffer supports devices
171 template<typename U = BufferT>
173 deviceUpload(void* deviceGrid, void* stream = nullptr, bool sync = true)
174 {
175 assert(deviceGrid);
176 auto *data = reinterpret_cast<NodeManagerData*>(mBuffer.data());
177 void *tmp = data->mGrid;
178 data->mGrid = deviceGrid;
179 mBuffer.deviceUpload(stream, sync);
180 data->mGrid = tmp;
181 }
182
183 /// @brief Download the NodeManager to from the device, e.g. from GPU to CPU
184 ///
185 /// @note This method is only available if the buffer supports devices
186 template<typename U = BufferT>
188 deviceDownload(void* stream = nullptr, bool sync = true)
189 {
190 auto *data = reinterpret_cast<NodeManagerData*>(mBuffer.data());
191 void *tmp = data->mGrid;
192 mBuffer.deviceDownload(stream, sync);
193 data->mGrid = tmp;
194 }
195};// NodeManagerHandle
196
197/// @brief This class allows for sequential access to nodes in a NanoVDB tree
198///
199/// @details Nodes are always arranged breadth first during sequential access of nodes
200/// at a particular level.
201template<typename BuildT>
203{
204 using DataT = NodeManagerData;
205 using GridT = NanoGrid<BuildT>;
206 using TreeT = typename GridTree<GridT>::type;
207 template<int LEVEL>
208 using NodeT = typename NodeTrait<TreeT, LEVEL>::type;
209 using RootT = NodeT<3>;// root node
210 using Node2 = NodeT<2>;// upper internal node
211 using Node1 = NodeT<1>;// lower internal node
212 using Node0 = NodeT<0>;// leaf node
213
214public:
215 static constexpr bool FIXED_SIZE = Node0::FIXED_SIZE && Node1::FIXED_SIZE && Node2::FIXED_SIZE;
216
217 NodeManager(const NodeManager&) = delete;
221 ~NodeManager() = delete;
222
223 /// @brief return true if the nodes have both fixed size and are arranged breadth-first in memory.
224 /// This allows for direct and memory-efficient linear access to nodes.
225 __hostdev__ static bool isLinear(const GridT &grid) {return FIXED_SIZE && grid.isBreadthFirst();}
226
227 /// @brief return true if the nodes have both fixed size and are arranged breadth-first in memory.
228 /// This allows for direct and memory-efficient linear access to nodes.
229 __hostdev__ bool isLinear() const {return DataT::mLinear!=0u;}
230
231 /// @brief Return the memory footprint in bytes of the NodeManager derived from the specified grid
232 __hostdev__ static uint64_t memUsage(const GridT &grid) {
233 uint64_t size = sizeof(NodeManagerData);
235 const uint32_t *p = grid.tree().mNodeCount;
236 size += sizeof(int64_t)*(p[0]+p[1]+p[2]);
237 }
238 return size;
239 }
240
241 /// @brief Return the memory footprint in bytes of this instance
242 __hostdev__ uint64_t memUsage() const {return NodeManager::memUsage(this->grid());}
243
244 /// @brief Return a reference to the grid
245 __hostdev__ GridT& grid() { return *reinterpret_cast<GridT*>(DataT::mGrid); }
246 __hostdev__ const GridT& grid() const { return *reinterpret_cast<const GridT*>(DataT::mGrid); }
247
248 /// @brief Return a reference to the tree
249 __hostdev__ TreeT& tree() { return this->grid().tree(); }
250 __hostdev__ const TreeT& tree() const { return this->grid().tree(); }
251
252 /// @brief Return a reference to the root
253 __hostdev__ RootT& root() { return this->tree().root(); }
254 __hostdev__ const RootT& root() const { return this->tree().root(); }
255
256 /// @brief Return the number of tree nodes at the specified level
257 /// @details 0 is leaf, 1 is lower internal, and 2 is upper internal level
258 __hostdev__ uint64_t nodeCount(int level) const { return this->tree().nodeCount(level); }
259
260 __hostdev__ uint64_t leafCount() const { return this->tree().nodeCount(0); }
261 __hostdev__ uint64_t lowerCount() const { return this->tree().nodeCount(1); }
262 __hostdev__ uint64_t upperCount() const { return this->tree().nodeCount(2); }
263
264 /// @brief Return the i'th leaf node with respect to breadth-first ordering
265 template <int LEVEL>
266 __hostdev__ const NodeT<LEVEL>& node(uint32_t i) const {
267 NANOVDB_ASSERT(i < this->nodeCount(LEVEL));
268 const NodeT<LEVEL>* ptr = nullptr;
269 if (DataT::mLinear) {
271 } else {
273 }
274 NANOVDB_ASSERT(ptr && isAligned(ptr));
275 return *ptr;
276 }
277
278 /// @brief Return the i'th node with respect to breadth-first ordering
279 template <int LEVEL>
280 __hostdev__ NodeT<LEVEL>& node(uint32_t i) {
281 NANOVDB_ASSERT(i < this->nodeCount(LEVEL));
282 NodeT<LEVEL>* ptr = nullptr;
283 if (DataT::mLinear) {
285 } else {
287 }
288 NANOVDB_ASSERT(ptr && isAligned(ptr));
289 return *ptr;
290 }
291
292 /// @brief Return the i'th leaf node with respect to breadth-first ordering
293 __hostdev__ const Node0& leaf(uint32_t i) const { return this->node<0>(i); }
294 __hostdev__ Node0& leaf(uint32_t i) { return this->node<0>(i); }
295
296 /// @brief Return the i'th lower internal node with respect to breadth-first ordering
297 __hostdev__ const Node1& lower(uint32_t i) const { return this->node<1>(i); }
298 __hostdev__ Node1& lower(uint32_t i) { return this->node<1>(i); }
299
300 /// @brief Return the i'th upper internal node with respect to breadth-first ordering
301 __hostdev__ const Node2& upper(uint32_t i) const { return this->node<2>(i); }
302 __hostdev__ Node2& upper(uint32_t i) { return this->node<2>(i); }
303
304}; // NodeManager<BuildT> class
305
306template <typename BuildT, typename BufferT>
308 const BufferT& buffer)
309{
310 NodeManagerHandle<BufferT> handle(toGridType<BuildT>(), BufferT::create(NodeManager<BuildT>::memUsage(grid), &buffer));
311 auto *data = reinterpret_cast<NodeManagerData*>(handle.data());
312 NANOVDB_ASSERT(data && isAligned(data));
314 *data = NodeManagerData((void*)&grid);
315
317 data->mLinear = uint8_t(1u);
318 data->mOff[0] = util::PtrDiff(grid.tree().template getFirstNode<0>(), &grid);
319 data->mOff[1] = util::PtrDiff(grid.tree().template getFirstNode<1>(), &grid);
320 data->mOff[2] = util::PtrDiff(grid.tree().template getFirstNode<2>(), &grid);
321 } else {
322 int64_t *ptr0 = data->mPtr[0] = reinterpret_cast<int64_t*>(data + 1);
323 int64_t *ptr1 = data->mPtr[1] = data->mPtr[0] + grid.tree().nodeCount(0);
324 int64_t *ptr2 = data->mPtr[2] = data->mPtr[1] + grid.tree().nodeCount(1);
325 // Performs depth first traversal but breadth first insertion
326 for (auto it2 = grid.tree().root().cbeginChild(); it2; ++it2) {
327 *ptr2++ = util::PtrDiff(&*it2, &grid);
328 for (auto it1 = it2->cbeginChild(); it1; ++it1) {
329 *ptr1++ = util::PtrDiff(&*it1, &grid);
330 for (auto it0 = it1->cbeginChild(); it0; ++it0) {
331 *ptr0++ = util::PtrDiff(&*it0, &grid);
332 }// loop over child nodes of the lower internal node
333 }// loop over child nodes of the upper internal node
334 }// loop over child nodes of the root node
335 }
336
337 return handle;// // is converted to r-value so return value is move constructed!
338}// createNodeManager
339
340} // namespace nanovdb
341
342#if defined(__CUDACC__)
343#include <nanovdb/cuda/NodeManager.cuh>
344#endif// defined(__CUDACC__)
345
346#endif // NANOVDB_NODEMANAGER_H_HAS_BEEN_INCLUDED
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,...
const GridType & gridType() const
Definition NanoVDB.h:2310
const TreeT & tree() const
Return a const reference to the tree.
Definition NanoVDB.h:2236
NodeManagerHandle manages the memory of a NodeManager.
Definition NodeManager.h:55
NodeManagerHandle & operator=(const NodeManagerHandle &)=delete
Disallow copy assignment operation.
BufferT & buffer()
Return a reference to the buffer.
Definition NodeManager.h:111
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceDownload(void *stream=nullptr, bool sync=true)
Download the NodeManager to from the device, e.g. from GPU to CPU.
Definition NodeManager.h:188
NodeManagerHandle & operator=(NodeManagerHandle &&other) noexcept
Move copy assignment operation.
Definition NodeManager.h:89
util::enable_if< BufferTraits< U >::hasDeviceDual, constNodeManager< BuildT > * >::type deviceMgr() const
Return a const pointer to the NodeManager encoded in this NodeManagerHandle on the device,...
Definition NodeManager.h:146
const void * data() const
Definition NodeManager.h:123
util::enable_if< BufferTraits< U >::hasDeviceDual, NodeManager< BuildT > * >::type deviceMgr()
Return a const pointer to the NodeManager encoded in this NodeManagerHandle on the device,...
Definition NodeManager.h:153
uint64_t size() const
Returns the size in bytes of the raw memory buffer managed by this NodeManagerHandle's allocator.
Definition NodeManager.h:127
util::enable_if< BufferHasDeviceSingle< U >::value, NodeManager< BuildT > * >::type deviceMgr()
Definition NodeManager.h:165
const BufferT & buffer() const
Return a const reference to the buffer.
Definition NodeManager.h:114
util::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceUpload(void *deviceGrid, void *stream=nullptr, bool sync=true)
Upload the NodeManager to the device, e.g. from CPU to GPU.
Definition NodeManager.h:173
NodeManager< BuildT > * mgr()
Returns a pointer to the NodeManager encoded in this NodeManagerHandle.
Definition NodeManager.h:139
const NodeManager< BuildT > * mgr() const
Returns a const pointer to the NodeManager encoded in this NodeManagerHandle.
Definition NodeManager.h:133
NodeManagerHandle()=default
Empty ctor.
NodeManagerHandle(const NodeManagerHandle &)=delete
Disallow copy-construction.
void reset()
Release the buffer's storage.
Definition NodeManager.h:105
void * data()
Returns a pointer to the host data; not available for a single-space device buffer,...
Definition NodeManager.h:121
util::enable_if< BufferHasDeviceSingle< U >::value, constNodeManager< BuildT > * >::type deviceMgr() const
Return a pointer to the NodeManager of a single-space device buffer.
Definition NodeManager.h:160
NodeManagerHandle(NodeManagerHandle &&other) noexcept
Move copy-constructor.
Definition NodeManager.h:96
~NodeManagerHandle()
Default destructor.
Definition NodeManager.h:103
NodeManagerHandle(GridType gridType, BufferT &&buffer)
Move constructor from a buffer.
Definition NodeManager.h:79
NodeManager allows for sequential access to nodes.
Definition NodeManager.h:203
NodeManager & operator=(const NodeManager &)=delete
__hostdev__ uint64_t lowerCount() const
Definition NodeManager.h:261
NodeManager & operator=(NodeManager &&)=delete
__hostdev__ uint64_t leafCount() const
Definition NodeManager.h:260
static constexpr bool FIXED_SIZE
Definition NodeManager.h:215
__hostdev__ const TreeT & tree() const
Definition NodeManager.h:250
__hostdev__ Node2 & upper(uint32_t i)
Definition NodeManager.h:302
__hostdev__ GridT & grid()
Return a reference to the grid.
Definition NodeManager.h:245
__hostdev__ const GridT & grid() const
Definition NodeManager.h:246
__hostdev__ RootT & root()
Return a reference to the root.
Definition NodeManager.h:253
NodeManager(const NodeManager &)=delete
NodeManager(NodeManager &&)=delete
__hostdev__ const NodeT< LEVEL > & node(uint32_t i) const
Return the i'th leaf node with respect to breadth-first ordering.
Definition NodeManager.h:266
static __hostdev__ bool isLinear(const GridT &grid)
return true if the nodes have both fixed size and are arranged breadth-first in memory....
Definition NodeManager.h:225
__hostdev__ uint64_t upperCount() const
Definition NodeManager.h:262
__hostdev__ uint64_t nodeCount(int level) const
Return the number of tree nodes at the specified level.
Definition NodeManager.h:258
__hostdev__ Node0 & leaf(uint32_t i)
Definition NodeManager.h:294
__hostdev__ NodeT< LEVEL > & node(uint32_t i)
Return the i'th node with respect to breadth-first ordering.
Definition NodeManager.h:280
__hostdev__ const Node0 & leaf(uint32_t i) const
Return the i'th leaf node with respect to breadth-first ordering.
Definition NodeManager.h:293
__hostdev__ uint64_t memUsage() const
Return the memory footprint in bytes of this instance.
Definition NodeManager.h:242
static __hostdev__ uint64_t memUsage(const GridT &grid)
Return the memory footprint in bytes of the NodeManager derived from the specified grid.
Definition NodeManager.h:232
__hostdev__ bool isLinear() const
return true if the nodes have both fixed size and are arranged breadth-first in memory....
Definition NodeManager.h:229
__hostdev__ Node1 & lower(uint32_t i)
Definition NodeManager.h:298
__hostdev__ const Node2 & upper(uint32_t i) const
Return the i'th upper internal node with respect to breadth-first ordering.
Definition NodeManager.h:301
__hostdev__ const Node1 & lower(uint32_t i) const
Return the i'th lower internal node with respect to breadth-first ordering.
Definition NodeManager.h:297
__hostdev__ const RootT & root() const
Definition NodeManager.h:254
__hostdev__ TreeT & tree()
Return a reference to the tree.
Definition NodeManager.h:249
#define __hostdev__
Definition SampleFromVoxels.h:29
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
static int64_t PtrDiff(const void *p, const void *q)
Compute the distance, in bytes, between two pointers, dist = p - q.
Definition Util.h:510
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:31
GridType toGridType()
Maps from a templated build type to a GridType enum.
Definition NanoVDB.h:851
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:4742
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:219
@ Unknown
Definition NanoVDB.h:219
static bool isAligned(const void *p)
return true if the specified pointer is 32 byte aligned
Definition NanoVDB.h:600
NodeManagerHandle< BufferT > createNodeManager(const NanoGrid< BuildT > &grid, const BufferT &buffer=BufferT())
brief Construct a NodeManager and return its handle
Definition NodeManager.h:307
Definition Coord.h:590
#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
typename GridT::TreeType type
Definition NanoVDB.h:2464
Definition NodeManager.h:45
__hostdev__ NodeManagerData(void *grid)
Definition NodeManager.h:46
int64_t * mPtr[3]
Definition NodeManager.h:49
int64_t mOff[3]
Definition NodeManager.h:49
void * mGrid
Definition NodeManager.h:48
uint8_t mLinear
Definition NodeManager.h:47
int64_t mPadding
Definition NodeManager.h:47
Struct to derive node type from its level in a given grid, tree or root while preserving constness.
Definition NanoVDB.h:1723
C++11 implementation of std::enable_if.
Definition Util.h:353