@woosh/meep-engine 3.61.2 → 3.61.3

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 (389) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/package.json +1 -1
  3. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  4. package/src/shade/playground/probe_clipmap/README.md +3 -4
  5. package/src/shade/playground/probe_clipmap/index.html +5 -13
  6. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  7. package/src/shade/playground/probe_clipmap/main.js +0 -5
  8. package/src/shade/playground/probe_clipmap_box/README.md +1 -1
  9. package/src/shade/playground/probe_clipmap_box/index.html +1 -1
  10. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  11. package/src/shade/renderer/Renderer.js +50 -11
  12. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  13. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  14. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  15. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  16. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  17. package/src/shade/renderer/geometry/meshlet/meshlet_batch_colored.d.ts +10 -0
  18. package/src/shade/renderer/geometry/meshlet/meshlet_batch_colored.d.ts.map +1 -0
  19. package/src/shade/renderer/geometry/meshlet/meshlet_batch_colored.js +54 -0
  20. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +85 -36
  21. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  22. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +813 -412
  23. package/src/shade/renderer/geometry/sdf/MESH_SDF.d.ts +7 -0
  24. package/src/shade/renderer/geometry/sdf/MESH_SDF.d.ts.map +1 -1
  25. package/src/shade/renderer/geometry/sdf/MESH_SDF.js +8 -0
  26. package/src/shade/renderer/geometry/sdf/MESH_SDF_BRICK_KEY.d.ts +14 -0
  27. package/src/shade/renderer/geometry/sdf/MESH_SDF_BRICK_KEY.d.ts.map +1 -0
  28. package/src/shade/renderer/geometry/sdf/MESH_SDF_BRICK_KEY.js +35 -0
  29. package/src/shade/renderer/geometry/sdf/MESH_SDF_STRUCT.d.ts.map +1 -1
  30. package/src/shade/renderer/geometry/sdf/MESH_SDF_STRUCT.js +0 -4
  31. package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.d.ts +55 -10
  32. package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.d.ts.map +1 -1
  33. package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.js +86 -16
  34. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.d.ts +2 -2
  35. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.d.ts.map +1 -1
  36. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.js +28 -2
  37. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_contents.d.ts +54 -0
  38. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_contents.d.ts.map +1 -0
  39. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_contents.js +146 -0
  40. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.d.ts +1 -1
  41. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.d.ts.map +1 -1
  42. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.js +2 -1
  43. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_content_rehash.d.ts +18 -0
  44. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_content_rehash.d.ts.map +1 -0
  45. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_content_rehash.js +66 -0
  46. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_count.d.ts +17 -0
  47. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_count.d.ts.map +1 -0
  48. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_count.js +66 -0
  49. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.d.ts +5 -3
  50. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.d.ts.map +1 -1
  51. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.js +15 -14
  52. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.d.ts +2 -1
  53. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.d.ts.map +1 -1
  54. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.js +12 -3
  55. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_key.d.ts +21 -0
  56. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_key.d.ts.map +1 -0
  57. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_key.js +84 -0
  58. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_resolve.d.ts +53 -0
  59. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_resolve.d.ts.map +1 -0
  60. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_resolve.js +343 -0
  61. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.d.ts +3 -3
  62. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.d.ts.map +1 -1
  63. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.js +9 -5
  64. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.d.ts +2 -2
  65. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.d.ts.map +1 -1
  66. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.js +3 -2
  67. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_upload.d.ts +69 -0
  68. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_upload.d.ts.map +1 -0
  69. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_upload.js +294 -0
  70. package/src/shade/renderer/geometry/sdf/bundle/MODEL_CACHE_BUNDLE.d.ts +16 -0
  71. package/src/shade/renderer/geometry/sdf/bundle/MODEL_CACHE_BUNDLE.d.ts.map +1 -0
  72. package/src/shade/renderer/geometry/sdf/bundle/MODEL_CACHE_BUNDLE.js +36 -0
  73. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +126 -0
  74. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -0
  75. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +148 -0
  76. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_read.d.ts +10 -0
  77. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_read.d.ts.map +1 -0
  78. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_read.js +140 -0
  79. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_write.d.ts +8 -0
  80. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_write.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_write.js +76 -0
  82. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.d.ts +9 -0
  83. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.d.ts.map +1 -1
  84. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.js +23 -0
  85. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_brick_key.d.ts +13 -0
  86. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_brick_key.d.ts.map +1 -0
  87. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_brick_key.js +23 -0
  88. package/src/shade/renderer/geometry/sdf/surface/GPUMeshSurfaceCaches.d.ts +262 -0
  89. package/src/shade/renderer/geometry/sdf/surface/GPUMeshSurfaceCaches.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/sdf/surface/GPUMeshSurfaceCaches.js +1819 -0
  91. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BAKE.d.ts +118 -0
  92. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BAKE.d.ts.map +1 -0
  93. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BAKE.js +204 -0
  94. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BLOCK.d.ts +66 -0
  95. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BLOCK.d.ts.map +1 -0
  96. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BLOCK.js +103 -0
  97. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_RESOURCES.d.ts +19 -0
  98. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_RESOURCES.d.ts.map +1 -0
  99. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_RESOURCES.js +23 -0
  100. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_STRUCT.d.ts +15 -0
  101. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_STRUCT.d.ts.map +1 -0
  102. package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_STRUCT.js +70 -0
  103. package/src/shade/renderer/geometry/sdf/surface/SURFACE_MATERIAL.d.ts +13 -0
  104. package/src/shade/renderer/geometry/sdf/surface/SURFACE_MATERIAL.d.ts.map +1 -0
  105. package/src/shade/renderer/geometry/sdf/surface/SURFACE_MATERIAL.js +35 -0
  106. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_block.d.ts +32 -0
  107. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_block.d.ts.map +1 -0
  108. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_block.js +111 -0
  109. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_listed.d.ts +17 -0
  110. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_listed.d.ts.map +1 -0
  111. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_listed.js +49 -0
  112. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_run_find.d.ts +13 -0
  113. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_run_find.d.ts.map +1 -0
  114. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_run_find.js +35 -0
  115. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_sample.d.ts +24 -0
  116. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_sample.d.ts.map +1 -0
  117. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_sample.js +169 -0
  118. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_texel_ray.d.ts +19 -0
  119. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_texel_ray.d.ts.map +1 -0
  120. package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_texel_ray.js +49 -0
  121. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_fit.d.ts +19 -0
  122. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_fit.d.ts.map +1 -0
  123. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_fit.js +67 -0
  124. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_read.d.ts +78 -0
  125. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_read.d.ts.map +1 -0
  126. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_read.js +320 -0
  127. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_store.d.ts +15 -0
  128. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_store.d.ts.map +1 -0
  129. package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_store.js +48 -0
  130. package/src/shade/renderer/geometry/sdf/surface/mesh_surface_channels.d.ts +51 -0
  131. package/src/shade/renderer/geometry/sdf/surface/mesh_surface_channels.d.ts.map +1 -0
  132. package/src/shade/renderer/geometry/sdf/surface/mesh_surface_channels.js +109 -0
  133. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_command.d.ts +11 -0
  134. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_command.d.ts.map +1 -0
  135. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_command.js +51 -0
  136. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_encode.d.ts +26 -0
  137. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_encode.d.ts.map +1 -0
  138. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_encode.js +453 -0
  139. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_list.d.ts +12 -0
  140. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_list.d.ts.map +1 -0
  141. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_list.js +99 -0
  142. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_survey.d.ts +22 -0
  143. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_survey.d.ts.map +1 -0
  144. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_survey.js +140 -0
  145. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.d.ts +32 -0
  146. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.d.ts.map +1 -0
  147. package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.js +261 -0
  148. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +2 -2
  149. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +2 -2
  150. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +6 -6
  151. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +7 -7
  152. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +15 -7
  153. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  154. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +82 -17
  155. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +26 -19
  156. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  157. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +226 -148
  158. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +25 -52
  159. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  160. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +29 -69
  161. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts +19 -16
  162. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts.map +1 -1
  163. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.js +24 -21
  164. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +46 -22
  165. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
  166. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +49 -36
  167. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts +3 -2
  168. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts.map +1 -1
  169. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.js +7 -6
  170. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +8 -22
  171. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
  172. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +15 -51
  173. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts +1 -6
  174. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts.map +1 -1
  175. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.js +6 -13
  176. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.d.ts.map +1 -1
  177. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.js +0 -2
  178. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.d.ts +4 -4
  179. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.d.ts.map +1 -1
  180. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.js +9 -34
  181. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.d.ts +4 -6
  182. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.d.ts.map +1 -1
  183. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.js +15 -39
  184. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_clear.d.ts +1 -1
  185. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_clear.js +1 -1
  186. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.d.ts +1 -2
  187. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.d.ts.map +1 -1
  188. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.js +2 -6
  189. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.d.ts +2 -2
  190. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.d.ts.map +1 -1
  191. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.js +5 -2
  192. package/src/shade/renderer/global_illumination/probe_clipmap/debug/ProbeClipmapDebugView.d.ts +5 -1
  193. package/src/shade/renderer/global_illumination/probe_clipmap/debug/ProbeClipmapDebugView.js +16 -2
  194. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts +45 -0
  195. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -0
  196. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +208 -0
  197. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_indirect.d.ts +24 -0
  198. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_indirect.d.ts.map +1 -0
  199. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_indirect.js +40 -0
  200. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_surfaces.d.ts +34 -0
  201. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_surfaces.d.ts.map +1 -0
  202. package/src/shade/renderer/global_illumination/probe_clipmap/debug/{graph_probe_clipmap_debug_mesh_cards.js → graph_probe_clipmap_debug_mesh_surfaces.js} +38 -57
  203. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts +61 -0
  204. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -0
  205. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +193 -0
  206. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +67 -0
  207. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -0
  208. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +142 -0
  209. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_cell.d.ts +32 -0
  210. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_cell.d.ts.map +1 -0
  211. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_cell.js +70 -0
  212. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_store.d.ts +30 -0
  213. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_store.d.ts.map +1 -0
  214. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_store.js +71 -0
  215. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts +26 -0
  216. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -0
  217. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +176 -0
  218. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +18 -9
  219. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  220. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +63 -44
  221. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +21 -1
  222. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  223. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +24 -1
  224. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_INDIRECT_LOBE.d.ts +10 -0
  225. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_INDIRECT_LOBE.d.ts.map +1 -0
  226. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_INDIRECT_LOBE.js +11 -0
  227. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapIndirectLobe.d.ts +11 -0
  228. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapIndirectLobe.d.ts.map +1 -0
  229. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapIndirectLobe.js +15 -0
  230. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +44 -7
  231. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  232. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +88 -11
  233. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +43 -0
  234. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts.map +1 -0
  235. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +138 -0
  236. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_indirect_lobe.d.ts +21 -0
  237. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_indirect_lobe.d.ts.map +1 -0
  238. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_indirect_lobe.js +49 -0
  239. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts +2 -0
  240. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts.map +1 -1
  241. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +10 -4
  242. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_select.d.ts +22 -0
  243. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_select.d.ts.map +1 -0
  244. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_select.js +50 -0
  245. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +4 -4
  246. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
  247. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +8 -8
  248. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts +3 -3
  249. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.js +5 -5
  250. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts +2 -0
  251. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts.map +1 -1
  252. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.js +5 -1
  253. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts +1 -1
  254. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +2 -2
  255. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts +7 -4
  256. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  257. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +30 -26
  258. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +6 -5
  259. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  260. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +22 -16
  261. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
  262. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +6 -2
  263. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts +2 -2
  264. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.js +6 -6
  265. package/src/shade/renderer/gpu_primitive/hash_table/chunk_generate_next_linear_congruential_index.d.ts +14 -0
  266. package/src/shade/renderer/gpu_primitive/hash_table/chunk_generate_next_linear_congruential_index.d.ts.map +1 -0
  267. package/src/shade/renderer/gpu_primitive/hash_table/chunk_generate_next_linear_congruential_index.js +22 -0
  268. package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_atomic.d.ts +37 -0
  269. package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_atomic.d.ts.map +1 -0
  270. package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_atomic.js +122 -0
  271. package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_get.d.ts.map +1 -1
  272. package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_get.js +1 -11
  273. package/src/shade/renderer/gpu_primitive/hash_table/cpu_build_hash_table.d.ts +8 -0
  274. package/src/shade/renderer/gpu_primitive/hash_table/cpu_build_hash_table.d.ts.map +1 -1
  275. package/src/shade/renderer/gpu_primitive/hash_table/cpu_build_hash_table.js +6 -4
  276. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  277. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +1 -1
  278. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  279. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +2 -18
  280. package/src/shade/renderer/material/resident/NEUTRAL_SURFACE.d.ts +17 -0
  281. package/src/shade/renderer/material/resident/NEUTRAL_SURFACE.d.ts.map +1 -0
  282. package/src/shade/renderer/material/resident/NEUTRAL_SURFACE.js +16 -0
  283. package/src/shade/renderer/path_tracer/shader/INDIRECT_TEXTURE_FILTER.d.ts +1 -1
  284. package/src/shade/renderer/path_tracer/shader/INDIRECT_TEXTURE_FILTER.js +1 -1
  285. package/src/shade/renderer/path_tracer/shader/IndirectTextureFilter.js +1 -1
  286. package/src/shade/renderer/path_tracer/shader/chunk_beam_texture_level.d.ts +20 -0
  287. package/src/shade/renderer/path_tracer/shader/chunk_beam_texture_level.d.ts.map +1 -0
  288. package/src/shade/renderer/path_tracer/shader/chunk_beam_texture_level.js +65 -0
  289. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  290. package/src/shade/renderer/scene/GPUSceneContext.d.ts +1 -1
  291. package/src/shade/renderer/scene/GPUSceneContext.js +1 -1
  292. package/src/shade/renderer/shader/chunk/material/albedo_compress.d.ts +12 -0
  293. package/src/shade/renderer/shader/chunk/material/albedo_compress.d.ts.map +1 -0
  294. package/src/shade/renderer/shader/chunk/material/albedo_compress.js +26 -0
  295. package/src/shade/renderer/shader/chunk/material/chunk_albedo_compress.d.ts +16 -0
  296. package/src/shade/renderer/shader/chunk/material/chunk_albedo_compress.d.ts.map +1 -0
  297. package/src/shade/renderer/shader/chunk/material/chunk_albedo_compress.js +22 -0
  298. package/src/shade/renderer/shader/chunk/material/chunk_albedo_uncompress.d.ts +15 -0
  299. package/src/shade/renderer/shader/chunk/material/chunk_albedo_uncompress.d.ts.map +1 -0
  300. package/src/shade/renderer/shader/chunk/material/chunk_albedo_uncompress.js +23 -0
  301. package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_compress.d.ts +16 -0
  302. package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_compress.d.ts.map +1 -0
  303. package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_compress.js +25 -0
  304. package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_uncompress.d.ts +25 -0
  305. package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_uncompress.d.ts.map +1 -0
  306. package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_uncompress.js +36 -0
  307. package/src/shade/renderer/shader/chunk/material/metal_rough_compress.d.ts +11 -0
  308. package/src/shade/renderer/shader/chunk/material/metal_rough_compress.d.ts.map +1 -0
  309. package/src/shade/renderer/shader/chunk/material/metal_rough_compress.js +38 -0
  310. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot.d.ts +20 -0
  311. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot.d.ts.map +1 -0
  312. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot.js +35 -0
  313. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_compress.d.ts +28 -0
  314. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_compress.d.ts.map +1 -0
  315. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_compress.js +79 -0
  316. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_fit.d.ts +25 -0
  317. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_fit.d.ts.map +1 -0
  318. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_fit.js +89 -0
  319. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_uncompress.d.ts +31 -0
  320. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_uncompress.d.ts.map +1 -0
  321. package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_uncompress.js +66 -0
  322. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_add.d.ts.map +1 -1
  323. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_add.js +2 -0
  324. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_load.d.ts +17 -0
  325. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_load.d.ts.map +1 -0
  326. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_load.js +34 -0
  327. package/src/shade/renderer/volumetrics/chunk_frustum_unit_box_coverage_multisample.d.ts +18 -0
  328. package/src/shade/renderer/volumetrics/chunk_frustum_unit_box_coverage_multisample.d.ts.map +1 -1
  329. package/src/shade/renderer/volumetrics/chunk_frustum_unit_box_coverage_multisample.js +31 -23
  330. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
  331. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +5 -6
  332. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  333. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  334. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +0 -213
  335. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +0 -1
  336. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +0 -1468
  337. package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.d.ts +0 -82
  338. package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.d.ts.map +0 -1
  339. package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.js +0 -127
  340. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.d.ts +0 -24
  341. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.d.ts.map +0 -1
  342. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.js +0 -29
  343. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.d.ts +0 -12
  344. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.js +0 -31
  346. package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.d.ts +0 -11
  347. package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.js +0 -21
  349. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.d.ts +0 -29
  350. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.js +0 -179
  352. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.d.ts +0 -17
  353. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.js +0 -107
  355. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.d.ts +0 -65
  356. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.d.ts.map +0 -1
  357. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.js +0 -376
  358. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts +0 -40
  359. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts.map +0 -1
  360. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.js +0 -301
  361. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.d.ts +0 -19
  362. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.d.ts.map +0 -1
  363. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.js +0 -61
  364. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts +0 -18
  365. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts.map +0 -1
  366. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.js +0 -102
  367. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.d.ts +0 -15
  368. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.d.ts.map +0 -1
  369. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.js +0 -65
  370. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.d.ts +0 -22
  371. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.d.ts.map +0 -1
  372. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.js +0 -136
  373. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.d.ts +0 -20
  374. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.d.ts.map +0 -1
  375. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.js +0 -104
  376. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.d.ts +0 -20
  377. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.d.ts.map +0 -1
  378. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.js +0 -80
  379. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.d.ts +0 -18
  380. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.d.ts.map +0 -1
  381. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.js +0 -113
  382. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.d.ts +0 -30
  383. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.d.ts.map +0 -1
  384. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.js +0 -146
  385. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_cards.d.ts +0 -34
  386. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_cards.d.ts.map +0 -1
  387. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +0 -31
  388. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +0 -1
  389. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +0 -82
