warp-lang 1.1.0__py3-none-macosx_10_13_universal2.whl → 1.2.1__py3-none-macosx_10_13_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (218) hide show
  1. warp/bin/libwarp-clang.dylib +0 -0
  2. warp/bin/libwarp.dylib +0 -0
  3. warp/build.py +10 -37
  4. warp/build_dll.py +2 -2
  5. warp/builtins.py +274 -6
  6. warp/codegen.py +51 -4
  7. warp/config.py +2 -2
  8. warp/constants.py +4 -0
  9. warp/context.py +422 -203
  10. warp/examples/benchmarks/benchmark_api.py +0 -2
  11. warp/examples/benchmarks/benchmark_cloth_warp.py +0 -1
  12. warp/examples/benchmarks/benchmark_launches.py +0 -2
  13. warp/examples/core/example_dem.py +0 -2
  14. warp/examples/core/example_fluid.py +0 -2
  15. warp/examples/core/example_graph_capture.py +0 -2
  16. warp/examples/core/example_marching_cubes.py +0 -2
  17. warp/examples/core/example_mesh.py +0 -2
  18. warp/examples/core/example_mesh_intersect.py +0 -2
  19. warp/examples/core/example_nvdb.py +0 -2
  20. warp/examples/core/example_raycast.py +0 -2
  21. warp/examples/core/example_raymarch.py +0 -2
  22. warp/examples/core/example_render_opengl.py +0 -2
  23. warp/examples/core/example_sph.py +0 -2
  24. warp/examples/core/example_torch.py +0 -3
  25. warp/examples/core/example_wave.py +0 -2
  26. warp/examples/fem/example_apic_fluid.py +140 -115
  27. warp/examples/fem/example_burgers.py +262 -0
  28. warp/examples/fem/example_convection_diffusion.py +0 -2
  29. warp/examples/fem/example_convection_diffusion_dg.py +0 -2
  30. warp/examples/fem/example_deformed_geometry.py +0 -2
  31. warp/examples/fem/example_diffusion.py +0 -2
  32. warp/examples/fem/example_diffusion_3d.py +5 -4
  33. warp/examples/fem/example_diffusion_mgpu.py +0 -2
  34. warp/examples/fem/example_mixed_elasticity.py +0 -2
  35. warp/examples/fem/example_navier_stokes.py +0 -2
  36. warp/examples/fem/example_stokes.py +0 -2
  37. warp/examples/fem/example_stokes_transfer.py +0 -2
  38. warp/examples/optim/example_bounce.py +0 -2
  39. warp/examples/optim/example_cloth_throw.py +0 -2
  40. warp/examples/optim/example_diffray.py +0 -2
  41. warp/examples/optim/example_drone.py +0 -2
  42. warp/examples/optim/example_inverse_kinematics.py +0 -2
  43. warp/examples/optim/example_inverse_kinematics_torch.py +0 -2
  44. warp/examples/optim/example_spring_cage.py +0 -2
  45. warp/examples/optim/example_trajectory.py +0 -2
  46. warp/examples/optim/example_walker.py +0 -2
  47. warp/examples/sim/example_cartpole.py +0 -2
  48. warp/examples/sim/example_cloth.py +0 -2
  49. warp/examples/sim/example_granular.py +0 -2
  50. warp/examples/sim/example_granular_collision_sdf.py +0 -2
  51. warp/examples/sim/example_jacobian_ik.py +0 -2
  52. warp/examples/sim/example_particle_chain.py +0 -2
  53. warp/examples/sim/example_quadruped.py +0 -2
  54. warp/examples/sim/example_rigid_chain.py +0 -2
  55. warp/examples/sim/example_rigid_contact.py +0 -2
  56. warp/examples/sim/example_rigid_force.py +0 -2
  57. warp/examples/sim/example_rigid_gyroscopic.py +0 -2
  58. warp/examples/sim/example_rigid_soft_contact.py +0 -2
  59. warp/examples/sim/example_soft_body.py +0 -2
  60. warp/fem/__init__.py +1 -0
  61. warp/fem/cache.py +3 -1
  62. warp/fem/geometry/__init__.py +1 -0
  63. warp/fem/geometry/element.py +4 -0
  64. warp/fem/geometry/grid_3d.py +0 -4
  65. warp/fem/geometry/nanogrid.py +455 -0
  66. warp/fem/integrate.py +63 -9
  67. warp/fem/space/__init__.py +43 -158
  68. warp/fem/space/basis_space.py +34 -0
  69. warp/fem/space/collocated_function_space.py +1 -1
  70. warp/fem/space/grid_2d_function_space.py +13 -132
  71. warp/fem/space/grid_3d_function_space.py +16 -154
  72. warp/fem/space/hexmesh_function_space.py +37 -134
  73. warp/fem/space/nanogrid_function_space.py +202 -0
  74. warp/fem/space/quadmesh_2d_function_space.py +12 -119
  75. warp/fem/space/restriction.py +4 -1
  76. warp/fem/space/shape/__init__.py +77 -0
  77. warp/fem/space/shape/cube_shape_function.py +5 -15
  78. warp/fem/space/tetmesh_function_space.py +6 -76
  79. warp/fem/space/trimesh_2d_function_space.py +6 -76
  80. warp/native/array.h +12 -3
  81. warp/native/builtin.h +48 -5
  82. warp/native/bvh.cpp +14 -10
  83. warp/native/bvh.cu +23 -15
  84. warp/native/bvh.h +1 -0
  85. warp/native/clang/clang.cpp +2 -1
  86. warp/native/crt.cpp +11 -1
  87. warp/native/crt.h +18 -1
  88. warp/native/exports.h +187 -0
  89. warp/native/mat.h +47 -0
  90. warp/native/mesh.cpp +1 -1
  91. warp/native/mesh.cu +1 -2
  92. warp/native/nanovdb/GridHandle.h +366 -0
  93. warp/native/nanovdb/HostBuffer.h +590 -0
  94. warp/native/nanovdb/NanoVDB.h +3999 -2157
  95. warp/native/nanovdb/PNanoVDB.h +936 -99
  96. warp/native/quat.h +28 -1
  97. warp/native/rand.h +5 -1
  98. warp/native/vec.h +45 -1
  99. warp/native/volume.cpp +335 -103
  100. warp/native/volume.cu +39 -13
  101. warp/native/volume.h +725 -303
  102. warp/native/volume_builder.cu +381 -360
  103. warp/native/volume_builder.h +16 -1
  104. warp/native/volume_impl.h +61 -0
  105. warp/native/warp.cu +8 -2
  106. warp/native/warp.h +15 -7
  107. warp/render/render_opengl.py +191 -52
  108. warp/sim/integrator_featherstone.py +10 -3
  109. warp/sim/integrator_xpbd.py +16 -22
  110. warp/sparse.py +89 -27
  111. warp/stubs.py +83 -0
  112. warp/tests/assets/test_index_grid.nvdb +0 -0
  113. warp/tests/aux_test_dependent.py +0 -2
  114. warp/tests/aux_test_grad_customs.py +0 -2
  115. warp/tests/aux_test_reference.py +0 -2
  116. warp/tests/aux_test_reference_reference.py +0 -2
  117. warp/tests/aux_test_square.py +0 -2
  118. warp/tests/disabled_kinematics.py +0 -2
  119. warp/tests/test_adam.py +0 -2
  120. warp/tests/test_arithmetic.py +0 -36
  121. warp/tests/test_array.py +9 -11
  122. warp/tests/test_array_reduce.py +0 -2
  123. warp/tests/test_async.py +0 -2
  124. warp/tests/test_atomic.py +0 -2
  125. warp/tests/test_bool.py +58 -50
  126. warp/tests/test_builtins_resolution.py +0 -2
  127. warp/tests/test_bvh.py +0 -2
  128. warp/tests/test_closest_point_edge_edge.py +0 -1
  129. warp/tests/test_codegen.py +0 -4
  130. warp/tests/test_compile_consts.py +130 -10
  131. warp/tests/test_conditional.py +0 -2
  132. warp/tests/test_copy.py +0 -2
  133. warp/tests/test_ctypes.py +6 -8
  134. warp/tests/test_dense.py +0 -2
  135. warp/tests/test_devices.py +0 -2
  136. warp/tests/test_dlpack.py +9 -11
  137. warp/tests/test_examples.py +42 -39
  138. warp/tests/test_fabricarray.py +0 -3
  139. warp/tests/test_fast_math.py +0 -2
  140. warp/tests/test_fem.py +75 -54
  141. warp/tests/test_fp16.py +0 -2
  142. warp/tests/test_func.py +0 -2
  143. warp/tests/test_generics.py +27 -2
  144. warp/tests/test_grad.py +147 -8
  145. warp/tests/test_grad_customs.py +0 -2
  146. warp/tests/test_hash_grid.py +1 -3
  147. warp/tests/test_import.py +0 -2
  148. warp/tests/test_indexedarray.py +0 -2
  149. warp/tests/test_intersect.py +0 -2
  150. warp/tests/test_jax.py +0 -2
  151. warp/tests/test_large.py +11 -9
  152. warp/tests/test_launch.py +0 -2
  153. warp/tests/test_lerp.py +10 -54
  154. warp/tests/test_linear_solvers.py +3 -5
  155. warp/tests/test_lvalue.py +0 -2
  156. warp/tests/test_marching_cubes.py +0 -2
  157. warp/tests/test_mat.py +0 -2
  158. warp/tests/test_mat_lite.py +0 -2
  159. warp/tests/test_mat_scalar_ops.py +0 -2
  160. warp/tests/test_math.py +0 -2
  161. warp/tests/test_matmul.py +35 -37
  162. warp/tests/test_matmul_lite.py +29 -31
  163. warp/tests/test_mempool.py +0 -2
  164. warp/tests/test_mesh.py +0 -3
  165. warp/tests/test_mesh_query_aabb.py +0 -2
  166. warp/tests/test_mesh_query_point.py +0 -2
  167. warp/tests/test_mesh_query_ray.py +0 -2
  168. warp/tests/test_mlp.py +0 -2
  169. warp/tests/test_model.py +0 -2
  170. warp/tests/test_module_hashing.py +111 -0
  171. warp/tests/test_modules_lite.py +0 -3
  172. warp/tests/test_multigpu.py +0 -2
  173. warp/tests/test_noise.py +0 -4
  174. warp/tests/test_operators.py +0 -2
  175. warp/tests/test_options.py +0 -2
  176. warp/tests/test_peer.py +0 -2
  177. warp/tests/test_pinned.py +0 -2
  178. warp/tests/test_print.py +0 -2
  179. warp/tests/test_quat.py +0 -2
  180. warp/tests/test_rand.py +41 -5
  181. warp/tests/test_reload.py +0 -10
  182. warp/tests/test_rounding.py +0 -2
  183. warp/tests/test_runlength_encode.py +0 -2
  184. warp/tests/test_sim_grad.py +0 -2
  185. warp/tests/test_sim_kinematics.py +0 -2
  186. warp/tests/test_smoothstep.py +0 -2
  187. warp/tests/test_snippet.py +0 -2
  188. warp/tests/test_sparse.py +0 -2
  189. warp/tests/test_spatial.py +0 -2
  190. warp/tests/test_special_values.py +362 -0
  191. warp/tests/test_streams.py +0 -2
  192. warp/tests/test_struct.py +0 -2
  193. warp/tests/test_tape.py +0 -2
  194. warp/tests/test_torch.py +0 -2
  195. warp/tests/test_transient_module.py +0 -2
  196. warp/tests/test_types.py +0 -2
  197. warp/tests/test_utils.py +0 -2
  198. warp/tests/test_vec.py +0 -2
  199. warp/tests/test_vec_lite.py +0 -2
  200. warp/tests/test_vec_scalar_ops.py +0 -2
  201. warp/tests/test_verify_fp.py +0 -2
  202. warp/tests/test_volume.py +237 -13
  203. warp/tests/test_volume_write.py +86 -3
  204. warp/tests/unittest_serial.py +10 -9
  205. warp/tests/unittest_suites.py +6 -2
  206. warp/tests/unittest_utils.py +2 -171
  207. warp/tests/unused_test_misc.py +0 -2
  208. warp/tests/walkthrough_debug.py +1 -1
  209. warp/thirdparty/unittest_parallel.py +37 -40
  210. warp/types.py +526 -85
  211. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/METADATA +61 -31
  212. warp_lang-1.2.1.dist-info/RECORD +359 -0
  213. warp/examples/fem/example_convection_diffusion_dg0.py +0 -204
  214. warp/native/nanovdb/PNanoVDBWrite.h +0 -295
  215. warp_lang-1.1.0.dist-info/RECORD +0 -352
  216. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/LICENSE.md +0 -0
  217. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/WHEEL +0 -0
  218. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/top_level.txt +0 -0
