@woosh/meep-engine 3.22.0 → 3.23.0

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.
Files changed (267) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +118 -0
  3. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -0
  4. package/src/core/geom/3d/hash-grid/PointHashGrid3.js +283 -0
  5. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/BoxShape3D.js +6 -17
  7. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/CapsuleShape3D.js +3 -14
  9. package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/CylinderShape3D.js +3 -21
  11. package/src/core/geom/3d/shape/PlaneShape3D.d.ts +105 -0
  12. package/src/core/geom/3d/shape/PlaneShape3D.d.ts.map +1 -0
  13. package/src/core/geom/3d/shape/PlaneShape3D.js +251 -0
  14. package/src/core/geom/3d/shape/SphereShape3D.js +3 -3
  15. package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
  16. package/src/core/geom/3d/shape/json/shape_to_type.js +3 -0
  17. package/src/core/geom/3d/shape/json/type_adapters.d.ts +14 -0
  18. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/json/type_adapters.js +15 -0
  20. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +51 -0
  21. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -0
  22. package/src/core/geom/3d/shape/sdf/sdf3_box.js +113 -0
  23. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +46 -0
  24. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -0
  25. package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +82 -0
  26. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +60 -0
  27. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -0
  28. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +126 -0
  29. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts +50 -0
  30. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts.map +1 -0
  31. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.js +53 -0
  32. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +52 -0
  33. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -0
  34. package/src/core/geom/3d/shape/sdf/sdf3_plane.js +61 -0
  35. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +41 -0
  36. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -0
  37. package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +71 -0
  38. package/src/core/process/ConcurrencyGate.d.ts +103 -0
  39. package/src/core/process/ConcurrencyGate.d.ts.map +1 -0
  40. package/src/core/process/ConcurrencyGate.js +207 -0
  41. package/src/engine/asset/AssetManager.d.ts +10 -0
  42. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  43. package/src/engine/asset/AssetManager.js +10 -0
  44. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +30 -13
  45. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +26 -0
  46. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -0
  47. package/src/engine/graphics3/pose/collect_entity_playbacks.js +40 -0
  48. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  49. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +74 -101
  50. package/src/engine/physics/cloth/MEASUREMENTS.md +1287 -4
  51. package/src/engine/physics/cloth/PLAN.md +1967 -1581
  52. package/src/engine/physics/cloth/build/ClothProxy.d.ts +147 -0
  53. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -0
  54. package/src/engine/physics/cloth/build/ClothProxy.js +207 -0
  55. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +70 -0
  56. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -0
  57. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +256 -0
  58. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +176 -0
  59. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +435 -0
  61. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts +12 -0
  62. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts.map +1 -0
  63. package/src/engine/physics/cloth/collider/ClothColliderKind.js +38 -0
  64. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts +120 -0
  65. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/collider/ClothColliderRecord.js +137 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +25 -0
  68. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -0
  69. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +190 -0
  70. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +44 -0
  71. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -0
  72. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +173 -0
  73. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +94 -0
  74. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +275 -0
  76. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts +126 -0
  77. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -0
  78. package/src/engine/physics/cloth/ecs/ClothCollider.js +199 -0
  79. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +9 -0
  80. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +32 -0
  82. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +114 -0
  83. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +243 -0
  85. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +66 -57
  86. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +109 -1
  87. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/ecs/ClothInstance.js +479 -363
  89. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +95 -0
  90. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -0
  91. package/src/engine/physics/cloth/ecs/ClothRig.js +140 -0
  92. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +30 -1
  93. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  94. package/src/engine/physics/cloth/ecs/ClothSystem.js +1021 -773
  95. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +90 -0
  96. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +374 -0
  98. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts +32 -3
  99. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.js +283 -254
  101. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +59 -0
  102. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +328 -0
  104. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +13 -0
  105. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +288 -0
  107. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +58 -0
  108. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +199 -0
  110. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +8 -63
  111. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  112. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +317 -645
  113. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +61 -0
  114. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  115. package/src/engine/physics/cloth/ecs/cloth_write_back.js +212 -449
  116. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +49 -0
  117. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -0
  118. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +115 -0
  119. package/src/engine/physics/cloth/playground/README.md +155 -1
  120. package/src/engine/physics/cloth/playground/collide.html +178 -0
  121. package/src/engine/physics/cloth/playground/collide_build.d.ts +95 -0
  122. package/src/engine/physics/cloth/playground/collide_build.d.ts.map +1 -0
  123. package/src/engine/physics/cloth/playground/collide_build.js +315 -0
  124. package/src/engine/physics/cloth/playground/collide_main.d.ts +2 -0
  125. package/src/engine/physics/cloth/playground/collide_main.d.ts.map +1 -0
  126. package/src/engine/physics/cloth/playground/collide_main.js +720 -0
  127. package/src/engine/physics/cloth/playground/garment.html +182 -0
  128. package/src/engine/physics/cloth/playground/garment_build.d.ts +78 -0
  129. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -0
  130. package/src/engine/physics/cloth/playground/garment_build.js +359 -0
  131. package/src/engine/physics/cloth/playground/garment_main.d.ts +2 -0
  132. package/src/engine/physics/cloth/playground/garment_main.d.ts.map +1 -0
  133. package/src/engine/physics/cloth/playground/garment_main.js +633 -0
  134. package/src/engine/physics/cloth/solver/ClothState.d.ts +208 -5
  135. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/ClothState.js +302 -8
  137. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +87 -0
  138. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_contact_find.js +343 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +112 -0
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -0
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +448 -0
  143. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts +4 -1
  144. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +16 -1
  146. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +112 -5
  147. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +117 -6
  149. package/src/engine/physics/cloth/solver/cloth_step.d.ts +40 -9
  150. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step.js +122 -10
  152. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +95 -0
  153. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -0
  154. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +285 -0
  155. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +129 -0
  156. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -0
  157. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +501 -0
  158. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +75 -0
  159. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -0
  160. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +202 -0
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/shade/playground/vgeo_viewer/README.md +18 -0
  163. package/src/shade/playground/vgeo_viewer/main.js +87 -50
  164. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  165. package/src/shade/renderer/buffer/table/GPUDatabase.js +191 -62
  166. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +94 -2
  167. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  168. package/src/shade/renderer/buffer/table/GPUTypedTable.js +414 -2
  169. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts +14 -0
  170. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts.map +1 -0
  171. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.js +13 -0
  172. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts +17 -0
  173. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts.map +1 -0
  174. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.js +116 -0
  175. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +9 -4
  176. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +843 -734
  178. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +12 -0
  179. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +13 -0
  181. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +17 -0
  182. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  183. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +185 -30
  184. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +17 -0
  185. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +141 -24
  186. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +204 -64
  187. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +110 -10
  188. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +19 -0
  189. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +19 -6
  190. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  191. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +26 -7
  192. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +173 -14
  193. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  194. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +458 -51
  195. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +49 -13
  196. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +52 -14
  198. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts +20 -0
  199. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts.map +1 -0
  200. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js +19 -0
  201. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts +27 -0
  202. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts.map +1 -0
  203. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js +48 -0
  204. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts +29 -0
  205. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts.map +1 -0
  206. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js +60 -0
  207. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +8 -1
  208. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +32 -2
  210. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +258 -0
  211. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +1 -0
  212. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +723 -0
  213. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +49 -0
  214. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +1 -0
  215. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +50 -0
  216. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  217. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  218. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts +3 -0
  219. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
  220. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +121 -21
  221. package/src/shade/renderer/texture/virtual/README.md +6 -4
  222. package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
  223. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +7 -0
  224. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.d.ts +3 -3
  225. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +3 -3
  226. package/src/engine/ecs/system/SystemExecutionPhase.d.ts +0 -9
  227. package/src/engine/ecs/system/SystemExecutionPhase.d.ts.map +0 -1
  228. package/src/engine/graphics/texture/virtual/NOTES.md +0 -128
  229. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts +0 -6
  230. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts.map +0 -1
  231. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.js +0 -5
  232. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts +0 -49
  233. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts.map +0 -1
  234. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.js +0 -264
  235. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts +0 -44
  236. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts.map +0 -1
  237. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.js +0 -228
  238. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts +0 -3
  239. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts.map +0 -1
  240. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.js +0 -73
  241. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts +0 -14
  242. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts.map +0 -1
  243. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.js +0 -85
  244. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts +0 -12
  245. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts.map +0 -1
  246. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.js +0 -63
  247. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts +0 -12
  248. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts.map +0 -1
  249. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.js +0 -243
  250. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts +0 -30
  251. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts.map +0 -1
  252. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.js +0 -39
  253. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts +0 -9
  254. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts.map +0 -1
  255. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.js +0 -24
  256. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts +0 -9
  257. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts.map +0 -1
  258. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.js +0 -26
  259. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts +0 -11
  260. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts.map +0 -1
  261. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.js +0 -12
  262. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts +0 -7
  263. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts.map +0 -1
  264. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.js +0 -16
  265. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts +0 -7
  266. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts.map +0 -1
  267. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.js +0 -35
