Blender V4.5
nanovdb.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020-2021 Contributors to the OpenVDB Project
2 * SPDX-FileCopyrightText: 2023-2025 Blender Authors
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * This is an extract from NanoVDB.h, with minimal code needed for kernel side access to grids. The
7 * original headers are not compatible with Metal due to missing address space qualifiers. */
8
9#pragma once
10
11#include "util/defines.h"
12#include "util/types_base.h"
13
14#ifndef __KERNEL_GPU__
15# include <climits>
16#endif
17
19
20#define NANOVDB_USE_SINGLE_ROOT_KEY
21#define NANOVDB_DATA_ALIGNMENT 32 // NOLINT
22
23namespace nanovdb {
24
25/* Utilities */
26
27template<typename DstT, typename SrcT>
28const ccl_device ccl_global DstT *PtrAdd(const ccl_global SrcT *p, int64_t offset)
29{
30 return reinterpret_cast<const ccl_global DstT *>(reinterpret_cast<const ccl_global char *>(p) +
31 offset);
32}
33
34/* Coord */
35
36struct Coord {
37 int x, y, z;
38
39 ccl_device_inline_method explicit Coord(int32_t n) : x(n), y(n), z(n) {}
41
43 {
44 return Coord(x & n, y & n, z & n);
45 }
46};
47
48/* Mask */
49
50template<uint32_t LOG2DIM> struct Mask {
51 ccl_static_constexpr uint32_t SIZE = 1U << (3 * LOG2DIM);
54
55 ccl_device_inline_method bool isOff(const uint32_t n) const ccl_global
56 {
57 return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63)));
58 }
59};
60
61/* Grid */
62
63template<typename TreeT> struct alignas(NANOVDB_DATA_ALIGNMENT) Grid {
67 uint32_t mVersion;
68 uint32_t mFlags;
69 uint32_t mGridIndex;
70 uint32_t mGridCount;
73 uint8_t mMap[264];
74 uint8_t mWorldBBox[48]; // double[6], but no doubles in Metal
75 uint8_t mVoxelSize[24]; // double[3], but no doubles in Metal
76 uint32_t mGridClass;
77 uint32_t mGridType;
78 uint32_t mData0;
80
81 using BuildType = typename TreeT::BuildType;
82
84 {
85 return *reinterpret_cast<const ccl_global TreeT *>(this + 1);
86 }
87};
88
89/* Tree */
90
91template<typename RootT> struct alignas(NANOVDB_DATA_ALIGNMENT) Tree {
93 uint32_t mNodeCount[3];
94 uint32_t mTileCount[3];
96
97 using ValueType = typename RootT::ValueType;
98 using BuildType = typename RootT::BuildType;
99
101 {
102 return *reinterpret_cast<const ccl_global RootT *>(
103 mNodeOffset[3] ? PtrAdd<uint8_t>(this, mNodeOffset[3]) : nullptr);
104 }
105};
106
107/* RootNode */
108
109template<typename ChildT> struct alignas(NANOVDB_DATA_ALIGNMENT) RootNode {
110 using ValueType = typename ChildT::ValueType;
111 using BuildType = typename ChildT::BuildType;
112
113#ifdef NANOVDB_USE_SINGLE_ROOT_KEY
114 using KeyT = uint64_t;
116 {
117 return (uint64_t(uint32_t(ijk.z) >> ChildT::TOTAL)) |
118 (uint64_t(uint32_t(ijk.y) >> ChildT::TOTAL) << 21) |
119 (uint64_t(uint32_t(ijk.x) >> ChildT::TOTAL) << 42);
120 }
121#else
122 using KeyT = Coord;
123 static ccl_device_inline_method Coord CoordToKey(const CoordT ijk)
124 {
125 return ijk & ~ChildT::MASK;
126 }
127#endif
129 uint32_t mTableSize;
130
134 float mAverage;
135 float mStdDevi;
136
137 struct alignas(NANOVDB_DATA_ALIGNMENT) Tile {
140 uint32_t state;
142 };
143
145 {
146 const auto key = CoordToKey(ijk);
147 const ccl_global Tile *p = reinterpret_cast<const ccl_global Tile *>(this + 1);
148 const ccl_global Tile *q = p + mTableSize;
149 for (; p < q; ++p) {
150 if (p->key == key) {
151 return p;
152 }
153 }
154 return nullptr;
155 }
156
159 {
160 return PtrAdd<ChildT>(this, tile->child);
161 }
162
163 ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
164};
165
166/* InternalNode */
167
168template<typename ChildT, const uint32_t Log2Dim = ChildT::LOG2DIM + 1>
169struct alignas(NANOVDB_DATA_ALIGNMENT) InternalNode {
170 using ValueType = typename ChildT::ValueType;
171 using BuildType = typename ChildT::BuildType;
172
177
182
185 float mAverage;
186 float mStdDevi;
187
188 alignas(32) Tile mTable[1u << (3 * Log2Dim)];
189
190 const ccl_device_inline_method ccl_global ChildT *getChild(const uint32_t n) const ccl_global
191 {
192 return PtrAdd<ChildT>(this, mTable[n].child);
193 }
194
195 ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
196 ccl_static_constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL;
198 ccl_static_constexpr uint32_t SIZE = 1u << (3 * LOG2DIM);
199 ccl_static_constexpr uint32_t MASK = (1u << TOTAL) - 1u;
200 ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
201
203 {
204 return (((ijk.x & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) |
205 (((ijk.y & MASK) >> ChildT::TOTAL) << (LOG2DIM)) | ((ijk.z & MASK) >> ChildT::TOTAL);
206 }
207};
208
209/* LeafData */
210
211template<typename ValueT, const uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData {
212 using ValueType = ValueT;
213 using BuildType = ValueT;
214
216 uint8_t mBBoxDif[3];
217 uint8_t mFlags;
219
222 float mAverage;
223 float mStdDevi;
224 alignas(32) ValueType mValues[1u << 3 * LOG2DIM];
225
227 {
228 return mValues[i];
229 }
230};
231
232/* LeafFnBase */
233
234template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafFnBase {
236 uint8_t mBBoxDif[3];
237 uint8_t mFlags;
239
240 float mMinimum;
241 float mQuantum;
242 uint16_t mMin, mMax, mAvg, mDev;
243};
244
245/* LeafData<Fp16> */
246
247class Fp16 {};
248
249template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<Fp16, LOG2DIM> {
250 using ValueType = float;
252
254 alignas(32) uint16_t mCode[1u << 3 * LOG2DIM];
255
256 ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
257 {
258 return mCode[i] * base.mQuantum + base.mMinimum;
259 }
260};
261
262/* LeafData<FpN> */
263
264class FpN {};
265
266template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<FpN, LOG2DIM> {
267 using ValueType = float;
268 using BuildType = FpN;
269
271
272 ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
273 {
274 const int b = base.mFlags >> 5;
275 uint32_t code = reinterpret_cast<const ccl_global uint32_t *>(this + 1)[i >> (5 - b)];
276 code >>= (i & ((32 >> b) - 1)) << b;
277 code &= (1 << (1 << b)) - 1;
278 return float(code) * base.mQuantum + base.mMinimum;
279 }
280};
281
282/* LeafNode */
283
284template<typename BuildT, const uint32_t Log2Dim = 3>
285struct alignas(NANOVDB_DATA_ALIGNMENT) LeafNode {
289
291
292 ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
295 ccl_static_constexpr uint32_t SIZE = 1u << 3 * LOG2DIM;
296 ccl_static_constexpr uint32_t MASK = (1u << LOG2DIM) - 1u;
298
300 {
301 return ((ijk.x & MASK) << (2 * LOG2DIM)) | ((ijk.y & MASK) << LOG2DIM) | (ijk.z & MASK);
302 }
303
305 {
306 return data.getValue(offset);
307 }
308
310 {
311 return getValue(CoordToOffset(ijk));
312 }
313};
314
315/* Template Specializations */
316
317template<typename BuildT> using NanoLeaf = LeafNode<BuildT, 3>;
318template<typename BuildT> using NanoLower = InternalNode<NanoLeaf<BuildT>, 4>;
319template<typename BuildT> using NanoUpper = InternalNode<NanoLower<BuildT>, 5>;
320template<typename BuildT> using NanoRoot = RootNode<NanoUpper<BuildT>>;
321template<typename BuildT> using NanoTree = Tree<NanoRoot<BuildT>>;
322template<typename BuildT> using NanoGrid = Grid<NanoTree<BuildT>>;
323
324/* ReadAccessor */
325
326template<typename BuildT> class ReadAccessor {
327 using RootT = NanoRoot<BuildT>;
328 using LeafT = NanoLeaf<BuildT>;
329
330 mutable const ccl_global RootT *mRoot;
331
332 public:
333 using ValueType = typename RootT::ValueType;
334
335 ccl_device_inline_method ReadAccessor(const ccl_global RootT &root) : mRoot(&root) {}
336
338 {
339 const ccl_global auto *tile = mRoot->probeTile(ijk);
340 if (tile == nullptr) {
341 return mRoot->mBackground;
342 }
343 if (tile->child == 0) {
344 return tile->value;
345 }
346
347 const ccl_global auto *upper = mRoot->getChild(tile);
348 const uint32_t upper_n = upper->CoordToOffset(ijk);
349 if (upper->mChildMask.isOff(upper_n)) {
350 return upper->mTable[upper_n].value;
351 }
352
353 const ccl_global auto *lower = upper->getChild(upper_n);
354 const uint32_t lower_n = lower->CoordToOffset(ijk);
355 if (lower->mChildMask.isOff(lower_n)) {
356 return lower->mTable[lower_n].value;
357 }
358
359 const ccl_global LeafT *leaf = lower->getChild(lower_n);
360 return leaf->getValue(ijk);
361 }
362};
363
364template<typename BuildT> class CachedReadAccessor {
365 using RootT = NanoRoot<BuildT>;
366 using UpperT = NanoUpper<BuildT>;
367 using LowerT = NanoLower<BuildT>;
368 using LeafT = NanoLeaf<BuildT>;
369
370 mutable Coord mKeys[3] = {Coord(INT_MAX), Coord(INT_MAX), Coord(INT_MAX)};
371 mutable const ccl_global RootT *mRoot = nullptr;
372 mutable const ccl_global void *mNode[3] = {nullptr, nullptr, nullptr};
373
374 public:
375 using ValueType = typename RootT::ValueType;
376
377 ccl_device_inline_method CachedReadAccessor(const ccl_global RootT &root) : mRoot(&root) {}
378
379 template<typename NodeT> ccl_device_inline_method bool isCached(const Coord ijk) const
380 {
381 return (ijk.x & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].x &&
382 (ijk.y & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].y &&
383 (ijk.z & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].z;
384 }
385
387 const Coord ijk) const
388 {
389 if (const ccl_global auto *tile = node.probeTile(ijk)) {
390 if (tile->child != 0) {
391 const ccl_global auto *child = node.getChild(tile);
392 insert(ijk, child);
393 return getValueAndCache(*child, ijk);
394 }
395 return tile->value;
396 }
397 return node.mBackground;
398 }
399
401 const Coord ijk) const
402 {
403 return node.getValue(ijk);
404 }
405
406 template<typename NodeT>
408 const Coord ijk) const
409 {
410 const uint32_t n = node.CoordToOffset(ijk);
411 if (node.mChildMask.isOff(n)) {
412 return node.mTable[n].value;
413 }
414 const ccl_global auto *child = node.getChild(n);
415 insert(ijk, child);
416 return getValueAndCache(*child, ijk);
417 }
418
420 {
421 if (isCached<LeafT>(ijk)) {
422 return getValueAndCache(*((const ccl_global LeafT *)mNode[0]), ijk);
423 }
424 if (isCached<LowerT>(ijk)) {
425 return getValueAndCache(*((const ccl_global LowerT *)mNode[1]), ijk);
426 }
427 if (isCached<UpperT>(ijk)) {
428 return getValueAndCache(*((const ccl_global UpperT *)mNode[2]), ijk);
429 }
430 return getValueAndCache(*mRoot, ijk);
431 }
432
433 template<typename NodeT>
434 ccl_device_inline_method void insert(const Coord ijk, const ccl_global NodeT *node) const
435 {
436 mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
437 mNode[NodeT::LEVEL] = node;
438 }
439};
440
441} // namespace nanovdb
442
void BLI_kdtree_nd_ insert(KDTree *tree, int index, const float co[KD_DIMS]) ATTR_NONNULL(1
#define MASK
long long int int64_t
unsigned long long int uint64_t
typename RootT::ValueType ValueType
Definition nanovdb.h:375
ccl_device_inline_method ValueType getValueAndCache(const ccl_global RootT &node, const Coord ijk) const
Definition nanovdb.h:386
ccl_device_inline_method ValueType getValueAndCache(const ccl_global LeafT &node, const Coord ijk) const
Definition nanovdb.h:400
ccl_device_inline_method CachedReadAccessor(const ccl_global RootT &root)
Definition nanovdb.h:377
ccl_device_inline_method bool isCached(const Coord ijk) const
Definition nanovdb.h:379
ccl_device_inline_method void insert(const Coord ijk, const ccl_global NodeT *node) const
Definition nanovdb.h:434
ccl_device_inline_method ValueType getValue(const Coord ijk) const
Definition nanovdb.h:419
ccl_device_inline_method ValueType getValueAndCache(const ccl_global NodeT &node, const Coord ijk) const
Definition nanovdb.h:407
typename RootT::ValueType ValueType
Definition nanovdb.h:333
ccl_device_inline_method ValueType getValue(const Coord ijk) const
Definition nanovdb.h:337
ccl_device_inline_method ReadAccessor(const ccl_global RootT &root)
Definition nanovdb.h:335
#define ccl_device
#define ccl_global
#define ccl_static_constexpr
#define ccl_device_inline_method
#define CCL_NAMESPACE_END
const ccl_global KernelWorkTile * tile
const ccl_device ccl_global DstT * PtrAdd(const ccl_global SrcT *p, int64_t offset)
Definition nanovdb.h:28
LeafNode< BuildT, 3 > NanoLeaf
Definition nanovdb.h:317
InternalNode< NanoLeaf< BuildT >, 4 > NanoLower
Definition nanovdb.h:318
InternalNode< NanoLower< BuildT >, 5 > NanoUpper
Definition nanovdb.h:319
Grid< NanoTree< BuildT > > NanoGrid
Definition nanovdb.h:322
RootNode< NanoUpper< BuildT > > NanoRoot
Definition nanovdb.h:320
Tree< NanoRoot< BuildT > > NanoTree
Definition nanovdb.h:321
ccl_device_inline_method Coord operator&(int32_t n) const
Definition nanovdb.h:42
ccl_device_inline_method Coord(int32_t x, int32_t y, int32_t z)
Definition nanovdb.h:40
ccl_device_inline_method Coord(int32_t n)
Definition nanovdb.h:39
const ccl_device_inline_method ccl_global TreeT & tree() const ccl_global
Definition nanovdb.h:83
typename TreeT::BuildType BuildType
Definition nanovdb.h:81
ccl_static_constexpr int MaxNameSize
Definition nanovdb.h:64
const ccl_device_inline_method ccl_global NanoLeaf< BuildT > * getChild(const uint32_t n) const ccl_global
Definition nanovdb.h:190
typename ChildT::ValueType ValueType
Definition nanovdb.h:170
static ccl_device_inline_method uint32_t CoordToOffset(const Coord ijk)
Definition nanovdb.h:202
typename ChildT::BuildType BuildType
Definition nanovdb.h:171
ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
Definition nanovdb.h:256
LeafFnBase< LOG2DIM > base
Definition nanovdb.h:253
uint16_t mCode[1u<< 3 *LOG2DIM]
Definition nanovdb.h:254
ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
Definition nanovdb.h:272
LeafFnBase< LOG2DIM > base
Definition nanovdb.h:270
ValueType mValues[1u<< 3 *LOG2DIM]
Definition nanovdb.h:224
ccl_device_inline_method ValueType getValue(const uint32_t i) const ccl_global
Definition nanovdb.h:226
Mask< LOG2DIM > mValueMask
Definition nanovdb.h:238
uint8_t mBBoxDif[3]
Definition nanovdb.h:236
ccl_static_constexpr uint32_t DIM
Definition nanovdb.h:294
ccl_static_constexpr uint32_t LOG2DIM
Definition nanovdb.h:292
ccl_static_constexpr uint32_t TOTAL
Definition nanovdb.h:293
typename DataType::BuildType BuildType
Definition nanovdb.h:288
ccl_static_constexpr uint32_t MASK
Definition nanovdb.h:296
LeafData< BuildT, Log2Dim > DataType
Definition nanovdb.h:286
ccl_static_constexpr uint32_t SIZE
Definition nanovdb.h:295
typename DataType::ValueType ValueType
Definition nanovdb.h:287
ccl_static_constexpr uint32_t LEVEL
Definition nanovdb.h:297
static ccl_device_inline_method uint32_t CoordToOffset(const Coord ijk)
Definition nanovdb.h:299
ccl_device_inline_method ValueType getValue(const Coord ijk) const ccl_global
Definition nanovdb.h:309
ccl_device_inline_method ValueType getValue(const uint32_t offset) const ccl_global
Definition nanovdb.h:304
ccl_device_inline_method bool isOff(const uint32_t n) const ccl_global
Definition nanovdb.h:55
ccl_static_constexpr uint32_t SIZE
Definition nanovdb.h:51
ccl_static_constexpr uint32_t WORD_COUNT
Definition nanovdb.h:52
uint64_t mWords[WORD_COUNT]
Definition nanovdb.h:53
static ccl_device_inline_method uint64_t CoordToKey(const Coord ijk)
Definition nanovdb.h:115
typename ChildT::ValueType ValueType
Definition nanovdb.h:110
typename ChildT::BuildType BuildType
Definition nanovdb.h:111
const ccl_device_inline_method ccl_global NanoUpper< BuildT > * getChild(const ccl_global Tile *tile) const ccl_global
Definition nanovdb.h:157
const ccl_device_inline_method ccl_global Tile * probeTile(const Coord ijk) const ccl_global
Definition nanovdb.h:144
uint64_t KeyT
Definition nanovdb.h:114
const ccl_device_inline_method ccl_global RootT & root() const ccl_global
Definition nanovdb.h:100
typename RootT::ValueType ValueType
Definition nanovdb.h:97
typename RootT::BuildType BuildType
Definition nanovdb.h:98
i
Definition text_draw.cc:230