warp/native/volume.h CHANGED
@@ -8,529 +8,951 @@
8
8
 
9
9
  #pragma once
10
10
 
11
+ #include "array.h"
11
12
  #include "builtin.h"
12
13
 
13
14
  #define PNANOVDB_C
14
15
  #define PNANOVDB_MEMCPY_CUSTOM
15
16
  #define pnanovdb_memcpy memcpy
17
+
18
+ #if defined(WP_NO_CRT) && !defined(__CUDACC__)
19
+ // PNanoVDB will try to include <stdint.h> unless __CUDACC_RTC__ is defined
20
+ #define __CUDACC_RTC__
21
+ #endif
22
+
16
23
  #include "nanovdb/PNanoVDB.h"
17
- #include "nanovdb/PNanoVDBWrite.h"
24
+
25
+ #if defined(WP_NO_CRT) && !defined(__CUDACC__)
26
+ #undef __CUDACC_RTC__
27
+ #endif
18
28
 
19
29
  namespace wp
20
30
  {
21
31
  namespace volume
22
32
  {
23
33
 
34
+ // Need to kept in sync with constants in python-side Volume class
24
35
  static constexpr int CLOSEST = 0;
25
36
  static constexpr int LINEAR = 1;
26
37
 
27
- // helper functions
38
+ // pnanovdb helper function
39
+
28
40
  CUDA_CALLABLE inline pnanovdb_buf_t id_to_buffer(uint64_t id)
29
41
  {
30
42
  pnanovdb_buf_t buf;
31
- buf.data = (uint32_t*)id;
43
+ buf.data = (uint32_t *)id;
32
44
  return buf;
33
45
  }
34
46
 
35
- CUDA_CALLABLE inline pnanovdb_uint32_t get_grid_type(const pnanovdb_buf_t& buf)
47
+ CUDA_CALLABLE inline pnanovdb_grid_handle_t get_grid(pnanovdb_buf_t buf)
36
48
  {
37
- const pnanovdb_grid_t *grid_data = (const pnanovdb_grid_t*)buf.data;
38
- return grid_data->grid_type;
49
+ return {0u};
39
50
  }
40
51
 
41
- CUDA_CALLABLE inline pnanovdb_root_handle_t get_root(const pnanovdb_buf_t& buf,
42
- const pnanovdb_grid_handle_t& grid = { 0u })
52
+ CUDA_CALLABLE inline pnanovdb_uint32_t get_grid_type(pnanovdb_buf_t buf)
43
53
  {
44
- const auto tree = pnanovdb_grid_get_tree(buf, grid);
45
- return pnanovdb_tree_get_root(buf, tree);
54
+ return pnanovdb_grid_get_grid_type(buf, get_grid(buf));
46
55
  }
47
- } // namespace volume
48
56
 
49
- CUDA_CALLABLE inline void pnano_read(float& result, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk) {
50
- const pnanovdb_address_t address = pnanovdb_root_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, root, ijk);
51
- result = pnanovdb_read_float(buf, address);
57
+ CUDA_CALLABLE inline pnanovdb_tree_handle_t get_tree(pnanovdb_buf_t buf)
58
+ {
59
+ return pnanovdb_grid_get_tree(buf, get_grid(buf));
52
60
  }
53
- CUDA_CALLABLE inline void pnano_read(int32_t& result, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk) {
54
- const pnanovdb_address_t address = pnanovdb_root_get_value_address(PNANOVDB_GRID_TYPE_INT32, buf, root, ijk);
55
- result = pnanovdb_read_int32(buf, address);
61
+
62
+ CUDA_CALLABLE inline pnanovdb_root_handle_t get_root(pnanovdb_buf_t buf)
63
+ {
64
+ return pnanovdb_tree_get_root(buf, get_tree(buf));
56
65
  }
57
- CUDA_CALLABLE inline void pnano_read(vec3& result, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk) {
58
- const pnanovdb_address_t address = pnanovdb_root_get_value_address(PNANOVDB_GRID_TYPE_VEC3F, buf, root, ijk);
59
- const pnanovdb_vec3_t v = pnanovdb_read_vec3f(buf, address);
60
- result = {v.x, v.y, v.z};
66
+
67
+ template <typename T> struct pnano_traits
68
+ {
69
+ };
70
+
71
+ // to add support for more grid types, extend this
72
+ // and update _volume_supported_value_types in builtins.py
73
+
74
+ template <> struct pnano_traits<int32_t>
75
+ {
76
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_INT32;
77
+ };
78
+
79
+ template <> struct pnano_traits<int64_t>
80
+ {
81
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_INT64;
82
+ };
83
+
84
+ template <> struct pnano_traits<uint32_t>
85
+ {
86
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_UINT32;
87
+ };
88
+
89
+ template <> struct pnano_traits<float>
90
+ {
91
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_FLOAT;
92
+ };
93
+
94
+ template <> struct pnano_traits<double>
95
+ {
96
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_DOUBLE;
97
+ };
98
+
99
+ template <> struct pnano_traits<vec3f>
100
+ {
101
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_VEC3F;
102
+ };
103
+
104
+ template <> struct pnano_traits<vec3d>
105
+ {
106
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_VEC3D;
107
+ };
108
+
109
+ template <> struct pnano_traits<vec4f>
110
+ {
111
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_VEC4F;
112
+ };
113
+
114
+ template <> struct pnano_traits<vec4d>
115
+ {
116
+ static constexpr int GRID_TYPE = PNANOVDB_GRID_TYPE_VEC4D;
117
+ };
118
+
119
+ // common accessors over various grid types
120
+ // WARNING: implementation below only for >=32b values, but that's the case for all types above
121
+ // for smaller types add a specialization
122
+
123
+ template <typename T> CUDA_CALLABLE inline void pnano_read(T &result, pnanovdb_buf_t buf, pnanovdb_address_t address)
124
+ {
125
+ result = *reinterpret_cast<const T *>(buf.data + (address.byte_offset >> 2));
61
126
  }
62
127
 
63
- CUDA_CALLABLE inline void pnano_read(float& result, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) {
64
- pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, ijk);
65
- result = pnanovdb_read_float(buf, address);
128
+ template <typename T>
129
+ CUDA_CALLABLE inline void pnano_write(const T &value, pnanovdb_buf_t buf, pnanovdb_address_t address)
130
+ {
131
+ *reinterpret_cast<T *>(buf.data + (address.byte_offset >> 2)) = value;
66
132
  }
67
- CUDA_CALLABLE inline void pnano_read(int32_t& result, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) {
68
- pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_INT32, buf, acc, ijk);
69
- result = pnanovdb_read_int32(buf, address);
133
+
134
+ template <typename T>
135
+ CUDA_CALLABLE inline void pnano_read(T &result, pnanovdb_buf_t buf, pnanovdb_root_handle_t root,
136
+ PNANOVDB_IN(pnanovdb_coord_t) ijk)
137
+ {
138
+ using traits = pnano_traits<T>;
139
+ const pnanovdb_address_t address = pnanovdb_root_get_value_address(traits::GRID_TYPE, buf, root, ijk);
140
+ pnano_read<T>(result, buf, address);
70
141
  }
71
- CUDA_CALLABLE inline void pnano_read(vec3& result, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) {
72
- pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_VEC3F, buf, acc, ijk);
73
- const pnanovdb_vec3_t v = pnanovdb_read_vec3f(buf, address);
74
- result = {v.x, v.y, v.z};
142
+
143
+ template <typename T>
144
+ CUDA_CALLABLE inline void pnano_read(T &result, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc,
145
+ PNANOVDB_IN(pnanovdb_coord_t) ijk)
146
+ {
147
+ using traits = pnano_traits<T>;
148
+ // pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(traits::GRID_TYPE, buf, acc, ijk);
149
+ pnanovdb_uint32_t level;
150
+ const pnanovdb_address_t address =
151
+ pnanovdb_readaccessor_get_value_address_and_level(traits::GRID_TYPE, buf, acc, ijk, PNANOVDB_REF(level));
152
+ pnano_read<T>(result, buf, address);
75
153
  }
76
154
 
77
- // Sampling the volume at the given index-space coordinates, uvw can be fractional
78
- template<typename T>
79
- CUDA_CALLABLE inline T volume_sample(uint64_t id, vec3 uvw, int sampling_mode)
155
+ /// regular grid accessor (values stored in leafs)
156
+
157
+ struct value_accessor_base
80
158
  {
81
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
82
- const pnanovdb_root_handle_t root = volume::get_root(buf);
83
- const pnanovdb_vec3_t uvw_pnano{ uvw[0], uvw[1], uvw[2] };
159
+ pnanovdb_buf_t buf;
160
+ pnanovdb_root_handle_t root;
161
+ pnanovdb_readaccessor_t accessor;
162
+
163
+ explicit inline CUDA_CALLABLE value_accessor_base(const pnanovdb_buf_t buf) : buf(buf), root(get_root(buf))
164
+ {
165
+ }
166
+
167
+ CUDA_CALLABLE inline void init_cache()
168
+ {
169
+ pnanovdb_readaccessor_init(PNANOVDB_REF(accessor), root);
170
+ }
171
+ };
172
+
173
+ template <typename T> struct leaf_value_accessor : value_accessor_base
174
+ {
175
+ using ValueType = T;
176
+
177
+ explicit inline CUDA_CALLABLE leaf_value_accessor(const pnanovdb_buf_t buf) : value_accessor_base(buf)
178
+ {
179
+ }
180
+
181
+ CUDA_CALLABLE inline bool is_valid() const
182
+ {
183
+ return get_grid_type(buf) == pnano_traits<T>::GRID_TYPE;
184
+ }
84
185
 
85
- if (sampling_mode == volume::CLOSEST)
186
+ CUDA_CALLABLE inline T read_single(const pnanovdb_coord_t &ijk) const
86
187
  {
87
- const pnanovdb_coord_t ijk = pnanovdb_vec3_round_to_coord(uvw_pnano);
88
188
  T val;
89
189
  pnano_read(val, buf, root, PNANOVDB_REF(ijk));
90
190
  return val;
91
191
  }
92
- else if (sampling_mode == volume::LINEAR)
192
+
193
+ CUDA_CALLABLE inline T read_cache(const pnanovdb_coord_t &ijk)
93
194
  {
94
- // NB. linear sampling is not used on int volumes
95
- constexpr pnanovdb_coord_t OFFSETS[] = {
96
- { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
97
- };
195
+ T val;
196
+ pnano_read(val, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk));
197
+ return val;
198
+ }
98
199
 
99
- const pnanovdb_vec3_t ijk_base{ floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z) };
100
- const pnanovdb_vec3_t ijk_frac{ uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z };
101
- const pnanovdb_coord_t ijk{ (pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y, (pnanovdb_int32_t)ijk_base.z };
200
+ CUDA_CALLABLE inline void adj_read_single(const pnanovdb_coord_t &ijk, const T &adj_ret)
201
+ {
202
+ // NOP
203
+ }
102
204
 
103
- pnanovdb_readaccessor_t accessor;
104
- pnanovdb_readaccessor_init(PNANOVDB_REF(accessor), root);
105
- T val = 0;
106
- const float wx[2]{ 1 - ijk_frac.x, ijk_frac.x };
107
- const float wy[2]{ 1 - ijk_frac.y, ijk_frac.y };
108
- const float wz[2]{ 1 - ijk_frac.z, ijk_frac.z };
109
- for (int idx = 0; idx < 8; ++idx)
110
- {
111
- const pnanovdb_coord_t& offs = OFFSETS[idx];
112
- const pnanovdb_coord_t ijk_shifted = pnanovdb_coord_add(ijk, offs);
113
- T v;
114
- pnano_read(v, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk_shifted));
115
- val = add(val, T(wx[offs.x] * wy[offs.y] * wz[offs.z] * v));
116
- }
117
- return val;
205
+ CUDA_CALLABLE inline void adj_read_cache(const pnanovdb_coord_t &ijk, const T &adj_ret)
206
+ {
207
+ // NOP
118
208
  }
119
- return 0;
120
- }
209
+ };
121
210
 
122
- // Sampling a float volume at the given index-space coordinates, uvw can be fractional
123
- CUDA_CALLABLE inline float volume_sample_f(uint64_t id, vec3 uvw, int sampling_mode)
211
+ CUDA_CALLABLE inline pnanovdb_uint64_t leaf_regular_get_voxel_index(pnanovdb_buf_t buf,
212
+ pnanovdb_address_t value_address,
213
+ PNANOVDB_IN(pnanovdb_coord_t) ijk)
124
214
  {
125
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_FLOAT) return 0.f;
126
- return volume_sample<float>(id, uvw, sampling_mode);
215
+ // compute leaf index from value address, assuming all leaf voxels are allocated
216
+ const pnanovdb_grid_type_t grid_type = get_grid_type(buf);
217
+ const pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk);
218
+ const pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_table) +
219
+ ((PNANOVDB_GRID_TYPE_GET(grid_type, value_stride_bits) * n) >> 3u);
220
+ const pnanovdb_address_t leaf_address = pnanovdb_address_offset_neg(value_address, byte_offset);
221
+
222
+ const pnanovdb_uint64_t first_leaf_offset = pnanovdb_tree_get_node_offset_leaf(buf, get_tree(buf));
223
+ const pnanovdb_uint32_t leaf_size = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_size);
224
+ const pnanovdb_uint64_t leaf_index = (leaf_address.byte_offset - first_leaf_offset) / leaf_size;
225
+
226
+ return leaf_index * PNANOVDB_LEAF_TABLE_COUNT + n + 1;
127
227
  }