@@ -1,3 +1,6 @@
1
+ /**
2
+ * @typedef {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation} Allocation
3
+ */
1
4
  export class GPUGeometryMeshletsBVH {
2
5
  /**
3
6
  * The tree's bytes as they were copied into the arena, once they have been. Not taken at
@@ -14,6 +17,14 @@ export class GPUGeometryMeshletsBVH {
14
17
  * @type {number}
15
18
  */
16
19
  address: number;
20
+ /**
21
+ * The arena region {@link address} names, as the allocator handed it out — kept so the
22
+ * region can be given back when this tree is released. `null` until the nodes are
23
+ * resident, and again once they have been released.
24
+ *
25
+ * @type {Allocation|null}
26
+ */
27
+ allocation: Allocation | null;
17
28
  /**
18
29
  * The shape of this tree — parents and leaf positions — shared with every other copy of the same
19
30
  * geometry, because a copy differs only in where its bounds are.
@@ -46,4 +57,5 @@ export class GPUGeometryMeshletsBVH {
46
57
  */
47
58
  released: boolean;
48
59
  }
60
+ export type Allocation = import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation;
49
61
  //# sourceMappingURL=GPUGeometryMeshletsBVH.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GPUGeometryMeshletsBVH.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js"],"names":[],"mappings":"AAAA;IAEI;;;;;;OAMG;IACH,KAFU,WAAW,GAAC,SAAS,CAE3B;IAEJ;;;;;OAKG;IACH,SAFU,MAAM,CAEJ;IAEZ;;;;;OAKG;IACH,UAFU,MAAM,CAEP;IAET;;;;;;OAMG;IACH,UAFU,OAAO,CAEA;IAEjB;;;;;;;OAOG;IACH,sBAFU,MAAM,CAES;IAEzB;;;;;OAKG;IACH,UAFU,OAAO,CAEA;CACpB"}
