warp-lang 1.1.0__py3-none-win_amd64.whl → 1.2.0__py3-none-win_amd64.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/warp-clang.dll +0 -0
  2. warp/bin/warp.dll +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 +418 -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 +514 -77
  211. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/METADATA +57 -30
  212. warp_lang-1.2.0.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.0.dist-info}/LICENSE.md +0 -0
  217. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/WHEEL +0 -0
  218. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/top_level.txt +0 -0
@@ -10,8 +10,23 @@ struct BuildGridParams {
10
10
  char name[256] = "";
11
11
  };
12
12
 
13
+ template<>
14
+ struct BuildGridParams<nanovdb::ValueIndex> {
15
+ double voxel_size = 1.0;
16
+ nanovdb::ValueIndex background_value;
17
+ nanovdb::Vec3d translation{0.0, 0.0, 0.0};
18
+ char name[256] = "";
19
+ };
20
+
21
+ template<>
22
+ struct BuildGridParams<nanovdb::ValueOnIndex> {
23
+ double voxel_size = 1.0;
24
+ nanovdb::Vec3d translation{0.0, 0.0, 0.0};
25
+ char name[256] = "";
26
+ };
27
+
13
28
  template <typename BuildT>
14
- void build_grid_from_tiles(nanovdb::Grid<nanovdb::NanoTree<BuildT>> *&out_grid,
29
+ void build_grid_from_points(nanovdb::Grid<nanovdb::NanoTree<BuildT>> *&out_grid,
15
30
  size_t &out_grid_size,
16
31
  const void *points,
17
32
  size_t num_points,
@@ -0,0 +1,61 @@
1
+ /** Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
2
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ * and proprietary rights in and to this software, related documentation
4
+ * and any modifications thereto. Any use, reproduction, disclosure or
5
+ * distribution of this software and related documentation without an express
6
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+ */
8
+
9
+ #pragma once
10
+
11
+ #include "volume.h"
12
+
13
+ // Helper functions for cpp/cu files, not to be exposed to user kernels
14
+
15
+ namespace wp
16
+ {
17
+
18
+ namespace volume
19
+ {
20
+
21
+ inline CUDA_CALLABLE pnanovdb_leaf_handle_t get_leaf(const pnanovdb_buf_t buf, const uint32_t leaf_id)
22
+ {
23
+ const pnanovdb_tree_handle_t tree = get_tree(buf);
24
+ const uint64_t first_leaf_offset = pnanovdb_tree_get_node_offset_leaf(buf, tree);
25
+ const uint32_t leaf_stride = PNANOVDB_GRID_TYPE_GET(get_grid_type(buf), leaf_size);
26
+ return {pnanovdb_address_offset64(tree.address, first_leaf_offset + uint64_t(leaf_id) * leaf_stride)};
27
+ }
28
+
29
+ inline CUDA_CALLABLE pnanovdb_coord_t leaf_origin(const pnanovdb_buf_t buf, const pnanovdb_leaf_handle_t leaf)
30
+ {
31
+ pnanovdb_coord_t origin = pnanovdb_leaf_get_bbox_min(buf, leaf);
32
+ // mask out last three bits corresponding to voxel coordinates within leaf
33
+ constexpr uint32_t MASK = (1u << 3u) - 1u;
34
+ origin.x &= ~MASK;
35
+ origin.y &= ~MASK;
36
+ origin.z &= ~MASK;
37
+ return origin;
38
+ }
39
+
40
+ inline CUDA_CALLABLE uint64_t leaf_voxel_index(const pnanovdb_buf_t buf, const uint32_t leaf_id,
41
+ const pnanovdb_coord_t &ijk)
42
+ {
43
+ const uint32_t grid_type = get_grid_type(buf);
44
+
45
+ const pnanovdb_leaf_handle_t leaf = get_leaf(buf, leaf_id);
46
+ const pnanovdb_address_t value_address = pnanovdb_leaf_get_value_address(grid_type, buf, leaf, &ijk);
47
+ return volume::get_grid_voxel_index(grid_type, buf, value_address, ijk) - 1;
48
+ }
49
+
50
+ inline CUDA_CALLABLE pnanovdb_coord_t leaf_offset_to_local_coord(uint32_t offset)
51
+ {
52
+ pnanovdb_coord_t coord;
53
+ coord.x = (offset >> 6) & 7;
54
+ coord.y = (offset >> 3) & 7;
55
+ coord.z = (offset >> 0) & 7;
56
+ return coord;
57
+ }
58
+
59
+ } // namespace volume
60
+
61
+ } // namespace wp
warp/native/warp.cu CHANGED
@@ -18,6 +18,7 @@
18
18
  #include <iterator>
19
19
  #include <list>
20
20
  #include <map>
21
+ #include <string>
21
22
  #include <unordered_map>
22
23
  #include <unordered_set>
23
24
  #include <vector>
@@ -2536,7 +2537,7 @@ size_t cuda_compile_program(const char* cuda_src, int arch, const char* include_
2536
2537
  std::vector<const char*> opts;
2537
2538
  opts.push_back(arch_opt);
2538
2539
  opts.push_back(include_opt);
2539
- opts.push_back("--std=c++11");
2540
+ opts.push_back("--std=c++17");
2540
2541
 
2541
2542
  if (debug)
2542
2543
  {
@@ -2864,7 +2865,12 @@ void* cuda_graphics_register_gl_buffer(void* context, uint32_t gl_buffer, unsign
2864
2865
  ContextGuard guard(context);
2865
2866
 
2866
2867
  CUgraphicsResource *resource = new CUgraphicsResource;
2867
- check_cu(cuGraphicsGLRegisterBuffer_f(resource, gl_buffer, flags));
2868
+ bool success = check_cu(cuGraphicsGLRegisterBuffer_f(resource, gl_buffer, flags));
2869
+ if (!success)
2870
+ {
2871
+ delete resource;
2872
+ return NULL;
2873
+ }
2868
2874
 
2869
2875
  return resource;
2870
2876
  }
warp/native/warp.h CHANGED
@@ -97,20 +97,28 @@ extern "C"
97
97
  const void* a, const void* b, const void* c, void* d, float alpha, float beta,
98
98
  bool row_major_a, bool row_major_b, bool allow_tf32x3_arith, int batch_count);
99
99
 
100
- WP_API uint64_t volume_create_host(void* buf, uint64_t size);
101
- WP_API void volume_get_buffer_info_host(uint64_t id, void** buf, uint64_t* size);
102
- WP_API void volume_get_tiles_host(uint64_t id, void** buf, uint64_t* size);
100
+ WP_API uint64_t volume_create_host(void* buf, uint64_t size, bool copy, bool owner);
101
+ WP_API void volume_get_tiles_host(uint64_t id, void* buf);
102
+ WP_API void volume_get_voxels_host(uint64_t id, void* buf);
103
103
  WP_API void volume_destroy_host(uint64_t id);
104
104
 
105
- WP_API uint64_t volume_create_device(void* context, void* buf, uint64_t size);
105
+ WP_API uint64_t volume_create_device(void* context, void* buf, uint64_t size, bool copy, bool owner);
106
+ WP_API void volume_get_tiles_device(uint64_t id, void* buf);
107
+ WP_API void volume_get_voxels_device(uint64_t id, void* buf);
108
+ WP_API void volume_destroy_device(uint64_t id);
109
+
106
110
  WP_API uint64_t volume_f_from_tiles_device(void* context, void* points, int num_points, float voxel_size, float bg_value, float tx, float ty, float tz, bool points_in_world_space);
107
111
  WP_API uint64_t volume_v_from_tiles_device(void* context, void* points, int num_points, float voxel_size, float bg_value_x, float bg_value_y, float bg_value_z, float tx, float ty, float tz, bool points_in_world_space);
108
112
  WP_API uint64_t volume_i_from_tiles_device(void* context, void* points, int num_points, float voxel_size, int bg_value, float tx, float ty, float tz, bool points_in_world_space);
109
- WP_API void volume_get_buffer_info_device(uint64_t id, void** buf, uint64_t* size);
110
- WP_API void volume_get_tiles_device(uint64_t id, void** buf, uint64_t* size);
111
- WP_API void volume_destroy_device(uint64_t id);
113
+ WP_API uint64_t volume_index_from_tiles_device(void* context, void* points, int num_points, float voxel_size, float tx, float ty, float tz, bool points_in_world_space);
114
+ WP_API uint64_t volume_from_active_voxels_device(void* context, void* points, int num_points, float voxel_size, float tx, float ty, float tz, bool points_in_world_space);
112
115
 
116
+ WP_API void volume_get_buffer_info(uint64_t id, void** buf, uint64_t* size);
113
117
  WP_API void volume_get_voxel_size(uint64_t id, float* dx, float* dy, float* dz);
118
+ WP_API void volume_get_tile_and_voxel_count(uint64_t id, uint32_t& tile_count, uint64_t& voxel_count);
119
+ WP_API const char* volume_get_grid_info(uint64_t id, uint64_t *grid_size, uint32_t *grid_index, uint32_t *grid_count, float translation[3], float transform[9], char type_str[16]);
120
+ WP_API uint32_t volume_get_blind_data_count(uint64_t id);
121
+ WP_API const char* volume_get_blind_data_info(uint64_t id, uint32_t data_index, void** buf, uint64_t* value_count, uint32_t* value_size, char type_str[16]);
114
122
 
115
123
  WP_API uint64_t marching_cubes_create_device(void* context);
116
124
  WP_API void marching_cubes_destroy_device(uint64_t id);
@@ -469,6 +469,24 @@ def copy_rgb_frame(
469
469
  output_img[v, w, 2] = b / 255.0
470
470
 
471
471
 
472
+ @wp.kernel
473
+ def copy_rgb_frame_uint8(
474
+ input_img: wp.array(dtype=wp.uint8),
475
+ width: int,
476
+ height: int,
477
+ # outputs
478
+ output_img: wp.array(dtype=wp.uint8, ndim=3),
479
+ ):
480
+ w, v = wp.tid()
481
+ pixel = v * width + w
482
+ pixel *= 3
483
+ # flip vertically (OpenGL coordinates start at bottom)
484
+ v = height - v - 1
485
+ output_img[v, w, 0] = input_img[pixel + 0]
486
+ output_img[v, w, 1] = input_img[pixel + 1]
487
+ output_img[v, w, 2] = input_img[pixel + 2]
488
+
489
+
472
490
  @wp.kernel
473
491
  def copy_depth_frame(
474
492
  input_img: wp.array(dtype=wp.float32),
@@ -519,6 +537,34 @@ def copy_rgb_frame_tiles(
519
537
  output_img[tile, y, x, 2] = b / 255.0
520
538
 
521
539
 
540
+ @wp.kernel
541
+ def copy_rgb_frame_tiles_uint8(
542
+ input_img: wp.array(dtype=wp.uint8),
543
+ positions: wp.array(dtype=int, ndim=2),
544
+ screen_width: int,
545
+ screen_height: int,
546
+ tile_height: int,
547
+ # outputs
548
+ output_img: wp.array(dtype=wp.uint8, ndim=4),
549
+ ):
550
+ tile, x, y = wp.tid()
551
+ p = positions[tile]
552
+ qx = x + p[0]
553
+ qy = y + p[1]
554
+ pixel = qy * screen_width + qx
555
+ # flip vertically (OpenGL coordinates start at bottom)
556
+ y = tile_height - y - 1
557
+ if qx >= screen_width or qy >= screen_height:
558
+ output_img[tile, y, x, 0] = wp.uint8(0)
559
+ output_img[tile, y, x, 1] = wp.uint8(0)
560
+ output_img[tile, y, x, 2] = wp.uint8(0)
561
+ return # prevent out-of-bounds access
562
+ pixel *= 3
563
+ output_img[tile, y, x, 0] = input_img[pixel + 0]
564
+ output_img[tile, y, x, 1] = input_img[pixel + 1]
565
+ output_img[tile, y, x, 2] = input_img[pixel + 2]
566
+
567
+
522
568
  @wp.kernel
523
569
  def copy_depth_frame_tiles(
524
570
  input_img: wp.array(dtype=wp.float32),
@@ -577,6 +623,34 @@ def copy_rgb_frame_tile(
577
623
  output_img[tile, y, x, 2] = b / 255.0
578
624
 
579
625
 
626
+ @wp.kernel
627
+ def copy_rgb_frame_tile_uint8(
628
+ input_img: wp.array(dtype=wp.uint8),
629
+ offset_x: int,
630
+ offset_y: int,
631
+ screen_width: int,
632
+ screen_height: int,
633
+ tile_height: int,
634
+ # outputs
635
+ output_img: wp.array(dtype=wp.uint8, ndim=4),
636
+ ):
637
+ tile, x, y = wp.tid()
638
+ qx = x + offset_x
639
+ qy = y + offset_y
640
+ pixel = qy * screen_width + qx
641
+ # flip vertically (OpenGL coordinates start at bottom)
642
+ y = tile_height - y - 1
643
+ if qx >= screen_width or qy >= screen_height:
644
+ output_img[tile, y, x, 0] = wp.uint8(0)
645
+ output_img[tile, y, x, 1] = wp.uint8(0)
646
+ output_img[tile, y, x, 2] = wp.uint8(0)
647
+ return # prevent out-of-bounds access
648
+ pixel *= 3
649
+ output_img[tile, y, x, 0] = input_img[pixel + 0]
650
+ output_img[tile, y, x, 1] = input_img[pixel + 1]
651
+ output_img[tile, y, x, 2] = input_img[pixel + 2]
652
+
653
+
580
654
  def check_gl_error():
581
655
  from pyglet import gl
582
656
 
@@ -860,7 +934,7 @@ class OpenGLRenderer:
860
934
 
861
935
  def __init__(
862
936
  self,
863
- title="Warp sim",
937
+ title="Warp",
864
938
  scaling=1.0,
865
939
  fps=60,
866
940
  up_axis="Y",
@@ -881,11 +955,57 @@ class OpenGLRenderer:
881
955
  render_depth=False,
882
956
  axis_scale=1.0,
883
957
  vsync=False,
884
- headless=False,
958
+ headless=None,
885
959
  enable_backface_culling=True,
886
960
  enable_mouse_interaction=True,
887
961
  enable_keyboard_interaction=True,
888
962
  ):
963
+ """
964
+ Args:
965
+
966
+ title (str): The window title.
967
+ scaling (float): The scaling factor for the scene.
968
+ fps (int): The target frames per second.
969
+ up_axis (str): The up axis of the scene. Can be "X", "Y", or "Z".
970
+ screen_width (int): The width of the window.
971
+ screen_height (int): The height of the window.
972
+ near_plane (float): The near clipping plane.
973
+ far_plane (float): The far clipping plane.
974
+ camera_fov (float): The camera field of view in degrees.
975
+ camera_pos (tuple): The initial camera position.
976
+ camera_front (tuple): The initial camera front direction.
977
+ camera_up (tuple): The initial camera up direction.
978
+ background_color (tuple): The background color of the scene.
979
+ draw_grid (bool): Whether to draw a grid indicating the ground plane.
980
+ draw_sky (bool): Whether to draw a sky sphere.
981
+ draw_axis (bool): Whether to draw the coordinate system axes.
982
+ show_info (bool): Whether to overlay rendering information.
983
+ render_wireframe (bool): Whether to render scene shapes as wireframes.
984
+ render_depth (bool): Whether to show the depth buffer instead of the RGB image.
985
+ axis_scale (float): The scale of the coordinate system axes being rendered (only if ``draw_axis`` is True).
986
+ vsync (bool): Whether to enable vertical synchronization.
987
+ headless (bool): Whether to run in headless mode (no window is created). If None, the value is determined by the Pyglet configuration defined in ``pyglet.options["headless"]``.
988
+ enable_backface_culling (bool): Whether to enable backface culling.
989
+ enable_mouse_interaction (bool): Whether to enable mouse interaction.
990
+ enable_keyboard_interaction (bool): Whether to enable keyboard interaction.
991
+
992
+ Note:
993
+
994
+ :class:`OpenGLRenderer` requires Pyglet (version >= 2.0, known to work on 2.0.7) to be installed.
995
+
996
+ Headless rendering is supported via EGL on UNIX operating systems. To enable headless rendering, set the following pyglet options before importing ``warp.render``:
997
+
998
+ .. code-block:: python
999
+
1000
+ import pyglet
1001
+
1002
+ pyglet.options["headless"] = True
1003
+
1004
+ import warp.render
1005
+
1006
+ # OpenGLRenderer is instantiated with headless=True by default
1007
+ renderer = warp.render.OpenGLRenderer()
1008
+ """
889
1009
  try:
890
1010
  import pyglet
891
1011
 
@@ -917,10 +1037,15 @@ class OpenGLRenderer:
917
1037
  self.window = pyglet.window.Window(
918
1038
  width=screen_width, height=screen_height, caption=title, resizable=True, vsync=vsync, visible=not headless
919
1039
  )
1040
+ if headless is None:
1041
+ self.headless = pyglet.options.get("headless", False)
1042
+ else:
1043
+ self.headless = headless
920
1044
  self.app = pyglet.app
921
1045
 
922
- # making window current opengl rendering context
923
- self.window.switch_to()
1046
+ if not headless:
1047
+ # making window current opengl rendering context
1048
+ self.window.switch_to()
924
1049
 
925
1050
  self.screen_width, self.screen_height = self.window.get_framebuffer_size()
926
1051
 
@@ -1011,15 +1136,16 @@ class OpenGLRenderer:
1011
1136
  self._frame_fbo = None
1012
1137
  self._frame_pbo = None
1013
1138
 
1014
- self.window.push_handlers(on_draw=self._draw)
1015
- self.window.push_handlers(on_resize=self._window_resize_callback)
1016
- self.window.push_handlers(on_key_press=self._key_press_callback)
1139
+ if not headless:
1140
+ self.window.push_handlers(on_draw=self._draw)
1141
+ self.window.push_handlers(on_resize=self._window_resize_callback)
1142
+ self.window.push_handlers(on_key_press=self._key_press_callback)
1017
1143
 
1018
- self._key_handler = pyglet.window.key.KeyStateHandler()
1019
- self.window.push_handlers(self._key_handler)
1144
+ self._key_handler = pyglet.window.key.KeyStateHandler()
1145
+ self.window.push_handlers(self._key_handler)
1020
1146
 
1021
- self.window.on_mouse_scroll = self._scroll_callback
1022
- self.window.on_mouse_drag = self._mouse_drag_callback
1147
+ self.window.on_mouse_scroll = self._scroll_callback
1148
+ self.window.on_mouse_drag = self._mouse_drag_callback
1023
1149
 
1024
1150
  gl.glClearColor(*self.background_color, 1)
1025
1151
  gl.glEnable(gl.GL_DEPTH_TEST)
@@ -1232,20 +1358,21 @@ class OpenGLRenderer:
1232
1358
  width=400,
1233
1359
  )
1234
1360
 
1235
- # set up our own event handling so we can synchronously render frames
1236
- # by calling update() in a loop
1237
- from pyglet.window import Window
1361
+ if not headless:
1362
+ # set up our own event handling so we can synchronously render frames
1363
+ # by calling update() in a loop
1364
+ from pyglet.window import Window
1238
1365
 
1239
- Window._enable_event_queue = False
1366
+ Window._enable_event_queue = False
1240
1367
 
1241
- self.window.switch_to()
1242
- self.window.dispatch_pending_events()
1368
+ self.window.switch_to()
1369
+ self.window.dispatch_pending_events()
1243
1370
 
1244
- platform_event_loop = self.app.platform_event_loop
1245
- platform_event_loop.start()
1371
+ platform_event_loop = self.app.platform_event_loop
1372
+ platform_event_loop.start()
1246
1373
 
1247
- # start event loop
1248
- self.app.event_loop.dispatch_event("on_enter")
1374
+ # start event loop
1375
+ self.app.event_loop.dispatch_event("on_enter")
1249
1376
 
1250
1377
  @property
1251
1378
  def paused(self):
@@ -1266,8 +1393,9 @@ class OpenGLRenderer:
1266
1393
  def clear(self):
1267
1394
  from pyglet import gl
1268
1395
 
1269
- self.app.event_loop.dispatch_event("on_exit")
1270
- self.app.platform_event_loop.stop()
1396
+ if not self.headless:
1397
+ self.app.event_loop.dispatch_event("on_exit")
1398
+ self.app.platform_event_loop.stop()
1271
1399
 
1272
1400
  if self._instance_transform_gl_buffer is not None:
1273
1401
  try:
@@ -1334,7 +1462,8 @@ class OpenGLRenderer:
1334
1462
  """
1335
1463
  Set up tiled rendering where the render buffer is split into multiple tiles that can visualize
1336
1464
  different shape instances of the scene with different view and projection matrices.
1337
- See `get_pixels` which allows to retrieve the pixels of for each tile.
1465
+ See :meth:`get_pixels` which allows to retrieve the pixels of for each tile.
1466
+ See :meth:`update_tile` which allows to update the shape instances, projection matrix, view matrix, tile size, or tile position for a given tile.
1338
1467
 
1339
1468
  :param instances: A list of lists of shape instance ids. Each list of shape instance ids
1340
1469
  will be rendered into a separate tile.
@@ -1516,7 +1645,7 @@ class OpenGLRenderer:
1516
1645
  )
1517
1646
 
1518
1647
  if gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) != gl.GL_FRAMEBUFFER_COMPLETE:
1519
- print("Framebuffer is not complete!")
1648
+ print("Framebuffer is not complete!", flush=True)
1520
1649
  gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
1521
1650
  sys.exit(1)
1522
1651
 
@@ -1590,9 +1719,21 @@ class OpenGLRenderer:
1590
1719
  def camera_up(self, value):
1591
1720
  self.update_view_matrix(cam_up=value)
1592
1721
 
1593
- def update_view_matrix(self, cam_pos=None, cam_front=None, cam_up=None, stiffness=1.0):
1722
+ def compute_view_matrix(self, cam_pos, cam_front, cam_up):
1594
1723
  from pyglet.math import Mat4, Vec3
1595
1724
 
1725
+ model = np.array(self._model_matrix).reshape((4, 4))
1726
+ cp = model @ np.array([*cam_pos / self._scaling, 1.0])
1727
+ cf = model @ np.array([*cam_front / self._scaling, 1.0])
1728
+ up = model @ np.array([*cam_up / self._scaling, 0.0])
1729
+ cp = Vec3(*cp[:3])
1730
+ cf = Vec3(*cf[:3])
1731
+ up = Vec3(*up[:3])
1732
+ return np.array(Mat4.look_at(cp, cp + cf, up), dtype=np.float32)
1733
+
1734
+ def update_view_matrix(self, cam_pos=None, cam_front=None, cam_up=None, stiffness=1.0):
1735
+ from pyglet.math import Vec3
1736
+
1596
1737
  if cam_pos is not None:
1597
1738
  self._camera_pos = self._camera_pos * (1.0 - stiffness) + Vec3(*cam_pos) * stiffness
1598
1739
  if cam_front is not None:
@@ -1600,22 +1741,16 @@ class OpenGLRenderer:
1600
1741
  if cam_up is not None:
1601
1742
  self._camera_up = self._camera_up * (1.0 - stiffness) + Vec3(*cam_up) * stiffness
1602
1743
 
1603
- model = np.array(self._model_matrix).reshape((4, 4))
1604
- cp = model @ np.array([*self._camera_pos / self._scaling, 1.0])
1605
- cf = model @ np.array([*self._camera_front / self._scaling, 1.0])
1606
- up = model @ np.array([*self._camera_up / self._scaling, 0.0])
1607
- cp = Vec3(*cp[:3])
1608
- cf = Vec3(*cf[:3])
1609
- up = Vec3(*up[:3])
1610
- self._view_matrix = np.array(Mat4.look_at(cp, cp + cf, up))
1744
+ self._view_matrix = self.compute_view_matrix(self._camera_pos, self._camera_front, self._camera_up)
1611
1745
 
1612
- def compute_model_matrix(self, camera_axis: int, scaling: float):
1746
+ @staticmethod
1747
+ def compute_model_matrix(camera_axis: int, scaling: float):
1613
1748
  if camera_axis == 0:
1614
- return np.array((0, 0, scaling, 0, scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, 0, 1))
1749
+ return np.array((0, 0, scaling, 0, scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, 0, 1), dtype=np.float32)
1615
1750
  elif camera_axis == 2:
1616
- return np.array((-scaling, 0, 0, 0, 0, 0, scaling, 0, 0, scaling, 0, 0, 0, 0, 0, 1))
1751
+ return np.array((-scaling, 0, 0, 0, 0, 0, scaling, 0, 0, scaling, 0, 0, 0, 0, 0, 1), dtype=np.float32)
1617
1752
 
1618
- return np.array((scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, 1))
1753
+ return np.array((scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, 1), dtype=np.float32)
1619
1754
 
1620
1755
  def update_model_matrix(self, model_matrix: Optional[Mat44] = None):
1621
1756
  from pyglet import gl
@@ -1684,8 +1819,8 @@ class OpenGLRenderer:
1684
1819
  self._last_time = self.clock_time
1685
1820
  self._frame_speed = update_duration * 100.0
1686
1821
 
1687
- # self.app.event_loop.idle()
1688
- self.app.platform_event_loop.step(self._frame_dt * 1e-3)
1822
+ if not self.headless:
1823
+ self.app.platform_event_loop.step(self._frame_dt * 1e-3)
1689
1824
 
1690
1825
  if not self.skip_rendering:
1691
1826
  self._skip_frame_counter += 1
@@ -1705,13 +1840,17 @@ class OpenGLRenderer:
1705
1840
  update = 1.0 / update_duration
1706
1841
  self._fps_render = (1.0 - self._fps_alpha) * self._fps_render + self._fps_alpha * update
1707
1842
 
1708
- self.app.event_loop._redraw_windows(self._frame_dt * 1e-3)
1843
+ if not self.headless:
1844
+ self.app.event_loop._redraw_windows(self._frame_dt * 1e-3)
1845
+ else:
1846
+ self._draw()
1709
1847
 
1710
1848
  def _draw(self):
1711
1849
  from pyglet import gl
1712
1850
 
1713
- # catch key hold events
1714
- self._process_inputs()
1851
+ if not self.headless:
1852
+ # catch key hold events
1853
+ self._process_inputs()
1715
1854
 
1716
1855
  if self.enable_backface_culling:
1717
1856
  gl.glEnable(gl.GL_CULL_FACE)
@@ -1860,7 +1999,9 @@ Instances: {len(self._instances)}"""
1860
1999
 
1861
2000
  for i, viewport in enumerate(self._tile_viewports):
1862
2001
  projection_matrix_ptr = arr_pointer(self._tile_projection_matrices[i])
1863
- view_matrix_ptr = arr_pointer(self._tile_view_matrices[i] or self._view_matrix)
2002
+ view_matrix_ptr = arr_pointer(
2003
+ self._tile_view_matrices[i] if self._tile_view_matrices[i] is not None else self._view_matrix
2004
+ )
1864
2005
 
1865
2006
  gl.glViewport(*viewport)
1866
2007
  if self.draw_grid:
@@ -2289,7 +2430,7 @@ Instances: {len(self._instances)}"""
2289
2430
  self.clear()
2290
2431
  self.app.event_loop.exit()
2291
2432
 
2292
- def get_pixels(self, target_image: wp.array, split_up_tiles=True, mode="rgb"):
2433
+ def get_pixels(self, target_image: wp.array, split_up_tiles=True, mode="rgb", use_uint8=False):
2293
2434
  """
2294
2435
  Read the pixels from the frame buffer (RGB or depth are supported) into the given array.
2295
2436
 
@@ -2302,6 +2443,7 @@ Instances: {len(self._instances)}"""
2302
2443
  target_image (array): The array to read the pixels into. Must have float32 as dtype and be on a CUDA device.
2303
2444
  split_up_tiles (bool): Whether to split up the viewport into tiles, see :meth:`setup_tiled_rendering`.
2304
2445
  mode (str): can be either "rgb" or "depth"
2446
+ use_uint8 (bool): Whether to use uint8 as dtype in RGB mode for the target_image array and return values in the range [0, 255]. Otherwise, float32 is assumed as dtype with values in the range [0, 1].
2305
2447
 
2306
2448
  Returns:
2307
2449
  bool: Whether the pixels were successfully read.
@@ -2328,7 +2470,7 @@ Instances: {len(self._instances)}"""
2328
2470
  self._tile_width,
2329
2471
  channels,
2330
2472
  )
2331
- ), f"Shape of `target_image` array does not match {self.num_tiles} x {self.screen_height} x {self.screen_width} x {channels}"
2473
+ ), f"Shape of `target_image` array does not match {self.num_tiles} x {self._tile_height} x {self._tile_width} x {channels}"
2332
2474
  else:
2333
2475
  assert target_image.shape == (
2334
2476
  self.screen_height,
@@ -2355,9 +2497,7 @@ Instances: {len(self._instances)}"""
2355
2497
  gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
2356
2498
  gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0)
2357
2499
 
2358
- pbo_buffer = wp.RegisteredGLBuffer(
2359
- int(self._frame_pbo.value), self._device, wp.RegisteredGLBuffer.WRITE_DISCARD
2360
- )
2500
+ pbo_buffer = wp.RegisteredGLBuffer(int(self._frame_pbo.value), self._device, wp.RegisteredGLBuffer.READ_ONLY)
2361
2501
  screen_size = self.screen_height * self.screen_width
2362
2502
  if mode == "rgb":
2363
2503
  img = pbo_buffer.map(dtype=wp.uint8, shape=(screen_size * channels))
@@ -2368,7 +2508,7 @@ Instances: {len(self._instances)}"""
2368
2508
  positions = wp.array(self._tile_viewports, ndim=2, dtype=wp.int32, device=target_image.device)
2369
2509
  if mode == "rgb":
2370
2510
  wp.launch(
2371
- copy_rgb_frame_tiles,
2511
+ copy_rgb_frame_tiles_uint8 if use_uint8 else copy_rgb_frame_tiles,
2372
2512
  dim=(self.num_tiles, self._tile_width, self._tile_height),
2373
2513
  inputs=[img, positions, self.screen_width, self.screen_height, self._tile_height],
2374
2514
  outputs=[target_image],
@@ -2393,7 +2533,7 @@ Instances: {len(self._instances)}"""
2393
2533
  else:
2394
2534
  if mode == "rgb":
2395
2535
  wp.launch(
2396
- copy_rgb_frame,
2536
+ copy_rgb_frame_uint8 if use_uint8 else copy_rgb_frame,
2397
2537
  dim=(self.screen_width, self.screen_height),
2398
2538
  inputs=[img, self.screen_width, self.screen_height],
2399
2539
  outputs=[target_image],
@@ -3213,5 +3353,4 @@ Instances: {len(self._instances)}"""
3213
3353
 
3214
3354
 
3215
3355
  if __name__ == "__main__":
3216
- wp.init()
3217
3356
  renderer = OpenGLRenderer()
@@ -1288,6 +1288,7 @@ def dense_solve(
1288
1288
  n: int,
1289
1289
  L_start: int,
1290
1290
  b_start: int,
1291
+ A: wp.array(dtype=float),
1291
1292
  L: wp.array(dtype=float),
1292
1293
  b: wp.array(dtype=float),
1293
1294
  # outputs
@@ -1303,13 +1304,14 @@ def adj_dense_solve(
1303
1304
  n: int,
1304
1305
  L_start: int,
1305
1306
  b_start: int,
1307
+ A: wp.array(dtype=float),
1306
1308
  L: wp.array(dtype=float),
1307
1309
  b: wp.array(dtype=float),
1308
1310
  # outputs
1309
1311
  x: wp.array(dtype=float),
1310
1312
  tmp: wp.array(dtype=float),
1311
1313
  ):
1312
- if not tmp or not wp.adjoint[x] or not wp.adjoint[L]:
1314
+ if not tmp or not wp.adjoint[x] or not wp.adjoint[A] or not wp.adjoint[L]:
1313
1315
  return
1314
1316
  for i in range(n):
1315
1317
  tmp[b_start + i] = 0.0
@@ -1324,12 +1326,17 @@ def adj_dense_solve(
1324
1326
  for j in range(n):
1325
1327
  wp.adjoint[L][L_start + dense_index(n, i, j)] += -tmp[b_start + i] * x[b_start + j]
1326
1328
 
1329
+ for i in range(n):
1330
+ for j in range(n):
1331
+ wp.adjoint[A][L_start + dense_index(n, i, j)] += -tmp[b_start + i] * x[b_start + j]
1332
+
1327
1333
 
1328
1334
  @wp.kernel
1329
1335
  def eval_dense_solve_batched(
1330
1336
  L_start: wp.array(dtype=int),
1331
1337
  L_dim: wp.array(dtype=int),
1332
1338
  b_start: wp.array(dtype=int),
1339
+ A: wp.array(dtype=float),
1333
1340
  L: wp.array(dtype=float),
1334
1341
  b: wp.array(dtype=float),
1335
1342
  # outputs
@@ -1338,7 +1345,7 @@ def eval_dense_solve_batched(
1338
1345
  ):
1339
1346
  batch = wp.tid()
1340
1347
 
1341
- dense_solve(L_dim[batch], L_start[batch], b_start[batch], L, b, x, tmp)
1348
+ dense_solve(L_dim[batch], L_start[batch], b_start[batch], A, L, b, x, tmp)
1342
1349
 
1343
1350
 
1344
1351
  @wp.kernel
@@ -1509,7 +1516,6 @@ class FeatherstoneIntegrator(Integrator):
1509
1516
  self.L = wp.zeros_like(self.H)
1510
1517
 
1511
1518
  if model.body_count:
1512
- # TODO use requires_grad here?
1513
1519
  self.body_I_m = wp.empty(
1514
1520
  (model.body_count,), dtype=wp.spatial_matrix, device=model.device, requires_grad=model.requires_grad
1515
1521
  )
@@ -1859,6 +1865,7 @@ class FeatherstoneIntegrator(Integrator):
1859
1865
  self.articulation_H_start,
1860
1866
  self.articulation_H_rows,
1861
1867
  self.articulation_dof_start,
1868
+ self.H,
1862
1869
  self.L,
1863
1870
  state_aug.joint_tau,
1864
1871
  ],