128
228
 
129
- // Sampling an int volume at the given index-space coordinates, uvw can be fractional
130
- CUDA_CALLABLE inline int32_t volume_sample_i(uint64_t id, vec3 uvw)
229
+ CUDA_CALLABLE inline pnanovdb_uint64_t get_grid_voxel_index(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf,
230
+ pnanovdb_address_t value_address,
231
+ const pnanovdb_coord_t &ijk)
131
232
  {
132
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_INT32) return 0;
133
- return volume_sample<int32_t>(id, uvw, volume::CLOSEST);
134
- }
233
+ switch (grid_type)
234
+ {
235
+ case PNANOVDB_GRID_TYPE_INDEX:
236
+ return pnanovdb_leaf_index_get_value_index(buf, value_address, PNANOVDB_REF(ijk));
237
+ case PNANOVDB_GRID_TYPE_ONINDEX:
238
+ return pnanovdb_leaf_onindex_get_value_index(buf, value_address, PNANOVDB_REF(ijk));
239
+ case PNANOVDB_GRID_TYPE_INDEXMASK:
240
+ return pnanovdb_leaf_indexmask_get_value_index(buf, value_address, PNANOVDB_REF(ijk));
241
+ case PNANOVDB_GRID_TYPE_ONINDEXMASK:
242
+ return pnanovdb_leaf_onindexmask_get_value_index(buf, value_address, PNANOVDB_REF(ijk));
243
+ default:
244
+ return leaf_regular_get_voxel_index(buf, value_address, PNANOVDB_REF(ijk));
245
+ }
246
+ };
135
247
 
136
- // Sampling a vector volume at the given index-space coordinates, uvw can be fractional
137
- CUDA_CALLABLE inline vec3 volume_sample_v(uint64_t id, vec3 uvw, int sampling_mode)
248
+ /// index grid accessor
249
+ template <typename T> struct index_value_accessor : value_accessor_base
138
250
  {
139
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_VEC3F) return vec3(0.f);
140
- return volume_sample<vec3>(id, uvw, sampling_mode);
251
+ using ValueType = T;
252
+
253
+ pnanovdb_grid_type_t grid_type;
254
+ array_t<T> data;
255
+ const T &background;
256
+ T *adj_background;
257
+
258
+ explicit inline CUDA_CALLABLE index_value_accessor(const pnanovdb_buf_t buf, const array_t<T> &data,
259
+ const T &background, T *adj_background = nullptr)
260
+ : value_accessor_base(buf), grid_type(get_grid_type(buf)), data(data), background(background),
261
+ adj_background(adj_background)
262
+ {
263
+ }
264
+
265
+ CUDA_CALLABLE inline bool is_valid() const
266
+ {
267
+ // Accessor is valid for all grid types
268
+ return true;
269
+ }
270
+
271
+ CUDA_CALLABLE inline T read_single(const pnanovdb_coord_t &ijk) const
272
+ {
273
+ pnanovdb_uint32_t level;
274
+ const pnanovdb_address_t address =
275
+ pnanovdb_root_get_value_address_and_level(grid_type, buf, root, PNANOVDB_REF(ijk), PNANOVDB_REF(level));
276
+ return read_at(level, address, ijk);
277
+ }
278
+
279
+ CUDA_CALLABLE inline T read_cache(const pnanovdb_coord_t &ijk)
280
+ {
281
+ pnanovdb_uint32_t level;
282
+ const pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address_and_level(
283
+ grid_type, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk), PNANOVDB_REF(level));
284
+ return read_at(level, address, ijk);
285
+ }
286
+
287
+ CUDA_CALLABLE inline T read_at(pnanovdb_uint32_t level, const pnanovdb_address_t address,
288
+ const pnanovdb_coord_t &ijk) const
289
+ {
290
+ if (level == 0)
291
+ {
292
+ pnanovdb_uint64_t voxel_index = get_grid_voxel_index(grid_type, buf, address, ijk);
293
+
294
+ if (voxel_index > 0)
295
+ {
296
+ return *wp::address(data, voxel_index - 1);
297
+ }
298
+ }
299
+
300
+ return background;
301
+ }
302
+
303
+ CUDA_CALLABLE inline void adj_read_single(const pnanovdb_coord_t &ijk, const T &adj_ret)
304
+ {
305
+ pnanovdb_uint32_t level;
306
+ const pnanovdb_address_t address =
307
+ pnanovdb_root_get_value_address_and_level(grid_type, buf, root, PNANOVDB_REF(ijk), PNANOVDB_REF(level));
308
+ adj_read_at(level, address, ijk, adj_ret);
309
+ }
310
+
311
+ CUDA_CALLABLE inline void adj_read_cache(const pnanovdb_coord_t &ijk, const T &adj_ret)
312
+ {
313
+ pnanovdb_uint32_t level;
314
+ const pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address_and_level(
315
+ grid_type, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk), PNANOVDB_REF(level));
316
+ adj_read_at(level, address, ijk, adj_ret);
317
+ }
318
+
319
+ CUDA_CALLABLE inline void adj_read_at(pnanovdb_uint32_t level, const pnanovdb_address_t address,
320
+ const pnanovdb_coord_t &ijk, const T &adj_ret) const
321
+ {
322
+ if (level == 0)
323
+ {
324
+ pnanovdb_uint64_t voxel_index = get_grid_voxel_index(grid_type, buf, address, ijk);
325
+
326
+ if (voxel_index > 0)
327
+ {
328
+ adj_atomic_add(&index_grad(data, voxel_index - 1), adj_ret);
329
+ return;
330
+ }
331
+ }
332
+ *adj_background += adj_ret;
333
+ }
334
+ };
335
+
336
+ CUDA_CALLABLE inline pnanovdb_coord_t vec3_round_to_coord(const pnanovdb_vec3_t a)
337
+ {
338
+ pnanovdb_coord_t v;
339
+ v.x = pnanovdb_float_to_int32(roundf(a.x));
340
+ v.y = pnanovdb_float_to_int32(roundf(a.y));
341
+ v.z = pnanovdb_float_to_int32(roundf(a.z));
342
+ return v;
141
343
  }