@@ -12,38 +12,63 @@ import {
12
12
  } from "../../gpu_primitive/slot_stack/shader_slot_stack_push_range.js";
13
13
  import { graph_import_buffer } from "../../shader/graph/graph_import_buffer.js";
14
14
  import { GPUTileAtlas3D } from "../../texture/atlas/GPUTileAtlas3D.js";
15
+ import { meshlet_batch_colored } from "../meshlet/meshlet_batch_colored.js";
15
16
  import {
16
17
  MESH_SDF_BAKE_WORKGROUP_SIZE,
17
18
  MESH_SDF_COUNTER_SLOTS,
18
19
  MESH_SDF_COUNTER_WORDS,
20
+ MESH_SDF_LOG_COLLIDED,
19
21
  MESH_SDF_LOG_COMPLETIONS,
20
22
  MESH_SDF_LOG_HEADER_WORDS,
21
- MESH_SDF_LOG_PLACED,
22
23
  MESH_SDF_LOG_QUEUED,
23
24
  MESH_SDF_LOG_RECORD_WORDS,
24
25
  MESH_SDF_LOG_FREE_SLOTS,
26
+ MESH_SDF_LOG_SHARED,
25
27
  MESH_SDF_LOG_STARVED,
28
+ MESH_SDF_LOG_STORED,
26
29
  MESH_SDF_LOG_TAKEN,
27
30
  MESH_SDF_STAGING_VEC4S,
28
31
  MESH_SDF_GROUPS_PER_BRICK,
29
32
  MESH_SDF_TAKE_DISPATCH,
30
- MESH_SDF_TAKE_PLACE_DISPATCH,
31
- MESH_SDF_TAKE_WORDS
33
+ MESH_SDF_TAKE_WORDS,
34
+ MESH_SDF_TAKEN_WORDS,
35
+ mesh_sdf_claim_size
32
36
  } from "./bake/MESH_SDF_BAKE.js";
37
+ import { MESH_SDF_CONTENT_WORDS, mesh_sdf_content_table_size } from "./bake/chunk_mesh_sdf_contents.js";
33
38
  import { shader_mesh_sdf_classify } from "./bake/shader_mesh_sdf_classify.js";
39
+ import { shader_mesh_sdf_content_rehash } from "./bake/shader_mesh_sdf_content_rehash.js";
34
40
  import { shader_mesh_sdf_evaluate } from "./bake/shader_mesh_sdf_evaluate.js";
35
41
  import { shader_mesh_sdf_free } from "./bake/shader_mesh_sdf_free.js";
42
+ import { shader_mesh_sdf_count } from "./bake/shader_mesh_sdf_count.js";
43
+ import { shader_mesh_sdf_key } from "./bake/shader_mesh_sdf_key.js";
44
+ import {
45
+ shader_mesh_sdf_resolve_compare,
46
+ shader_mesh_sdf_resolve_find,
47
+ shader_mesh_sdf_resolve_fresh,
48
+ shader_mesh_sdf_resolve_hold
49
+ } from "./bake/shader_mesh_sdf_resolve.js";
36
50
  import { shader_mesh_sdf_store } from "./bake/shader_mesh_sdf_store.js";
37
51
  import { shader_mesh_sdf_take } from "./bake/shader_mesh_sdf_take.js";
38
- import { GPUMeshCardSets, MESH_CARD_CAPTURE_BUDGET_MAX } from "./cards/GPUMeshCardSets.js";
39
- import { mesh_card_layout_words, mesh_card_placement_of } from "./cards/MESH_CARDS.js";
40
- import { shader_mesh_cards_compact } from "./cards/shader_mesh_cards_compact.js";
41
- import { shader_mesh_cards_histogram } from "./cards/shader_mesh_cards_histogram.js";
42
- import { shader_mesh_cards_log } from "./cards/shader_mesh_cards_log.js";
43
- import { shader_mesh_cards_merge } from "./cards/shader_mesh_cards_merge.js";
44
- import { shader_mesh_cards_pages } from "./cards/shader_mesh_cards_pages.js";
45
- import { shader_mesh_cards_split } from "./cards/shader_mesh_cards_split.js";
46
- import { MESH_SDF_BRICK_TEXELS, MESH_SDF_BRICK_VOXELS, MeshSDFState } from "./MESH_SDF.js";
52
+ import {
53
+ MESH_SDF_UPLOAD_BRICK_WORDS,
54
+ shader_mesh_sdf_upload_compare,
55
+ shader_mesh_sdf_upload_find,
56
+ shader_mesh_sdf_upload_fresh,
57
+ shader_mesh_sdf_upload_key,
58
+ shader_mesh_sdf_upload_link,
59
+ shader_mesh_sdf_upload_store
60
+ } from "./bake/shader_mesh_sdf_upload.js";
61
+ import { ModelCacheBundle, ModelCacheBundleCache, ModelCacheBundleField } from "./bundle/ModelCacheBundle.js";
62
+ import { download_texture_data } from "../../texture/download_texture_data.js";
63
+ import { GPUMeshSurfaceCaches } from "./surface/GPUMeshSurfaceCaches.js";
64
+ import {
65
+ MESH_SDF_BRICK_TEXEL_COUNT,
66
+ MESH_SDF_BRICK_TEXELS,
67
+ MESH_SDF_EMPTY,
68
+ MESH_SDF_UNNUMBERED,
69
+ MeshSDFState
70
+ } from "./MESH_SDF.js";
71
+ import { mesh_sdf_brick_key } from "./MESH_SDF_BRICK_KEY.js";
47
72
  import { MESH_SDF_SAMPLER } from "./MESH_SDF_RESOURCES.js";
48
73
  import { MESH_SDF_STRUCT } from "./MESH_SDF_STRUCT.js";
49
74
  import { MeshSDFLayout } from "./MeshSDFLayout.js";
@@ -54,7 +79,7 @@ import { ceilPowerOfTwo } from "../../../../core/binary/operations/ceilPowerOfTw
54
79
  * @typedef {import("../GPUGeometryManager.js").GPUGeometryManager} GPUGeometryManager
55
80
  * @typedef {import("../GPUGeometryMetadata.js").GPUGeometryMetadata} GPUGeometryMetadata
56
81
  * @typedef {import("../../material/resident/GPUResidentMaterialContext.js").GPUResidentMaterialContext} GPUResidentMaterialContext
57
- * @typedef {import("../../material/GPUMaterialManager.js").GPUMaterialManager} GPUMaterialManager
82
+ * @typedef {import("../../material/ShadeMaterial.js").ShadeMaterial} ShadeMaterial
58
83
  */
59
84
 
60
85
  /*
@@ -66,16 +91,45 @@ const HOST_QUEUED = 1;
66
91
  const HOST_BAKING = 2;
67
92
  const HOST_RESIDENT = 3;
68
93
  const HOST_ALIAS = 4;
94
+ /** Its field taken from a bundle, its bricks placed by the next bake; resident from the bake after. */
95
+ const HOST_UPLOADING = 5;
69
96
 
