Blender V5.0
kernel/util/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/math_int3.h"
13#include "util/types_base.h"
14#include "util/types_int3.h"
15
16#ifndef __KERNEL_GPU__
17# include <climits>
18#endif
19
21
22#define NANOVDB_USE_SINGLE_ROOT_KEY
23#define NANOVDB_DATA_ALIGNMENT 32 // NOLINT
24
25namespace nanovdb {
26
27/* Utilities */
28
29template<typename DstT, typename SrcT>
30const ccl_device ccl_global DstT *PtrAdd(const ccl_global SrcT *p, int64_t offset)
31{
32 return reinterpret_cast<const ccl_global DstT *>(reinterpret_cast<const ccl_global char *>(p) +
33 offset);
34}
35
36/* Coord */
37
38using Coord = int3;
40
41/* Mask */
42
43template<uint32_t LOG2DIM> struct Mask {
44 ccl_static_constexpr uint32_t SIZE = 1U << (3 * LOG2DIM);
47
48 ccl_device_inline_method bool isOff(const uint32_t n) const ccl_global
49 {
50 return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63)));
51 }
52};
53
54/* Grid */
55
56template<typename TreeT> struct alignas(NANOVDB_DATA_ALIGNMENT) Grid {
60 uint32_t mVersion;
61 uint32_t mFlags;
62 uint32_t mGridIndex;
63 uint32_t mGridCount;
66 uint8_t mMap[264];
67 uint8_t mWorldBBox[48]; // double[6], but no doubles in Metal
68 uint8_t mVoxelSize[24]; // double[3], but no doubles in Metal
69 uint32_t mGridClass;
70 uint32_t mGridType;
71 uint32_t mData0;
73
74 using BuildType = typename TreeT::BuildType;
75
77 {
78 return *reinterpret_cast<const ccl_global TreeT *>(this + 1);
79 }
80};
81
82/* Tree */
83
84template<typename RootT> struct alignas(NANOVDB_DATA_ALIGNMENT) Tree {
86 uint32_t mNodeCount[3];
87 uint32_t mTileCount[3];
89
90 using ValueType = typename RootT::ValueType;
91 using BuildType = typename RootT::BuildType;
92
94 {
95 return *reinterpret_cast<const ccl_global RootT *>(
96 mNodeOffset[3] ? PtrAdd<uint8_t>(this, mNodeOffset[3]) : nullptr);
97 }
98};
99
100/* RootNode */
101
102template<typename ChildT> struct alignas(NANOVDB_DATA_ALIGNMENT) RootNode {
103 using ValueType = typename ChildT::ValueType;
104 using BuildType = typename ChildT::BuildType;
105
106#ifdef NANOVDB_USE_SINGLE_ROOT_KEY
107 using KeyT = uint64_t;
109 {
110 return (uint64_t(uint32_t(ijk.z) >> ChildT::TOTAL)) |
111 (uint64_t(uint32_t(ijk.y) >> ChildT::TOTAL) << 21) |
112 (uint64_t(uint32_t(ijk.x) >> ChildT::TOTAL) << 42);
113 }
114#else
115 using KeyT = Coord;
116 static ccl_device_inline_method Coord CoordToKey(const CoordT ijk)
117 {
118 return ijk & ~ChildT::MASK;
119 }
120#endif
122 uint32_t mTableSize;
123
127 float mAverage;
128 float mStdDevi;
129
130 struct alignas(NANOVDB_DATA_ALIGNMENT) Tile {
133 uint32_t state;
135 };
136
138 {
139 const auto key = CoordToKey(ijk);
140 const ccl_global Tile *p = reinterpret_cast<const ccl_global Tile *>(this + 1);
141 const ccl_global Tile *q = p + mTableSize;
142 for (; p < q; ++p) {
143 if (p->key == key) {
144 return p;
145 }
146 }
147 return nullptr;
148 }
149
152 {
153 return PtrAdd<ChildT>(this, tile->child);
154 }
155
156 ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
157};
158
159/* InternalNode */
160
161template<typename ChildT, const uint32_t Log2Dim = ChildT::LOG2DIM + 1>
162struct alignas(NANOVDB_DATA_ALIGNMENT) InternalNode {
163 using ValueType = typename ChildT::ValueType;
164 using BuildType = typename ChildT::BuildType;
165
170
175
178 float mAverage;
179 float mStdDevi;
180
181 alignas(32) Tile mTable[1u << (3 * Log2Dim)];
182
183 const ccl_device_inline_method ccl_global ChildT *getChild(const uint32_t n) const ccl_global
184 {
185 return PtrAdd<ChildT>(this, mTable[n].child);
186 }
187
188 ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
189 ccl_static_constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL;
191 ccl_static_constexpr uint32_t SIZE = 1u << (3 * LOG2DIM);
192 ccl_static_constexpr uint32_t MASK = (1u << TOTAL) - 1u;
193 ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
194
196 {
197 return (((ijk.x & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) |
198 (((ijk.y & MASK) >> ChildT::TOTAL) << (LOG2DIM)) | ((ijk.z & MASK) >> ChildT::TOTAL);
199 }
200};
201
202/* LeafData */
203
204template<typename ValueT, const uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData {
205 using ValueType = ValueT;
206 using BuildType = ValueT;
207
209 uint8_t mBBoxDif[3];
210 uint8_t mFlags;
212
215 float mAverage;
216 float mStdDevi;
217 alignas(32) ValueType mValues[1u << 3 * LOG2DIM];
218
220 {
221 return mValues[i];
222 }
223};
224
225/* LeafFnBase */
226
227template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafFnBase {
229 uint8_t mBBoxDif[3];
230 uint8_t mFlags;
232
233 float mMinimum;
234 float mQuantum;
235 uint16_t mMin, mMax, mAvg, mDev;
236};
237
238/* LeafData<Fp16> */
239
240class Fp16 {};
241
242template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<Fp16, LOG2DIM> {
245
247 alignas(32) uint16_t mCode[1u << 3 * LOG2DIM];
248
249 ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
250 {
251 return mCode[i] * base.mQuantum + base.mMinimum;
252 }
253};
254
255/* LeafData<FpN> */
256
257class FpN {};
258
259template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<FpN, LOG2DIM> {
261 using BuildType = FpN;
262
264
265 ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
266 {
267 const int b = base.mFlags >> 5;
268 uint32_t code = reinterpret_cast<const ccl_global uint32_t *>(this + 1)[i >> (5 - b)];
269 code >>= (i & ((32 >> b) - 1)) << b;
270 code &= (1 << (1 << b)) - 1;
271 return float(code) * base.mQuantum + base.mMinimum;
272 }
273};
274
275/* LeafNode */
276
277template<typename BuildT, const uint32_t Log2Dim = 3>
278struct alignas(NANOVDB_DATA_ALIGNMENT) LeafNode {
282
284
285 ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
288 ccl_static_constexpr uint32_t SIZE = 1u << 3 * LOG2DIM;
289 ccl_static_constexpr uint32_t MASK = (1u << LOG2DIM) - 1u;
291
293 {
294 return ((ijk.x & MASK) << (2 * LOG2DIM)) | ((ijk.y & MASK) << LOG2DIM) | (ijk.z & MASK);
295 }
296
298 {
299 return data.getValue(offset);
300 }
301
303 {
304 return getValue(CoordToOffset(ijk));
305 }
306};
307
308/* Template Specializations */
309
310template<typename BuildT> using NanoLeaf = LeafNode<BuildT, 3>;
311template<typename BuildT> using NanoLower = InternalNode<NanoLeaf<BuildT>, 4>;
312template<typename BuildT> using NanoUpper = InternalNode<NanoLower<BuildT>, 5>;
313template<typename BuildT> using NanoRoot = RootNode<NanoUpper<BuildT>>;
314template<typename BuildT> using NanoTree = Tree<NanoRoot<BuildT>>;
315template<typename BuildT> using NanoGrid = Grid<NanoTree<BuildT>>;
316
317/* ReadAccessor */
318
319template<typename BuildT> class ReadAccessor {
320 using RootT = NanoRoot<BuildT>;
321 using LeafT = NanoLeaf<BuildT>;
322
323 mutable const ccl_global RootT *mRoot;
324
325 public:
326 using ValueType = typename RootT::ValueType;
327
328 ccl_device_inline_method ReadAccessor(const ccl_global RootT &root) : mRoot(&root) {}
329
331 {
332 const ccl_global auto *tile = mRoot->probeTile(ijk);
333 if (tile == nullptr) {
334 return mRoot->mBackground;
335 }
336 if (tile->child == 0) {
337 return tile->value;
338 }
339
340 const ccl_global auto *upper = mRoot->getChild(tile);
341 const uint32_t upper_n = upper->CoordToOffset(ijk);
342 if (upper->mChildMask.isOff(upper_n)) {
343 return upper->mTable[upper_n].value;
344 }
345
346 const ccl_global auto *lower = upper->getChild(upper_n);
347 const uint32_t lower_n = lower->CoordToOffset(ijk);
348 if (lower->mChildMask.isOff(lower_n)) {
349 return lower->mTable[lower_n].value;
350 }
351
352 const ccl_global LeafT *leaf = lower->getChild(lower_n);
353 return leaf->getValue(ijk);
354 }
355};
356
357template<typename BuildT> class CachedReadAccessor {
358 using RootT = NanoRoot<BuildT>;
359 using UpperT = NanoUpper<BuildT>;
360 using LowerT = NanoLower<BuildT>;
361 using LeafT = NanoLeaf<BuildT>;
362
363 mutable Coord mKeys[3] = {make_int3(INT_MAX), make_int3(INT_MAX), make_int3(INT_MAX)};
364 mutable const ccl_global RootT *mRoot = nullptr;
365 mutable const ccl_global void *mNode[3] = {nullptr, nullptr, nullptr};
366
367 public:
368 using ValueType = typename RootT::ValueType;
369
370 ccl_device_inline_method CachedReadAccessor(const ccl_global RootT &root) : mRoot(&root) {}
371
372 template<typename NodeT> ccl_device_inline_method bool isCached(const Coord ijk) const
373 {
374 return (ijk.x & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].x &&
375 (ijk.y & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].y &&
376 (ijk.z & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].z;
377 }
378
380 const Coord ijk) const
381 {
382 if (const ccl_global auto *tile = node.probeTile(ijk)) {
383 if (tile->child != 0) {
384 const ccl_global auto *child = node.getChild(tile);
385 insert(ijk, child);
386 return getValueAndCache(*child, ijk);
387 }
388 return tile->value;
389 }
390 return node.mBackground;
391 }
392
394 const Coord ijk) const
395 {
396 return node.getValue(ijk);
397 }
398
399 template<typename NodeT>
401 const Coord ijk) const
402 {
403 const uint32_t n = node.CoordToOffset(ijk);
404 if (node.mChildMask.isOff(n)) {
405 return node.mTable[n].value;
406 }
407 const ccl_global auto *child = node.getChild(n);
408 insert(ijk, child);
409 return getValueAndCache(*child, ijk);
410 }
411
413 {
414 if (isCached<LeafT>(ijk)) {
415 return getValueAndCache(*((const ccl_global LeafT *)mNode[0]), ijk);
416 }
417 if (isCached<LowerT>(ijk)) {
418 return getValueAndCache(*((const ccl_global LowerT *)mNode[1]), ijk);
419 }
420 if (isCached<UpperT>(ijk)) {
421 return getValueAndCache(*((const ccl_global UpperT *)mNode[2]), ijk);
422 }
423 return getValueAndCache(*mRoot, ijk);
424 }
425
426 template<typename NodeT>
427 ccl_device_inline_method void insert(const Coord ijk, const ccl_global NodeT *node) const
428 {
429 mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
430 mNode[NodeT::LEVEL] = node;
431 }
432};
433
434} // namespace nanovdb
435
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
ccl_device_inline_method ValueType getValueAndCache(const ccl_global RootT &node, const Coord ijk) const
ccl_device_inline_method ValueType getValueAndCache(const ccl_global LeafT &node, const Coord ijk) const
ccl_device_inline_method CachedReadAccessor(const ccl_global RootT &root)
ccl_device_inline_method bool isCached(const Coord ijk) const
ccl_device_inline_method void insert(const Coord ijk, const ccl_global NodeT *node) const
ccl_device_inline_method ValueType getValue(const Coord ijk) const
ccl_device_inline_method ValueType getValueAndCache(const ccl_global NodeT &node, const Coord ijk) const
typename RootT::ValueType ValueType
ccl_device_inline_method ValueType getValue(const Coord ijk) const
ccl_device_inline_method ReadAccessor(const ccl_global RootT &root)
nullptr float
#define ccl_global
#define ccl_static_constexpr
#define ccl_device_inline_method
#define CCL_NAMESPACE_END
ccl_device_forceinline int3 make_int3(const int x, const int y, const int z)
const ccl_global KernelWorkTile * tile
packed_int3 PackedCoord
const ccl_device ccl_global DstT * PtrAdd(const ccl_global SrcT *p, int64_t offset)
LeafNode< BuildT, 3 > NanoLeaf
InternalNode< NanoLeaf< BuildT >, 4 > NanoLower
InternalNode< NanoLower< BuildT >, 5 > NanoUpper
Grid< NanoTree< BuildT > > NanoGrid
RootNode< NanoUpper< BuildT > > NanoRoot
Tree< NanoRoot< BuildT > > NanoTree
#define ccl_device
const ccl_device_inline_method ccl_global TreeT & tree() const ccl_global
typename TreeT::BuildType BuildType
const ccl_device_inline_method ccl_global NanoLeaf< BuildT > * getChild(const uint32_t n) const ccl_global
typename ChildT::ValueType ValueType
static ccl_device_inline_method uint32_t CoordToOffset(const Coord ijk)
typename ChildT::BuildType BuildType
ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
ccl_device_inline_method float getValue(const uint32_t i) const ccl_global
ccl_device_inline_method ValueType getValue(const uint32_t i) const ccl_global
typename DataType::BuildType BuildType
LeafData< BuildT, Log2Dim > DataType
typename DataType::ValueType ValueType
static ccl_device_inline_method uint32_t CoordToOffset(const Coord ijk)
ccl_device_inline_method ValueType getValue(const Coord ijk) const ccl_global
ccl_device_inline_method ValueType getValue(const uint32_t offset) const ccl_global
ccl_device_inline_method bool isOff(const uint32_t n) const ccl_global
ccl_static_constexpr uint32_t SIZE
ccl_static_constexpr uint32_t WORD_COUNT
uint64_t mWords[WORD_COUNT]
static ccl_device_inline_method uint64_t CoordToKey(const Coord ijk)
typename ChildT::ValueType ValueType
typename ChildT::BuildType BuildType
const ccl_device_inline_method ccl_global NanoUpper< BuildT > * getChild(const ccl_global Tile *tile) const ccl_global
const ccl_device_inline_method ccl_global Tile * probeTile(const Coord ijk) const ccl_global
const ccl_device_inline_method ccl_global RootT & root() const ccl_global
typename RootT::ValueType ValueType
typename RootT::BuildType BuildType
i
Definition text_draw.cc:230