142
344
 
143
- CUDA_CALLABLE inline void adj_volume_sample_f(
144
- uint64_t id, vec3 uvw, int sampling_mode, uint64_t& adj_id, vec3& adj_uvw, int& adj_sampling_mode, const float& adj_ret)
345
+ template <typename T> struct val_traits
145
346
  {
146
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_FLOAT) return;
347
+ using grad_t = vec_t<3, T>;
348
+ using scalar_t = T;
147
349
 
148
- if (sampling_mode != volume::LINEAR) {
149
- return; // NOP
350
+ // multiplies the gradient on the right
351
+ // needs to be specialized for scalar types as gradient is stored as column rather than row vector
352
+ static CUDA_CALLABLE inline T rmul(const grad_t &grad, const vec_t<3, scalar_t> &rhs)
353
+ {
354
+ return dot(grad, rhs);
150
355
  }
356
+ };
151
357
 
152
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
153
- const pnanovdb_root_handle_t root = volume::get_root(buf);
154
- const pnanovdb_vec3_t uvw_pnano{ uvw[0], uvw[1], uvw[2] };
358
+ template <unsigned Length, typename T> struct val_traits<vec_t<Length, T>>
359
+ {
360
+ using grad_t = mat_t<3, Length, T>;
361
+ using scalar_t = T;
155
362
 
156
- constexpr pnanovdb_coord_t OFFSETS[] = {
157
- { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
158
- };
363
+ static CUDA_CALLABLE inline vec_t<Length, T> rmul(const grad_t &grad, const vec_t<3, scalar_t> &rhs)
364
+ {
365
+ return mul(grad, rhs);
366
+ }
367
+ };
159
368
 
160
- const pnanovdb_vec3_t ijk_base{ floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z) };
161
- const pnanovdb_vec3_t ijk_frac{ uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z };
162
- const pnanovdb_coord_t ijk{ (pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y, (pnanovdb_int32_t)ijk_base.z };
369
+ // Sampling the volume at the given index-space coordinates, uvw can be fractional
370
+ template <typename Accessor>
371
+ CUDA_CALLABLE inline typename Accessor::ValueType volume_sample(Accessor &accessor, vec3 uvw, int sampling_mode)
372
+ {
373
+ using T = typename Accessor::ValueType;
374
+ using w_t = typename val_traits<T>::scalar_t;
163
375
 
164
- pnanovdb_readaccessor_t accessor;
165
- pnanovdb_readaccessor_init(PNANOVDB_REF(accessor), root);
166
- const float wx[2]{ 1 - ijk_frac.x, ijk_frac.x };
167
- const float wy[2]{ 1 - ijk_frac.y, ijk_frac.y };
168
- const float wz[2]{ 1 - ijk_frac.z, ijk_frac.z };
169
- vec3 dphi(0,0,0);
170
- for (int idx = 0; idx < 8; ++idx)
376
+ if (!accessor.is_valid())
171
377
  {
172
- const pnanovdb_coord_t& offs = OFFSETS[idx];
173
- const pnanovdb_coord_t ijk_shifted = pnanovdb_coord_add(ijk, offs);
174
- float v;
175
- pnano_read(v, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk_shifted));
176
- const vec3 signs(offs.x * 2 - 1, offs.y * 2 - 1, offs.z * 2 - 1);
177
- const vec3 grad_w(signs[0] * wy[offs.y] * wz[offs.z], signs[1] * wx[offs.x] * wz[offs.z], signs[2] * wx[offs.x] * wy[offs.y]);
178
- dphi = add(dphi, mul(v, grad_w));
378
+ return 0;
379
+ }
380
+
381
+ const pnanovdb_buf_t buf = accessor.buf;
382
+ const pnanovdb_vec3_t uvw_pnano{uvw[0], uvw[1], uvw[2]};
383
+
384
+ if (sampling_mode == CLOSEST)
385
+ {
386
+ const pnanovdb_coord_t ijk = vec3_round_to_coord(uvw_pnano);
387
+ return accessor.read_single(ijk);
179
388
  }
389
+ else if (sampling_mode == LINEAR)
390
+ {
391
+ // NB. linear sampling is not used on int volumes
392
+ constexpr pnanovdb_coord_t OFFSETS[] = {
393
+ {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1},
394
+ };
395
+
396
+ const pnanovdb_vec3_t ijk_base{floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z)};
397
+ const pnanovdb_vec3_t ijk_frac{uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z};
398
+ const pnanovdb_coord_t ijk{(pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y,
399
+ (pnanovdb_int32_t)ijk_base.z};
400
+
401
+ accessor.init_cache();
402
+ T val = 0;
403
+ const float wx[2]{1 - ijk_frac.x, ijk_frac.x};
404
+ const float wy[2]{1 - ijk_frac.y, ijk_frac.y};
405
+ const float wz[2]{1 - ijk_frac.z, ijk_frac.z};
406
+ for (int idx = 0; idx < 8; ++idx)
407
+ {
408
+ const pnanovdb_coord_t &offs = OFFSETS[idx];
409
+ const pnanovdb_coord_t ijk_shifted = pnanovdb_coord_add(ijk, offs);
410
+ const T v = accessor.read_cache(ijk_shifted);
180
411
 
181
- adj_uvw += mul(dphi, adj_ret);
412
+ const w_t w = wx[offs.x] * wy[offs.y] * wz[offs.z];
413
+ val = add(val, w * v);
414
+ }
415
+ return val;
416
+ }
417
+ return 0;
182
418
  }
183
419
 
184
- CUDA_CALLABLE inline void adj_volume_sample_v(
185
- uint64_t id, vec3 uvw, int sampling_mode, uint64_t& adj_id, vec3& adj_uvw, int& adj_sampling_mode, const vec3& adj_ret)
420
+ template <typename Accessor>
421
+ CUDA_CALLABLE inline void adj_volume_sample(Accessor &accessor, vec3 uvw, int sampling_mode, vec3 &adj_uvw,
422
+ const typename Accessor::ValueType &adj_ret)
186
423
  {
187
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_VEC3F) return;
424
+ // TODO: accessor data gradients
188
425
 
189
- if (sampling_mode != volume::LINEAR) {
190
- return; // NOP
426
+ using T = typename Accessor::ValueType;
427
+ using w_t = typename val_traits<T>::scalar_t;
428
+ using w_grad_t = vec_t<3, w_t>;
429
+
430
+ if (!accessor.is_valid())
431
+ {
432
+ return;
191
433
  }
192
434
 
193
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
194
- const pnanovdb_root_handle_t root = volume::get_root(buf);
195
- const pnanovdb_vec3_t uvw_pnano{ uvw[0], uvw[1], uvw[2] };
435
+ const pnanovdb_buf_t buf = accessor.buf;
436
+ const pnanovdb_vec3_t uvw_pnano{uvw[0], uvw[1], uvw[2]};
437
+
438
+ if (sampling_mode != LINEAR)
439
+ {
440
+ const pnanovdb_coord_t ijk = vec3_round_to_coord(uvw_pnano);
441
+ accessor.adj_read_single(ijk, adj_ret);
442
+ return;
443
+ }
196
444
 
197
445
  constexpr pnanovdb_coord_t OFFSETS[] = {
198
- { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
446
+ {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1},
199
447
  };
200
448
 
201
- const pnanovdb_vec3_t ijk_base{ floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z) };
202
- const pnanovdb_vec3_t ijk_frac{ uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z };
203
- const pnanovdb_coord_t ijk{ (pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y, (pnanovdb_int32_t)ijk_base.z };
449
+ const pnanovdb_vec3_t ijk_base{floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z)};
450
+ const pnanovdb_vec3_t ijk_frac{uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z};
451
+ const pnanovdb_coord_t ijk{(pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y,
452
+ (pnanovdb_int32_t)ijk_base.z};
204
453
 
205
- pnanovdb_readaccessor_t accessor;
206
- pnanovdb_readaccessor_init(PNANOVDB_REF(accessor), root);
207
- const float wx[2]{ 1 - ijk_frac.x, ijk_frac.x };
208
- const float wy[2]{ 1 - ijk_frac.y, ijk_frac.y };
209
- const float wz[2]{ 1 - ijk_frac.z, ijk_frac.z };
210
- vec3 dphi[3] = {{0,0,0}, {0,0,0}, {0,0,0}};
454
+ accessor.init_cache();
455
+
456
+ const float wx[2]{1 - ijk_frac.x, ijk_frac.x};
457
+ const float wy[2]{1 - ijk_frac.y, ijk_frac.y};
458
+ const float wz[2]{1 - ijk_frac.z, ijk_frac.z};
211
459
  for (int idx = 0; idx < 8; ++idx)
212
460
  {
213
- const pnanovdb_coord_t& offs = OFFSETS[idx];
461
+ const pnanovdb_coord_t &offs = OFFSETS[idx];
214
462
  const pnanovdb_coord_t ijk_shifted = pnanovdb_coord_add(ijk, offs);
215
- vec3 v;
216
- pnano_read(v, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk_shifted));
463
+ const T v = accessor.read_cache(ijk_shifted);
464
+
217
465
  const vec3 signs(offs.x * 2 - 1, offs.y * 2 - 1, offs.z * 2 - 1);
218
- const vec3 grad_w(signs[0] * wy[offs.y] * wz[offs.z], signs[1] * wx[offs.x] * wz[offs.z], signs[2] * wx[offs.x] * wy[offs.y]);
219
- dphi[0] = add(dphi[0], mul(v[0], grad_w));
220
- dphi[1] = add(dphi[1], mul(v[1], grad_w));
221
- dphi[2] = add(dphi[2], mul(v[2], grad_w));
222
- }
223
466
 
224
- for (int k = 0; k < 3; ++k)
225
- {
226
- adj_uvw[k] += dot(dphi[k], adj_ret);
227
- }
228
- }
467
+ const w_t w = wx[offs.x] * wy[offs.y] * wz[offs.z];
468
+ const w_grad_t grad_w(signs[0] * wy[offs.y] * wz[offs.z], signs[1] * wx[offs.x] * wz[offs.z],
469
+ signs[2] * wx[offs.x] * wy[offs.y]);
229
470
 