70
- /*
71
- Where a resident geometry's cards are (§6.5): waiting for placement; being placed, in a range sized
72
- for any layout of its grid; placed, waiting to be moved into a range of their own size; placed.
97
+ /**
98
+ * A buffer's words, read back.
99
+ *
100
+ * @param {GPUDevice} device
101
+ * @param {GPUBuffer} buffer COPY_SRC
102
+ * @returns {Promise<Uint32Array>}
73
103
  */
74
- const CARDS_NONE = 0;
75
- const CARDS_QUEUED = 1;
76
- const CARDS_PLACING = 2;
77
- const CARDS_COMPACTING = 3;
78
- const CARDS_PLACED = 4;
104
+ async function read_back(device, buffer) {
105
+ const target = device.createBuffer({ size: buffer.size, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ });
106
+ const encoder = device.createCommandEncoder({ label: "GPUGeometrySDFManager/export" });
107
+
108
+ encoder.copyBufferToBuffer(buffer, 0, target, 0, buffer.size);
109
+ device.queue.submit([encoder.finish()]);
110
+
111
+ await target.mapAsync(GPUMapMode.READ);
112
+
113
+ const words = new Uint32Array(target.getMappedRange().slice(0));
114
+
115
+ target.unmap();
116
+ target.destroy();
117
+
118
+ return words;
119
+ }
120
+
121
+ /**
122
+ * Whether two bricks hold the same bytes.
123
+ */
124
+ function same_brick(a, a_offset, b, b_offset) {
125
+ for (let i = 0; i < MESH_SDF_BRICK_TEXEL_COUNT; i++) {
126
+ if (a[a_offset + i] !== b[b_offset + i]) {
127
+ return false;
128
+ }
129
+ }
130
+
131
+ return true;
132
+ }
79
133
 
80
134
  const HEADER_BYTES = MESH_SDF_STRUCT.size;
81
135
  const HEADER_ORIGIN = MESH_SDF_STRUCT.get("origin").offset;
@@ -83,7 +137,6 @@ const HEADER_VOXEL = MESH_SDF_STRUCT.get("voxel").offset;
83
137
  const HEADER_BRICKS = MESH_SDF_STRUCT.get("bricks").offset;
84
138
  const HEADER_LEVEL_COUNT = MESH_SDF_STRUCT.get("level_count").offset;
85
139
  const HEADER_INDIRECTION = MESH_SDF_STRUCT.get("indirection").offset;
86
- const HEADER_CARDS = MESH_SDF_STRUCT.get("cards").offset;
87
140
  const HEADER_STATE = MESH_SDF_STRUCT.get("state").offset;
88
141
  const HEADER_SOURCE = MESH_SDF_STRUCT.get("source").offset;
89
142
  const HEADER_GENERATION = MESH_SDF_STRUCT.get("generation").offset;
@@ -124,15 +177,6 @@ const INITIAL_LOG_CAPACITY = 64;
124
177
  */
125
178
  const INITIAL_ARENA_WORDS = 4096;
126
179
 
127
- /**
128
- * Geometries whose cards one frame places, at most: a safety net for a frame in which many complete.
129
- * A placement's five passes cost 140 µs a geometry at the median over Sponza's fill on the RTX 4090
130
- * (220 µs on the AMD iGPU), its split pass most of it, so ⌊1 ms / 140 µs⌋ of them fit the bake's
131
- * basis of 1 ms a frame there.
132
- * @type {number}
133
- */
134
- const MESH_CARD_PLACEMENTS_PER_FRAME = 7;
135
-
136
180
  /**
137
181
  * Most bricks a frame's take may hand out: evaluate and store run {@link MESH_SDF_GROUPS_PER_BRICK}
138
182
  * workgroups a brick in one dispatch row.
@@ -140,6 +184,26 @@ const MESH_CARD_PLACEMENTS_PER_FRAME = 7;
140
184
  */
141
185
  export const MESH_SDF_BAKE_BUDGET_MAX = Math.floor(WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION / MESH_SDF_GROUPS_PER_BRICK);
142
186
 
187
+ /**
188
+ * Whether a bundle's field is laid out as `layout` lays its geometry out: the header's words, origin
189
+ * and voxel as the header's f32 hold them.
190
+ *
191
+ * @param {ModelCacheBundleField} field
192
+ * @param {MeshSDFLayout} layout
193
+ * @returns {boolean}
194
+ */
195
+ function field_has_layout(field, layout) {
196
+ for (let axis = 0; axis < 3; axis++) {
197
+ if (field.origin[axis] !== Math.fround(layout.origin[axis]) || field.bricks[axis] !== layout.bricks[axis]) {
198
+ return false;
199
+ }
200
+ }
201
+
202
+ return field.voxel === Math.fround(layout.voxel)
203
+ && field.level_count === layout.level_count
204
+ && field.entries.length === layout.brick_count;
205
+ }
206
+
143
207
  /**
144
208
  * The most bricks one geometry can have under `max_bricks`: every level of a cube of that many.
145
209
  *
@@ -196,8 +260,8 @@ function grow_typed(array, length) {
196
260
  * queues a bake; the last one going leaves the cache in place until {@link trim}, which only a user of
197
261
  * the caches calls, so a cache outlives a mode that stops using it and is there when the mode comes
198
262
  * back (D28). {@link forget} drops a geometry the geometry manager has let go of, whatever holds it.
199
- * {@link alias} points a geometry's id at another's cache, which readers follow, and whose holders and card sets
200
- * the aliased geometry's become: a skinned clone's at its source's, a virtual geometry's at its proxy's.
263
+ * {@link alias} points a geometry's id at another's cache, which readers follow, and whose holders and surface
264
+ * caches the aliased geometry's become: a skinned clone's at its source's, a virtual geometry's at its proxy's.
201
265
  *
202
266
  * **Side.** A holder says whether it draws both sides of the geometry. A field is baked two-sided
203
267
  * while any of its holders does: its vote then counts no back face, so nothing is inside it.
@@ -207,21 +271,29 @@ function grow_typed(array, length) {
207
271
  *
208
272
  * **The bake** ({@link graph_bake}, once a frame) admits queued geometries in request order whose
209
273
  * trees are resident, while the ring has room for every brick they could queue, and runs free,
210
- * classify, take, evaluate and store (`bake/`). At most `budget` bricks are evaluated a frame. The
211
- * device logs each geometry it completes; the log is read back, and the host turns the header
212
- * resident and sends {@link onBaked}. A take held back by the free slots is logged too, and the atlas
213
- * and its slot stack double.
274
+ * classify, take, evaluate, key, resolve and store (`bake/`). At most `budget` bricks are evaluated a
275
+ * frame. The device logs each geometry it completes; the log is read back, and the host turns the
276
+ * header resident and sends {@link onBaked}. A take held back by the free slots is logged too, and the
277
+ * atlas and its slot stack double.
278
+ *
279
+ * **Shared bricks.** Bricks of the same bytes, of one geometry or of many, share one slot: a slot
280
+ * counts the entries holding it and is given back with the last. A content table lists slots by the
281
+ * content keys of their bytes (`chunk_mesh_sdf_contents`, `MESH_SDF_BRICK_KEY.js`), and a brick takes
282
+ * a slot it finds there only once their bytes compare equal: a key that two bytes share costs a share,
283
+ * never a brick its bytes.
284
+ *
285
+ * **Bundles.** {@link export_bundle} reads resident fields and surface caches out as a
286
+ * `ModelCacheBundle`, each brick once; {@link upload_bundle} takes one back as the fields of geometries
287
+ * that have none, its bricks placed by the next bake, with or without sharing them with what is
288
+ * resident, and its caches offered to the surface caches.
214
289
  *
215
- * **Cards** (§6.5): a geometry turned resident has its cards placed by the next bake that has room
216
- * (`cards/`), in a range sized for any layout of its grid. The placement is logged with the columns
217
- * and pages it took; on that readback the geometry gets a range of exactly that size, and the next bake
218
- * moves the layout into it and gives the placement's range back. The layout then reaches
219
- * {@link cards}, whose card sets — one per (geometry, material) pair — are captured after the bake,
220
- * `capture_budget` pages a frame.
290
+ * **Surface caches**: a geometry turned resident reaches {@link surfaces} with the bricks its field
291
+ * stored, whose Model Surface Caches, one per (geometry, material) pair, are baked after the bake,
292
+ * `surface_budget` bricks a frame.
221
293
  *
222
294
  * **A geometry with no tree of its own** to bake from, a virtual geometry's, waits queued, as one whose
223
295
  * tree is not resident yet does, until it is pointed at a stand-in ({@link alias}): an ordinary geometry
224
- * in the same local space, baked, placed and captured here as any is. Whoever makes stand-ins hears of
296
+ * in the same local space, baked here as any is. Whoever makes stand-ins hears of
225
297
  * each geometry queued ({@link onRequested}) and let go ({@link onForgotten}), and aliases between
226
298
  * frames, its stand-in added to the geometry manager as any geometry is.
227
299
  *
@@ -277,50 +349,14 @@ export class GPUGeometrySDFManager {
277
349
  #state = new Uint8Array(64);
278
350
  #generation = new Uint32Array(64);
279
351
  #brick_count = new Uint32Array(64);
280
-
281
- #card_state = new Uint8Array(64);
282
- /** Words of the range the geometry's cards are placed in. */
283
- #placement_words = new Uint32Array(64);
284
- /** Where the placement's scratch starts in it. */
285
- #placement_scratch = new Uint32Array(64);
286
- /** Columns over the six directions of the geometry's level-0 grid: the histogram's threads. */
287
- #placement_columns = new Uint32Array(64);
288
- /** Pages the placed layout has. */
289
- #card_pages = new Uint32Array(64);
290
- /** Words the placed layout keeps. */
291
- #card_words = new Uint32Array(64);
292
- /** Texels a side of the layout's largest card: the grid's longest axis in voxels, plus one. */
293
- #card_side = new Uint32Array(64);
294
-
295
- /**
296
- * The range each geometry's cards are being placed in.
297
- * @type {(import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null)[]}
298
- */
299
- #card_scratch = [];
300
-
301
- /**
302
- * The range each geometry's placed layout keeps.
303
- * @type {(import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null)[]}
304
- */
305
- #card_ranges = [];
306
-
307
- /**
308
- * Resident geometries whose cards wait for placement, in the order they turned resident.
309
- * @type {number[]}
310
- */
311
- #place_queue = [];
352
+ /** Bricks given a slot, numbered 0 up, as the resident cache's completion reported them. */
353
+ #stored_bricks = new Uint32Array(64);
312
354
 
313
355
  /**
314
- * Geometries whose placed layout waits to be moved into its own range.
315
- * @type {number[]}
356
+ * The (geometry, material) pairs' surface material texels on the fields.
357
+ * @type {GPUMeshSurfaceCaches}
316
358
  */
317
- #compact_queue = [];
318
-
319
- /**
320
- * The (geometry, material) pairs' captures of the layouts.
321
- * @type {GPUMeshCardSets}
322
- */
323
- #cards;
359
+ #surfaces;
324
360
 
325
361
  /**
326
362
  * @type {(import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null)[]}
@@ -407,12 +443,56 @@ export class GPUGeometrySDFManager {
407
443
  */
408
444
  #pushes = [];
409
445
 
446
+ /**
447
+ * What each slot holds: the entries holding it, and the content key it is listed under
448
+ * (`chunk_mesh_sdf_contents`), MESH_SDF_CONTENT_WORDS a slot.
449
+ * @type {GPUBuffer|null}
450
+ */
451
+ #contents = null;
452
+
453
+ /**
454
+ * The slots by content key: a device-kept hash table of twice the slot capacity in records
455
+ * (`mesh_sdf_content_table_size`).
456
+ * @type {GPUBuffer|null}
457
+ */
458
+ #content_table = null;
459
+
460
+ /**
461
+ * The content table of the atlas before it last grew, whose records the next bake moves into the
462
+ * grown one, and its records; null when none is left to move.
463
+ * @type {GPUBuffer|null}
464
+ */
465
+ #rehash_from = null;
466
+ #rehash_records = 0;
467
+
468
+ /**
469
+ * Uploads of bundles' bricks the next bake records: its buffers, its counts, and the fields it
470
+ * completes.
471
+ * @type {{bytes: GPUBuffer, bricks: GPUBuffer, ranges: GPUBuffer, brick_count: number, range_count: number, entry_count: number, deduplicate: boolean, fields: Object[]}[]}
472
+ */
473
+ #uploads = [];
474
+
475
+ /**
476
+ * Fields whose upload a bake has recorded, resident from the next: (id, generation, and what their
477
+ * surface caches are laid out by).
478
+ * @type {{id: number, generation: number, blocks: number, table: Uint32Array, provisions: Object[]}[]}
479
+ */
480
+ #uploaded = [];
481
+
482
+ /**
483
+ * Buffers only the last bake's commands read, its uploads' and the content table it rehashed from,
484
+ * destroyed by the next {@link graph_bake}, once those commands are submitted.
485
+ * @type {GPUBuffer[]}
486
+ */
487
+ #garbage = [];
488
+
410
489
  /** @type {GPUBuffer|null} */