1
+ {"version":3,"file":"GPUGeometryMeshletsBVH.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;IAEI;;;;;;OAMG;IACH,KAFU,WAAW,GAAC,SAAS,CAE3B;IAEJ;;;;;OAKG;IACH,SAFU,MAAM,CAEJ;IAEZ;;;;;;OAMG;IACH,YAFU,UAAU,GAAC,IAAI,CAEP;IAElB;;;;;OAKG;IACH,UAFU,MAAM,CAEP;IAET;;;;;;OAMG;IACH,UAFU,OAAO,CAEA;IAEjB;;;;;;;OAOG;IACH,sBAFU,MAAM,CAES;IAEzB;;;;;OAKG;IACH,UAFU,OAAO,CAEA;CACpB;yBAjEY,OAAO,sDAAsD,EAAE,UAAU"}
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @typedef {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation} Allocation
3
+ */
4
+
1
5
  export class GPUGeometryMeshletsBVH {
2
6
 
3
7
  /**
@@ -17,6 +21,15 @@ export class GPUGeometryMeshletsBVH {
17
21
  */
18
22
  address = 0;
19
23
 
24
+ /**
25
+ * The arena region {@link address} names, as the allocator handed it out — kept so the
26
+ * region can be given back when this tree is released. `null` until the nodes are
27
+ * resident, and again once they have been released.
28
+ *
29
+ * @type {Allocation|null}
30
+ */
31
+ allocation = null;
32
+
20
33
  /**
21
34
  * The shape of this tree — parents and leaf positions — shared with every other copy of the same
22
35
  * geometry, because a copy differs only in where its bounds are.
@@ -15,6 +15,23 @@ export class GPUMeshletManager {
15
15
  get buffer_metadata(): GPUBuffer;
16
16
  compact(): void;
17
17
  /**
18
+ * Enlarge the data and metadata arenas, leaving every batch exactly where it is.
19
+ *
20
+ * Growth appends. {@link OffsetAllocator#grow} files the new tail as free space and moves
21
+ * nothing, and each buffer's old contents go into the larger one at offset 0 in a single copy —
22
+ * so no record's `data.offset` or `metadata.offset` changes, no meshlet's `address` field needs
23
+ * re-patching, and no {@link MeshletBatchAllocationRecord#changed} fires. Compare {@link compact},
24
+ * which makes room by re-packing instead, and pays all three of those for every record it moves.
25
+ *
26
+ * Growing closes no holes, which is why it leaves {@link #deallocations_since_last_rebuild}
27
+ * alone: the holes it did not close are still there for a later {@link compact} to close.
28
+ *
29
+ * The arena an allocator is asked for is a little larger than the shortfall, because the bins
30
+ * round free runs down and requests up, up to 9/8 apart — room for exactly `extra_data_size`
31
+ * can still be refused the allocation that asked for it. And no larger than
32
+ * `maxBufferSize`: growth stops at what the device will hand out, so an arena that cannot
33
+ * hold the request reports that through the caller's failed allocation rather than through a
34
+ * buffer that is not there.
18
35
  *
19
36
  * @param {number} extra_data_size in words (4 bytes)
20
37
  * @param {number} extra_metadata_size in metadata elements
@@ -1 +1 @@
1
- {"version":3,"file":"GPUMeshletManager.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/meshlet/GPUMeshletManager.js"],"names":[],"mappings":"AAqEA;IAoEI;;;;;;OAMG;IACH;QAJ8B,MAAM;QACR,qBAAqB,GAAtC,MAAM;QACW,yBAAyB,GAA1C,MAAM;OAmChB;IAzFD,6BAEC;IAOD,iCAEC;IAgFD,gBAKC;IAED;;;;OAIG;IACH,sBAHW,MAAM,uBACN,MAAM,QAiDhB;IA+PD;;;;;;;;;;;OAWG;IACH,qBAJW,4BAA4B,GAE1B,OAAO,CAiBnB;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,+BAHW,4BAA4B,GAC1B,4BAA4B,CA8BxC;IAED;;;;;;;;;;;;OAYG;IACH,gBAFW,sBAAsB,QA8GhC;IAED,gBAGC;IAED;;;;OAIG;IACH,iBAHW,YAAY,GACV,4BAA4B,CA6BxC;IAED,mCASC;IAED,wCAQC;IAED,+BAYC;;CACJ;yBApvBY,OAAO,sDAAsD,EAAE,UAAU;qCACzE,OAAO,2CAA2C,EAAE,sBAAsB;2BAC1E,OAAO,mBAAmB,EAAE,YAAY;AAerD;IACI;;OAEG;IACH,UAFU,UAAU,CAEZ;IACR;;OAEG;IACH,MAFU,UAAU,CAEhB;IAEJ;;;OAGG;IACH,WAFU,MAAM,CAEF;IAEd;;;OAGG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,0BAFU,WAAW,CAEI;IAEzB;;;OAGG;IACH,aAAsB;CACzB"}
1
+ {"version":3,"file":"GPUMeshletManager.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/meshlet/GPUMeshletManager.js"],"names":[],"mappings":"AAmFA;IAqEI;;;;;;OAMG;IACH;QAJ8B,MAAM;QACR,qBAAqB,GAAtC,MAAM;QACW,yBAAyB,GAA1C,MAAM;OAkChB;IAzFD,6BAEC;IAOD,iCAEC;IAgFD,gBAKC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,sBAHW,MAAM,uBACN,MAAM,QAuHhB;IAqRD;;;;;;;;;;;OAWG;IACH,qBAJW,4BAA4B,GAE1B,OAAO,CAmBnB;IAgCD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,+BAHW,4BAA4B,GAC1B,4BAA4B,CA8BxC;IAED;;;;;;;;;;;;OAYG;IACH,gBAFW,sBAAsB,QA8GhC;IAED,gBAGC;IAED;;;;OAIG;IACH,iBAHW,YAAY,GACV,4BAA4B,CA6BxC;IAED,mCASC;IAED,wCAQC;IAED,+BAYC;;CACJ;yBA/4BY,OAAO,sDAAsD,EAAE,UAAU;qCACzE,OAAO,2CAA2C,EAAE,sBAAsB;2BAC1E,OAAO,mBAAmB,EAAE,YAAY;AA6BrD;IACI;;OAEG;IACH,UAFU,UAAU,CAEZ;IACR;;OAEG;IACH,MAFU,UAAU,CAEhB;IAEJ;;;OAGG;IACH,WAFU,MAAM,CAEF;IAEd;;;OAGG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,0BAFU,WAAW,CAEI;IAEzB;;;OAGG;IACH,aAAsB;CACzB"}
@@ -32,6 +32,20 @@ const DEFAULT_METADATA_CAPACITY = 128 * 1024;
32
32
  */
33
33
  const DEFAULT_DATA_CAPACITY = 32 * MEGABYTE;
34
34
 
35
+ /**
36
+ * Node budget both allocators are built with — the ceiling on how many ranges either can be
37
+ * describing at once, live allocations and free holes together.
38
+ *
39
+ * {@link OffsetAllocator#grow} cannot raise it: the node table cannot be enlarged in place, and the
40
+ * allocation count a caller needs does not follow from the arena's size anyway. So a manager that
41
+ * grows keeps whatever it was constructed with, where one that rebuilt got the number re-picked
42
+ * every time. It loses nothing by that — {@link #rebuild} re-picks the larger of this and twice the
43
+ * live batch count, which only exceeds this past 65,536 batches.
44
+ *
45
+ * @type {number}
46
+ */
47
+ const ALLOCATION_LIMIT = 128 * 1024;
48
+
35
49
  class MeshletBatchAllocationRecord {
36
50
  /**
37
51
  * @type {Allocation}
@@ -123,10 +137,11 @@ export class GPUMeshletManager {
123
137
  * commands and N `(record_index, address_delta)` patch entries.
124
138
  *
125
139
  * Entries name the two records, not the addresses they held when the
126
- * clone was queued: a {@link compact} or {@link grow} in between
127
- * migrates both, and {@link update} reads where they ended up. What
128
- * an entry does require is that neither record is handed back to
129
- * {@link remove_batch} before the flush.
140
+ * clone was queued: a {@link compact} in between migrates both, and
141
+ * {@link update} reads where they ended up. ({@link grow} moves
142
+ * nothing, so it needs nothing of them.) What an entry does require
143
+ * is that neither record is handed back to {@link remove_batch}
144
+ * before the flush.
130
145
  *
131
146
  * @type {{
132
147
  * source: MeshletBatchAllocationRecord,
@@ -159,9 +174,8 @@ export class GPUMeshletManager {
159
174
 
160
175
  const data_buffer_size_words = Math.ceil(initial_data_capacity / 4);
161
176
 
162
- // TODO manage max-allocations as well
163
- this.#allocator_data = new OffsetAllocator(data_buffer_size_words);
164
- this.#allocator_metadata = new OffsetAllocator(initial_metadata_capacity);
177
+ this.#allocator_data = new OffsetAllocator(data_buffer_size_words, ALLOCATION_LIMIT);
178
+ this.#allocator_metadata = new OffsetAllocator(initial_metadata_capacity, ALLOCATION_LIMIT);
165
179
 
166
180
  this.#meshlet_data_buffer = device.createBuffer({
167
181
  label: 'GPUMeshletManager/data',
@@ -185,6 +199,23 @@ export class GPUMeshletManager {
185
199
  }
186
200
 
187
201
  /**
202
+ * Enlarge the data and metadata arenas, leaving every batch exactly where it is.
203
+ *
204
+ * Growth appends. {@link OffsetAllocator#grow} files the new tail as free space and moves
205
+ * nothing, and each buffer's old contents go into the larger one at offset 0 in a single copy —
206
+ * so no record's `data.offset` or `metadata.offset` changes, no meshlet's `address` field needs
207
+ * re-patching, and no {@link MeshletBatchAllocationRecord#changed} fires. Compare {@link compact},
208
+ * which makes room by re-packing instead, and pays all three of those for every record it moves.
209
+ *
210
+ * Growing closes no holes, which is why it leaves {@link #deallocations_since_last_rebuild}
211
+ * alone: the holes it did not close are still there for a later {@link compact} to close.
212
+ *
213
+ * The arena an allocator is asked for is a little larger than the shortfall, because the bins
214
+ * round free runs down and requests up, up to 9/8 apart — room for exactly `extra_data_size`
215
+ * can still be refused the allocation that asked for it. And no larger than
216
+ * `maxBufferSize`: growth stops at what the device will hand out, so an arena that cannot
217
+ * hold the request reports that through the caller's failed allocation rather than through a
218
+ * buffer that is not there.
188
219
  *
189
220
  * @param {number} extra_data_size in words (4 bytes)
190
221
  * @param {number} extra_metadata_size in metadata elements
@@ -198,11 +229,13 @@ export class GPUMeshletManager {
198
229
  return;
199
230
  }
200
231
 
201
- const current_data_buffer_size_bytes = this.#meshlet_data_buffer.size;
202
- const current_metadata_buffer_size = this.#meshlet_metadata_buffer.size;
232
+ const device = this.#device;
233
+
234
+ const old_buffer_data = this.#meshlet_data_buffer;
235
+ const old_buffer_metadata = this.#meshlet_metadata_buffer;
203
236
 
204
- const current_buffer_size_words = current_data_buffer_size_bytes >> 2;
205
- const current_metadata_buffer_size_elements = Math.ceil(current_metadata_buffer_size / MESHLET_METADATA_STRUCT.aligned_size);
237
+ const current_buffer_size_words = old_buffer_data.size >> 2;
238
+ const current_metadata_buffer_size_elements = Math.ceil(old_buffer_metadata.size / MESHLET_METADATA_STRUCT.aligned_size);
206
239
 
207
240
  const DATA_GROWTH_STEP = 16 * 1024;
208
241
  const METADATA_GROWTH_STEP = 256;
@@ -214,7 +247,7 @@ export class GPUMeshletManager {
214
247
  } else {
215
248
  // grow
216
249
  new_data_size = Math.max(
217
- current_buffer_size_words + extra_data_size,
250
+ current_buffer_size_words + Math.ceil(extra_data_size * 9 / 8),
218
251
  current_buffer_size_words + DATA_GROWTH_STEP,
219
252
  Math.ceil(current_buffer_size_words * GROWTH_MULTIPLIER)
220
253
  );
@@ -226,16 +259,84 @@ export class GPUMeshletManager {
226
259
  } else {
227
260
  // grow
228
261
  new_metadata_size = Math.max(
229
- current_metadata_buffer_size_elements + extra_metadata_size,
262
+ current_metadata_buffer_size_elements + Math.ceil(extra_metadata_size * 9 / 8),
230
263
  current_metadata_buffer_size_elements + METADATA_GROWTH_STEP,
231
- current_metadata_buffer_size_elements * GROWTH_MULTIPLIER
264
+ Math.ceil(current_metadata_buffer_size_elements * GROWTH_MULTIPLIER)
232
265
  );
233
266
  }
234
267
 
235
- this.#rebuild(
236
- new_data_size,
237
- new_metadata_size
268
+ // `createBuffer` answers a size past the device's limit with an *invalid* buffer rather than
269
+ // an exception. Swapping one of those in would destroy the arena, leave the allocator sized
270
+ // for space that does not exist, and throw nothing on the way. Capping means a growth gets
271
+ // as far as the device allows, which is often still enough — and when it is not, the caller's
272
+ // allocation is what fails.
273
+ const max_buffer_size = device.limits.maxBufferSize;
274
+
275
+ new_data_size = Math.min(new_data_size, Math.floor(max_buffer_size / 4));
276
+ new_metadata_size = Math.min(
277
+ new_metadata_size,
278
+ Math.floor(max_buffer_size / MESHLET_METADATA_STRUCT.aligned_size)
238
279
  );
280
+
281
+ // A buffer is left alone when its arena did not change, so growing one of the two costs
282
+ // nothing on the other — and an arena already at the cap is left alone by the same test.
283
+ const grows_data = new_data_size > current_buffer_size_words;
284
+ const grows_metadata = new_metadata_size > current_metadata_buffer_size_elements;
285
+
286
+ if (!grows_data && !grows_metadata) {
287
+ // both are as large as this device will allow
288
+ return;
289
+ }
290
+
291
+ // Buffers first. `OffsetAllocator#grow` cannot be undone, so nothing irreversible happens
292
+ // until the space it is about to describe exists.
293
+ const new_buffer_data = grows_data
294
+ ? device.createBuffer({
295
+ label: old_buffer_data.label,
296
+ usage: old_buffer_data.usage,
297
+ size: new_data_size * 4,
298
+ })
299
+ : null;
300
+
301
+ const new_buffer_metadata = grows_metadata
302
+ ? device.createBuffer({
303
+ label: old_buffer_metadata.label,
304
+ usage: old_buffer_metadata.usage,
305
+ size: new_metadata_size * MESHLET_METADATA_STRUCT.aligned_size,
306
+ })
307
+ : null;
308
+
309
+ const encoder = device.createCommandEncoder({
310
+ label: "GPUMeshletManager/grow",
311
+ });
312
+
313
+ if (new_buffer_data !== null) {
314
+ this.#allocator_data.grow(new_data_size);
315
+
316
+ // One copy of the whole arena at offset 0. No offset moved, so the bytes land back under
317
+ // the addresses the records already hold — and the metadata addressing them stays right.
318
+ encoder.copyBufferToBuffer(old_buffer_data, 0, new_buffer_data, 0, old_buffer_data.size);
319
+ }
320
+
321
+ if (new_buffer_metadata !== null) {
322
+ this.#allocator_metadata.grow(new_metadata_size);
323
+
324
+ encoder.copyBufferToBuffer(old_buffer_metadata, 0, new_buffer_metadata, 0, old_buffer_metadata.size);
325
+ }
326
+
327
+ device.queue.submit([encoder.finish()]);
328
+
329
+ if (new_buffer_data !== null) {
330
+ old_buffer_data.destroy();
331
+
332
+ this.#meshlet_data_buffer = new_buffer_data;
333
+ }
334
+
335
+ if (new_buffer_metadata !== null) {
336
+ old_buffer_metadata.destroy();
337
+
338
+ this.#meshlet_metadata_buffer = new_buffer_metadata;
339
+ }
239
340
  }
240
341
 
241
342
  /**
@@ -305,7 +406,7 @@ export class GPUMeshletManager {
305
406
  const record_count = records.length;
306
407
  const new_allocator_data = new OffsetAllocator(
307
408
  new_data_size,
308
- Math.max(record_count * 2, 128 * 1024)
409
+ Math.max(record_count * 2, ALLOCATION_LIMIT)
309
410
  );
310
411
 
311
412
  const old_buffer_data = this.#meshlet_data_buffer;
@@ -317,7 +418,7 @@ export class GPUMeshletManager {
317
418
 
318
419
  const new_allocator_metadata = new OffsetAllocator(
319
420
  new_metadata_size,
320
- Math.max(record_count * 2, 128 * 1024)
421
+ Math.max(record_count * 2, ALLOCATION_LIMIT)
321
422
  );
322
423
 
323
424
  const old_buffer_metadata = this.#meshlet_metadata_buffer;
@@ -396,15 +497,21 @@ export class GPUMeshletManager {
396
497
 
397
498
  /**
398
499
  * Allocate `data_size_words` in the data buffer and `meshlet_count`
399
- * in the metadata buffer, retrying with compact-then-grow on failure.
400
- * Throws if the third attempt still can't satisfy both. The two
500
+ * in the metadata buffer, growing or compacting on failure and trying
501
+ * again. Throws if the third attempt still can't satisfy both. The two
401
502
  * allocations are kept in lockstep — partial successes are released
402
503
  * before retrying so we never leak.
403
504
  *
404
- * Compaction triggers a full {@link #rebuild} which migrates every
405
- * existing allocation to a new buffer pair. Queued clone work is
406
- * carried through it — {@link #pending_clones} names records, not
407
- * addresses — so an allocation made while a clone is pending is safe.
505
+ * Which of the two a failure gets is decided by what the failure is.
506
+ * {@link grow} appends a contiguous run and moves nothing, so it is
507
+ * the cheap and complete answer to an arena that is merely full.
508
+ * {@link compact} adds no space at all — it closes holes — and pays a
509
+ * migration of every allocation, a CPU metadata rewrite each and a
510
+ * `changed` for every moved address to do it, so it is reserved for
511
+ * the failure it is the only answer to: the room is already there and
512
+ * merely scattered. Queued clone work is carried through either —
513
+ * {@link #pending_clones} names records, not addresses — so an
514
+ * allocation made while a clone is pending is safe.
408
515
  *
409
516
  * @param {number} data_size_words
410
517
  * @param {number} meshlet_count
@@ -440,14 +547,30 @@ export class GPUMeshletManager {
440
547
  metadata_allocation.metadata = ALLOCATOR_NO_SPACE;
441
548
  }
442
549
 
443
- if (this.#deallocations_since_last_rebuild > 0) {
444
- // try compaction
550
+ // An allocator holding enough free space for the request it just refused is one whose
551
+ // space is scattered, and closing the holes is the only thing that helps. Anything else
552
+ // is a shortfall, which growth covers by appending. The margin is the bins': a free run
553
+ // the allocator rounds down can still be refused a request it rounds up, so "enough"
554
+ // has to mean 9/8 of it, or a compaction could hand back a single run and still refuse.
555
+ const data_is_fragmented = !data_ok
556
+ && this.#allocator_data.freeStorage >= Math.ceil(data_size_words * 9 / 8);
557
+
558
+ const metadata_is_fragmented = !metadata_ok
559
+ && this.#allocator_metadata.freeStorage >= Math.ceil(meshlet_count * 9 / 8);
560
+
561
+ // #rebuild zeroes the counter, so a compaction that does not free the request through
562
+ // leaves the next pass to grow — the loop always makes progress
563
+ if (
564
+ this.#deallocations_since_last_rebuild > 0
565
+ && (data_is_fragmented || metadata_is_fragmented)
566
+ ) {
445
567
  this.compact();
568
+
446
569
  continue;
447
570
  }
448
571
 
449
- let grow_data_size = data_ok ? 0 : data_size_words;
450
- let grow_metadata_size = metadata_ok ? 0 : meshlet_count;
572
+ const grow_data_size = data_ok ? 0 : data_size_words;
573
+ const grow_metadata_size = metadata_ok ? 0 : meshlet_count;
451
574
 
452
575
  this.grow(grow_data_size, grow_metadata_size);
453
576
 
@@ -511,6 +634,8 @@ export class GPUMeshletManager {
511
634
  return false;
512
635
  }
513
636
 
637
+ this.#cancel_pending_clones_naming(record);
638
+
514
639
  this.#allocator_data.free(record.data);
515
640
  this.#allocator_metadata.free(record.metadata);
516
641
 
@@ -520,6 +645,36 @@ export class GPUMeshletManager {
520
645
  return true;
521
646
  }
522
647
 
648
+ /**
649
+ * Drop the queued clone copies that name `record`, because it is about to stop owning the
650
+ * ranges they were going to read from or write to.
651
+ *
652
+ * A queued copy holds records, not addresses, precisely so a rebuild can move them under it —
653
+ * but a *released* record keeps the offsets it had while the allocator hands those same
654
+ * ranges to whoever asks next. Flushing such a copy writes a stale source over a live batch's
655
+ * vertices, or copies a live batch's vertices into a clone, with nothing to say it happened.
656
+ * This was unreachable while nothing released a clone; it became reachable the moment
657
+ * {@link GPUGeometryManager#remove_clone} did.
658
+ *
659
+ * Cancelling by source as well as by clone gives up the copy rather than reading a region the
660
+ * source no longer owns. The clone is left holding its ranges with nothing written into them,
661
+ * which renders as whatever those bytes were — wrong, but bounded, and it is what removing a
662
+ * geometry out from under a clone of it already asks for.
663
+ *
664
+ * @param {MeshletBatchAllocationRecord} record
665
+ */
666
+ #cancel_pending_clones_naming(record) {
667
+ const pending = this.#pending_clones;
668
+
669
+ for (let i = pending.length - 1; i >= 0; i--) {
670
+ const entry = pending[i];
671
+
672
+ if (entry.clone === record || entry.source === record) {
673
+ pending.splice(i, 1);
674
+ }
675
+ }
676
+ }
677
+
523
678
  /**
524
679
  * Allocate a fresh (data, metadata) pair sized to mirror `source`,
525
680
  * and queue a GPU-side clone: the source's data and metadata are
@@ -569,7 +724,7 @@ export class GPUMeshletManager {
569
724
  // hold right now. Both are in `#records`, so a rebuild between
570
725
  // this call and the flush moves them and the flush still reads
571
726
  // where they went — which is what lets a clone be queued in the
572
- // same frame as the growth another geometry's arrival forces.
727
+ // same frame as the compaction another geometry's arrival forces.
573
728
  this.#pending_clones.push({ source, clone: record });
574
729
 
575
730
  return record;
@@ -12,6 +12,11 @@ Paths below are relative to the Micron root.
12
12
  > scheduled but not yet built, all live in
13
13
  > [VIRTUAL_GEOMETRY_PLAN.md](./VIRTUAL_GEOMETRY_PLAN.md) — that file is the one to act on.
14
14
  > This one is kept as the analysis behind those decisions.
15
+ >
16
+ > It is a **snapshot dated in its filename** and is not maintained against the code. Statements
17
+ > about meep that have since gone stale are corrected inline in block quotes like this one,
18
+ > rather than edited away — the argument that was made at the time is the reason the decision
19
+ > was taken, and rewriting it hides that.
15
20
 
16
21
  ## 1. Where the two already agree
17
22
 
@@ -108,6 +113,11 @@ meep hard-gates on an error band and falls back to a full sweep when the band ha
108
113
  The soft form has no escape hatch to justify, and would work as a tie-breaker *inside* a
109
114
  band, which is where meep currently uses shared-boundary weight alone.
110
115
 
116
+ > **Since this was written**: not alone any more. The adjacency edge weight is shared boundary
117
+ > *times* `compactness()` (plan §1), so the tie-break slot this proposes is occupied — by a
118
+ > spatial term rather than an error-similarity one. A level tie-break would now have to argue
119
+ > its way past compactness, not past nothing.
120
+
111
121
  ```js
112
122
  normal_score = 1 - merged_cone_angle² / π²
113
123
  ```
@@ -116,6 +126,13 @@ Prefers merging co-facing patches, which keeps the normal cone tight. meep reser
116
126
  `cone_reserved` in the cluster record and has no producer; if the cone ever lands, the
117
127
  grouping should be aware of it or the cones will be useless at coarse levels.
118
128
 
129
+ > **Since this was written**: moot — **backface cone culling is declined** (plan §5). The
130
+ > warning above turned out to be the argument against the whole idea rather than a caveat on
131
+ > implementing it: making cones tight enough to be worth testing means letting cone angle
132
+ > distort grouping, to feed a cull the two-pass HZB was already performing on evidence. The
133
+ > producer did land in the meantime and has no callers
134
+ > (`bt_face_cluster_compute_normal_bounding_cone`); `cone_reserved` stays 0 for good.
135
+
119
136
  The weighting itself should **not** be copied: the terms are heterogeneous in scale and
120
137
  `shared_vertex_count` enters unnormalized, so it dominates everything else. The terms are
121
138
  the finding, not the sum.