230
- CUDA_CALLABLE inline void adj_volume_sample_i(uint64_t id, vec3 uvw, uint64_t& adj_id, vec3& adj_uvw, const int32_t& adj_ret)
231
- {
232
- // NOP
471
+ adj_uvw += vec3(mul(w_t(dot(v, adj_ret)), grad_w));
472
+
473
+ const T adj_v = w * adj_ret;
474
+ accessor.adj_read_cache(ijk_shifted, adj_v);
475
+ }
233
476
  }
234
477
 
235
478
  // Sampling the volume at the given index-space coordinates, uvw can be fractional
236
- CUDA_CALLABLE inline float volume_sample_grad_f(uint64_t id, vec3 uvw, int sampling_mode, vec3& grad)
479
+ template <typename Accessor>
480
+ CUDA_CALLABLE inline typename Accessor::ValueType volume_sample_grad(
481
+ Accessor &accessor, vec3 uvw, int sampling_mode, typename val_traits<typename Accessor::ValueType>::grad_t &grad)
237
482
  {
238
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
239
- const pnanovdb_root_handle_t root = volume::get_root(buf);
240
- const pnanovdb_vec3_t uvw_pnano{ uvw[0], uvw[1], uvw[2] };
483
+ using T = typename Accessor::ValueType;
484
+ using grad_T = typename val_traits<T>::grad_t;
485
+ using w_t = typename val_traits<T>::scalar_t;
486
+ using w_grad_t = vec_t<3, w_t>;
487
+
488
+ grad = grad_T{};
241
489
 
242
- if (sampling_mode == volume::CLOSEST)
490
+ if (!accessor.is_valid())
243
491
  {
244
- const pnanovdb_coord_t ijk = pnanovdb_vec3_round_to_coord(uvw_pnano);
245
- float val;
246
- pnano_read(val, buf, root, PNANOVDB_REF(ijk));
247
- grad = vec3(0.0f, 0.0f, 0.0f);
248
- return val;
492
+ return 0;
249
493
  }
250
- else if (sampling_mode == volume::LINEAR)
494
+
495
+ const pnanovdb_buf_t buf = accessor.buf;
496
+ const pnanovdb_vec3_t uvw_pnano{uvw[0], uvw[1], uvw[2]};
497
+
498
+ if (sampling_mode == CLOSEST)
499
+ {
500
+ const pnanovdb_coord_t ijk = vec3_round_to_coord(uvw_pnano);
501
+ return accessor.read_single(ijk);
502
+ }
503
+ else if (sampling_mode == LINEAR)
251
504
  {
252
505
  // NB. linear sampling is not used on int volumes
253
506
  constexpr pnanovdb_coord_t OFFSETS[] = {
254
- { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
507
+ {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1},
255
508
  };
256
509
 
257
- const pnanovdb_vec3_t ijk_base{ floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z) };
258
- const pnanovdb_vec3_t ijk_frac{ uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z };
259
- const pnanovdb_coord_t ijk{ (pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y, (pnanovdb_int32_t)ijk_base.z };
510
+ const pnanovdb_vec3_t ijk_base{floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z)};
511
+ const pnanovdb_vec3_t ijk_frac{uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z};
512
+ const pnanovdb_coord_t ijk{(pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y,
513
+ (pnanovdb_int32_t)ijk_base.z};
260
514
 
261
- pnanovdb_readaccessor_t accessor;
262
- pnanovdb_readaccessor_init(PNANOVDB_REF(accessor), root);
263
- float val = 0.0f;
264
- const float wx[2]{ 1 - ijk_frac.x, ijk_frac.x };
265
- const float wy[2]{ 1 - ijk_frac.y, ijk_frac.y };
266
- const float wz[2]{ 1 - ijk_frac.z, ijk_frac.z };
267
-
268
- const float sign_dx[8] = {-1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
269
- const float sign_dy[8] = {-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f};
270
- const float sign_dz[8] = {-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f};
271
-
272
- float dfdx = 0.0f;
273
- float dfdy = 0.0f;
274
- float dfdz = 0.0f;
515
+ accessor.init_cache();
516
+ T val = 0;
517
+ const float wx[2]{1 - ijk_frac.x, ijk_frac.x};
518
+ const float wy[2]{1 - ijk_frac.y, ijk_frac.y};
519
+ const float wz[2]{1 - ijk_frac.z, ijk_frac.z};
275
520
  for (int idx = 0; idx < 8; ++idx)
276
521
  {
277
- const pnanovdb_coord_t& offs = OFFSETS[idx];
522
+ const pnanovdb_coord_t &offs = OFFSETS[idx];
278
523
  const pnanovdb_coord_t ijk_shifted = pnanovdb_coord_add(ijk, offs);
279
- float v;
280
- pnano_read(v, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk_shifted));
281
- val = add(val, wx[offs.x] * wy[offs.y] * wz[offs.z] * v);
282
- dfdx = add(dfdx, wy[offs.y] * wz[offs.z] * sign_dx[idx] * v);
283
- dfdy = add(dfdy, wx[offs.x] * wz[offs.z] * sign_dy[idx] * v);
284
- dfdz = add(dfdz, wx[offs.x] * wy[offs.y] * sign_dz[idx] * v);
524
+ const T v = accessor.read_cache(ijk_shifted);
525
+
526
+ const vec3 signs(offs.x * 2 - 1, offs.y * 2 - 1, offs.z * 2 - 1);
527
+
528
+ const w_t w = wx[offs.x] * wy[offs.y] * wz[offs.z];
529
+ const w_grad_t grad_w(signs[0] * wy[offs.y] * wz[offs.z], signs[1] * wx[offs.x] * wz[offs.z],
530
+ signs[2] * wx[offs.x] * wy[offs.y]);
531
+
532
+ val = add(val, w * v);
533
+ grad += outer(v, grad_w);
285
534
  }
286
- grad = vec3(dfdx, dfdy, dfdz);
287
535
  return val;
288
536
  }
289
- return 0.0f;
537
+ return 0;
290
538
  }
291
539
 
292
- CUDA_CALLABLE inline void adj_volume_sample_grad_f(
293
- uint64_t id, vec3 uvw, int sampling_mode, vec3& grad, uint64_t& adj_id, vec3& adj_uvw, int& adj_sampling_mode, vec3& adj_grad, const float& adj_ret)
540
+ template <typename Accessor>
541
+ CUDA_CALLABLE inline void adj_volume_sample_grad(Accessor &accessor, vec3 uvw, int sampling_mode,
542
+ typename val_traits<typename Accessor::ValueType>::grad_t &grad,
543
+ vec3 &adj_uvw,
544
+ typename val_traits<typename Accessor::ValueType>::grad_t &adj_grad,
545
+ const typename Accessor::ValueType &adj_ret)
294
546
  {
295
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_FLOAT) return;
547
+ // TODO: accessor data gradients
296
548
 
297
- if (sampling_mode != volume::LINEAR) {
298
- return; // NOP
549
+ using T = typename Accessor::ValueType;
550
+ using grad_T = typename val_traits<T>::grad_t;
551
+ using w_t = typename val_traits<T>::scalar_t;
552
+ using w_grad_t = vec_t<3, w_t>;
553
+ using w_hess_t = mat_t<3, 3, w_t>;
554
+
555
+ if (!accessor.is_valid())
556
+ {
557
+ return;
299
558
  }
300
559
 
301
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
302
- const pnanovdb_root_handle_t root = volume::get_root(buf);
303
- const pnanovdb_vec3_t uvw_pnano{ uvw[0], uvw[1], uvw[2] };
560
+ const pnanovdb_buf_t buf = accessor.buf;
561
+ const pnanovdb_vec3_t uvw_pnano{uvw[0], uvw[1], uvw[2]};
562
+
563
+ if (sampling_mode != LINEAR)
564
+ {
565
+ const pnanovdb_coord_t ijk = vec3_round_to_coord(uvw_pnano);
566
+ accessor.adj_read_single(ijk, adj_ret);
567
+ return;
568
+ }
304
569
 
305
570
  constexpr pnanovdb_coord_t OFFSETS[] = {
306
- { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
571
+ {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1},
307
572
  };
308
573
 
309
- const pnanovdb_vec3_t ijk_base{ floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z) };
310
- const pnanovdb_vec3_t ijk_frac{ uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z };
311
- const pnanovdb_coord_t ijk{ (pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y, (pnanovdb_int32_t)ijk_base.z };
574
+ const pnanovdb_vec3_t ijk_base{floorf(uvw_pnano.x), floorf(uvw_pnano.y), floorf(uvw_pnano.z)};
575
+ const pnanovdb_vec3_t ijk_frac{uvw_pnano.x - ijk_base.x, uvw_pnano.y - ijk_base.y, uvw_pnano.z - ijk_base.z};
576
+ const pnanovdb_coord_t ijk{(pnanovdb_int32_t)ijk_base.x, (pnanovdb_int32_t)ijk_base.y,
577
+ (pnanovdb_int32_t)ijk_base.z};
312
578
 
313
- pnanovdb_readaccessor_t accessor;
314
- pnanovdb_readaccessor_init(PNANOVDB_REF(accessor), root);
315
- const float wx[2]{ 1 - ijk_frac.x, ijk_frac.x };
316
- const float wy[2]{ 1 - ijk_frac.y, ijk_frac.y };
317
- const float wz[2]{ 1 - ijk_frac.z, ijk_frac.z };
318
- const float sign_dx[8] = {-1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
319
- const float sign_dy[8] = {-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f};
320
- const float sign_dz[8] = {-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f};
321
-
322
- float dfdxdy = 0.0f;
323
- float dfdxdz = 0.0f;
324
- float dfdydx = 0.0f;
325
- float dfdydz = 0.0f;
326
- float dfdzdx = 0.0f;
327
- float dfdzdy = 0.0f;
328
- vec3 dphi(0,0,0);
579
+ accessor.init_cache();
580
+
581
+ const float wx[2]{1 - ijk_frac.x, ijk_frac.x};
582
+ const float wy[2]{1 - ijk_frac.y, ijk_frac.y};
583
+ const float wz[2]{1 - ijk_frac.z, ijk_frac.z};
329
584
  for (int idx = 0; idx < 8; ++idx)
330
585
  {
331
- const pnanovdb_coord_t& offs = OFFSETS[idx];
586
+ const pnanovdb_coord_t &offs = OFFSETS[idx];
332
587
  const pnanovdb_coord_t ijk_shifted = pnanovdb_coord_add(ijk, offs);
333
- float v;
334
- pnano_read(v, buf, PNANOVDB_REF(accessor), PNANOVDB_REF(ijk_shifted));
588
+ const T v = accessor.read_cache(ijk_shifted);
589
+
335
590
  const vec3 signs(offs.x * 2 - 1, offs.y * 2 - 1, offs.z * 2 - 1);
336
- const vec3 grad_w(signs[0] * wy[offs.y] * wz[offs.z], signs[1] * wx[offs.x] * wz[offs.z], signs[2] * wx[offs.x] * wy[offs.y]);
337
- dphi = add(dphi, mul(v, grad_w));
338
591
 
339
- dfdxdy = add(dfdxdy, signs[1] * wz[offs.z] * sign_dx[idx] * v);
340
- dfdxdz = add(dfdxdz, wy[offs.y] * signs[2] * sign_dx[idx] * v);
592
+ const w_t w = wx[offs.x] * wy[offs.y] * wz[offs.z];
593
+ const w_grad_t grad_w(signs[0] * wy[offs.y] * wz[offs.z], signs[1] * wx[offs.x] * wz[offs.z],
594
+ signs[2] * wx[offs.x] * wy[offs.y]);
595
+ adj_uvw += vec3(mul(w_t(dot(v, adj_ret)), grad_w));
341
596
 
342
- dfdydx = add(dfdydx, signs[0] * wz[offs.z] * sign_dy[idx] * v);
343
- dfdydz = add(dfdydz, wx[offs.x] * signs[2] * sign_dy[idx] * v);
597
+ const w_hess_t hess_w(0.0, signs[1] * signs[0] * wz[offs.z], signs[2] * signs[0] * wy[offs.y],
598
+ signs[0] * signs[1] * wz[offs.z], 0.0, signs[2] * signs[1] * wx[offs.x],
599
+ signs[0] * signs[2] * wy[offs.y], signs[1] * signs[2] * wx[offs.x], 0.0);
600
+ adj_uvw += vec3(mul(mul(v, adj_grad), hess_w));
344
601
 
345
- dfdzdx = add(dfdzdx, signs[0] * wy[offs.y] * sign_dz[idx] * v);
346
- dfdzdy = add(dfdzdy, wx[offs.x] * signs[1] * sign_dz[idx] * v);
602
+ const T adj_v = w * adj_ret + val_traits<T>::rmul(adj_grad, grad_w);
603
+ accessor.adj_read_cache(ijk_shifted, adj_v);
347
604
  }
605
+ }
606
+
607
+ } // namespace volume
608
+ // namespace volume
609
+
610
+ // exposed kernel builtins
611
+
612
+ // volume_sample
348
613
 
349
- adj_uvw += mul(dphi, adj_ret);
350
- adj_uvw[0] += adj_grad[1] * dfdydx + adj_grad[2] * dfdzdx;
351
- adj_uvw[1] += adj_grad[0] * dfdxdy + adj_grad[2] * dfdzdy;
352
- adj_uvw[2] += adj_grad[0] * dfdxdz + adj_grad[1] * dfdydz;
614
+ template <typename T> CUDA_CALLABLE inline T volume_sample(uint64_t id, vec3 uvw, int sampling_mode)
615
+ {
616
+ volume::leaf_value_accessor<T> accessor(volume::id_to_buffer(id));
617
+ return volume::volume_sample(accessor, uvw, sampling_mode);
353
618
  }
354
619
 
355
- CUDA_CALLABLE inline float volume_lookup_f(uint64_t id, int32_t i, int32_t j, int32_t k)
620
+ template <typename T>
621
+ CUDA_CALLABLE inline void adj_volume_sample(uint64_t id, vec3 uvw, int sampling_mode, uint64_t &adj_id, vec3 &adj_uvw,
622
+ int &adj_sampling_mode, const T &adj_ret)
356
623
  {
357
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_FLOAT) return 0.f;
624
+ volume::leaf_value_accessor<T> accessor(volume::id_to_buffer(id));
625
+ volume::adj_volume_sample(accessor, uvw, sampling_mode, adj_uvw, adj_ret);
626
+ }
358
627
 
359
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
360
- const pnanovdb_root_handle_t root = volume::get_root(buf);
628
+ template <typename T>
629
+ CUDA_CALLABLE inline T volume_sample_grad(uint64_t id, vec3 uvw, int sampling_mode,
630
+ typename volume::val_traits<T>::grad_t &grad)
631
+ {
632
+ volume::leaf_value_accessor<T> accessor(volume::id_to_buffer(id));
633
+ return volume::volume_sample_grad(accessor, uvw, sampling_mode, grad);
634
+ }
361
635
 
362
- const pnanovdb_coord_t ijk{ i, j, k };
363
- float val;
364
- pnano_read(val, buf, root, PNANOVDB_REF(ijk));
365
- return val;
636
+ template <typename T>
637
+ CUDA_CALLABLE inline void adj_volume_sample_grad(uint64_t id, vec3 uvw, int sampling_mode,
638
+ typename volume::val_traits<T>::grad_t &grad, uint64_t &adj_id,
639
+ vec3 &adj_uvw, int &adj_sampling_mode,
640
+ typename volume::val_traits<T>::grad_t &adj_grad, const T &adj_ret)
641
+ {
642
+ volume::leaf_value_accessor<T> accessor(volume::id_to_buffer(id));
643
+ volume::adj_volume_sample_grad(accessor, uvw, sampling_mode, grad, adj_uvw, adj_grad, adj_ret);
366
644
  }
367
645
 
368
- CUDA_CALLABLE inline int32_t volume_lookup_i(uint64_t id, int32_t i, int32_t j, int32_t k)
646
+ // Sampling a float volume at the given index-space coordinates, uvw can be fractional
647
+ CUDA_CALLABLE inline float volume_sample_f(uint64_t id, vec3 uvw, int sampling_mode)
369
648
  {
370
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_INT32) return 0;
649
+ return volume_sample<float>(id, uvw, sampling_mode);
650
+ }
371
651
 