411
490
  #take = null;
412
491
 
413
492
  /**
414
- * The frame's words in the arena: its log, room for {@link #log_capacity} completions, then its
415
- * tallies, a word for each of {@link #staging_bricks} bricks taken.
493
+ * The frame's words in the arena: its log, room for {@link #log_capacity} completions, then a
494
+ * record of MESH_SDF_TAKEN_WORDS for each of {@link #staging_bricks} bricks taken, then the claims
495
+ * of that many bricks (`mesh_sdf_claim_size`).
416
496
  * @type {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null}
417
497
  */
418
498
  #frame_range = null;
@@ -447,29 +527,24 @@ export class GPUGeometrySDFManager {
447
527
  #frame_log_offset = 0;
448
528
  #frame_log_bytes = 0;
449
529
  #frame_tally_offset = 0;
530
+ #frame_claim_offset = 0;
531
+ #frame_claim_size = 0;
450
532
  #frame_bytes = 0;
451
533
 
452
534
  #log_data = { arena: -1 };
453
535
 
454
- /** The frame's placements, as geometry, the range's first word, and where its scratch starts. */
455
- #frame_placements = [];
456
- /** The frame's layout moves, as source, destination and words. */
457
- #frame_compactions = [];
458
-
459
- #histogram_settings = { geometry: 0, columns: 0 };
460
- #split_settings = { geometry: 0 };
461
- #merge_settings = { geometry: 0, dispatch: MESH_SDF_TAKE_PLACE_DISPATCH };
462
- #pages_settings = { geometry: 0 };
463
- #place_log_settings = { geometry: 0, log_offset: 0, log_capacity: 0 };
464
- #compact_settings = { source: 0, destination: 0, count: 0, groups_x: 0 };
465
-
466
536
  #blas_bindings = { blas_lookup: null, blas_data: null, geometries: null, meshlet_metadata: null, meshlet_data: null };
467
537
 
468
538
  #classify_settings = { range_count: 0, brick_count: 0, groups_x: 0, ring_capacity: 0, log_offset: 0, log_capacity: 0 };
469
539
  #free_settings = { range_count: 0, entry_count: 0, groups_x: 0 };
470
540
  #take_settings = { budget: 0, log_offset: 0 };
471
- #evaluate_settings = { ring_capacity: 0, slot_capacity: 0, log_offset: 0, log_capacity: 0, tally_offset: 0 };
472
- #store_settings = { ring_capacity: 0 };
541
+ #evaluate_settings = { ring_capacity: 0, log_offset: 0, log_capacity: 0, tally_offset: 0 };
542
+ #key_settings = { ring_capacity: 0, tally_offset: 0 };
543
+ #resolve_settings = { ring_capacity: 0, slot_capacity: 0, log_offset: 0, tally_offset: 0, claim_offset: 0, claim_size: 0 };
544
+ #store_settings = { ring_capacity: 0, tally_offset: 0 };
545
+ #rehash_settings = { groups_x: 0 };
546
+ #upload_settings = { brick_count: 0, deduplicate: 0, slot_capacity: 0, range_count: 0, entry_count: 0, groups_x: 0 };
547
+ #count_settings = { log_offset: 0, log_capacity: 0 };
473
548
  #push_settings = { first: 0, count: 0, counter: MESH_SDF_COUNTER_SLOTS };
474
549
  #bindings = {};
475
550
 
@@ -492,6 +567,8 @@ export class GPUGeometrySDFManager {
492
567
  #resident_count = 0;
493
568
  #starved_frames = 0;
494
569
  #bricks_evaluated = 0;
570
+ #bricks_shared = 0;
571
+ #bricks_collided = 0;
495
572
  #free_slots = 0;
496
573
 
497
574
  #destroyed = false;
@@ -506,16 +583,17 @@ export class GPUGeometrySDFManager {
506
583
 
507
584
  this.#device = device;
508
585
  this.#geometries = geometries;
509
- this.#cards = new GPUMeshCardSets(device);
586
+ this.#surfaces = new GPUMeshSurfaceCaches(device);
510
587
  }
511
588
 
512
589
  /**
513
- * The card sets: one capture of a geometry's layout per (geometry, material) pair, which their
514
- * user acquires and releases. Layouts reach it as they are placed.
515
- * @returns {GPUMeshCardSets}
590
+ * The Model Surface Caches: one (geometry, material) pair's surface material texels on its
591
+ * geometry's field, which their user acquires and releases. Fields reach it as they turn resident,
592
+ * with the bricks they stored.
593
+ * @returns {GPUMeshSurfaceCaches}
516
594
  */
517
- get cards() {
518
- return this.#cards;
595
+ get surfaces() {
596
+ return this.#surfaces;
519
597
  }
520
598
 
521
599
  /**
@@ -696,9 +774,9 @@ export class GPUGeometrySDFManager {
696
774
  * follows the source through its bake.
697
775
  *
698
776
  * Whatever held `clone`'s own cache holds `source`'s from here on, its side included, as does every holder of
699
- * `clone` after; and `clone`'s card sets capture `source`'s layout through `source`'s meshlets
700
- * ({@link GPUMeshCardSets#alias}). So a source whose stand-in arrives after `clone` was asked for needs
701
- * nothing moved by its holders.
777
+ * `clone` after; and `clone`'s surface caches follow `source`'s field and are baked from `source`'s
778
+ * triangles ({@link GPUMeshSurfaceCaches#alias}). So a source whose stand-in arrives after `clone` was
779
+ * asked for needs nothing moved by its holders.
702
780
  *
703
781
  * @param {GPUGeometryMetadata} clone
704
782
  * @param {GPUGeometryMetadata} source
@@ -751,7 +829,7 @@ export class GPUGeometrySDFManager {
751
829
 
752
830
  clones.push(id);
753
831
 
754
- this.#cards.alias(id, source.index);
832
+ this.#surfaces.alias(id, source.index);
755
833
 
756
834
  if (this.#state[source.index] === HOST_RESIDENT) {
757
835
  // its readers read a resident cache from here on
@@ -780,6 +858,7 @@ export class GPUGeometrySDFManager {
780
858
  state_of(record) {
781
859
  switch (this.#state[record.index] ?? HOST_NONE) {
782
860
  case HOST_BAKING:
861
+ case HOST_UPLOADING:
783
862
  return MeshSDFState.Baking;
784
863
  case HOST_RESIDENT:
785
864
  return MeshSDFState.Resident;
@@ -866,6 +945,23 @@ export class GPUGeometrySDFManager {
866
945
  return this.#bricks_evaluated;
867
946
  }
868
947
 
948
+ /**
949
+ * Bricks the bake gave a slot already holding their bytes, as read back.
950
+ * @returns {number}
951
+ */
952
+ get bricks_shared() {
953
+ return this.#bricks_shared;
954
+ }
955
+
956
+ /**
957
+ * Bricks the bake gave a slot of their own because the slot their content key found, or the
958
+ * frame's first brick of that key, holds other bytes, as read back.
959
+ * @returns {number}
960
+ */
961
+ get bricks_collided() {
962
+ return this.#bricks_collided;
963
+ }
964
+
869
965
  /**
870
966
  * Free slots of the atlas before the last take read back.
871
967
  * @returns {number}
@@ -942,7 +1038,7 @@ export class GPUGeometrySDFManager {
942
1038
  get gpu_memory_usage() {
943
1039
  let bytes = 0;
944
1040
 
945
- for (const buffer of [this.#headers, this.#indirection, this.#slots, this.#take, this.#ring, this.#classify_ranges, this.#free_ranges]) {
1041
+ for (const buffer of [this.#headers, this.#indirection, this.#slots, this.#contents, this.#content_table, this.#rehash_from, this.#take, this.#ring, this.#classify_ranges, this.#free_ranges]) {
946
1042
  if (buffer !== null) {
947
1043
  bytes += buffer.size;
948
1044
  }
@@ -952,32 +1048,387 @@ export class GPUGeometrySDFManager {
952
1048
  bytes += this.#atlas.capacity * MESH_SDF_BRICK_TEXELS ** 3;
953
1049
  }
954
1050
 
955
- return bytes + this.#cards.gpu_memory_usage;
1051
+ return bytes + this.#surfaces.gpu_memory_usage;
1052
+ }
1053
+
1054
+ /**
1055
+ * Take a bundle's fields (`ModelCacheBundle`) as the caches of the geometries `records` names, in
1056
+ * place of baking them, and offer its surface caches to the caches of the materials `materials`
1057
+ * names. A field is taken by a geometry that has no cache and no bake under way, whose layout at this
1058
+ * manager's voxel size and cap is the field's; any other is left to bake as it would. The next bake
1059
+ * places the bundle's bricks and links the fields' entries to them, and the fields are resident from
1060
+ * the bake after, their surface caches laid out by the bundle's tables (`GPUMeshSurfaceCaches.adopt_layout`).
1061
+ *
1062
+ * A bundle keeps each brick once however many fields hold it. Deduplicating, a brick whose bytes a
1063
+ * slot already holds takes that slot, and the rest are listed for bricks baked later to share; not
1064
+ * deduplicating, each takes a slot of its own, never shared, which suits a bundle of a whole scene
1065
+ * loaded alone. The atlas grows ahead of the bake for every brick, so none waits for a slot.
1066
+ *
1067
+ * A field taken is the geometry's like a baked one: held, released and trimmed alike.
1068
+ *
1069
+ * @param {ModelCacheBundle} bundle baked at this manager's `configure`
1070
+ * @param {(GPUGeometryMetadata|null)[]} records the geometry of each of the bundle's fields; null takes none
1071
+ * @param {(ShadeMaterial|null)[]} materials the material of each of the bundle's caches; null offers none
1072
+ * @param {boolean} deduplicate whether its bricks share slots with those resident, and are shared
1073
+ * @returns {number} the fields taken
1074
+ */
1075
+ upload_bundle(bundle, records, materials, deduplicate) {
1076
+ assert.equal(bundle.voxel_size, Math.fround(this.#voxel_size), 'bundle.voxel_size: baked at another voxel');
1077
+ assert.equal(bundle.max_bricks, this.#max_bricks, 'bundle.max_bricks: baked under another cap');
1078
+ assert.equal(records.length, bundle.fields.length, 'records: one for each field');
1079
+ assert.equal(materials.length, bundle.caches.length, 'materials: one for each cache');
1080
+ assert.isBoolean(deduplicate, 'deduplicate');
1081
+
1082
+ this.#ensure_device();
1083
+ this.#ensure_headers(this.#geometries.__last_geometry_index);
1084
+
1085
+ const layout = this.#layout;
1086
+ /** the bundle's bricks the upload carries, by their place in it */
1087
+ const place_of = new Map();
1088
+ const runs = [];
1089
+ const fields = [];
1090
+
1091
+ let entries = 0;
1092
+
1093
+ for (let f = 0; f < bundle.fields.length; f++) {
1094
+ const record = records[f];
1095
+
1096
+ if (record === null) {
1097
+ continue;
1098
+ }
1099
+
1100
+ const id = record.index;
1101
+
1102
+ this.#ensure_id(id);
1103
+
1104
+ if (this.#state[id] !== HOST_NONE && this.#state[id] !== HOST_QUEUED) {
1105
+ continue;
1106
+ }
1107
+
1108
+ const field = bundle.fields[f];
1109
+
1110
+ layout.compute(record.geometry.bounding_box, this.#voxel_size, this.#max_bricks);
1111
+
1112
+ if (!field_has_layout(field, layout)) {
1113
+ continue;
1114
+ }
1115
+
1116
+ const count = layout.brick_count;
1117
+ const stored = field.numbered.length;
1118
+
1119
+ // its stored count and pending word, then its entries, its bricks' numbers and its bricks by number
1120
+ const words = 3 * count + 2;
1121
+
1122
+ this.#ensure_indirection(words);
1123
+
1124
+ const range = this.#indirection_allocator.allocate(words);
1125
+
1126
+ assert.notEqual(range.offset, ALLOCATOR_NO_SPACE, 'indirection allocation after growth');
1127
+
1128
+ const scratch = new Uint32Array(words);
1129
+
1130
+ scratch[0] = stored;
1131
+
1132
+ for (let e = 0; e < count; e++) {
1133
+ const entry = field.entries[e];
1134
+
1135
+ if (entry < MESH_SDF_EMPTY) {
1136
+ let place = place_of.get(entry);
1137
+
1138
+ if (place === undefined) {
1139
+ place = place_of.size;
1140
+ place_of.set(entry, place);
1141
+ }
1142
+
1143
+ // its place in the upload, which link turns into its slot
1144
+ scratch[2 + e] = place;
1145
+ } else {
1146
+ scratch[2 + e] = entry;
1147
+ }
1148
+
1149
+ scratch[2 + count + e] = MESH_SDF_UNNUMBERED;
1150
+ }
1151
+
1152
+ for (let n = 0; n < stored; n++) {
1153
+ scratch[2 + count + field.numbered[n]] = n;
1154
+ scratch[2 + 2 * count + n] = field.numbered[n];
1155
+ }
1156
+
1157
+ this.#device.queue.writeBuffer(this.#indirection, 4 * range.offset, scratch);
1158
+
1159
+ this.#records[id] = record;
1160
+ this.#ranges[id] = range;
1161
+ this.#brick_count[id] = count;
1162
+ this.#stored_bricks[id] = stored;
1163
+ this.#generation[id]++;
1164
+ this.#two_sided[id] = field.two_sided;
1165
+ this.#state[id] = HOST_UPLOADING;
1166
+
1167
+ this.#write_header(id, layout, range.offset + 2, MeshSDFState.Baking);
1168
+
1169
+ const provisions = [];
1170
+
1171
+ for (let c = 0; c < bundle.caches.length; c++) {
1172
+ if (bundle.caches[c].field === f && materials[c] !== null) {
1173
+ provisions.push({ material: materials[c], cache: bundle.caches[c] });
1174
+ }
1175
+ }
1176
+
1177
+ fields.push({ id, generation: this.#generation[id], blocks: field.blocks, table: field.table, provisions });
1178
+
1179
+ runs.push(entries, range.offset + 2);
1180
+ entries += count;
1181
+ }
1182
+
1183
+ if (fields.length === 0) {
1184
+ return 0;
1185
+ }
1186
+
1187
+ const brick_count = place_of.size;
1188
+ const bytes = new Uint8Array(Math.max(4, brick_count * MESH_SDF_BRICK_TEXEL_COUNT));
1189
+
1190
+ for (const [brick, place] of place_of) {
1191
+ bytes.set(bundle.bricks.subarray(brick * MESH_SDF_BRICK_TEXEL_COUNT, (brick + 1) * MESH_SDF_BRICK_TEXEL_COUNT), place * MESH_SDF_BRICK_TEXEL_COUNT);
1192
+ }
1193
+
1194
+ // room on the stack for every brick, whatever is free there now: no pop of the upload's is refused
1195
+ const target = this.#slot_capacity + brick_count;
1196
+
1197
+ while (this.#slot_capacity < target) {
1198
+ const before = this.#slot_capacity;
1199
+
1200
+ this.#grow_slots();
1201
+
1202
+ assert.greaterThan(this.#slot_capacity, before, 'the atlas is at its limit: the bundle\'s bricks do not fit');
1203
+
1204
+ // a log from before this growth asked for what it gives
1205
+ this.#grown_frame = this.#frame;
1206
+ }
1207
+
1208
+ const device = this.#device;
1209
+ const upload_bytes = this.#create_buffer("upload bytes", bytes.length, GPUBufferUsage.COPY_DST);
1210
+ const upload_bricks = this.#create_buffer("upload bricks", 4 * Math.max(1, brick_count * MESH_SDF_UPLOAD_BRICK_WORDS), GPUBufferUsage.COPY_DST);
1211
+ const upload_ranges = this.#create_buffer("upload ranges", 4 * runs.length, GPUBufferUsage.COPY_DST);
1212
+
1213
+ device.queue.writeBuffer(upload_bytes, 0, bytes);
1214
+ device.queue.writeBuffer(upload_ranges, 0, Uint32Array.from(runs));
1215
+
1216
+ this.#uploads.push({
1217
+ bytes: upload_bytes,
1218
+ bricks: upload_bricks,
1219
+ ranges: upload_ranges,
1220
+ brick_count,
1221
+ range_count: runs.length / 2,
1222
+ entry_count: entries,
1223
+ deduplicate,
1224
+ fields,
1225
+ });
1226
+
1227
+ return fields.length;
1228
+ }
1229
+
1230
+ /**
1231
+ * The fields taken from bundles whose bricks the last bake placed are resident.
1232
+ */
1233
+ #complete_uploads() {
1234
+ const uploaded = this.#uploaded;
1235
+
1236
+ for (let i = 0; i < uploaded.length; i++) {
1237
+ const { id, generation, blocks, table, provisions } = uploaded[i];
1238
+
1239
+ if (this.#state[id] !== HOST_UPLOADING || this.#generation[id] !== generation) {
1240
+ // dropped since, or taken again
1241
+ continue;
1242
+ }
1243
+
1244
+ this.#state[id] = HOST_RESIDENT;
1245
+ this.#resident_count++;
1246
+
1247
+ const meshlets = this.#records[id].geometry?.meshlets;
1248
+
1249
+ this.#surfaces.adopt_layout(id, this.#stored_bricks[id], meshlets === undefined ? true : meshlet_batch_colored(meshlets), blocks, table, provisions);
1250
+
1251
+ this.#word_scratch[0] = MeshSDFState.Resident;
1252
+ this.#device.queue.writeBuffer(this.#headers, id * HEADER_BYTES + HEADER_STATE, this.#word_scratch, 0, 1);
1253
+
1254
+ // its side, against its holders', as for a bake done
1255
+ this.#holders_changed.push(id);
1256
+
1257
+ this.onBaked.send1(id);
1258
+
1259
+ const clones = this.#clones_of.get(id);
1260
+
1261
+ if (clones !== undefined) {
1262
+ for (let c = 0; c < clones.length; c++) {
1263
+ this.onBaked.send1(clones[c]);
1264
+ }
1265
+ }
1266
+ }
1267
+
1268
+ uploaded.length = 0;
1269
+ }
1270
+
1271
+ /**
1272
+ * A bundle (`ModelCacheBundle`) of the resident fields of `records` and the resident surface caches
1273
+ * `caches`, as the device holds them when the readbacks land: each brick once, however many fields
1274
+ * hold it, and each cache naming its field. Read while nothing bakes, it is what was baked.
1275
+ *
1276
+ * @param {GPUGeometryMetadata[]} records
1277
+ * @param {number[]} caches surface cache ids, each of a geometry of `records`
1278
+ * @returns {Promise<ModelCacheBundle>}
1279
+ */
1280
+ async export_bundle(records, caches) {
1281
+ this.#ensure_device();
1282
+
1283
+ for (let i = 0; i < records.length; i++) {
1284
+ assert.equal(this.#state[records[i].index], HOST_RESIDENT, `geometry ${records[i].index} has no resident cache`);
1285
+ }
1286
+
1287
+ const device = this.#device;
1288
+ const atlas = this.#atlas;
1289
+ const [arena, texels, data] = await Promise.all([
1290
+ read_back(device, this.#indirection),
1291
+ download_texture_data({ device, source: atlas.texture.gpu_texture }),
1292
+ read_back(device, this.#surfaces.data),
1293
+ ]);
1294
+
1295
+ const bundle = new ModelCacheBundle();
1296
+
1297
+ bundle.voxel_size = Math.fround(this.#voxel_size);
1298
+ bundle.max_bricks = this.#max_bricks;
1299
+
1300
+ const t = MESH_SDF_BRICK_TEXELS;
1301
+ const width = atlas.slots_x * t;
1302
+ const height = atlas.slots_y * t;
1303
+ const bricks = [];
1304
+ const brick_of_slot = new Map();
1305
+ const bricks_by_key = new Map();
1306
+ const scratch = new Uint8Array(MESH_SDF_BRICK_TEXEL_COUNT);
1307
+
1308
+ // a slot's bytes, as one of the bundle's bricks: the first brick of the same bytes
1309
+ const brick_of = slot => {
1310
+ let brick = brick_of_slot.get(slot);
1311
+
1312
+ if (brick !== undefined) {
1313
+ return brick;
1314
+ }
1315
+
1316
+ const x = (slot % atlas.slots_x) * t;
1317
+ const y = (Math.floor(slot / atlas.slots_x) % atlas.slots_y) * t;
1318
+ const z = Math.floor(slot / (atlas.slots_x * atlas.slots_y)) * t;
1319
+
1320
+ for (let tz = 0; tz < t; tz++) {
1321
+ for (let ty = 0; ty < t; ty++) {
1322
+ const row = (x) + width * ((y + ty) + height * (z + tz));
1323
+
1324
+ scratch.set(texels.subarray(row, row + t), t * (ty + t * tz));
1325
+ }
1326
+ }
1327
+
1328
+ // the key groups the bricks whose bytes may agree, and the bytes say which do
1329
+ const key = mesh_sdf_brick_key(scratch, 0);
1330
+ const candidates = bricks_by_key.get(key);
1331
+
1332
+ if (candidates !== undefined) {
1333
+ for (let i = 0; i < candidates.length; i++) {
1334
+ if (same_brick(bricks[candidates[i]], 0, scratch, 0)) {
1335
+ brick = candidates[i];
1336
+ break;
1337
+ }
1338
+ }
1339
+ }
1340
+
1341
+ if (brick === undefined) {
1342
+ brick = bricks.length;
1343
+ bricks.push(scratch.slice());
1344
+
1345
+ if (candidates === undefined) {
1346
+ bricks_by_key.set(key, [brick]);
1347
+ } else {
1348
+ candidates.push(brick);
1349
+ }
1350
+ }
1351
+
1352
+ brick_of_slot.set(slot, brick);
1353
+
1354
+ return brick;
1355
+ };
1356
+
1357
+ const layout = this.#layout;
1358
+ const field_of = new Map();
1359
+
1360
+ for (let i = 0; i < records.length; i++) {
1361
+ const id = records[i].index;
1362
+ const count = this.#brick_count[id];
1363
+ const stored = this.#stored_bricks[id];
1364
+ const base = this.#ranges[id].offset + 2;
1365
+ const field = new ModelCacheBundleField();
1366
+
1367
+ layout.compute(records[i].geometry.bounding_box, this.#voxel_size, this.#max_bricks);
1368
+
1369
+ for (let axis = 0; axis < 3; axis++) {
1370
+ field.origin[axis] = layout.origin[axis];
1371
+ field.bricks[axis] = layout.bricks[axis];
1372
+ }
1373
+
1374
+ field.voxel = Math.fround(layout.voxel);
1375
+ field.level_count = layout.level_count;
1376
+ field.two_sided = this.#two_sided[id];
1377
+ field.entries = new Uint32Array(count);
1378
+
1379
+ for (let e = 0; e < count; e++) {
1380
+ const entry = arena[base + e];
1381
+
1382
+ field.entries[e] = entry < MESH_SDF_EMPTY ? brick_of(entry) : entry;
1383
+ }
1384
+
1385
+ field.numbered = arena.slice(base + 2 * count, base + 2 * count + stored);
1386
+
1387
+ const { blocks, table } = this.#surfaces.export_table(id, data);
1388
+
1389
+ field.blocks = blocks;
1390
+ field.table = table;
1391
+
1392
+ field_of.set(id, bundle.fields.length);
1393
+ bundle.fields.push(field);
1394
+ }
1395
+
1396
+ bundle.bricks = new Uint8Array(bricks.length * MESH_SDF_BRICK_TEXEL_COUNT);
1397
+
1398
+ for (let i = 0; i < bricks.length; i++) {
1399
+ bundle.bricks.set(bricks[i], i * MESH_SDF_BRICK_TEXEL_COUNT);
1400
+ }
1401
+
1402
+ for (let i = 0; i < caches.length; i++) {
1403
+ const field = field_of.get(this.#surfaces.geometry_of(caches[i]));
1404
+
1405
+ assert.defined(field, `surface cache ${caches[i]}'s geometry is not among the records`);
1406
+
1407
+ bundle.caches.push(this.#surfaces.export_cache(caches[i], field, data, new ModelCacheBundleCache()));
1408
+ }
1409
+
1410
+ return bundle;
956
1411
  }
957
1412
 
958
1413
  /**
959
1414
  * Record the frame's bake: queue again what is held for the other side than it was baked for, free
960
- * what was given back, classify what is admitted, take, evaluate and store up to `budget` bricks,
961
- * place the cards of what turned resident and move placed layouts into their ranges. Then, with a
962
- * `capture_budget`, capture up to that many pages of card sets. Records nothing when there is
963
- * nothing to do.
1415
+ * what was given back, classify what is admitted, and take, evaluate and store up to `budget`
1416
+ * bricks. Then, with a `surface_budget`, bake up to that many bricks of surface caches. Records
1417
+ * nothing when there is nothing to do.
964
1418
  *
965
1419
  * @param {Object} options
966
1420
  * @param {FrameGraph} options.graph
967
1421
  * @param {number} options.budget bricks evaluated at most, `mesh_sdf_bake_budget`
968
- * @param {number} [options.capture_budget] card pages captured at most, `card_capture_budget`; 0
969
- * captures nothing
970
- * @param {GPUResidentMaterialContext|null} [options.materials] what a traced capture shades with,
971
- * which makes what it traces resident; needed with a `capture_budget`
972
- * @param {GPUMaterialManager|null} [options.material_contexts] what a raster capture draws with
973
- * ({@link GPUMeshCardSets#capture_mode}); needed with a `capture_budget` in that mode
974
- */
975
- graph_bake({ graph, budget, capture_budget = 0, materials = null, material_contexts = null }) {
1422
+ * @param {number} [options.surface_budget] surface cache bricks baked at most,
1423
+ * `surface_bake_budget`; 0 bakes nothing
1424
+ * @param {GPUResidentMaterialContext|null} [options.materials] what the surface bake shades with,
1425
+ * which makes what it traces resident; needed with a `surface_budget`
1426
+ */
1427
+ graph_bake({ graph, budget, surface_budget = 0, materials = null }) {
976
1428
  assert.defined(graph, 'graph');
977
1429
  assert.isPositiveInteger(budget, 'budget');
978
1430
  assert.lessThanOrEqual(budget, MESH_SDF_BAKE_BUDGET_MAX, 'budget');
979
- assert.isNonNegativeInteger(capture_budget, 'capture_budget');
980
- assert.lessThanOrEqual(capture_budget, MESH_CARD_CAPTURE_BUDGET_MAX, 'capture_budget');
1431
+ assert.isNonNegativeInteger(surface_budget, 'surface_budget');
981
1432
 
982
1433
  this.#frame++;
983
1434
 
@@ -992,15 +1443,24 @@ export class GPUGeometrySDFManager {
992
1443
 
993
1444
  release_next.length = 0;
994
1445
 
1446
+ const garbage = this.#garbage;
1447
+
1448
+ for (let i = 0; i < garbage.length; i++) {
1449
+ garbage[i].destroy();
1450
+ }
1451
+
1452
+ garbage.length = 0;
1453
+
1454
+ this.#complete_uploads();
1455
+
995
1456
  const queued_bound = this.#read_queued + (this.#admitted_total - this.#read_admitted);
996
1457
 
997
1458
  const has_work = this.#admittable()
998
1459
  || queued_bound > 0
999
1460
  || this.#freed.length > 0
1000
1461
  || this.#pushes.length > 0
1001
- || this.#fill_pending
1002
- || this.#placeable()
1003
- || this.#compact_queue.length > 0;
1462
+ || this.#uploads.length > 0
1463
+ || this.#fill_pending;
1004
1464
 
1005
1465
  let arena = -1;
1006
1466
 
@@ -1012,7 +1472,7 @@ export class GPUGeometrySDFManager {
1012
1472
  }
1013
1473
  }
1014
1474
 
1015
- if (capture_budget > 0 && this.#cards.has_pending_capture) {
1475
+ if (surface_budget > 0 && this.#surfaces.has_pending_bake) {
1016
1476
  assert.notNull(materials, 'materials');
1017
1477
 
1018
1478
  this.#ensure_device();
@@ -1030,13 +1490,13 @@ export class GPUGeometrySDFManager {
1030
1490
  blas.meshlet_metadata = geometries.meshlets.buffer_metadata;
1031
1491
  blas.meshlet_data = geometries.meshlets.buffer_data;
1032
1492
 
1033
- this.#cards.graph_capture({
1493
+ this.#surfaces.graph_bake({
1034
1494
  graph,
1035
- budget: capture_budget,
1495
+ budget: surface_budget,
1036
1496
  arena,
1037
1497
  headers: this.#headers,
1498
+ field_atlas: this.#atlas.texture.obtainView(),
1038
1499
  materials,
1039
- material_contexts,
1040
1500
  blas,
1041
1501
  });
1042
1502
  }
@@ -1054,12 +1514,10 @@ export class GPUGeometrySDFManager {
1054
1514
 
1055
1515
  this.#admit(queued_bound);
1056
1516
  this.#upload_free_ranges();
1057
- this.#take_placements();
1058
- this.#take_compactions();
1059
1517
 
1060
- // room for a completion of every geometry in flight and a record of every placement, and a tally
1061
- // and staging for every brick the budget takes
1062
- this.#ensure_frame(Math.max(1, this.#baking + this.#frame_placements.length / 3), budget);
1518
+ // room for a completion of every geometry in flight, and a record and staging for every brick the
1519
+ // budget takes
1520
+ this.#ensure_frame(Math.max(1, this.#baking), budget);
1063
1521
 
1064
1522
  const log_words = MESH_SDF_LOG_HEADER_WORDS + MESH_SDF_LOG_RECORD_WORDS * this.#log_capacity;
1065
1523
 
@@ -1068,7 +1526,9 @@ export class GPUGeometrySDFManager {
1068
1526
  this.#frame_log_offset = this.#frame_range.offset;
1069
1527
  this.#frame_log_bytes = 4 * log_words;
1070
1528
  this.#frame_tally_offset = this.#frame_range.offset + log_words;
1071
- this.#frame_bytes = 4 * (log_words + this.#staging_bricks);
1529
+ this.#frame_claim_offset = this.#frame_tally_offset + MESH_SDF_TAKEN_WORDS * this.#staging_bricks;
1530
+ this.#frame_claim_size = mesh_sdf_claim_size(this.#staging_bricks);
1531
+ this.#frame_bytes = 4 * (log_words + MESH_SDF_TAKEN_WORDS * this.#staging_bricks + this.#frame_claim_size);
1072
1532
 
1073
1533
  const data = this.#log_data;
1074
1534
 
@@ -1136,80 +1596,6 @@ export class GPUGeometrySDFManager {
1136
1596
  changed.length = 0;
1137
1597
  }
1138
1598
 
1139
- /**
1140
- * Give the frame's placements their ranges, in the order the geometries turned resident.
1141
- */
1142
- #take_placements() {
1143
- const queue = this.#place_queue;
1144
- const placements = this.#frame_placements;
1145
-
1146
- placements.length = 0;
1147
-
1148
- let taken = 0;
1149
-
1150
- while (taken < queue.length && placements.length < 3 * MESH_CARD_PLACEMENTS_PER_FRAME) {
1151
- const id = queue[taken++];
1152
-
1153
- if (this.#state[id] !== HOST_RESIDENT || this.#card_state[id] !== CARDS_QUEUED) {
1154
- // dropped since it was queued
1155
- continue;
1156
- }
1157
-
1158
- const words = this.#placement_words[id];
1159
-
1160
- this.#ensure_indirection(words);
1161
-
1162
- const range = this.#indirection_allocator.allocate(words);
1163
-
1164
- assert.notEqual(range.offset, ALLOCATOR_NO_SPACE, 'card placement allocation after growth');
1165
-
1166
- this.#card_scratch[id] = range;
1167
- this.#card_state[id] = CARDS_PLACING;
1168
- this.#write_header_cards(id, range.offset);
1169
-
1170
- placements.push(id, range.offset, this.#placement_scratch[id]);
1171
- }
1172
-
1173
- queue.copyWithin(0, taken);
1174
- queue.length -= taken;
1175
- }
1176
-
1177
- /**
1178
- * Move the layouts whose placement has been read back into their own ranges, this frame; their
1179
- * card sets can be captured from here.
1180
- */
1181
- #take_compactions() {
1182
- const queue = this.#compact_queue;
1183
- const moves = this.#frame_compactions;
1184
-
1185
- moves.length = 0;
1186
-
1187
- for (let i = 0; i < queue.length; i++) {
1188
- const id = queue[i];
1189
-
1190
- if (this.#card_state[id] !== CARDS_COMPACTING) {
1191
- // dropped since
1192
- continue;
1193
- }
1194
-
1195
- const source = this.#card_scratch[id];
1196
- const target = this.#card_ranges[id];
1197
-
1198
- moves.push(source.offset, target.offset, this.#card_words[id]);
1199
-
1200
- // the copy reads it this frame
1201
- this.#release_next.push(source);
1202
- this.#card_scratch[id] = null;
1203
-
1204
- this.#card_state[id] = CARDS_PLACED;
1205
- this.#write_header_cards(id, target.offset);
1206
-
1207
- this.#cards.set_layout(id, this.#card_pages[id], this.#card_side[id]);
1208
- }
1209
-
1210
- queue.length = 0;
1211
- }
1212
-
1213
1599
  /**
1214
1600
  * Whether a queued geometry's tree is traceable, so that a bake could admit it. A geometry that
1215
1601
  * waits for its tree, or for a source's cache, records no bake while it waits. Drops from the queue
@@ -1243,30 +1629,6 @@ export class GPUGeometrySDFManager {
1243
1629
  return admittable;
1244
1630
  }
1245
1631
 
1246
- /**
1247
- * Whether a resident geometry's cards wait for placement. Drops from the queue what was dropped
1248
- * since it was queued.
1249
- *
1250
- * @returns {boolean}
1251
- */
1252
- #placeable() {
1253
- const queue = this.#place_queue;
1254
-
1255
- let kept = 0;
1256
-
1257
- for (let i = 0; i < queue.length; i++) {
1258
- const id = queue[i];
1259
-
1260
- if (this.#state[id] === HOST_RESIDENT && this.#card_state[id] === CARDS_QUEUED) {
1261
- queue[kept++] = id;
1262
- }
1263
- }
1264
-
1265
- queue.length = kept;
1266
-
1267
- return kept > 0;
1268
- }
1269
-
1270
1632
  /**
1271
1633
  * Admit queued geometries in request order: those whose tree is resident, while every brick they
1272
1634
  * could queue fits on the ring beside what may be on it already.
@@ -1312,10 +1674,12 @@ export class GPUGeometrySDFManager {
1312
1674
  continue;
1313
1675
  }
1314
1676
 
1315
- // the geometry's pending word, then its entries
1316
- this.#ensure_indirection(count + 1);
1677
+ // its stored count and pending word, then its entries, its bricks' numbers and its bricks by number
1678
+ const words = 3 * count + 2;
1317
1679
 
1318
- const range = this.#indirection_allocator.allocate(count + 1);
1680
+ this.#ensure_indirection(words);
1681
+
1682
+ const range = this.#indirection_allocator.allocate(words);
1319
1683
 
1320
1684
  assert.notEqual(range.offset, ALLOCATOR_NO_SPACE, 'indirection allocation after growth');
1321
1685
 
@@ -1330,19 +1694,12 @@ export class GPUGeometrySDFManager {
1330
1694
  this.#coarsened_count++;
1331
1695
  }
1332
1696
 
1333
- this.#write_header(id, layout, range.offset + 1, MeshSDFState.Baking);
1334
-
1335
- // level 0's grid, which the cards are placed over
1336
- const grid = layout.bricks;
1337
- const placement = mesh_card_placement_of(grid);
1697
+ this.#write_header(id, layout, range.offset + 2, MeshSDFState.Baking);
1338
1698
 
1339
- this.#placement_words[id] = placement.words;
1340
- this.#placement_scratch[id] = placement.histograms;
1341
- this.#placement_columns[id] = 2 * (grid[0] * grid[1] + grid[1] * grid[2] + grid[0] * grid[2]);
1342
- this.#card_side[id] = Math.max(grid[0], grid[1], grid[2]) * MESH_SDF_BRICK_VOXELS + 1;
1343
-
1344
- this.#word_scratch[0] = count;
1345
- this.#device.queue.writeBuffer(this.#indirection, range.offset * 4, this.#word_scratch, 0, 1);
1699
+ // nothing stored yet, every brick pending
1700
+ this.#word_scratch[0] = 0;
1701
+ this.#word_scratch[1] = count;
1702
+ this.#device.queue.writeBuffer(this.#indirection, range.offset * 4, this.#word_scratch, 0, 2);
1346
1703
 
1347
1704
  this.#classify_scratch = grow_typed(this.#classify_scratch, 2 * (runs + 1));
1348
1705
  this.#classify_scratch[2 * runs] = bricks;
@@ -1406,6 +1763,68 @@ export class GPUGeometrySDFManager {
1406
1763
  */
1407
1764
  #execute = (data, resources, context) => this.#execute_bake(data, resources, context);
1408
1765
 
1766
+ /**
1767
+ * Each upload's passes (`shader_mesh_sdf_upload`), after the content table's rehash and before free:
1768
+ * deduplicating, its bricks' keys, the slots listed under them and their bytes compared with the
1769
+ * bricks'; then fresh slots for the rest, their bytes stored, and the fields' entries linked.
1770
+ *
1771
+ * @param {GPUCommandEncoder} encoder
1772
+ * @param {GPUBuffer} arena
1773
+ */
1774
+ #execute_uploads(encoder, arena) {
1775
+ const b = this.#bindings;
1776
+ const settings = this.#upload_settings;
1777
+
1778
+ b.mesh_sdf_indirection = arena;
1779
+ b.mesh_sdf_slots = this.#slots;
1780
+ b.mesh_sdf_atlas = this.#atlas.texture.obtainView();
1781
+ b.mesh_sdf_atlas_store = this.#atlas.texture.obtainView();
1782
+ b.settings = settings;
1783
+
1784
+ const fold = threads => {
1785
+ const groups = Math.max(1, Math.ceil(threads / MESH_SDF_BAKE_WORKGROUP_SIZE));
1786
+ const groups_x = Math.min(groups, WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION);
1787
+
1788
+ settings.groups_x = groups_x;
1789
+
1790
+ return { group_count_x: groups_x, group_count_y: Math.ceil(groups / groups_x) };
1791
+ };
1792
+
1793
+ for (const upload of this.#uploads) {
1794
+ settings.brick_count = upload.brick_count;
1795
+ settings.deduplicate = upload.deduplicate ? 1 : 0;
1796
+ settings.slot_capacity = this.#slot_capacity;
1797
+ settings.range_count = upload.range_count;
1798
+ settings.entry_count = upload.entry_count;
1799
+
1800
+ b.mesh_sdf_upload_bytes = upload.bytes;
1801
+ b.mesh_sdf_upload_bricks = upload.bricks;
1802
+ b.mesh_sdf_ranges = upload.ranges;
1803
+
1804
+ const texels = upload.brick_count * MESH_SDF_BRICK_TEXEL_COUNT;
1805
+
1806
+ if (upload.brick_count > 0) {
1807
+ if (upload.deduplicate) {
1808
+ shader_mesh_sdf_upload_key.dispatch({ encoder, ...fold(texels), bindings: b });
1809
+ shader_mesh_sdf_upload_find.dispatch({ encoder, ...fold(upload.brick_count), bindings: b });
1810
+ shader_mesh_sdf_upload_compare.dispatch({ encoder, ...fold(texels), bindings: b });
1811
+ }
1812
+
1813
+ shader_mesh_sdf_upload_fresh.dispatch({ encoder, ...fold(upload.brick_count), bindings: b });
1814
+ shader_mesh_sdf_upload_store.dispatch({ encoder, ...fold(texels), bindings: b });
1815
+ shader_mesh_sdf_upload_link.dispatch({ encoder, ...fold(upload.entry_count), bindings: b });
1816
+ }
1817
+
1818
+ for (let i = 0; i < upload.fields.length; i++) {
1819
+ this.#uploaded.push(upload.fields[i]);
1820
+ }
1821
+
1822
+ this.#garbage.push(upload.bytes, upload.bricks, upload.ranges);
1823
+ }
1824
+
1825
+ this.#uploads.length = 0;
1826
+ }
1827
+
1409
1828
  /**
1410
1829
  * @param {Object} data
1411
1830
  * @param {import("../../../../engine/graphics/render/frame_graph/FramePassResources.js").FramePassResources} resources
@@ -1446,6 +1865,35 @@ export class GPUGeometrySDFManager {
1446
1865
 
1447
1866
  pushes.length = 0;
1448
1867
 
1868
+ b.mesh_sdf_contents = this.#contents;
1869
+ b.mesh_sdf_content_table = this.#content_table;
1870
+
1871
+ if (this.#rehash_from !== null) {
1872
+ const groups = Math.ceil(this.#rehash_records / MESH_SDF_BAKE_WORKGROUP_SIZE);
1873
+ const groups_x = Math.min(groups, WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION);
1874
+ const settings = this.#rehash_settings;
1875
+
1876
+ settings.groups_x = groups_x;
1877
+
1878
+ b.settings = settings;
1879
+ b.mesh_sdf_content_table_before = this.#rehash_from;
1880
+
1881
+ shader_mesh_sdf_content_rehash.dispatch({
1882
+ encoder,
1883
+ group_count_x: groups_x,
1884
+ group_count_y: Math.ceil(groups / groups_x),
1885
+ bindings: b,
1886
+ });
1887
+
1888
+ this.#garbage.push(this.#rehash_from);
1889
+ this.#rehash_from = null;
1890
+ b.mesh_sdf_content_table_before = null;
1891
+ }
1892
+
1893
+ if (this.#uploads.length > 0) {
1894
+ this.#execute_uploads(encoder, arena);
1895
+ }
1896
+
1449
1897
  const geometries = this.#geometries;
1450
1898
 
1451
1899
  b.blas_lookup = geometries.blas.buffer_metadata;
@@ -1511,7 +1959,6 @@ export class GPUGeometrySDFManager {
1511
1959
  const evaluate_settings = this.#evaluate_settings;
1512
1960
 
1513
1961
  evaluate_settings.ring_capacity = this.#ring_capacity;
1514
- evaluate_settings.slot_capacity = this.#slot_capacity;
1515
1962
  evaluate_settings.log_offset = this.#frame_log_offset;
1516
1963
  evaluate_settings.log_capacity = this.#frame_log_capacity;
1517
1964
  evaluate_settings.tally_offset = this.#frame_tally_offset;
@@ -1525,91 +1972,70 @@ export class GPUGeometrySDFManager {
1525
1972
  command_offset: MESH_SDF_TAKE_DISPATCH * 4,
1526
1973
  });
1527
1974
 
1528
- this.#store_settings.ring_capacity = this.#ring_capacity;
1529
- b.settings = this.#store_settings;
1530
- b.mesh_sdf_atlas_store = this.#atlas.texture.obtainView();
1975
+ const key_settings = this.#key_settings;
1531
1976
 
1532
- shader_mesh_sdf_store.dispatchIndirect({
1977
+ key_settings.ring_capacity = this.#ring_capacity;
1978
+ key_settings.tally_offset = this.#frame_tally_offset;
1979
+ b.settings = key_settings;
1980
+
1981
+ shader_mesh_sdf_key.dispatchIndirect({
1533
1982
  encoder,
1534
1983
  bindings: b,
1535
1984
  command: this.#take,
1536
1985
  command_offset: MESH_SDF_TAKE_DISPATCH * 4,
1537
1986
  });
1538
1987
 
1539
- // card placement, a geometry at a time over its level-0 entries: the scratch cleared, then
1540
- // histogram, split, merge, pages and log
1541
- const placements = this.#frame_placements;
1988
+ const resolve_settings = this.#resolve_settings;
1542
1989
 
1543
- for (let i = 0; i < placements.length; i += 3) {
1544
- const id = placements[i];
1545
- const first = placements[i + 1];
1546
- const scratch = placements[i + 2];
1990
+ resolve_settings.ring_capacity = this.#ring_capacity;
1991
+ resolve_settings.slot_capacity = this.#slot_capacity;
1992
+ resolve_settings.log_offset = this.#frame_log_offset;
1993
+ resolve_settings.tally_offset = this.#frame_tally_offset;
1994
+ resolve_settings.claim_offset = this.#frame_claim_offset;
1995
+ resolve_settings.claim_size = this.#frame_claim_size;
1996
+ b.settings = resolve_settings;
1547
1997
 
1548
- encoder.clearBuffer(arena, 4 * (first + scratch), 4 * (this.#placement_words[id] - scratch));
1998
+ // a thread a brick the budget can take
1999
+ const resolve_groups = Math.ceil(this.#frame_budget / MESH_SDF_BAKE_WORKGROUP_SIZE);
1549
2000
 
1550
- const histogram = this.#histogram_settings;
2001
+ shader_mesh_sdf_resolve_find.dispatch({ encoder, group_count_x: resolve_groups, bindings: b });
1551
2002
 
1552
- histogram.geometry = id;
1553
- histogram.columns = this.#placement_columns[id];
1554
- b.settings = histogram;
2003
+ b.mesh_sdf_atlas = this.#atlas.texture.obtainView();
1555
2004
 
1556
- shader_mesh_cards_histogram.dispatch({
1557
- encoder,
1558
- group_count_x: Math.ceil(histogram.columns / MESH_SDF_BAKE_WORKGROUP_SIZE),
1559
- bindings: b,
1560
- });
1561
-
1562
- this.#split_settings.geometry = id;
1563
- b.settings = this.#split_settings;
1564
-
1565
- shader_mesh_cards_split.dispatch({ encoder, bindings: b });
1566
-
1567
- this.#merge_settings.geometry = id;
1568
- b.settings = this.#merge_settings;
1569
-
1570
- shader_mesh_cards_merge.dispatch({ encoder, bindings: b });
1571
-
1572
- this.#pages_settings.geometry = id;
1573
- b.settings = this.#pages_settings;
1574
-
1575
- shader_mesh_cards_pages.dispatchIndirect({
1576
- encoder,
1577
- bindings: b,
1578
- command: this.#take,
1579
- command_offset: MESH_SDF_TAKE_PLACE_DISPATCH * 4,
1580
- });
1581
-
1582
- const log = this.#place_log_settings;
2005
+ shader_mesh_sdf_resolve_compare.dispatchIndirect({
2006
+ encoder,
2007
+ bindings: b,
2008
+ command: this.#take,
2009
+ command_offset: MESH_SDF_TAKE_DISPATCH * 4,
2010
+ });
1583
2011
 
1584
- log.geometry = id;
1585
- log.log_offset = this.#frame_log_offset;
1586
- log.log_capacity = this.#frame_log_capacity;
1587
- b.settings = log;
2012
+ shader_mesh_sdf_resolve_fresh.dispatch({ encoder, group_count_x: resolve_groups, bindings: b });
2013
+ shader_mesh_sdf_resolve_hold.dispatch({ encoder, group_count_x: resolve_groups, bindings: b });
1588
2014
 
1589
- shader_mesh_cards_log.dispatch({ encoder, bindings: b });
1590
- }
2015
+ this.#store_settings.ring_capacity = this.#ring_capacity;
2016
+ this.#store_settings.tally_offset = this.#frame_tally_offset;
2017
+ b.settings = this.#store_settings;
2018
+ b.mesh_sdf_atlas_store = this.#atlas.texture.obtainView();
1591
2019
 
1592
- // placed layouts into ranges of their own size
1593
- const moves = this.#frame_compactions;
2020
+ shader_mesh_sdf_store.dispatchIndirect({
2021
+ encoder,
2022
+ bindings: b,
2023
+ command: this.#take,
2024
+ command_offset: MESH_SDF_TAKE_DISPATCH * 4,
2025
+ });
1594
2026
 
1595
- for (let i = 0; i < moves.length; i += 3) {
1596
- const settings = this.#compact_settings;
1597
- const groups = Math.ceil(moves[i + 2] / MESH_SDF_BAKE_WORKGROUP_SIZE);
1598
- const groups_x = Math.min(groups, WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION);
2027
+ // the frame's completions get their stored bricks
2028
+ const count_settings = this.#count_settings;
1599
2029
 
1600
- settings.source = moves[i];
1601
- settings.destination = moves[i + 1];
1602
- settings.count = moves[i + 2];
1603
- settings.groups_x = groups_x;
1604
- b.settings = settings;
2030
+ count_settings.log_offset = this.#frame_log_offset;
2031
+ count_settings.log_capacity = this.#frame_log_capacity;
2032
+ b.settings = count_settings;
1605
2033
 
1606
- shader_mesh_cards_compact.dispatch({
1607
- encoder,
1608
- group_count_x: groups_x,
1609
- group_count_y: Math.ceil(groups / groups_x),
1610
- bindings: b,
1611
- });
1612
- }
2034
+ shader_mesh_sdf_count.dispatch({
2035
+ encoder,
2036
+ group_count_x: Math.ceil(this.#frame_log_capacity / MESH_SDF_BAKE_WORKGROUP_SIZE),
2037
+ bindings: b,
2038
+ });
1613
2039
  }
1614
2040
 
1615
2041
  /**
@@ -1627,6 +2053,8 @@ export class GPUGeometrySDFManager {
1627
2053
  }
1628
2054
 
1629
2055
  this.#bricks_evaluated += words[MESH_SDF_LOG_TAKEN];
2056
+ this.#bricks_shared += words[MESH_SDF_LOG_SHARED];
2057
+ this.#bricks_collided += words[MESH_SDF_LOG_COLLIDED];
1630
2058
 
1631
2059
  if (frame === this.#read_frame) {
1632
2060
  this.#free_slots = words[MESH_SDF_LOG_FREE_SLOTS];
@@ -1648,14 +2076,7 @@ export class GPUGeometrySDFManager {
1648
2076
 
1649
2077
  for (let i = 0; i < count; i++) {
1650
2078
  const word = MESH_SDF_LOG_HEADER_WORDS + i * MESH_SDF_LOG_RECORD_WORDS;
1651
- const marked = words[word];
1652
-
1653
- if ((marked & MESH_SDF_LOG_PLACED) !== 0) {
1654
- this.#apply_placed((marked & ~MESH_SDF_LOG_PLACED) >>> 0, words[word + 1], words[word + 2], words[word + 3]);
1655
- continue;
1656
- }
1657
-
1658
- const id = marked;
2079
+ const id = words[word];
1659
2080
 
1660
2081
  if (this.#state[id] !== HOST_BAKING || this.#generation[id] !== words[word + 1]) {
1661
2082
  // of a bake dropped since
@@ -1665,13 +2086,16 @@ export class GPUGeometrySDFManager {
1665
2086
  this.#state[id] = HOST_RESIDENT;
1666
2087
  this.#baking--;
1667
2088
  this.#resident_count++;
2089
+ this.#stored_bricks[id] = words[word + MESH_SDF_LOG_STORED];
2090
+
2091
+ // a geometry with no meshlets on the host to look at counts as colored: its albedo keeps texels
2092
+ const meshlets = this.#records[id].geometry?.meshlets;
2093
+
2094
+ this.#surfaces.set_layout(id, this.#stored_bricks[id], meshlets === undefined ? true : meshlet_batch_colored(meshlets));
1668
2095
 
1669
2096
  this.#word_scratch[0] = MeshSDFState.Resident;
1670
2097
  this.#device.queue.writeBuffer(this.#headers, id * HEADER_BYTES + HEADER_STATE, this.#word_scratch, 0, 1);
1671
2098
 
1672
- this.#card_state[id] = CARDS_QUEUED;
1673
- this.#place_queue.push(id);
1674
-
1675
2099
  this.onBaked.send1(id);
1676
2100
 
1677
2101
  const clones = this.#clones_of.get(id);
@@ -1684,70 +2108,6 @@ export class GPUGeometrySDFManager {
1684
2108
  }
1685
2109
  }
1686
2110
 
1687
- /**
1688
- * A geometry's cards are placed, with `columns` over every card and `pages` pages: a range of that
1689
- * size for the layout, which the next bake moves it into.
1690
- *
1691
- * @param {number} id
1692
- * @param {number} generation the bake's the placement read
1693
- * @param {number} columns
1694
- * @param {number} pages
1695
- */
1696
- #apply_placed(id, generation, columns, pages) {
1697
- if (this.#state[id] !== HOST_RESIDENT || this.#generation[id] !== generation || this.#card_state[id] !== CARDS_PLACING) {
1698
- // of a placement whose geometry was dropped since
1699
- return;
1700
- }
1701
-
1702
- const words = mesh_card_layout_words(columns, pages);
1703
-
1704
- this.#ensure_indirection(words);
1705
-
1706
- const range = this.#indirection_allocator.allocate(words);
1707
-
1708
- assert.notEqual(range.offset, ALLOCATOR_NO_SPACE, 'card layout allocation after growth');
1709
-
1710
- this.#card_ranges[id] = range;
1711
- this.#card_pages[id] = pages;
1712
- this.#card_words[id] = words;
1713
- this.#card_state[id] = CARDS_COMPACTING;
1714
- this.#compact_queue.push(id);
1715
- }
1716
-
1717
- /**
1718
- * @param {number} id
1719
- * @param {number} offset the layout's first word in the arena
1720
- */
1721
- #write_header_cards(id, offset) {
1722
- this.#word_scratch[0] = offset;
1723
- this.#device.queue.writeBuffer(this.#headers, id * HEADER_BYTES + HEADER_CARDS, this.#word_scratch, 0, 1);
1724
- }
1725
-
1726
- /**
1727
- * Give back a geometry's cards: its ranges once the passes reading them are submitted, its card
1728
- * sets back to waiting.
1729
- *
1730
- * @param {number} id
1731
- */
1732
- #drop_cards(id) {
1733
- if (this.#card_state[id] === CARDS_NONE) {
1734
- return;
1735
- }
1736
-
1737
- this.#card_state[id] = CARDS_NONE;
1738
-
1739
- for (const ranges of [this.#card_scratch, this.#card_ranges]) {
1740
- const range = ranges[id];
1741
-
1742
- if (range !== null && range !== undefined) {
1743
- this.#release_next.push(range);
1744
- ranges[id] = null;
1745
- }
1746
- }
1747
-
1748
- this.#cards.drop_layout(id);
1749
- }
1750
-
1751
2111
  /**
1752
2112
  * Drop whatever the id holds: a place in the queue, a bake, a resident cache, an alias.
1753
2113
  *
@@ -1772,21 +2132,21 @@ export class GPUGeometrySDFManager {
1772
2132
  clones.splice(clones.indexOf(id), 1);
1773
2133
 
1774
2134
  this.#aliases.delete(id);
1775
- this.#cards.unalias(id);
2135
+ this.#surfaces.unalias(id);
1776
2136
  } else {
1777
2137
  if (state === HOST_BAKING) {
1778
2138
  this.#baking--;
1779
- } else {
2139
+ } else if (state === HOST_RESIDENT) {
1780
2140
  this.#resident_count--;
1781
2141
  }
1782
2142
 
1783
2143
  const range = this.#ranges[id];
1784
2144
 
1785
- this.#freed.push(range.offset + 1, this.#brick_count[id]);
2145
+ this.#freed.push(range.offset + 2, this.#brick_count[id]);
1786
2146
  this.#freeing.push(range);
1787
2147
  this.#ranges[id] = null;
1788
2148
 
1789
- this.#drop_cards(id);
2149
+ this.#surfaces.drop_layout(id);
1790
2150
  }
1791
2151
 
1792
2152
  // bricks of this id still on the ring are stale from here on, by the state
@@ -1825,7 +2185,6 @@ export class GPUGeometrySDFManager {
1825
2185
  view.setFloat32(HEADER_VOXEL, layout.voxel, true);
1826
2186
  view.setUint32(HEADER_LEVEL_COUNT, layout.level_count, true);
1827
2187
  view.setUint32(HEADER_INDIRECTION, indirection, true);
1828
- view.setUint32(HEADER_CARDS, GPU_DATABASE_NULL, true);
1829
2188
  view.setUint32(HEADER_STATE, state, true);
1830
2189
  view.setUint32(HEADER_SOURCE, GPU_DATABASE_NULL, true);
1831
2190
  view.setUint32(HEADER_GENERATION, this.#generation[id], true);
@@ -1843,7 +2202,6 @@ export class GPUGeometrySDFManager {
1843
2202
 
1844
2203
  new Uint8Array(view.buffer).fill(0);
1845
2204
 
1846
- view.setUint32(HEADER_CARDS, GPU_DATABASE_NULL, true);
1847
2205
  view.setUint32(HEADER_STATE, MeshSDFState.Alias, true);
1848
2206
  view.setUint32(HEADER_SOURCE, source, true);
1849
2207
  view.setUint32(HEADER_GENERATION, this.#generation[id], true);
@@ -1863,13 +2221,7 @@ export class GPUGeometrySDFManager {
1863
2221
  this.#state = grow_typed(this.#state, length);
1864
2222
  this.#generation = grow_typed(this.#generation, length);
1865
2223
  this.#brick_count = grow_typed(this.#brick_count, length);
1866
- this.#card_state = grow_typed(this.#card_state, length);
1867
- this.#placement_words = grow_typed(this.#placement_words, length);
1868
- this.#placement_scratch = grow_typed(this.#placement_scratch, length);
1869
- this.#placement_columns = grow_typed(this.#placement_columns, length);
1870
- this.#card_pages = grow_typed(this.#card_pages, length);
1871
- this.#card_words = grow_typed(this.#card_words, length);
1872
- this.#card_side = grow_typed(this.#card_side, length);
2224
+ this.#stored_bricks = grow_typed(this.#stored_bricks, length);
1873
2225
  }
1874
2226
 
1875
2227
  #ensure_device() {
@@ -1910,6 +2262,9 @@ export class GPUGeometrySDFManager {
1910
2262
  this.#slots = this.#create_buffer("slots", 4 * this.#slot_capacity, GPUBufferUsage.COPY_SRC);
1911
2263
  this.#fill_pending = true;
1912
2264
 
2265
+ this.#contents = this.#create_buffer("contents", 4 * MESH_SDF_CONTENT_WORDS * this.#slot_capacity, GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST);
2266
+ this.#content_table = this.#create_content_table(this.#slot_capacity);
2267
+
1913
2268
  this.#take = this.#create_buffer("take", 4 * MESH_SDF_TAKE_WORDS, GPUBufferUsage.INDIRECT);
1914
2269
 
1915
2270
  this.#word_scratch[0] = this.#slot_capacity;
@@ -1994,7 +2349,7 @@ export class GPUGeometrySDFManager {
1994
2349
  this.#indirection_allocator.free(this.#frame_range);
1995
2350
  }
1996
2351
 
1997
- const words = MESH_SDF_LOG_HEADER_WORDS + MESH_SDF_LOG_RECORD_WORDS * log_capacity + staging;
2352
+ const words = MESH_SDF_LOG_HEADER_WORDS + MESH_SDF_LOG_RECORD_WORDS * log_capacity + MESH_SDF_TAKEN_WORDS * staging + mesh_sdf_claim_size(staging);
1998
2353
 
1999
2354
  this.#ensure_indirection(words);
2000
2355
 
@@ -2049,8 +2404,38 @@ export class GPUGeometrySDFManager {
2049
2404
  atlas.reserve(capacity);
2050
2405
 
2051
2406
  this.#slots = this.#regrow(this.#slots, "slots", 4 * capacity, GPUBufferUsage.COPY_SRC);
2407
+ this.#contents = this.#regrow(this.#contents, "contents", 4 * MESH_SDF_CONTENT_WORDS * capacity, 0);
2052
2408
  this.#slot_capacity = capacity;
2053
2409
  this.#pushes.push(old_capacity, capacity - old_capacity);
2410
+
2411
+ // a table of the grown size, which the next bake gives the records of the one it replaces before
2412
+ // anything reads it
2413
+ if (this.#rehash_from === null) {
2414
+ this.#rehash_from = this.#content_table;
2415
+ this.#rehash_records = mesh_sdf_content_table_size(old_capacity);
2416
+ } else {
2417
+ // grown again before a bake: the table it replaces was never bound
2418
+ this.#content_table.destroy();
2419
+ }
2420
+
2421
+ this.#content_table = this.#create_content_table(capacity);
2422
+ }
2423
+
2424
+ /**
2425
+ * An empty content table for `slot_capacity` slots: its header written, every record empty.
2426
+ *
2427
+ * @param {number} slot_capacity
2428
+ * @returns {GPUBuffer}
2429
+ */
2430
+ #create_content_table(slot_capacity) {
2431
+ const size = mesh_sdf_content_table_size(slot_capacity);
2432
+ const buffer = this.#create_buffer("content table", 4 * (2 + 2 * size), GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST);
2433
+
2434
+ this.#word_scratch[0] = 0;
2435
+ this.#word_scratch[1] = size;
2436
+ this.#device.queue.writeBuffer(buffer, 0, this.#word_scratch, 0, 2);
2437
+
2438
+ return buffer;
2054
2439
  }
2055
2440
 
2056
2441
  /**
@@ -2123,16 +2508,32 @@ export class GPUGeometrySDFManager {
2123
2508
 
2124
2509
  this.#destroyed = true;
2125
2510
 
2126
- for (const buffer of [this.#headers, this.#indirection, this.#slots, this.#take, this.#ring, this.#classify_ranges, this.#free_ranges]) {
2511
+ for (const buffer of [this.#headers, this.#indirection, this.#slots, this.#contents, this.#content_table, this.#rehash_from, this.#take, this.#ring, this.#classify_ranges, this.#free_ranges]) {
2127
2512
  buffer?.destroy();
2128
2513
  }
2129
2514
 
2515
+ for (const upload of this.#uploads) {
2516
+ upload.bytes.destroy();
2517
+ upload.bricks.destroy();
2518
+ upload.ranges.destroy();
2519
+ }
2520
+
2521
+ for (const buffer of this.#garbage) {
2522
+ buffer.destroy();
2523
+ }
2524
+
2525
+ this.#uploads.length = 0;
2526
+ this.#garbage.length = 0;
2527
+
2130
2528
  this.#atlas?.destroy();
2131
- this.#cards.destroy();
2529
+ this.#surfaces.destroy();
2132
2530
 
2133
2531
  this.#headers = null;
2134
2532
  this.#indirection = null;
2135
2533
  this.#slots = null;
2534
+ this.#contents = null;
2535
+ this.#content_table = null;
2536
+ this.#rehash_from = null;
2136
2537
  this.#take = null;
2137
2538
  this.#ring = null;
2138
2539
  this.#classify_ranges = null;