@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
@@ -0,0 +1,1819 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+ import { ALLOCATOR_NO_SPACE, OffsetAllocator } from "../../../../../core/binary/allocator/OffsetAllocator.js";
3
+ import Signal from "../../../../../core/events/signal/Signal.js";
4
+ import IdPool from "../../../../../core/IdPool.js";
5
+ import { warn_limited } from "../../../../util/warn_limited.js";
6
+ import { BufferDescriptor } from "../../../../descriptor/buffer/BufferDescriptor.js";
7
+ import { graph_read_buffer } from "../../../buffer/graph_read_buffer.js";
8
+ import { WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION } from "../../../gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.js";
9
+ import { graph_import_buffer } from "../../../shader/graph/graph_import_buffer.js";
10
+ import { MESH_SDF_BAKE_WORKGROUP_SIZE } from "../bake/MESH_SDF_BAKE.js";
11
+ import { MESH_SDF_BRICK_TEXEL_COUNT } from "../MESH_SDF.js";
12
+ import { MESH_SDF_SAMPLER } from "../MESH_SDF_RESOURCES.js";
13
+ import { mesh_surface_channels, MeshSurfaceChannels } from "./mesh_surface_channels.js";
14
+ import {
15
+ MESH_SURFACE_COMMAND_WORDS,
16
+ MESH_SURFACE_COUNTER_WORDS,
17
+ MESH_SURFACE_STAGING_WORDS,
18
+ MESH_SURFACE_SURVEY_RESULT_WORDS,
19
+ MESH_SURFACE_TEXEL_STRUCT
20
+ } from "./MESH_SURFACE_BAKE.js";
21
+ import {
22
+ MESH_SURFACE_BRICK_BLOCKS,
23
+ MESH_SURFACE_PLANE_BLOCK_WORDS,
24
+ MESH_SURFACE_PRESENCE_BLOCK_WORDS
25
+ } from "./MESH_SURFACE_BLOCK.js";
26
+ import { MESH_SURFACE_STRUCT } from "./MESH_SURFACE_STRUCT.js";
27
+ import { shader_mesh_surface_command } from "./shader_mesh_surface_command.js";
28
+ import { shader_mesh_surface_encode } from "./shader_mesh_surface_encode.js";
29
+ import { shader_mesh_surface_list } from "./shader_mesh_surface_list.js";
30
+ import { shader_mesh_surface_number, shader_mesh_surface_survey } from "./shader_mesh_surface_survey.js";
31
+ import { shader_mesh_surface_trace } from "./shader_mesh_surface_trace.js";
32
+ import {
33
+ SURFACE_MATERIAL_ALBEDO_PLANE,
34
+ SURFACE_MATERIAL_EMISSIVE_PLANE,
35
+ SURFACE_MATERIAL_METAL_ROUGH_PLANE
36
+ } from "./SURFACE_MATERIAL.js";
37
+
38
+ /**
39
+ * @typedef {import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} FrameGraph
40
+ * @typedef {import("../../../material/ShadeMaterial.js").ShadeMaterial} ShadeMaterial
41
+ * @typedef {import("../../../material/resident/GPUResidentMaterialContext.js").GPUResidentMaterialContext} GPUResidentMaterialContext
42
+ * @typedef {import("../../../../../core/binary/allocator/OffsetAllocator.js").Allocation} Allocation
43
+ * @typedef {import("../bundle/ModelCacheBundle.js").ModelCacheBundleCache} ModelCacheBundleCache
44
+ */
45
+
46
+ /** The id is free. */
47
+ const CACHE_NONE = 0;
48
+ /** Its geometry's field is not resident, or not surveyed yet: nothing to lay its blocks out by. */
49
+ const CACHE_WAITING = 1;
50
+ /** Its first bake is queued or part done; readers find no cache. */
51
+ const CACHE_BAKING = 2;
52
+ /** Baked; it may be queued to bake again, and reads the last bake until that is done. */
53
+ const CACHE_RESIDENT = 3;
54
+
55
+ /**
56
+ * The planes, in `SURFACE_MATERIAL.js`'s order, and the record's field of each one's blocks.
57
+ */
58
+ const PLANES = [SURFACE_MATERIAL_ALBEDO_PLANE, SURFACE_MATERIAL_METAL_ROUGH_PLANE, SURFACE_MATERIAL_EMISSIVE_PLANE];
59
+ const PLANE_BLOCK_FIELDS = ["albedo_blocks", "metal_rough_blocks", "emissive_blocks"];
60
+
61
+ /**
62
+ * Words the caches' storage starts with: it grows to what its allocations take.
63
+ * @type {number}
64
+ */
65
+ const INITIAL_DATA_WORDS = 64 * 1024;
66
+
67
+ /**
68
+ * A capacity of at least `count`, doubled from `capacity`, 64 at least.
69
+ *
70
+ * @param {number} count
71
+ * @param {number} capacity
72
+ * @returns {number}
73
+ */
74
+ function doubled_capacity(count, capacity) {
75
+ let grown = Math.max(64, capacity);
76
+
77
+ while (grown < count) {
78
+ grown *= 2;
79
+ }
80
+
81
+ return grown;
82
+ }
83
+
84
+ /**
85
+ * @template {Uint8Array|Uint32Array} T
86
+ * @param {T} array
87
+ * @param {number} length
88
+ * @returns {T}
89
+ */
90
+ function grow_typed(array, length) {
91
+ if (array.length >= length) {
92
+ return array;
93
+ }
94
+
95
+ let size = Math.max(64, array.length);
96
+
97
+ while (size < length) {
98
+ size *= 2;
99
+ }
100
+
101
+ const grown = new array.constructor(size);
102
+
103
+ grown.set(array);
104
+
105
+ return grown;
106
+ }
107
+
108
+ /**
109
+ * A run's first `count` words, copied out of the storage read back whole; none for no run.
110
+ *
111
+ * @param {Allocation|null|undefined} run
112
+ * @param {number} count
113
+ * @param {Uint32Array} words
114
+ * @returns {Uint32Array}
115
+ */
116
+ function run_words(run, count, words) {
117
+ return run === null || run === undefined ? new Uint32Array(0) : words.slice(run.offset, run.offset + count);
118
+ }
119
+
120
+ /**
121
+ * Model Surface Caches: one (geometry, material) pair's surface material (`SURFACE_MATERIAL.js`) on its
122
+ * geometry's field, by cache id, the storage of which {@link GPUGeometrySDFManager} keeps beside the
123
+ * fields.
124
+ *
125
+ * - **Blocks.** A field's bricks are surveyed once (`MESH_SURFACE_BAKE.js`): a brick keeps each of its
126
+ * eight 4³ blocks (`MESH_SURFACE_BLOCK.js`) some texel of which can hold surface, numbered in the
127
+ * geometry's block table, a word a brick, and the count read back. Every cache of the geometry keeps
128
+ * its blocks by those numbers.
129
+ * - **What a cache keeps** follows its material and its geometry (`mesh_surface_channels`): each plane
130
+ * that varies over the surface keeps its blocks, coded, and each other plane only its code in the
131
+ * record, the value every texel takes. A cache that keeps any plane keeps a block of presence for each
132
+ * block: which texels a bake found surface under. A cache that keeps no plane is never baked.
133
+ * - **Storage** is one buffer of words, `mesh_surface_data`, for the tables and for each cache's run of
134
+ * blocks in its presence and each plane it keeps, each run its own allocation. The record
135
+ * (`MESH_SURFACE_STRUCT`) is written when the runs are given.
136
+ *
137
+ * **Lifetime.** {@link acquire} makes a cache for a pair and {@link release} gives it back; the caller
138
+ * keeps one per pair. A cache of an aliased geometry ({@link alias}) is its source's, baked from the
139
+ * source's triangles. A cache waits until its geometry's field is resident ({@link set_layout}) and,
140
+ * when it keeps a plane, surveyed ({@link set_blocks}); it is then baked, and turns resident on the frame
141
+ * its last brick is recorded: the bake's writes come before any later pass reads it. Every bake recorded
142
+ * in full sends {@link onBaked}, the first and each one after. A field that goes ({@link drop_layout})
143
+ * withdraws its caches ({@link onWithdrawn}) back to waiting.
144
+ *
145
+ * **A frame** ({@link graph_bake}) takes at most `budget` bricks: surveys first, then first bakes in the
146
+ * order they were asked for, then bakes again in the order queued. A bake is a thread a texel of each
147
+ * brick, then a workgroup a texel that holds surface, then a workgroup a block. A survey's or a bake's
148
+ * bricks may span frames. {@link recapture} takes a cache's material as it is now: a resident cache
149
+ * keeping the same planes is queued again and reads its last bake until the new one is done, a cache
150
+ * whose bake is under way starts it again, and one keeping other planes than before is withdrawn and
151
+ * laid out anew. The rays read the geometry's BLAS and the material's resident row: what reads a cache
152
+ * needs neither.
153
+ */
154
+ export class GPUMeshSurfaceCaches {
155
+
156
+ /**
157
+ * @type {GPUDevice}
158
+ */
159
+ #device;
160
+
161
+ /**
162
+ * Sent with a cache id each time a bake of it is recorded in full, its first and each one after:
163
+ * what was taken from its last one is to be taken again.
164
+ * @type {Signal<number>}
165
+ */
166
+ onBaked = new Signal();
167
+
168
+ /**
169
+ * Sent with a resident cache's id when what it holds goes: its field went, or its material now
170
+ * varies in other planes. It is baked again.
171
+ * @type {Signal<number>}
172
+ */
173
+ onWithdrawn = new Signal();
174
+
175
+ #ids = new IdPool();
176
+
177
+ /**
178
+ * The source of each aliased geometry id.
179
+ * @type {Map<number, number>}
180
+ */
181
+ #source_of = new Map();
182
+
183
+ // ---- per cache id ----
184
+
185
+ #state = new Uint8Array(64);
186
+ #geometry = new Uint32Array(64);
187
+ /**
188
+ * Bumped whenever the id's queue entries go stale: given out, given back, its field gone.
189
+ */
190
+ #ticket = new Uint32Array(64);
191
+ /** Bricks of the bake under way taken so far. */
192
+ #next_brick = new Uint32Array(64);
193
+ /** Whether a queue holds a live entry of the id. */
194
+ #queued = new Uint8Array(64);
195
+
196
+ /** Bit `1 << plane` for each plane the cache keeps, as its runs were given. */
197
+ #texels = new Uint8Array(64);
198
+ /** Each plane's code, which a plane it keeps no blocks of takes everywhere, by plane. */
199
+ #codes = [new Uint32Array(64), new Uint32Array(64), new Uint32Array(64)];
200
+
201
+ /**
202
+ * @type {(ShadeMaterial|undefined)[]}
203
+ */
204
+ #material = [];
205
+
206
+ /**
207
+ * Each cache's presence run.
208
+ * @type {(Allocation|null)[]}
209
+ */
210
+ #presence_runs = [];
211
+
212
+ /**
213
+ * Each cache's run of each plane it keeps, by plane.
214
+ * @type {(Allocation|null)[][]}
215
+ */
216
+ #plane_runs = [[], [], []];
217
+
218
+ // ---- per geometry id ----
219
+
220
+ /**
221
+ * Bricks each resident field stored, by geometry id.
222
+ * @type {Map<number, number>}
223
+ */
224
+ #stored = new Map();
225
+
226
+ /**
227
+ * Whether each resident field's geometry has vertices of a color other than white, by geometry id.
228
+ * @type {Map<number, boolean>}
229
+ */
230
+ #colored = new Map();
231
+
232
+ /**
233
+ * Blocks each surveyed field's bricks keep, by geometry id.
234
+ * @type {Map<number, number>}
235
+ */
236
+ #blocks = new Map();
237
+
238
+ /**
239
+ * Each resident field's block table, a word a stored brick, by geometry id.
240
+ * @type {Map<number, Allocation>}
241
+ */
242
+ #tables = new Map();
243
+
244
+ /**
245
+ * The ticket each field's survey under way was asked under, by geometry id.
246
+ * @type {Map<number, number>}
247
+ */
248
+ #survey_tickets = new Map();
249
+
250
+ /**
251
+ * Bricks of each survey under way taken so far, by geometry id.
252
+ * @type {Map<number, number>}
253
+ */
254
+ #survey_next = new Map();
255
+
256
+ #survey_count = 0;
257
+
258
+ /**
259
+ * The caches of each geometry, by geometry id.
260
+ * @type {Map<number, number[]>}
261
+ */
262
+ #caches_of_geometry = new Map();
263
+
264
+ /**
265
+ * The bundle's caches each field taken from a bundle offers its geometry's caches, by geometry id,
266
+ * kept while that field is the geometry's ({@link adopt_layout}).
267
+ * @type {Map<number, {material: ShadeMaterial, cache: ModelCacheBundleCache}[]>}
268
+ */
269
+ #provisions = new Map();
270
+
271
+ // ---- the queues: (id, ticket) pairs, from a head ----
272
+
273
+ #queue_survey = [];
274
+ #head_survey = 0;
275
+ #queue_new = [];
276
+ #head_new = 0;
277
+ #queue_re = [];
278
+ #head_re = 0;
279
+
280
+ // ---- device storage, made on first use ----
281
+
282
+ /** @type {GPUBuffer|null} */
283
+ #records = null;
284
+ #record_capacity = 0;
285
+ #record_scratch = new DataView(new ArrayBuffer(MESH_SURFACE_STRUCT.size));
286
+
287
+ /** @type {GPUBuffer|null} */
288
+ #data = null;
289
+ /** @type {OffsetAllocator|null} */
290
+ #data_allocator = null;
291
+
292
+ /** @type {GPUBuffer|null} */
293
+ #runs = null;
294
+ #run_capacity = 0;
295
+ #run_scratch = new Uint32Array(4 * 64);
296
+
297
+ /** @type {GPUBuffer|null} */
298
+ #survey_runs = null;
299
+ #survey_run_capacity = 0;
300
+ #survey_run_scratch = new Uint32Array(4 * 64);
301
+
302
+ /** @type {GPUBuffer|null} */
303
+ #number_runs = null;
304
+ #number_run_capacity = 0;
305
+ #number_run_scratch = new Uint32Array(4 * 64);
306
+
307
+ /** @type {GPUBuffer|null} */
308
+ #survey_results = null;
309
+ #survey_result_capacity = 0;
310
+
311
+ /** @type {GPUBuffer|null} */
312
+ #texel_list = null;
313
+ /** @type {GPUBuffer|null} */
314
+ #staging = null;
315
+ #texel_capacity = 0;
316
+
317
+ /** @type {GPUBuffer|null} */
318
+ #counter = null;
319
+ /** @type {GPUBuffer|null} */
320
+ #command = null;
321
+
322
+ #frame_runs = 0;
323
+ #frame_threads = 0;
324
+ #frame_survey_runs = 0;
325
+ #frame_survey_threads = 0;
326
+ #frame_number_runs = 0;
327
+ #frame_number_threads = 0;
328
+ /** The tables a frame's surveys start with, cleared before them: (word, words) pairs. */
329
+ #frame_clears = [];
330
+ /**
331
+ * The surveys a frame completes: (geometry, ticket) pairs, in their results' order; null for none.
332
+ * @type {number[]|null}
333
+ */
334
+ #frame_completed_surveys = null;
335
+ /** Bricks of the frame's budget not yet taken. */
336
+ #frame_left = 0;
337
+
338
+ /**
339
+ * What a frame's bake shades with: set by {@link graph_bake}. Only what is baked is made resident,
340
+ * each run's material as its run is taken.
341
+ * @type {GPUResidentMaterialContext|null}
342
+ */
343
+ #frame_materials = null;
344
+
345
+ #channels = new MeshSurfaceChannels();
346
+
347
+ #list_settings = { run_count: 0, thread_count: 0, groups_x: 0, capacity: 0 };
348
+ #command_settings = { capacity: 0 };
349
+ #encode_settings = { run_count: 0, brick_count: 0, groups_x: 0 };
350
+ #survey_settings = { run_count: 0, thread_count: 0, groups_x: 0 };
351
+ #number_settings = { run_count: 0, thread_count: 0, groups_x: 0 };
352
+ #bindings = {};
353
+ #pass_data = { arena: -1 };
354
+ #survey_pass_data = { arena: -1, results: -1 };
355
+
356
+ /** Caches whose bake the frame completes, sent once it is recorded. */
357
+ #completed = [];
358
+
359
+ #count = 0;
360
+ #resident_count = 0;
361
+ #bricks_baked = 0;
362
+ #destroyed = false;
363
+
364
+ /**
365
+ * @param {GPUDevice} device
366
+ */
367
+ constructor(device) {
368
+ assert.defined(device, 'device');
369
+
370
+ this.#device = device;
371
+ }
372
+
373
+ /**
374
+ * Caches given out: acquired and not yet released.
375
+ * @returns {number}
376
+ */
377
+ get count() {
378
+ return this.#count;
379
+ }
380
+
381
+ /**
382
+ * Caches readers may use.
383
+ * @returns {number}
384
+ */
385
+ get resident_count() {
386
+ return this.#resident_count;
387
+ }
388
+
389
+ /**
390
+ * Bricks baked since this was made, every bake's.
391
+ * @returns {number}
392
+ */
393
+ get bricks_baked() {
394
+ return this.#bricks_baked;
395
+ }
396
+
397
+ /**
398
+ * Whether a frame has anything to do: bricks to survey or bake, or caches turned resident with
399
+ * nothing to bake, still to be announced.
400
+ * @returns {boolean}
401
+ */
402
+ get has_pending_bake() {
403
+ return this.#head_survey < this.#queue_survey.length
404
+ || this.#head_new < this.#queue_new.length
405
+ || this.#head_re < this.#queue_re.length
406
+ || this.#completed.length > 0;
407
+ }
408
+
409
+ /**
410
+ * Whether readers may use the cache: baked at least once, and its field still there.
411
+ *
412
+ * @param {number} id
413
+ * @returns {boolean}
414
+ */
415
+ is_resident(id) {
416
+ return this.#state[id] === CACHE_RESIDENT;
417
+ }
418
+
419
+ /**
420
+ * The cache's geometry id: the source's, for an aliased geometry.
421
+ *
422
+ * @param {number} id
423
+ * @returns {number}
424
+ */
425
+ geometry_of(id) {
426
+ return this.#geometry[id];
427
+ }
428
+
429
+ /**
430
+ * The material the cache was acquired for: what a bundle exported with it names it by, to offer it
431
+ * back (`GPUGeometrySDFManager.upload_bundle`).
432
+ *
433
+ * @param {number} id
434
+ * @returns {ShadeMaterial}
435
+ */
436
+ material_of(id) {
437
+ return this.#material[id];
438
+ }
439
+
440
+ /**
441
+ * The blocks a surveyed field's bricks keep, or undefined before its survey is read back.
442
+ *
443
+ * @param {number} geometry
444
+ * @returns {number|undefined}
445
+ */
446
+ blocks_of(geometry) {
447
+ return this.#blocks.get(geometry);
448
+ }
449
+
450
+ /**
451
+ * Every cache's record, by id. Replaced when it grows; take it each frame.
452
+ * @returns {GPUBuffer}
453
+ */
454
+ get records() {
455
+ this.#ensure_device();
456
+
457
+ return this.#records;
458
+ }
459
+
460
+ /**
461
+ * The caches' words: the block tables and the caches' blocks. Replaced when it grows; take it each
462
+ * frame.
463
+ * @returns {GPUBuffer}
464
+ */
465
+ get data() {
466
+ this.#ensure_device();
467
+
468
+ return this.#data;
469
+ }
470
+
471
+ /**
472
+ * Put what the caches' readers (`chunk_mesh_surface_sample`) take into their bindings, under the
473
+ * names they take. The records and the words are replaced as they grow: take them each frame.
474
+ *
475
+ * @param {Object} bindings
476
+ * @returns {Object} bindings
477
+ */
478
+ write_bindings(bindings) {
479
+ this.#ensure_device();
480
+
481
+ bindings.mesh_surface_records = this.#records;
482
+ bindings.mesh_surface_data = this.#data;
483
+
484
+ return bindings;
485
+ }
486
+
487
+ /**
488
+ * A cache for a pair. The caller keeps one per pair.
489
+ *
490
+ * @param {number} geometry the geometry id the pair draws; an aliased one's cache is its source's ({@link alias})
491
+ * @param {ShadeMaterial} material
492
+ * @returns {number} cache id
493
+ */
494
+ acquire(geometry, material) {
495
+ assert.isNonNegativeInteger(geometry, 'geometry');
496
+ assert.defined(material, 'material');
497
+
498
+ geometry = this.#source_of.get(geometry) ?? geometry;
499
+
500
+ const id = this.#ids.get();
501
+
502
+ this.#ensure_id(id);
503
+ this.#count++;
504
+
505
+ this.#state[id] = CACHE_WAITING;
506
+ this.#geometry[id] = geometry;
507
+ this.#material[id] = material;
508
+ this.#ticket[id]++;
509
+ this.#next_brick[id] = 0;
510
+ this.#queued[id] = 0;
511
+
512
+ let caches = this.#caches_of_geometry.get(geometry);
513
+
514
+ if (caches === undefined) {
515
+ caches = [];
516
+ this.#caches_of_geometry.set(geometry, caches);
517
+ }
518
+
519
+ caches.push(id);
520
+
521
+ if (this.#stored.has(geometry)) {
522
+ this.#start(id);
523
+ }
524
+
525
+ return id;
526
+ }
527
+
528
+ /**
529
+ * @param {number} id
530
+ */
531
+ release(id) {
532
+ assert.notEqual(this.#state[id] ?? CACHE_NONE, CACHE_NONE, `surface cache ${id} is not given out`);
533
+
534
+ if (this.#state[id] === CACHE_RESIDENT) {
535
+ this.#resident_count--;
536
+ }
537
+
538
+ this.#free_runs(id);
539
+ this.#count--;
540
+
541
+ this.#state[id] = CACHE_NONE;
542
+ this.#ticket[id]++;
543
+ this.#queued[id] = 0;
544
+ this.#material[id] = undefined;
545
+
546
+ const caches = this.#caches_of_geometry.get(this.#geometry[id]);
547
+ const at = caches.indexOf(id);
548
+
549
+ caches[at] = caches[caches.length - 1];
550
+ caches.pop();
551
+
552
+ if (caches.length === 0) {
553
+ this.#caches_of_geometry.delete(this.#geometry[id]);
554
+ }
555
+
556
+ this.#ids.release(id);
557
+ }
558
+
559
+ /**
560
+ * The cache's material has changed (its version moved): take it as it is now. A cache that keeps the
561
+ * same planes as before is baked again, and a resident one reads its last bake until the new one is
562
+ * done; one that keeps none has its record's codes rewritten and is announced at once. A cache that
563
+ * keeps other planes than before is withdrawn and laid out anew.
564
+ *
565
+ * @param {number} id
566
+ */
567
+ recapture(id) {
568
+ const state = this.#state[id];
569
+
570
+ assert.notEqual(state ?? CACHE_NONE, CACHE_NONE, `surface cache ${id} is not given out`);
571
+
572
+ if (state === CACHE_WAITING) {
573
+ // it takes the material as it is when it is laid out
574
+ return;
575
+ }
576
+
577
+ const channels = this.#channels_of(id);
578
+
579
+ if (channels.texels !== this.#texels[id]) {
580
+ if (state === CACHE_RESIDENT) {
581
+ this.#resident_count--;
582
+ this.onWithdrawn.send1(id);
583
+ }
584
+
585
+ this.#free_runs(id);
586
+
587
+ this.#state[id] = CACHE_WAITING;
588
+ this.#ticket[id]++;
589
+ this.#queued[id] = 0;
590
+ this.#next_brick[id] = 0;
591
+
592
+ this.#start(id);
593
+
594
+ return;
595
+ }
596
+
597
+ this.#keep_codes(id, channels);
598
+
599
+ if (!this.#bakes(id)) {
600
+ // nothing to bake: its codes are all it holds
601
+ this.#write_record(id, 0);
602
+ this.#complete(id);
603
+
604
+ return;
605
+ }
606
+
607
+ // from its first brick, whether queued or not
608
+ this.#next_brick[id] = 0;
609
+
610
+ if (this.#queued[id] === 0) {
611
+ this.#queued[id] = 1;
612
+ this.#queue_re.push(id, this.#ticket[id]);
613
+ }
614
+ }
615
+
616
+ /**
617
+ * A geometry's field is resident, having stored `stored` bricks: its caches that keep no plane are
618
+ * laid out at once, and the first that keeps one has its bricks queued to be surveyed.
619
+ *
620
+ * @param {number} geometry
621
+ * @param {number} stored
622
+ * @param {boolean} colored whether the geometry has vertices of a color other than white, which the
623
+ * diffuse albedo varies with (`meshlet_batch_colored`)
624
+ */
625
+ set_layout(geometry, stored, colored) {
626
+ assert.isNonNegativeInteger(stored, 'stored');
627
+ assert.isBoolean(colored, 'colored');
628
+
629
+ this.#ensure_device();
630
+
631
+ if (this.#stored.has(geometry)) {
632
+ // laid out anew without going: what it had goes first
633
+ this.drop_layout(geometry);
634
+ }
635
+
636
+ this.#stored.set(geometry, stored);
637
+ this.#colored.set(geometry, colored);
638
+
639
+ if (stored === 0) {
640
+ // nothing to survey: it keeps no block
641
+ this.#blocks.set(geometry, 0);
642
+ }
643
+
644
+ this.#start_waiting(geometry);
645
+ }
646
+
647
+ /**
648
+ * A geometry's field is resident, taken from a bundle (`ModelCacheBundle`) with the survey its
649
+ * caches were laid out by: `blocks` blocks numbered in `table`, a word a stored brick, or no table
650
+ * when no cache of it kept a plane, which leaves a cache that keeps one to have the field surveyed.
651
+ * Each of `provisions` offers a cache of the bundle to the geometry's cache of its material, for as
652
+ * long as this field is the geometry's: a cache whose material makes it keep the planes the bundle's
653
+ * did, with the same codes, takes the bundle's blocks and is resident without a bake; any other is
654
+ * baked as `set_layout` would have it.
655
+ *
656
+ * @param {number} geometry
657
+ * @param {number} stored
658
+ * @param {boolean} colored whether the geometry has vertices of a color other than white
659
+ * @param {number} blocks
660
+ * @param {Uint32Array} table `stored` words, or none
661
+ * @param {{material: ShadeMaterial, cache: ModelCacheBundleCache}[]} provisions
662
+ */
663
+ adopt_layout(geometry, stored, colored, blocks, table, provisions) {
664
+ assert.isNonNegativeInteger(stored, 'stored');
665
+ assert.isBoolean(colored, 'colored');
666
+ assert.isNonNegativeInteger(blocks, 'blocks');
667
+ assert.ok(table.length === 0 || table.length === stored, 'table: a word a stored brick, or none');
668
+
669
+ this.#ensure_device();
670
+
671
+ if (this.#stored.has(geometry)) {
672
+ this.drop_layout(geometry);
673
+ }
674
+
675
+ this.#stored.set(geometry, stored);
676
+ this.#colored.set(geometry, colored);
677
+ this.#provisions.set(geometry, provisions);
678
+
679
+ if (stored === 0) {
680
+ this.#blocks.set(geometry, 0);
681
+ } else if (table.length > 0) {
682
+ const allocation = this.#allocate_words(stored);
683
+
684
+ if (allocation !== null) {
685
+ this.#device.queue.writeBuffer(this.#data, 4 * allocation.offset, table, 0, stored);
686
+ this.#tables.set(geometry, allocation);
687
+ this.#blocks.set(geometry, blocks);
688
+ }
689
+ }
690
+
691
+ this.#start_waiting(geometry);
692
+ }
693
+
694
+ /**
695
+ * The bundle's cache offered to a cache laying itself out, when it matches what the cache keeps:
696
+ * its material's, the same planes, the codes of the planes it keeps none of, and its field's blocks.
697
+ *
698
+ * @param {number} id
699
+ * @param {MeshSurfaceChannels} channels
700
+ * @param {number} blocks
701
+ * @returns {ModelCacheBundleCache|null}
702
+ */
703
+ #provision_of(id, channels, blocks) {
704
+ const provisions = this.#provisions.get(this.#geometry[id]);
705
+
706
+ if (provisions === undefined) {
707
+ return null;
708
+ }
709
+
710
+ const codes = [channels.albedo, channels.metal_rough, channels.emissive];
711
+
712
+ for (let i = 0; i < provisions.length; i++) {
713
+ const { material, cache } = provisions[i];
714
+
715
+ if (material !== this.#material[id] || cache.texels !== channels.texels) {
716
+ continue;
717
+ }
718
+
719
+ let matches = cache.texels === 0 || cache.presence.length === blocks * MESH_SURFACE_PRESENCE_BLOCK_WORDS;
720
+
721
+ for (let p = 0; p < PLANES.length && matches; p++) {
722
+ if ((cache.texels & (1 << PLANES[p])) === 0 && cache.codes[PLANES[p]] !== codes[p]) {
723
+ matches = false;
724
+ }
725
+ }
726
+
727
+ if (matches) {
728
+ return cache;
729
+ }
730
+ }
731
+
732
+ return null;
733
+ }
734
+
735
+ /**
736
+ * The block table of a geometry's field as the storage holds it, read back whole as `words`: its
737
+ * blocks and words, or 0 and none before a survey.
738
+ *
739
+ * @param {number} geometry
740
+ * @param {Uint32Array} words `data` read back
741
+ * @returns {{blocks: number, table: Uint32Array}}
742
+ */
743
+ export_table(geometry, words) {
744
+ const table = this.#tables.get(geometry);
745
+ const blocks = this.#blocks.get(geometry);
746
+
747
+ if (table === undefined || blocks === undefined) {
748
+ return { blocks: 0, table: new Uint32Array(0) };
749
+ }
750
+
751
+ return { blocks, table: words.slice(table.offset, table.offset + this.#stored.get(geometry)) };
752
+ }
753
+
754
+ /**
755
+ * A resident cache as a bundle's cache laid out by bundle field `field`, its blocks as the storage
756
+ * holds them, read back whole as `words`.
757
+ *
758
+ * @param {number} id
759
+ * @param {number} field
760
+ * @param {Uint32Array} words `data` read back
761
+ * @param {ModelCacheBundleCache} out
762
+ * @returns {ModelCacheBundleCache} out
763
+ */
764
+ export_cache(id, field, words, out) {
765
+ assert.equal(this.#state[id], CACHE_RESIDENT, `surface cache ${id} is not resident`);
766
+
767
+ out.field = field;
768
+ out.texels = this.#texels[id];
769
+
770
+ for (let p = 0; p < PLANES.length; p++) {
771
+ out.codes[PLANES[p]] = this.#codes[PLANES[p]][id];
772
+ }
773
+
774
+ const blocks = this.#blocks.get(this.#geometry[id]) ?? 0;
775
+
776
+ out.presence = run_words(this.#presence_runs[id], blocks * MESH_SURFACE_PRESENCE_BLOCK_WORDS, words);
777
+
778
+ for (let p = 0; p < PLANES.length; p++) {
779
+ out.planes[PLANES[p]] = run_words(this.#plane_runs[p][id], blocks * MESH_SURFACE_PLANE_BLOCK_WORDS[PLANES[p]], words);
780
+ }
781
+
782
+ return out;
783
+ }
784
+
785
+ /**
786
+ * Queue a resident field's survey, unless it is queued or done: its table, and its bricks taken from
787
+ * the next frame on.
788
+ *
789
+ * @param {number} geometry
790
+ */
791
+ #request_survey(geometry) {
792
+ if (this.#survey_tickets.has(geometry) || this.#blocks.has(geometry)) {
793
+ return;
794
+ }
795
+
796
+ const table = this.#allocate_words(this.#stored.get(geometry));
797
+
798
+ if (table === null) {
799
+ // the storage is at its binding's limit: its caches that keep a plane wait for the next field
800
+ return;
801
+ }
802
+
803
+ this.#tables.set(geometry, table);
804
+
805
+ const ticket = ++this.#survey_count;
806
+
807
+ this.#survey_tickets.set(geometry, ticket);
808
+ this.#survey_next.set(geometry, 0);
809
+ this.#queue_survey.push(geometry, ticket);
810
+ }
811
+
812
+ /**
813
+ * A geometry's survey is read back: its field's bricks keep `blocks` blocks, numbered in its table.
814
+ * Its caches that keep a plane are laid out.
815
+ *
816
+ * @param {number} geometry
817
+ * @param {number} blocks
818
+ */
819
+ set_blocks(geometry, blocks) {
820
+ assert.isNonNegativeInteger(blocks, 'blocks');
821
+ assert.ok(this.#stored.has(geometry), `geometry ${geometry} has no resident field to have surveyed`);
822
+
823
+ this.#blocks.set(geometry, blocks);
824
+ this.#survey_tickets.delete(geometry);
825
+ this.#survey_next.delete(geometry);
826
+
827
+ this.#start_waiting(geometry);
828
+ }
829
+
830
+ /**
831
+ * A geometry's field is gone: its caches wait for the next.
832
+ *
833
+ * @param {number} geometry
834
+ */
835
+ drop_layout(geometry) {
836
+ if (!this.#stored.delete(geometry)) {
837
+ return;
838
+ }
839
+
840
+ this.#colored.delete(geometry);
841
+ this.#blocks.delete(geometry);
842
+ this.#provisions.delete(geometry);
843
+ this.#survey_tickets.delete(geometry);
844
+ this.#survey_next.delete(geometry);
845
+
846
+ const table = this.#tables.get(geometry);
847
+
848
+ if (table !== undefined) {
849
+ this.#data_allocator.free(table);
850
+ this.#tables.delete(geometry);
851
+ }
852
+
853
+ const caches = this.#caches_of_geometry.get(geometry);
854
+
855
+ if (caches === undefined) {
856
+ return;
857
+ }
858
+
859
+ for (let i = 0; i < caches.length; i++) {
860
+ const id = caches[i];
861
+ const was = this.#state[id];
862
+
863
+ this.#free_runs(id);
864
+
865
+ this.#state[id] = CACHE_WAITING;
866
+ this.#ticket[id]++;
867
+ this.#queued[id] = 0;
868
+ this.#next_brick[id] = 0;
869
+
870
+ if (was === CACHE_RESIDENT) {
871
+ this.#resident_count--;
872
+ this.onWithdrawn.send1(id);
873
+ }
874
+ }
875
+ }
876
+
877
+ /**
878
+ * The geometry `clone` is drawn as `source` from here on: its caches, and those acquired for it after,
879
+ * follow `source`'s field and are baked from `source`'s triangles, the two being in one local space.
880
+ * A cache of `clone` waits for `source`'s field, as one acquired for `source` does.
881
+ *
882
+ * @param {number} clone
883
+ * @param {number} source
884
+ */
885
+ alias(clone, source) {
886
+ assert.notEqual(clone, source, 'a geometry cannot alias itself');
887
+
888
+ this.#source_of.set(clone, source);
889
+
890
+ // its own field, if it had one, is gone: what it has waits
891
+ this.drop_layout(clone);
892
+
893
+ const caches = this.#caches_of_geometry.get(clone);
894
+
895
+ if (caches === undefined) {
896
+ return;
897
+ }
898
+
899
+ this.#caches_of_geometry.delete(clone);
900
+
901
+ for (let i = 0; i < caches.length; i++) {
902
+ const id = caches[i];
903
+
904
+ this.#geometry[id] = source;
905
+
906
+ let of_source = this.#caches_of_geometry.get(source);
907
+
908
+ if (of_source === undefined) {
909
+ of_source = [];
910
+ this.#caches_of_geometry.set(source, of_source);
911
+ }
912
+
913
+ of_source.push(id);
914
+
915
+ if (this.#stored.has(source)) {
916
+ this.#start(id);
917
+ }
918
+ }
919
+ }
920
+
921
+ /**
922
+ * `clone` is no longer aliased: caches acquired for it from here on follow its own field. Those it has
923
+ * keep following its source's until they are given back.
924
+ *
925
+ * @param {number} clone
926
+ */
927
+ unalias(clone) {
928
+ this.#source_of.delete(clone);
929
+ }
930
+
931
+ /**
932
+ * @param {number} geometry
933
+ */
934
+ #start_waiting(geometry) {
935
+ const caches = this.#caches_of_geometry.get(geometry);
936
+
937
+ if (caches === undefined) {
938
+ return;
939
+ }
940
+
941
+ for (let i = 0; i < caches.length; i++) {
942
+ if (this.#state[caches[i]] === CACHE_WAITING) {
943
+ this.#start(caches[i]);
944
+ }
945
+ }
946
+ }
947
+
948
+ /**
949
+ * What the cache's material and geometry make of its surface material now.
950
+ *
951
+ * @param {number} id
952
+ * @returns {MeshSurfaceChannels} shared scratch, good until the next call
953
+ */
954
+ #channels_of(id) {
955
+ const geometry = this.#geometry[id];
956
+
957
+ return mesh_surface_channels(this.#material[id], this.#colored.get(geometry) === true, this.#channels);
958
+ }
959
+
960
+ /**
961
+ * @param {number} id
962
+ * @param {MeshSurfaceChannels} channels
963
+ */
964
+ #keep_codes(id, channels) {
965
+ this.#codes[SURFACE_MATERIAL_ALBEDO_PLANE][id] = channels.albedo;
966
+ this.#codes[SURFACE_MATERIAL_METAL_ROUGH_PLANE][id] = channels.metal_rough;
967
+ this.#codes[SURFACE_MATERIAL_EMISSIVE_PLANE][id] = channels.emissive;
968
+ }
969
+
970
+ /**
971
+ * Whether a laid out cache has blocks to bake.
972
+ *
973
+ * @param {number} id
974
+ * @returns {boolean}
975
+ */
976
+ #bakes(id) {
977
+ return this.#texels[id] !== 0 && this.#presence_runs[id] !== null && this.#presence_runs[id] !== undefined;
978
+ }
979
+
980
+ /**
981
+ * Runs for a cache whose field is resident, and surveyed when it keeps a plane, and its first bake
982
+ * queued; a cache with no blocks to bake is resident at once.
983
+ *
984
+ * @param {number} id
985
+ */
986
+ #start(id) {
987
+ const geometry = this.#geometry[id];
988
+
989
+ this.#ensure_device();
990
+
991
+ const channels = this.#channels_of(id);
992
+ const blocks = this.#blocks.get(geometry);
993
+
994
+ if (channels.texels !== 0 && blocks === undefined) {
995
+ // its field's survey is not read back yet: asked for, if no cache has asked
996
+ this.#request_survey(geometry);
997
+ return;
998
+ }
999
+
1000
+ if (!this.#allocate(id, channels.texels, channels.texels === 0 ? 0 : blocks)) {
1001
+ // the storage is at its binding's limit; it waits, and is tried again with the next field
1002
+ return;
1003
+ }
1004
+
1005
+ this.#texels[id] = channels.texels;
1006
+ this.#keep_codes(id, channels);
1007
+
1008
+ this.#state[id] = CACHE_BAKING;
1009
+ this.#next_brick[id] = 0;
1010
+
1011
+ const provision = this.#provision_of(id, channels, channels.texels === 0 ? 0 : blocks);
1012
+
1013
+ if (provision !== null) {
1014
+ // the bundle's blocks, in the runs just given: resident without a bake
1015
+ this.#write_run(this.#presence_runs[id], provision.presence);
1016
+
1017
+ for (let p = 0; p < PLANES.length; p++) {
1018
+ this.#write_run(this.#plane_runs[p][id], provision.planes[PLANES[p]]);
1019
+ }
1020
+
1021
+ this.#write_record(id, 0);
1022
+ this.#complete(id);
1023
+
1024
+ return;
1025
+ }
1026
+
1027
+ this.#write_record(id, 0);
1028
+
1029
+ if (!this.#bakes(id)) {
1030
+ // nothing that varies, or no block kept: resident at once, its record all it holds
1031
+ this.#complete(id);
1032
+ return;
1033
+ }
1034
+
1035
+ this.#queued[id] = 1;
1036
+ this.#queue_new.push(id, this.#ticket[id]);
1037
+ }
1038
+
1039
+ /**
1040
+ * A bake of the cache is recorded in full.
1041
+ *
1042
+ * @param {number} id
1043
+ */
1044
+ #complete(id) {
1045
+ if (this.#state[id] === CACHE_BAKING) {
1046
+ this.#state[id] = CACHE_RESIDENT;
1047
+ this.#resident_count++;
1048
+ }
1049
+
1050
+ this.#completed.push(id);
1051
+ }
1052
+
1053
+ /**
1054
+ * Give a cache its runs: `blocks` blocks of presence and of each plane in `texels`, none when it
1055
+ * keeps no plane or its field keeps no block. On failure gives back what it took.
1056
+ *
1057
+ * @param {number} id
1058
+ * @param {number} texels
1059
+ * @param {number} blocks
1060
+ * @returns {boolean} whether every run was given
1061
+ */
1062
+ #allocate(id, texels, blocks) {
1063
+ this.#presence_runs[id] = null;
1064
+
1065
+ for (let p = 0; p < PLANES.length; p++) {
1066
+ this.#plane_runs[p][id] = null;
1067
+ }
1068
+
1069
+ if (texels === 0 || blocks === 0) {
1070
+ return true;
1071
+ }
1072
+
1073
+ const presence = this.#allocate_words(blocks * MESH_SURFACE_PRESENCE_BLOCK_WORDS);
1074
+
1075
+ if (presence === null) {
1076
+ return false;
1077
+ }
1078
+
1079
+ this.#presence_runs[id] = presence;
1080
+
1081
+ for (let p = 0; p < PLANES.length; p++) {
1082
+ if ((texels & (1 << PLANES[p])) === 0) {
1083
+ continue;
1084
+ }
1085
+
1086
+ const run = this.#allocate_words(blocks * MESH_SURFACE_PLANE_BLOCK_WORDS[PLANES[p]]);
1087
+
1088
+ if (run === null) {
1089
+ this.#free_runs(id);
1090
+ return false;
1091
+ }
1092
+
1093
+ this.#plane_runs[p][id] = run;
1094
+ }
1095
+
1096
+ return true;
1097
+ }
1098
+
1099
+ /**
1100
+ * Words of the storage, grown to what they take; the words are copied over.
1101
+ *
1102
+ * @param {number} words
1103
+ * @returns {Allocation|null}
1104
+ */
1105
+ #allocate_words(words) {
1106
+ const allocator = this.#data_allocator;
1107
+
1108
+ if (!allocator.can_allocate(words)) {
1109
+ const target = allocator.grow_target_for(words);
1110
+ const bytes = 4 * target;
1111
+
1112
+ if (bytes > this.#device.limits.maxStorageBufferBindingSize) {
1113
+ warn_limited(`GPUMeshSurfaceCaches: the storage can't hold ${target} words`);
1114
+ return null;
1115
+ }
1116
+
1117
+ const buffer = this.#create_buffer("data", bytes, GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC);
1118
+ const encoder = this.#device.createCommandEncoder({ label: "GPUMeshSurfaceCaches/data growth" });
1119
+
1120
+ encoder.copyBufferToBuffer(this.#data, 0, buffer, 0, this.#data.size);
1121
+ this.#device.queue.submit([encoder.finish()]);
1122
+
1123
+ this.#data.destroy();
1124
+ this.#data = buffer;
1125
+
1126
+ allocator.grow(target);
1127
+ }
1128
+
1129
+ const allocation = allocator.allocate(words);
1130
+
1131
+ assert.notEqual(allocation.offset, ALLOCATOR_NO_SPACE, 'storage allocation after growth');
1132
+
1133
+ return allocation;
1134
+ }
1135
+
1136
+ /**
1137
+ * @param {Allocation|null|undefined} run
1138
+ * @param {Uint32Array} words as many as the run was given
1139
+ */
1140
+ #write_run(run, words) {
1141
+ if (run === null || run === undefined) {
1142
+ return;
1143
+ }
1144
+
1145
+ this.#device.queue.writeBuffer(this.#data, 4 * run.offset, words, 0, words.length);
1146
+ }
1147
+
1148
+ /**
1149
+ * @param {number} id
1150
+ */
1151
+ #free_runs(id) {
1152
+ // only bakes write blocks, in submission order: a later owner's bake comes after
1153
+ const presence = this.#presence_runs[id];
1154
+
1155
+ if (presence !== null && presence !== undefined) {
1156
+ this.#data_allocator.free(presence);
1157
+ this.#presence_runs[id] = null;
1158
+ }
1159
+
1160
+ for (let p = 0; p < PLANES.length; p++) {
1161
+ const run = this.#plane_runs[p][id];
1162
+
1163
+ if (run !== null && run !== undefined) {
1164
+ this.#data_allocator.free(run);
1165
+ this.#plane_runs[p][id] = null;
1166
+ }
1167
+ }
1168
+ }
1169
+
1170
+ /**
1171
+ * @param {number} id
1172
+ * @param {number} material the material's resident id, 0 until a bake takes it
1173
+ */
1174
+ #write_record(id, material) {
1175
+ const view = this.#record_scratch;
1176
+ const geometry = this.#geometry[id];
1177
+ const presence = this.#presence_runs[id];
1178
+ const table = this.#tables.get(geometry);
1179
+
1180
+ view.setUint32(MESH_SURFACE_STRUCT.get("geometry").offset, geometry, true);
1181
+ view.setUint32(MESH_SURFACE_STRUCT.get("material").offset, material, true);
1182
+ view.setUint32(MESH_SURFACE_STRUCT.get("tiles").offset, this.#stored.get(geometry), true);
1183
+ view.setUint32(MESH_SURFACE_STRUCT.get("blocks").offset, this.#blocks.get(geometry) ?? 0, true);
1184
+ view.setUint32(MESH_SURFACE_STRUCT.get("texels").offset, this.#texels[id], true);
1185
+ view.setUint32(MESH_SURFACE_STRUCT.get("table").offset, table === undefined ? 0 : table.offset, true);
1186
+ view.setUint32(MESH_SURFACE_STRUCT.get("presence_blocks").offset, presence === null || presence === undefined ? 0 : presence.offset, true);
1187
+
1188
+ for (let p = 0; p < PLANES.length; p++) {
1189
+ const run = this.#plane_runs[p][id];
1190
+
1191
+ view.setUint32(MESH_SURFACE_STRUCT.get(PLANE_BLOCK_FIELDS[p]).offset, run === null || run === undefined ? 0 : run.offset, true);
1192
+ }
1193
+
1194
+ view.setUint32(MESH_SURFACE_STRUCT.get("albedo").offset, this.#codes[SURFACE_MATERIAL_ALBEDO_PLANE][id], true);
1195
+ view.setUint32(MESH_SURFACE_STRUCT.get("metal_rough").offset, this.#codes[SURFACE_MATERIAL_METAL_ROUGH_PLANE][id], true);
1196
+ view.setUint32(MESH_SURFACE_STRUCT.get("emissive").offset, this.#codes[SURFACE_MATERIAL_EMISSIVE_PLANE][id], true);
1197
+
1198
+ this.#ensure_records(id + 1);
1199
+
1200
+ this.#device.queue.writeBuffer(this.#records, id * MESH_SURFACE_STRUCT.size, view.buffer, 0, MESH_SURFACE_STRUCT.size);
1201
+ }
1202
+
1203
+ /**
1204
+ * Take the frame's survey bricks off its queue into runs, while the frame's budget lasts, and the
1205
+ * fields whose surveys they complete into numbering runs.
1206
+ */
1207
+ #take_surveys() {
1208
+ this.#frame_survey_runs = 0;
1209
+ this.#frame_survey_threads = 0;
1210
+ this.#frame_number_runs = 0;
1211
+ this.#frame_number_threads = 0;
1212
+ this.#frame_clears.length = 0;
1213
+ // made when a survey completes: the frame's readback keeps it
1214
+ this.#frame_completed_surveys = null;
1215
+
1216
+ const queue = this.#queue_survey;
1217
+ let head = this.#head_survey;
1218
+
1219
+ while (this.#frame_left > 0 && head < queue.length) {
1220
+ const geometry = queue[head];
1221
+ const ticket = queue[head + 1];
1222
+
1223
+ if (this.#survey_tickets.get(geometry) !== ticket) {
1224
+ // its field went since it was queued
1225
+ head += 2;
1226
+ continue;
1227
+ }
1228
+
1229
+ const stored = this.#stored.get(geometry);
1230
+ const table = this.#tables.get(geometry);
1231
+ const first = this.#survey_next.get(geometry);
1232
+ const count = Math.min(stored - first, this.#frame_left);
1233
+
1234
+ if (first === 0) {
1235
+ this.#frame_clears.push(table.offset, stored);
1236
+ }
1237
+
1238
+ const runs = this.#frame_survey_runs;
1239
+
1240
+ this.#survey_run_scratch = grow_typed(this.#survey_run_scratch, 4 * (runs + 1));
1241
+ this.#survey_run_scratch[4 * runs] = this.#frame_survey_threads;
1242
+ this.#survey_run_scratch[4 * runs + 1] = geometry;
1243
+ this.#survey_run_scratch[4 * runs + 2] = first;
1244
+ this.#survey_run_scratch[4 * runs + 3] = table.offset;
1245
+
1246
+ this.#frame_survey_runs = runs + 1;
1247
+ this.#frame_survey_threads += count * MESH_SDF_BRICK_TEXEL_COUNT;
1248
+ this.#frame_left -= count;
1249
+
1250
+ if (first + count < stored) {
1251
+ // the budget ran out inside it: it goes on from here next frame
1252
+ this.#survey_next.set(geometry, first + count);
1253
+ break;
1254
+ }
1255
+
1256
+ // surveyed in full this frame: numbered after
1257
+ const numbering = this.#frame_number_runs;
1258
+
1259
+ this.#number_run_scratch = grow_typed(this.#number_run_scratch, 4 * (numbering + 1));
1260
+ this.#number_run_scratch[4 * numbering] = this.#frame_number_threads;
1261
+ this.#number_run_scratch[4 * numbering + 1] = table.offset;
1262
+ this.#number_run_scratch[4 * numbering + 2] = numbering;
1263
+ this.#number_run_scratch[4 * numbering + 3] = ticket;
1264
+
1265
+ this.#frame_number_runs = numbering + 1;
1266
+ this.#frame_number_threads += stored;
1267
+
1268
+ if (this.#frame_completed_surveys === null) {
1269
+ this.#frame_completed_surveys = [];
1270
+ }
1271
+
1272
+ this.#frame_completed_surveys.push(geometry, ticket);
1273
+
1274
+ this.#survey_next.delete(geometry);
1275
+ head += 2;
1276
+ }
1277
+
1278
+ this.#head_survey = this.#compact(queue, head);
1279
+ }
1280
+
1281
+ /**
1282
+ * Take bricks off the bake queues from their heads into the frame's runs, while the frame's budget
1283
+ * lasts: first bakes before bakes again.
1284
+ */
1285
+ #take_bakes() {
1286
+ this.#frame_runs = 0;
1287
+ this.#frame_threads = 0;
1288
+
1289
+ const left = this.#frame_left;
1290
+
1291
+ this.#head_new = this.#compact(this.#queue_new, this.#take_from(this.#queue_new, this.#head_new));
1292
+ this.#head_re = this.#compact(this.#queue_re, this.#take_from(this.#queue_re, this.#head_re));
1293
+
1294
+ this.#bricks_baked += left - this.#frame_left;
1295
+ }
1296
+
1297
+ /**
1298
+ * Take bricks off one queue from its head into the frame's runs, while the frame's budget lasts.
1299
+ *
1300
+ * @param {number[]} queue (id, ticket) pairs
1301
+ * @param {number} head
1302
+ * @returns {number} the queue's head after what was taken
1303
+ */
1304
+ #take_from(queue, head) {
1305
+ while (this.#frame_left > 0 && head < queue.length) {
1306
+ const id = queue[head];
1307
+
1308
+ if (queue[head + 1] !== this.#ticket[id] || this.#queued[id] === 0) {
1309
+ // given back, or its field went, since it was queued
1310
+ head += 2;
1311
+ continue;
1312
+ }
1313
+
1314
+ const stored = this.#stored.get(this.#geometry[id]);
1315
+ const first = this.#next_brick[id];
1316
+ const count = Math.min(stored - first, this.#frame_left);
1317
+
1318
+ if (first === 0) {
1319
+ // its row as the material stands now, repacked if it has moved since
1320
+ this.#frame_materials.obtain_material(this.#material[id]);
1321
+ this.#write_record(id, this.#material[id].id);
1322
+ }
1323
+
1324
+ const runs = this.#frame_runs;
1325
+
1326
+ this.#run_scratch = grow_typed(this.#run_scratch, 4 * (runs + 1));
1327
+ this.#run_scratch[4 * runs] = this.#frame_threads;
1328
+ this.#run_scratch[4 * runs + 1] = id;
1329
+ this.#run_scratch[4 * runs + 2] = first;
1330
+ this.#run_scratch[4 * runs + 3] = 0;
1331
+
1332
+ this.#frame_runs = runs + 1;
1333
+ this.#frame_threads += count * MESH_SDF_BRICK_TEXEL_COUNT;
1334
+ this.#frame_left -= count;
1335
+
1336
+ this.#next_brick[id] = first + count;
1337
+
1338
+ if (first + count < stored) {
1339
+ // the budget ran out inside it: it goes on from here next frame
1340
+ return head;
1341
+ }
1342
+
1343
+ this.#next_brick[id] = 0;
1344
+ this.#queued[id] = 0;
1345
+ head += 2;
1346
+
1347
+ this.#complete(id);
1348
+ }
1349
+
1350
+ return head;
1351
+ }
1352
+
1353
+ /**
1354
+ * Drop a queue's taken entries once they are most of it.
1355
+ *
1356
+ * @param {number[]} queue
1357
+ * @param {number} head
1358
+ * @returns {number} the new head
1359
+ */
1360
+ #compact(queue, head) {
1361
+ if (head === queue.length) {
1362
+ queue.length = 0;
1363
+ return 0;
1364
+ }
1365
+
1366
+ if (head > 64 && head * 2 > queue.length) {
1367
+ queue.copyWithin(0, head);
1368
+ queue.length -= head;
1369
+ return 0;
1370
+ }
1371
+
1372
+ return head;
1373
+ }
1374
+
1375
+ /**
1376
+ * Record the frame's surveys and bake: at most `budget` bricks. Records nothing when nothing waits.
1377
+ * Caches whose bake this completes are announced through {@link onBaked}, resident from here; the
1378
+ * surveys it completes are read back.
1379
+ *
1380
+ * @param {Object} options
1381
+ * @param {FrameGraph} options.graph
1382
+ * @param {number} options.budget bricks surveyed and baked at most, `surface_bake_budget`: a frame
1383
+ * lists every texel of its bricks in one storage binding
1384
+ * @param {number} options.arena graph handle of the fields' indirection, as the frame's bake left it
1385
+ * @param {GPUBuffer} options.headers the fields' headers
1386
+ * @param {GPUTextureView} options.field_atlas the fields' atlas
1387
+ * @param {GPUResidentMaterialContext} options.materials what the trace shades with: each baked
1388
+ * material is made resident, and the rows committed, before the trace is recorded
1389
+ * @param {Object} options.blas the geometry bindings `ray_query_blas_nearest` reads
1390
+ */
1391
+ graph_bake({ graph, budget, arena, headers, field_atlas, materials, blas }) {
1392
+ assert.defined(graph, 'graph');
1393
+ assert.isPositiveInteger(budget, 'budget');
1394
+ assert.lessThanOrEqual(budget * MESH_SDF_BRICK_TEXEL_COUNT * MESH_SURFACE_TEXEL_STRUCT.aligned_size, this.#device.limits.maxStorageBufferBindingSize, "budget, a frame's texel list of every texel of its bricks past maxStorageBufferBindingSize");
1395
+ assert.defined(materials, 'materials');
1396
+
1397
+ this.#frame_materials = materials;
1398
+ this.#frame_left = budget;
1399
+
1400
+ this.#take_surveys();
1401
+ this.#take_bakes();
1402
+
1403
+ this.#frame_materials = null;
1404
+
1405
+ const b = this.#bindings;
1406
+
1407
+ b.mesh_sdf_headers = headers;
1408
+ b.mesh_sdf_atlas = field_atlas;
1409
+ b.mesh_sdf_sampler = MESH_SDF_SAMPLER;
1410
+
1411
+ if (this.#frame_survey_runs > 0) {
1412
+ this.#record_surveys(graph, arena);
1413
+ }
1414
+
1415
+ if (this.#frame_runs > 0) {
1416
+ this.#ensure_device();
1417
+
1418
+ // what the runs' materials made resident, written before the trace reads it
1419
+ materials.commit();
1420
+
1421
+ if (this.#runs === null || this.#frame_runs > this.#run_capacity) {
1422
+ this.#run_capacity = doubled_capacity(this.#frame_runs, this.#run_capacity);
1423
+ this.#runs?.destroy();
1424
+ this.#runs = this.#create_buffer("runs", 16 * this.#run_capacity, GPUBufferUsage.COPY_DST);
1425
+ }
1426
+
1427
+ this.#ensure_texels(this.#frame_threads);
1428
+
1429
+ this.#device.queue.writeBuffer(this.#runs, 0, this.#run_scratch, 0, 4 * this.#frame_runs);
1430
+
1431
+ const data = this.#pass_data;
1432
+ const pass = graph.add("Mesh Surface Bake", data, this.#execute);
1433
+
1434
+ data.arena = pass.read(arena);
1435
+
1436
+ pass.make_side_effect();
1437
+
1438
+ b.materials = materials.buffer_materials;
1439
+ b.textures = materials.textureView;
1440
+ b.blas_lookup = blas.blas_lookup;
1441
+ b.blas_data = blas.blas_data;
1442
+ b.geometries = blas.geometries;
1443
+ b.meshlet_metadata = blas.meshlet_metadata;
1444
+ b.meshlet_data = blas.meshlet_data;
1445
+ }
1446
+
1447
+ const completed = this.#completed;
1448
+
1449
+ for (let i = 0; i < completed.length; i++) {
1450
+ this.onBaked.send1(completed[i]);
1451
+ }
1452
+
1453
+ completed.length = 0;
1454
+ }
1455
+
1456
+ /**
1457
+ * @param {FrameGraph} graph
1458
+ * @param {number} arena
1459
+ */
1460
+ #record_surveys(graph, arena) {
1461
+ this.#ensure_device();
1462
+
1463
+ if (this.#survey_runs === null || this.#frame_survey_runs > this.#survey_run_capacity) {
1464
+ this.#survey_run_capacity = doubled_capacity(this.#frame_survey_runs, this.#survey_run_capacity);
1465
+ this.#survey_runs?.destroy();
1466
+ this.#survey_runs = this.#create_buffer("survey runs", 16 * this.#survey_run_capacity, GPUBufferUsage.COPY_DST);
1467
+ }
1468
+
1469
+ this.#device.queue.writeBuffer(this.#survey_runs, 0, this.#survey_run_scratch, 0, 4 * this.#frame_survey_runs);
1470
+
1471
+ const numbering = this.#frame_number_runs;
1472
+
1473
+ if (numbering > 0) {
1474
+ if (this.#number_runs === null || numbering > this.#number_run_capacity) {
1475
+ this.#number_run_capacity = doubled_capacity(numbering, this.#number_run_capacity);
1476
+ this.#number_runs?.destroy();
1477
+ this.#number_runs = this.#create_buffer("number runs", 16 * this.#number_run_capacity, GPUBufferUsage.COPY_DST);
1478
+ }
1479
+
1480
+ this.#device.queue.writeBuffer(this.#number_runs, 0, this.#number_run_scratch, 0, 4 * numbering);
1481
+ this.#ensure_survey_results(numbering);
1482
+ }
1483
+
1484
+ const data = this.#survey_pass_data;
1485
+ const pass = graph.add("Mesh Surface Survey", data, this.#execute_surveys);
1486
+
1487
+ data.arena = pass.read(arena);
1488
+ data.results = -1;
1489
+
1490
+ pass.make_side_effect();
1491
+
1492
+ if (numbering === 0) {
1493
+ return;
1494
+ }
1495
+
1496
+ data.results = pass.write(graph_import_buffer(graph, this.#survey_results, "mesh_surface_survey_results"));
1497
+
1498
+ const completed = this.#frame_completed_surveys;
1499
+
1500
+ graph_read_buffer({ graph, buffer: data.results, offset: 0, size: 4 * MESH_SURFACE_SURVEY_RESULT_WORDS * numbering })
1501
+ .then(reference => {
1502
+ try {
1503
+ if (!this.#destroyed) {
1504
+ this.#apply_surveys(new Uint32Array(reference.getValue()), completed);
1505
+ }
1506
+ } finally {
1507
+ reference.release();
1508
+ }
1509
+ })
1510
+ .catch(error => {
1511
+ if (!this.#destroyed) {
1512
+ // a lost result leaves its field's caches waiting until the field is laid out again; say so
1513
+ console.warn('GPUMeshSurfaceCaches: survey readback failed', error);
1514
+ }
1515
+ });
1516
+ }
1517
+
1518
+ /**
1519
+ * @param {Uint32Array} words the frame's results
1520
+ * @param {number[]} completed the (geometry, ticket) pairs they were asked for
1521
+ */
1522
+ #apply_surveys(words, completed) {
1523
+ for (let i = 0; i < completed.length; i += 2) {
1524
+ const geometry = completed[i];
1525
+ const ticket = completed[i + 1];
1526
+ const result = (i / 2) * MESH_SURFACE_SURVEY_RESULT_WORDS;
1527
+
1528
+ // a result no pass wrote holds no ticket, and a field gone since holds another
1529
+ if (words[result] !== ticket || this.#survey_tickets.get(geometry) !== ticket) {
1530
+ continue;
1531
+ }
1532
+
1533
+ this.set_blocks(geometry, words[result + 1]);
1534
+ }
1535
+ }
1536
+
1537
+ /**
1538
+ * {@link #execute_surveys_now}, bound once.
1539
+ * @type {function(Object, Object, Object): void}
1540
+ */
1541
+ #execute_surveys = (data, resources, context) => this.#execute_surveys_now(data, resources, context);
1542
+
1543
+ #execute_surveys_now(data, resources, context) {
1544
+ const encoder = context.encoder;
1545
+ const b = this.#bindings;
1546
+
1547
+ // each field's table, before its first bricks set their bits
1548
+ const clears = this.#frame_clears;
1549
+
1550
+ for (let i = 0; i < clears.length; i += 2) {
1551
+ encoder.clearBuffer(this.#data, 4 * clears[i], 4 * clears[i + 1]);
1552
+ }
1553
+
1554
+ b.mesh_sdf_indirection = resources.get(data.arena);
1555
+ b.mesh_surface_data = this.#data;
1556
+ b.mesh_surface_runs = this.#survey_runs;
1557
+
1558
+ const survey = this.#survey_settings;
1559
+ const groups = Math.ceil(this.#frame_survey_threads / MESH_SDF_BAKE_WORKGROUP_SIZE);
1560
+ const groups_x = Math.min(groups, WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION);
1561
+
1562
+ survey.run_count = this.#frame_survey_runs;
1563
+ survey.thread_count = this.#frame_survey_threads;
1564
+ survey.groups_x = groups_x;
1565
+ b.settings = survey;
1566
+
1567
+ shader_mesh_surface_survey.dispatch({
1568
+ encoder,
1569
+ group_count_x: groups_x,
1570
+ group_count_y: Math.ceil(groups / groups_x),
1571
+ bindings: b,
1572
+ });
1573
+
1574
+ if (this.#frame_number_runs === 0) {
1575
+ return;
1576
+ }
1577
+
1578
+ const results = resources.get(data.results);
1579
+
1580
+ encoder.clearBuffer(results, 0, 4 * MESH_SURFACE_SURVEY_RESULT_WORDS * this.#frame_number_runs);
1581
+
1582
+ b.mesh_surface_runs = this.#number_runs;
1583
+ b.mesh_surface_survey_results = results;
1584
+
1585
+ const number = this.#number_settings;
1586
+ const number_groups = Math.ceil(this.#frame_number_threads / MESH_SDF_BAKE_WORKGROUP_SIZE);
1587
+ const number_x = Math.min(number_groups, WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION);
1588
+
1589
+ number.run_count = this.#frame_number_runs;
1590
+ number.thread_count = this.#frame_number_threads;
1591
+ number.groups_x = number_x;
1592
+ b.settings = number;
1593
+
1594
+ shader_mesh_surface_number.dispatch({
1595
+ encoder,
1596
+ group_count_x: number_x,
1597
+ group_count_y: Math.ceil(number_groups / number_x),
1598
+ bindings: b,
1599
+ });
1600
+ }
1601
+
1602
+ /**
1603
+ * {@link #execute_bake}, bound once.
1604
+ * @type {function(Object, Object, Object): void}
1605
+ */
1606
+ #execute = (data, resources, context) => this.#execute_bake(data, resources, context);
1607
+
1608
+ #execute_bake(data, resources, context) {
1609
+ const encoder = context.encoder;
1610
+ const b = this.#bindings;
1611
+
1612
+ encoder.clearBuffer(this.#counter);
1613
+
1614
+ b.mesh_sdf_indirection = resources.get(data.arena);
1615
+ b.mesh_surface_records = this.#records;
1616
+ b.mesh_surface_runs = this.#runs;
1617
+ b.mesh_surface_texels = this.#texel_list;
1618
+ b.mesh_surface_staging = this.#staging;
1619
+ b.mesh_surface_counter = this.#counter;
1620
+ b.mesh_surface_command = this.#command;
1621
+ b.mesh_surface_data = this.#data;
1622
+
1623
+ const groups = Math.ceil(this.#frame_threads / MESH_SDF_BAKE_WORKGROUP_SIZE);
1624
+ const groups_x = Math.min(groups, WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION);
1625
+ const list = this.#list_settings;
1626
+
1627
+ list.run_count = this.#frame_runs;
1628
+ list.thread_count = this.#frame_threads;
1629
+ list.groups_x = groups_x;
1630
+ list.capacity = this.#texel_capacity;
1631
+ b.settings = list;
1632
+
1633
+ shader_mesh_surface_list.dispatch({
1634
+ encoder,
1635
+ group_count_x: groups_x,
1636
+ group_count_y: Math.ceil(groups / groups_x),
1637
+ bindings: b,
1638
+ });
1639
+
1640
+ this.#command_settings.capacity = this.#texel_capacity;
1641
+ b.settings = this.#command_settings;
1642
+
1643
+ shader_mesh_surface_command.dispatch({ encoder, bindings: b });
1644
+
1645
+ shader_mesh_surface_trace.dispatchIndirect({
1646
+ encoder,
1647
+ bindings: b,
1648
+ command: this.#command,
1649
+ });
1650
+
1651
+ // a workgroup a block: 8 a brick
1652
+ const bricks = this.#frame_threads / MESH_SDF_BRICK_TEXEL_COUNT;
1653
+ const blocks = bricks * MESH_SURFACE_BRICK_BLOCKS;
1654
+ const blocks_x = Math.min(blocks, WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION);
1655
+ const encode = this.#encode_settings;
1656
+
1657
+ encode.run_count = this.#frame_runs;
1658
+ encode.brick_count = bricks;
1659
+ encode.groups_x = blocks_x;
1660
+ b.settings = encode;
1661
+
1662
+ shader_mesh_surface_encode.dispatch({
1663
+ encoder,
1664
+ group_count_x: blocks_x,
1665
+ group_count_y: Math.ceil(blocks / blocks_x),
1666
+ bindings: b,
1667
+ });
1668
+ }
1669
+
1670
+ #ensure_id(id) {
1671
+ const length = id + 1;
1672
+
1673
+ this.#state = grow_typed(this.#state, length);
1674
+ this.#geometry = grow_typed(this.#geometry, length);
1675
+ this.#ticket = grow_typed(this.#ticket, length);
1676
+ this.#next_brick = grow_typed(this.#next_brick, length);
1677
+ this.#queued = grow_typed(this.#queued, length);
1678
+ this.#texels = grow_typed(this.#texels, length);
1679
+
1680
+ for (let p = 0; p < PLANES.length; p++) {
1681
+ this.#codes[p] = grow_typed(this.#codes[p], length);
1682
+ }
1683
+ }
1684
+
1685
+ #ensure_device() {
1686
+ if (this.#records !== null || this.#destroyed) {
1687
+ return;
1688
+ }
1689
+
1690
+ this.#data = this.#create_buffer("data", 4 * INITIAL_DATA_WORDS, GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC);
1691
+ this.#data_allocator = new OffsetAllocator(INITIAL_DATA_WORDS);
1692
+
1693
+ this.#counter = this.#create_buffer("counter", 4 * MESH_SURFACE_COUNTER_WORDS, GPUBufferUsage.COPY_DST);
1694
+ this.#command = this.#create_buffer("command", 4 * MESH_SURFACE_COMMAND_WORDS, GPUBufferUsage.INDIRECT);
1695
+
1696
+ this.#ensure_records(64);
1697
+ }
1698
+
1699
+ /**
1700
+ * @param {number} count
1701
+ */
1702
+ #ensure_records(count) {
1703
+ if (count <= this.#record_capacity) {
1704
+ return;
1705
+ }
1706
+
1707
+ let capacity = Math.max(64, this.#record_capacity);
1708
+
1709
+ while (capacity < count) {
1710
+ capacity *= 2;
1711
+ }
1712
+
1713
+ const size = MESH_SURFACE_STRUCT.size * capacity;
1714
+ const buffer = this.#create_buffer("records", size, GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC);
1715
+
1716
+ if (this.#records !== null) {
1717
+ const encoder = this.#device.createCommandEncoder({ label: "GPUMeshSurfaceCaches/records growth" });
1718
+
1719
+ encoder.copyBufferToBuffer(this.#records, 0, buffer, 0, this.#records.size);
1720
+ this.#device.queue.submit([encoder.finish()]);
1721
+
1722
+ this.#records.destroy();
1723
+ }
1724
+
1725
+ this.#records = buffer;
1726
+ this.#record_capacity = capacity;
1727
+ }
1728
+
1729
+ /**
1730
+ * @param {number} results
1731
+ */
1732
+ #ensure_survey_results(results) {
1733
+ if (this.#survey_results !== null && results <= this.#survey_result_capacity) {
1734
+ return;
1735
+ }
1736
+
1737
+ const capacity = doubled_capacity(results, this.#survey_result_capacity);
1738
+
1739
+ this.#survey_results?.destroy();
1740
+ this.#survey_results = this.#create_buffer("survey results", 4 * MESH_SURFACE_SURVEY_RESULT_WORDS * capacity, GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC);
1741
+ this.#survey_result_capacity = capacity;
1742
+ }
1743
+
1744
+ /**
1745
+ * @param {number} texels the most a frame may list: every texel of its runs
1746
+ */
1747
+ #ensure_texels(texels) {
1748
+ if (this.#texel_list !== null && this.#texel_capacity >= texels) {
1749
+ return;
1750
+ }
1751
+
1752
+ let capacity = Math.max(MESH_SDF_BRICK_TEXEL_COUNT, this.#texel_capacity);
1753
+
1754
+ while (capacity < texels) {
1755
+ capacity *= 2;
1756
+ }
1757
+
1758
+ // doubled no further than one binding holds; the need itself fits one, by the budget's check
1759
+ const binding = Math.floor(this.#device.limits.maxStorageBufferBindingSize / MESH_SURFACE_TEXEL_STRUCT.aligned_size);
1760
+
1761
+ capacity = Math.max(texels, Math.min(capacity, binding));
1762
+
1763
+ this.#texel_list?.destroy();
1764
+ this.#staging?.destroy();
1765
+ this.#texel_list = this.#create_buffer("texels", MESH_SURFACE_TEXEL_STRUCT.aligned_size * capacity, 0);
1766
+ this.#staging = this.#create_buffer("staging", 4 * MESH_SURFACE_STAGING_WORDS * capacity, 0);
1767
+ this.#texel_capacity = capacity;
1768
+ }
1769
+
1770
+ /**
1771
+ * @param {string} name
1772
+ * @param {number} size
1773
+ * @param {number} usage beside STORAGE
1774
+ * @returns {GPUBuffer}
1775
+ */
1776
+ #create_buffer(name, size, usage) {
1777
+ // bound whole, as storage
1778
+ assert.lessThanOrEqual(size, this.#device.limits.maxStorageBufferBindingSize, `${name} past maxStorageBufferBindingSize`);
1779
+
1780
+ return this.#device.createBuffer(BufferDescriptor.fromJSON({
1781
+ label: `GPUMeshSurfaceCaches/${name}`,
1782
+ size,
1783
+ usage: GPUBufferUsage.STORAGE | usage,
1784
+ }));
1785
+ }
1786
+
1787
+ /**
1788
+ * @returns {number} bytes
1789
+ */
1790
+ get gpu_memory_usage() {
1791
+ let bytes = 0;
1792
+
1793
+ for (const buffer of [this.#records, this.#data, this.#runs, this.#survey_runs, this.#number_runs, this.#survey_results, this.#texel_list, this.#staging, this.#counter, this.#command]) {
1794
+ if (buffer !== null) {
1795
+ bytes += buffer.size;
1796
+ }
1797
+ }
1798
+
1799
+ return bytes;
1800
+ }
1801
+
1802
+ destroy() {
1803
+ for (const buffer of [this.#records, this.#data, this.#runs, this.#survey_runs, this.#number_runs, this.#survey_results, this.#texel_list, this.#staging, this.#counter, this.#command]) {
1804
+ buffer?.destroy();
1805
+ }
1806
+
1807
+ this.#records = null;
1808
+ this.#data = null;
1809
+ this.#runs = null;
1810
+ this.#survey_runs = null;
1811
+ this.#number_runs = null;
1812
+ this.#survey_results = null;
1813
+ this.#texel_list = null;
1814
+ this.#staging = null;
1815
+ this.#counter = null;
1816
+ this.#command = null;
1817
+ this.#destroyed = true;
1818
+ }
1819
+ }