372
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
373
- const pnanovdb_root_handle_t root = volume::get_root(buf);
652
+ // Sampling an int volume at the given index-space coordinates, uvw can be fractional
653
+ CUDA_CALLABLE inline int32_t volume_sample_i(uint64_t id, vec3 uvw)
654
+ {
655
+ return volume_sample<int32_t>(id, uvw, volume::CLOSEST);
656
+ }
374
657
 
375
- const pnanovdb_coord_t ijk{ i, j, k };
376
- int32_t val;
377
- pnano_read(val, buf, root, PNANOVDB_REF(ijk));
378
- return val;
658
+ // Sampling a vector volume at the given index-space coordinates, uvw can be fractional
659
+ CUDA_CALLABLE inline vec3 volume_sample_v(uint64_t id, vec3 uvw, int sampling_mode)
660
+ {
661
+ return volume_sample<vec3>(id, uvw, sampling_mode);
379
662
  }
380
663
 
381
- CUDA_CALLABLE inline vec3 volume_lookup_v(uint64_t id, int32_t i, int32_t j, int32_t k)
664
+ CUDA_CALLABLE inline void adj_volume_sample_f(uint64_t id, vec3 uvw, int sampling_mode, uint64_t &adj_id, vec3 &adj_uvw,
665
+ int &adj_sampling_mode, const float &adj_ret)
666
+ {
667
+ adj_volume_sample(id, uvw, sampling_mode, adj_id, adj_uvw, adj_sampling_mode, adj_ret);
668
+ }
669
+
670
+ CUDA_CALLABLE inline void adj_volume_sample_v(uint64_t id, vec3 uvw, int sampling_mode, uint64_t &adj_id, vec3 &adj_uvw,
671
+ int &adj_sampling_mode, const vec3 &adj_ret)
672
+ {
673
+ adj_volume_sample(id, uvw, sampling_mode, adj_id, adj_uvw, adj_sampling_mode, adj_ret);
674
+ }
675
+
676
+ CUDA_CALLABLE inline void adj_volume_sample_i(uint64_t id, vec3 uvw, uint64_t &adj_id, vec3 &adj_uvw,
677
+ const int32_t &adj_ret)
678
+ {
679
+ // NOP
680
+ }
681
+
682
+ // Sampling the volume at the given index-space coordinates, uvw can be fractional
683
+ CUDA_CALLABLE inline float volume_sample_grad_f(uint64_t id, vec3 uvw, int sampling_mode, vec3 &grad)
684
+ {
685
+ return volume_sample_grad<float>(id, uvw, sampling_mode, grad);
686
+ }
687
+
688
+ CUDA_CALLABLE inline void adj_volume_sample_grad_f(uint64_t id, vec3 uvw, int sampling_mode, vec3 &grad,
689
+ uint64_t &adj_id, vec3 &adj_uvw, int &adj_sampling_mode,
690
+ vec3 &adj_grad, const float &adj_ret)
691
+ {
692
+ adj_volume_sample_grad<float>(id, uvw, sampling_mode, grad, adj_id, adj_uvw, adj_sampling_mode, adj_grad, adj_ret);
693
+ }
694
+
695
+ // volume_sample_index
696
+
697
+ template <typename T>
698
+ CUDA_CALLABLE inline T volume_sample_index(uint64_t id, vec3 uvw, int sampling_mode, const array_t<T> &voxel_data,
699
+ const T &background)
700
+ {
701
+ volume::index_value_accessor<T> accessor(volume::id_to_buffer(id), voxel_data, background);
702
+ return volume::volume_sample(accessor, uvw, sampling_mode);
703
+ }
704
+
705
+ template <typename T>
706
+ CUDA_CALLABLE inline void adj_volume_sample_index(uint64_t id, vec3 uvw, int sampling_mode,
707
+ const array_t<T> &voxel_data, const T &background, uint64_t &adj_id,
708
+ vec3 &adj_uvw, int &adj_sampling_mode, array_t<T> &adj_voxel_data,
709
+ T &adj_background, const T &adj_ret)
382
710
  {
383
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_VEC3F) return vec3(0.f);
711
+ volume::index_value_accessor<T> accessor(volume::id_to_buffer(id), voxel_data, background, &adj_background);
712
+ volume::adj_volume_sample(accessor, uvw, sampling_mode, adj_uvw, adj_ret);
713
+ }
714
+
715
+ template <typename T>
716
+ CUDA_CALLABLE inline T volume_sample_grad_index(uint64_t id, vec3 uvw, int sampling_mode, const array_t<T> &voxel_data,
717
+ const T &background, typename volume::val_traits<T>::grad_t &grad)
718
+ {
719
+ volume::index_value_accessor<T> accessor(volume::id_to_buffer(id), voxel_data, background);
720
+ return volume::volume_sample_grad(accessor, uvw, sampling_mode, grad);
721
+ }
722
+
723
+ template <typename T>
724
+ CUDA_CALLABLE inline void adj_volume_sample_grad_index(
725
+ uint64_t id, vec3 uvw, int sampling_mode, const array_t<T> &voxel_data, const T &background,
726
+ typename volume::val_traits<T>::grad_t &grad, uint64_t &adj_id, vec3 &adj_uvw, int &adj_sampling_mode,
727
+ array_t<T> &adj_voxel_data, T &adj_background, typename volume::val_traits<T>::grad_t &adj_grad, const T &adj_ret)
728
+ {
729
+ volume::index_value_accessor<T> accessor(volume::id_to_buffer(id), voxel_data, background, &adj_background);
730
+ volume::adj_volume_sample_grad(accessor, uvw, sampling_mode, grad, adj_uvw, adj_grad, adj_ret);
731
+ }
732
+
733
+ // volume_lookup
734
+
735
+ template <typename T> CUDA_CALLABLE inline T volume_lookup(uint64_t id, int32_t i, int32_t j, int32_t k)
736
+ {
737
+ using traits = volume::pnano_traits<T>;
384
738
 
385
739
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
740
+ if (volume::get_grid_type(buf) != traits::GRID_TYPE)
741
+ return 0;
742
+
386
743
  const pnanovdb_root_handle_t root = volume::get_root(buf);
387
744
 
388
- const pnanovdb_coord_t ijk{ i, j, k };
389
- vec3 val;
390
- pnano_read(val, buf, root, PNANOVDB_REF(ijk));
745
+ const pnanovdb_coord_t ijk{i, j, k};
746
+ T val;
747
+ volume::pnano_read(val, buf, root, PNANOVDB_REF(ijk));
391
748
  return val;
392
749
  }
393
750
 
394
- CUDA_CALLABLE inline void adj_volume_lookup_f(
395
- uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t& adj_id, int32_t& adj_i, int32_t& adj_j, int32_t& adj_k, const float& adj_ret)
751
+ template <typename T>
752
+ CUDA_CALLABLE inline void adj_volume_lookup(uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t &adj_id,
753
+ int32_t &adj_i, int32_t &adj_j, int32_t &adj_k, const T &adj_ret)
396
754
  {
397
- // NOP
755
+ // NOP -- adjoint of grid values is not available
756
+ }
757
+
758
+ CUDA_CALLABLE inline float volume_lookup_f(uint64_t id, int32_t i, int32_t j, int32_t k)
759
+ {
760
+ return volume_lookup<float>(id, i, j, k);
398
761
  }
399
762
 
400
- CUDA_CALLABLE inline void adj_volume_lookup_i(
401
- uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t& adj_id, int32_t& adj_i, int32_t& adj_j, int32_t& adj_k, const int32_t& adj_ret)
763
+ CUDA_CALLABLE inline int32_t volume_lookup_i(uint64_t id, int32_t i, int32_t j, int32_t k)
402
764
  {
403
- // NOP
765
+ return volume_lookup<int32_t>(id, i, j, k);
404
766
  }
405
767
 
406
- CUDA_CALLABLE inline void adj_volume_lookup_v(
407
- uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t& adj_id, int32_t& adj_i, int32_t& adj_j, int32_t& adj_k, const vec3& adj_ret)
768
+ CUDA_CALLABLE inline vec3 volume_lookup_v(uint64_t id, int32_t i, int32_t j, int32_t k)
408
769
  {
409
- // NOP
770
+ return volume_lookup<vec3>(id, i, j, k);
410
771
  }
411
772
 
412
- CUDA_CALLABLE inline void volume_store_f(uint64_t id, int32_t i, int32_t j, int32_t k, const float& value)
773
+ CUDA_CALLABLE inline void adj_volume_lookup_f(uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t &adj_id,
774
+ int32_t &adj_i, int32_t &adj_j, int32_t &adj_k, const float &adj_ret)
413
775
  {
414
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_FLOAT) return;
776
+ adj_volume_lookup(id, i, j, k, adj_id, adj_i, adj_j, adj_k, adj_ret);
777
+ }
415
778
 
779
+ CUDA_CALLABLE inline void adj_volume_lookup_i(uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t &adj_id,
780
+ int32_t &adj_i, int32_t &adj_j, int32_t &adj_k, const int32_t &adj_ret)
781
+ {
782
+ adj_volume_lookup(id, i, j, k, adj_id, adj_i, adj_j, adj_k, adj_ret);
783
+ }
784
+
785
+ CUDA_CALLABLE inline void adj_volume_lookup_v(uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t &adj_id,
786
+ int32_t &adj_i, int32_t &adj_j, int32_t &adj_k, const vec3 &adj_ret)
787
+ {
788
+ adj_volume_lookup(id, i, j, k, adj_id, adj_i, adj_j, adj_k, adj_ret);
789
+ }
790
+
791
+ CUDA_CALLABLE inline int32_t volume_lookup_index(uint64_t id, int32_t i, int32_t j, int32_t k)
792
+ {
416
793
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
417
794
  const pnanovdb_root_handle_t root = volume::get_root(buf);
795
+ const pnanovdb_grid_type_t grid_type = volume::get_grid_type(buf);
796
+
797
+ const pnanovdb_coord_t ijk{i, j, k};
798
+
799
+ pnanovdb_uint32_t level;
800
+ const pnanovdb_address_t address =
801
+ pnanovdb_root_get_value_address_and_level(grid_type, buf, root, PNANOVDB_REF(ijk), PNANOVDB_REF(level));
802
+
803
+ if (level == 0)
804
+ {
805
+ pnanovdb_uint64_t voxel_index = volume::get_grid_voxel_index(grid_type, buf, address, ijk);
418
806
 
419
- const pnanovdb_coord_t ijk{ i, j, k };
420
- const pnanovdb_address_t address = pnanovdb_root_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, root, PNANOVDB_REF(ijk));
421
- pnanovdb_write_float(buf, address, value);
807
+ return static_cast<int32_t>(voxel_index) - 1;
808
+ }
809
+ return -1;
422
810
  }
423
811
 
424
- CUDA_CALLABLE inline void adj_volume_store_f(
425
- uint64_t id, int32_t i, int32_t j, int32_t k, const float& value,
426
- uint64_t& adj_id, int32_t& adj_i, int32_t& adj_j, int32_t& adj_k, float& adj_value)
812
+ CUDA_CALLABLE inline void adj_volume_lookup_index(uint64_t id, int32_t i, int32_t j, int32_t k, uint64_t &adj_id,
813
+ int32_t &adj_i, int32_t &adj_j, int32_t &adj_k, const vec3 &adj_ret)
427
814
  {
428
- adj_value += volume_lookup_f(id, i, j, k);
815
+ // NOP
429
816
  }
430
817
 
431
- CUDA_CALLABLE inline void volume_store_v(uint64_t id, int32_t i, int32_t j, int32_t k, const vec3& value)
818
+ // volume_store
819
+
820
+ template <typename T>
821
+ CUDA_CALLABLE inline void volume_store(uint64_t id, int32_t i, int32_t j, int32_t k, const T &value)
432
822
  {
433
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_VEC3F) return;
823
+ using traits = volume::pnano_traits<T>;
434
824
 
435
825
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
826
+ if (volume::get_grid_type(buf) != traits::GRID_TYPE)
827
+ return;
828
+
436
829
  const pnanovdb_root_handle_t root = volume::get_root(buf);
830
+ const pnanovdb_coord_t ijk{i, j, k};
831
+
832
+ pnanovdb_uint32_t level;
833
+ const pnanovdb_address_t address =
834
+ pnanovdb_root_get_value_address_and_level(traits::GRID_TYPE, buf, root, PNANOVDB_REF(ijk), PNANOVDB_REF(level));
437
835
 
438
- const pnanovdb_coord_t ijk{ i, j, k };
439
- const pnanovdb_address_t address = pnanovdb_root_get_value_address(PNANOVDB_GRID_TYPE_VEC3F, buf, root, PNANOVDB_REF(ijk));
440
- const pnanovdb_vec3_t v{ value[0], value[1], value[2] };
441
- pnanovdb_write_vec3(buf, address, &v);
836
+ if (level == 0)
837
+ {
838
+ // only write at at leaf level (prevent modifying background value)
839
+ // TODO is this the intended semantics? or should be allow writing to background?
840
+ volume::pnano_write(value, buf, address);
841
+ }
442
842
  }
443
843
 
444
- CUDA_CALLABLE inline void adj_volume_store_v(
445
- uint64_t id, int32_t i, int32_t j, int32_t k, const vec3& value,
446
- uint64_t& adj_id, int32_t& adj_i, int32_t& adj_j, int32_t& adj_k, vec3& adj_value)
844
+ template <typename T>
845
+ CUDA_CALLABLE inline void adj_volume_store(uint64_t id, int32_t i, int32_t j, int32_t k, const T &value,
846
+ uint64_t &adj_id, int32_t &adj_i, int32_t &adj_j, int32_t &adj_k,
847
+ T &adj_value)
447
848
  {
448
- adj_value = add(adj_value, volume_lookup_v(id, i, j, k));
849
+ // NOP -- adjoint of grid values is not available
449
850
  }
450
851
 
451
- CUDA_CALLABLE inline void volume_store_i(uint64_t id, int32_t i, int32_t j, int32_t k, const int32_t& value)
852
+ CUDA_CALLABLE inline void volume_store_f(uint64_t id, int32_t i, int32_t j, int32_t k, const float &value)
452
853
  {
453
- if (volume::get_grid_type(volume::id_to_buffer(id)) != PNANOVDB_GRID_TYPE_INT32) return;
854
+ volume_store(id, i, j, k, value);
855
+ }
454
856
 
455
- const pnanovdb_buf_t buf = volume::id_to_buffer(id);
456
- const pnanovdb_root_handle_t root = volume::get_root(buf);
857
+ CUDA_CALLABLE inline void adj_volume_store_f(uint64_t id, int32_t i, int32_t j, int32_t k, const float &value,
858
+ uint64_t &adj_id, int32_t &adj_i, int32_t &adj_j, int32_t &adj_k,
859
+ float &adj_value)
860
+ {
861
+ adj_volume_store(id, i, j, k, value, adj_id, adj_i, adj_j, adj_k, adj_value);
862
+ }
863
+
864
+ CUDA_CALLABLE inline void volume_store_v(uint64_t id, int32_t i, int32_t j, int32_t k, const vec3 &value)
865
+ {
866
+ volume_store(id, i, j, k, value);
867
+ }
457
868
 
458
- const pnanovdb_coord_t ijk{ i, j, k };
459
- const pnanovdb_address_t address = pnanovdb_root_get_value_address(PNANOVDB_GRID_TYPE_INT32, buf, root, PNANOVDB_REF(ijk));
460
- pnanovdb_write_int32(buf, address, value);
869
+ CUDA_CALLABLE inline void adj_volume_store_v(uint64_t id, int32_t i, int32_t j, int32_t k, const vec3 &value,
870
+ uint64_t &adj_id, int32_t &adj_i, int32_t &adj_j, int32_t &adj_k,
871
+ vec3 &adj_value)
872
+ {
873
+ adj_volume_store(id, i, j, k, value, adj_id, adj_i, adj_j, adj_k, adj_value);
874
+ }
875
+
876
+ CUDA_CALLABLE inline void volume_store_i(uint64_t id, int32_t i, int32_t j, int32_t k, const int32_t &value)
877
+ {
878
+ volume_store(id, i, j, k, value);
461
879
  }
462
880
 
463
- CUDA_CALLABLE inline void adj_volume_store_i(
464
- uint64_t id, int32_t i, int32_t j, int32_t k, const int32_t& value,
465
- uint64_t& adj_id, int32_t& adj_i, int32_t& adj_j, int32_t& adj_k, int32_t& adj_value)
881
+ CUDA_CALLABLE inline void adj_volume_store_i(uint64_t id, int32_t i, int32_t j, int32_t k, const int32_t &value,
882
+ uint64_t &adj_id, int32_t &adj_i, int32_t &adj_j, int32_t &adj_k,
883
+ int32_t &adj_value)
466
884
  {
467
- adj_value = add(adj_value, volume_lookup_i(id, i, j, k));
885
+ adj_volume_store(id, i, j, k, value, adj_id, adj_i, adj_j, adj_k, adj_value);
468
886
  }
469
887
 
470
888
  // Transform position from index space to world space
471
889
  CUDA_CALLABLE inline vec3 volume_index_to_world(uint64_t id, vec3 uvw)
472
890
  {
473
891
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
474
- const pnanovdb_grid_handle_t grid = { 0u };
475
- const pnanovdb_vec3_t pos{ uvw[0], uvw[1], uvw[2] };
892
+ const pnanovdb_grid_handle_t grid = {0u};
893
+ const pnanovdb_vec3_t pos{uvw[0], uvw[1], uvw[2]};
476
894
  const pnanovdb_vec3_t xyz = pnanovdb_grid_index_to_worldf(buf, grid, PNANOVDB_REF(pos));
477
- return { xyz.x, xyz.y, xyz.z };
895
+ return {xyz.x, xyz.y, xyz.z};
478
896
  }
479
897
 
480
898
  // Transform position from world space to index space
481
899
  CUDA_CALLABLE inline vec3 volume_world_to_index(uint64_t id, vec3 xyz)
482
900
  {
483
901
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
484
- const pnanovdb_grid_handle_t grid = { 0u };
485
- const pnanovdb_vec3_t pos{ xyz[0], xyz[1], xyz[2] };
902
+ const pnanovdb_grid_handle_t grid = {0u};
903
+ const pnanovdb_vec3_t pos{xyz[0], xyz[1], xyz[2]};
486
904
  const pnanovdb_vec3_t uvw = pnanovdb_grid_world_to_indexf(buf, grid, PNANOVDB_REF(pos));
487
- return { uvw.x, uvw.y, uvw.z };
905
+ return {uvw.x, uvw.y, uvw.z};
488
906
  }
489
907
 
490
- CUDA_CALLABLE inline void adj_volume_index_to_world(uint64_t id, vec3 uvw, uint64_t& adj_id, vec3& adj_uvw, const vec3& adj_ret)
908
+ CUDA_CALLABLE inline void adj_volume_index_to_world(uint64_t id, vec3 uvw, uint64_t &adj_id, vec3 &adj_uvw,
909
+ const vec3 &adj_ret)
491
910
  {
492
911
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
493
- const pnanovdb_grid_handle_t grid = { 0u };
494
- const pnanovdb_vec3_t pos{ adj_ret[0], adj_ret[1], adj_ret[2] };
912
+ const pnanovdb_grid_handle_t grid = {0u};
913
+ const pnanovdb_vec3_t pos{adj_ret[0], adj_ret[1], adj_ret[2]};
495
914
  const pnanovdb_vec3_t xyz = pnanovdb_grid_index_to_world_dirf(buf, grid, PNANOVDB_REF(pos));
496
- adj_uvw = add(adj_uvw, vec3{ xyz.x, xyz.y, xyz.z });
915
+ adj_uvw = add(adj_uvw, vec3{xyz.x, xyz.y, xyz.z});
497
916
  }
498
917
 
499
- CUDA_CALLABLE inline void adj_volume_world_to_index(uint64_t id, vec3 xyz, uint64_t& adj_id, vec3& adj_xyz, const vec3& adj_ret)
918
+ CUDA_CALLABLE inline void adj_volume_world_to_index(uint64_t id, vec3 xyz, uint64_t &adj_id, vec3 &adj_xyz,
919
+ const vec3 &adj_ret)
500
920
  {
501
921
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
502
- const pnanovdb_grid_handle_t grid = { 0u };
503
- const pnanovdb_vec3_t pos{ adj_ret[0], adj_ret[1], adj_ret[2] };
922
+ const pnanovdb_grid_handle_t grid = {0u};
923
+ const pnanovdb_vec3_t pos{adj_ret[0], adj_ret[1], adj_ret[2]};
504
924
  const pnanovdb_vec3_t uvw = pnanovdb_grid_world_to_index_dirf(buf, grid, PNANOVDB_REF(pos));
505
- adj_xyz = add(adj_xyz, vec3{ uvw.x, uvw.y, uvw.z });
925
+ adj_xyz = add(adj_xyz, vec3{uvw.x, uvw.y, uvw.z});
506
926
  }
507
927
 
508
928
  // Transform direction from index space to world space
509
929
  CUDA_CALLABLE inline vec3 volume_index_to_world_dir(uint64_t id, vec3 uvw)
510
930
  {
511
931
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
512
- const pnanovdb_grid_handle_t grid = { 0u };
513
- const pnanovdb_vec3_t pos{ uvw[0], uvw[1], uvw[2] };
932
+ const pnanovdb_grid_handle_t grid = {0u};
933
+ const pnanovdb_vec3_t pos{uvw[0], uvw[1], uvw[2]};
514
934
  const pnanovdb_vec3_t xyz = pnanovdb_grid_index_to_world_dirf(buf, grid, PNANOVDB_REF(pos));
515
- return { xyz.x, xyz.y, xyz.z };
935
+ return {xyz.x, xyz.y, xyz.z};
516
936
  }
517
937
 
518
938
  // Transform direction from world space to index space
519
939
  CUDA_CALLABLE inline vec3 volume_world_to_index_dir(uint64_t id, vec3 xyz)
520
940
  {
521
941
  const pnanovdb_buf_t buf = volume::id_to_buffer(id);
522
- const pnanovdb_grid_handle_t grid = { 0u };
523
- const pnanovdb_vec3_t pos{ xyz[0], xyz[1], xyz[2] };
942
+ const pnanovdb_grid_handle_t grid = {0u};
943
+ const pnanovdb_vec3_t pos{xyz[0], xyz[1], xyz[2]};
524
944
  const pnanovdb_vec3_t uvw = pnanovdb_grid_world_to_index_dirf(buf, grid, PNANOVDB_REF(pos));
525
- return { uvw.x, uvw.y, uvw.z };
945
+ return {uvw.x, uvw.y, uvw.z};
526
946
  }
527
947
 
528
- CUDA_CALLABLE inline void adj_volume_index_to_world_dir(uint64_t id, vec3 uvw, uint64_t& adj_id, vec3& adj_uvw, const vec3& adj_ret)
948
+ CUDA_CALLABLE inline void adj_volume_index_to_world_dir(uint64_t id, vec3 uvw, uint64_t &adj_id, vec3 &adj_uvw,
949
+ const vec3 &adj_ret)
529
950
  {
530
951
  adj_volume_index_to_world(id, uvw, adj_id, adj_uvw, adj_ret);
531
952
  }
532
953
 
533
- CUDA_CALLABLE inline void adj_volume_world_to_index_dir(uint64_t id, vec3 xyz, uint64_t& adj_id, vec3& adj_xyz, const vec3& adj_ret)
954
+ CUDA_CALLABLE inline void adj_volume_world_to_index_dir(uint64_t id, vec3 xyz, uint64_t &adj_id, vec3 &adj_xyz,
955
+ const vec3 &adj_ret)
534
956
  {
535
957
  adj_volume_world_to_index(id, xyz, adj_id, adj_xyz, adj_ret);
536
958
  }