@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.
- package/CHANGELOG.md +111 -0
- package/package.json +1 -1
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/probe_clipmap/README.md +3 -4
- package/src/shade/playground/probe_clipmap/index.html +5 -13
- package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap/main.js +0 -5
- package/src/shade/playground/probe_clipmap_box/README.md +1 -1
- package/src/shade/playground/probe_clipmap_box/index.html +1 -1
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +50 -11
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/geometry/meshlet/meshlet_batch_colored.d.ts +10 -0
- package/src/shade/renderer/geometry/meshlet/meshlet_batch_colored.d.ts.map +1 -0
- package/src/shade/renderer/geometry/meshlet/meshlet_batch_colored.js +54 -0
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +85 -36
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +813 -412
- package/src/shade/renderer/geometry/sdf/MESH_SDF.d.ts +7 -0
- package/src/shade/renderer/geometry/sdf/MESH_SDF.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/MESH_SDF.js +8 -0
- package/src/shade/renderer/geometry/sdf/MESH_SDF_BRICK_KEY.d.ts +14 -0
- package/src/shade/renderer/geometry/sdf/MESH_SDF_BRICK_KEY.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/MESH_SDF_BRICK_KEY.js +35 -0
- package/src/shade/renderer/geometry/sdf/MESH_SDF_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/MESH_SDF_STRUCT.js +0 -4
- package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.d.ts +55 -10
- package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.js +86 -16
- package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.d.ts +2 -2
- package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.js +28 -2
- package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_contents.d.ts +54 -0
- package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_contents.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_contents.js +146 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.d.ts +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.js +2 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_content_rehash.d.ts +18 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_content_rehash.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_content_rehash.js +66 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_count.d.ts +17 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_count.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_count.js +66 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.d.ts +5 -3
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.js +15 -14
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.d.ts +2 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.js +12 -3
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_key.d.ts +21 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_key.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_key.js +84 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_resolve.d.ts +53 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_resolve.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_resolve.js +343 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.d.ts +3 -3
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.js +9 -5
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.d.ts +2 -2
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.js +3 -2
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_upload.d.ts +69 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_upload.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_upload.js +294 -0
- package/src/shade/renderer/geometry/sdf/bundle/MODEL_CACHE_BUNDLE.d.ts +16 -0
- package/src/shade/renderer/geometry/sdf/bundle/MODEL_CACHE_BUNDLE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bundle/MODEL_CACHE_BUNDLE.js +36 -0
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +126 -0
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +148 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_read.d.ts +10 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_read.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_read.js +140 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_write.d.ts +8 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_write.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_write.js +76 -0
- package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.d.ts +9 -0
- package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.js +23 -0
- package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_brick_key.d.ts +13 -0
- package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_brick_key.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_brick_key.js +23 -0
- package/src/shade/renderer/geometry/sdf/surface/GPUMeshSurfaceCaches.d.ts +262 -0
- package/src/shade/renderer/geometry/sdf/surface/GPUMeshSurfaceCaches.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/GPUMeshSurfaceCaches.js +1819 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BAKE.d.ts +118 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BAKE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BAKE.js +204 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BLOCK.d.ts +66 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BLOCK.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_BLOCK.js +103 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_RESOURCES.d.ts +19 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_RESOURCES.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_RESOURCES.js +23 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_STRUCT.d.ts +15 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/MESH_SURFACE_STRUCT.js +70 -0
- package/src/shade/renderer/geometry/sdf/surface/SURFACE_MATERIAL.d.ts +13 -0
- package/src/shade/renderer/geometry/sdf/surface/SURFACE_MATERIAL.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/SURFACE_MATERIAL.js +35 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_block.d.ts +32 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_block.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_block.js +111 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_listed.d.ts +17 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_listed.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_listed.js +49 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_run_find.d.ts +13 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_run_find.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_run_find.js +35 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_sample.d.ts +24 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_sample.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_sample.js +169 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_texel_ray.d.ts +19 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_texel_ray.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_mesh_surface_texel_ray.js +49 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_fit.d.ts +19 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_fit.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_fit.js +67 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_read.d.ts +78 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_read.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_read.js +320 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_store.d.ts +15 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_store.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/chunk_surface_material_store.js +48 -0
- package/src/shade/renderer/geometry/sdf/surface/mesh_surface_channels.d.ts +51 -0
- package/src/shade/renderer/geometry/sdf/surface/mesh_surface_channels.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/mesh_surface_channels.js +109 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_command.d.ts +11 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_command.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_command.js +51 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_encode.d.ts +26 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_encode.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_encode.js +453 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_list.d.ts +12 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_list.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_list.js +99 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_survey.d.ts +22 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_survey.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_survey.js +140 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.d.ts +32 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/surface/shader_mesh_surface_trace.js +261 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +2 -2
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +2 -2
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +6 -6
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +7 -7
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +15 -7
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +82 -17
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +26 -19
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +226 -148
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +25 -52
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +29 -69
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts +19 -16
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.js +24 -21
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +46 -22
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +49 -36
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts +3 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.js +7 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +8 -22
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +15 -51
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts +1 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.js +6 -13
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.js +0 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.d.ts +4 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.js +9 -34
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.d.ts +4 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.js +15 -39
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_clear.d.ts +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_clear.js +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.d.ts +1 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.js +2 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.d.ts +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.js +5 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/ProbeClipmapDebugView.d.ts +5 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/ProbeClipmapDebugView.js +16 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts +45 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +208 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_indirect.d.ts +24 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_indirect.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_indirect.js +40 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_surfaces.d.ts +34 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_surfaces.d.ts.map +1 -0
- 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
- package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts +61 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +193 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +67 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +142 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_cell.d.ts +32 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_cell.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_cell.js +70 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_store.d.ts +30 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_store.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material_store.js +71 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts +26 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +176 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +18 -9
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +63 -44
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +21 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +24 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_INDIRECT_LOBE.d.ts +10 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_INDIRECT_LOBE.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_INDIRECT_LOBE.js +11 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapIndirectLobe.d.ts +11 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapIndirectLobe.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapIndirectLobe.js +15 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +44 -7
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +88 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +43 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +138 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_indirect_lobe.d.ts +21 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_indirect_lobe.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_indirect_lobe.js +49 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts +2 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +10 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_select.d.ts +22 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_select.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_select.js +50 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +4 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +8 -8
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts +3 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.js +5 -5
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts +2 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.js +5 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts +7 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +30 -26
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +6 -5
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +22 -16
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +6 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.js +6 -6
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_generate_next_linear_congruential_index.d.ts +14 -0
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_generate_next_linear_congruential_index.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_generate_next_linear_congruential_index.js +22 -0
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_atomic.d.ts +37 -0
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_atomic.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_atomic.js +122 -0
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_get.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/hash_table/chunk_hash_table_get.js +1 -11
- package/src/shade/renderer/gpu_primitive/hash_table/cpu_build_hash_table.d.ts +8 -0
- package/src/shade/renderer/gpu_primitive/hash_table/cpu_build_hash_table.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/hash_table/cpu_build_hash_table.js +6 -4
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +1 -1
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +2 -18
- package/src/shade/renderer/material/resident/NEUTRAL_SURFACE.d.ts +17 -0
- package/src/shade/renderer/material/resident/NEUTRAL_SURFACE.d.ts.map +1 -0
- package/src/shade/renderer/material/resident/NEUTRAL_SURFACE.js +16 -0
- package/src/shade/renderer/path_tracer/shader/INDIRECT_TEXTURE_FILTER.d.ts +1 -1
- package/src/shade/renderer/path_tracer/shader/INDIRECT_TEXTURE_FILTER.js +1 -1
- package/src/shade/renderer/path_tracer/shader/IndirectTextureFilter.js +1 -1
- package/src/shade/renderer/path_tracer/shader/chunk_beam_texture_level.d.ts +20 -0
- package/src/shade/renderer/path_tracer/shader/chunk_beam_texture_level.d.ts.map +1 -0
- package/src/shade/renderer/path_tracer/shader/chunk_beam_texture_level.js +65 -0
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +1 -1
- package/src/shade/renderer/shader/chunk/material/albedo_compress.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/material/albedo_compress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/albedo_compress.js +26 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_compress.d.ts +16 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_compress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_compress.js +22 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_uncompress.d.ts +15 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_uncompress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_uncompress.js +23 -0
- package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_compress.d.ts +16 -0
- package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_compress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_compress.js +25 -0
- package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_uncompress.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_uncompress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/chunk_metal_rough_uncompress.js +36 -0
- package/src/shade/renderer/shader/chunk/material/metal_rough_compress.d.ts +11 -0
- package/src/shade/renderer/shader/chunk/material/metal_rough_compress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/metal_rough_compress.js +38 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot.d.ts +20 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot.js +35 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_compress.d.ts +28 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_compress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_compress.js +79 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_fit.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_fit.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_fit.js +89 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_uncompress.d.ts +31 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_uncompress.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/pivot/chunk_sh2_color_pivot_uncompress.js +66 -0
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_add.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_add.js +2 -0
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_load.d.ts +17 -0
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_load.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_load.js +34 -0
- package/src/shade/renderer/volumetrics/chunk_frustum_unit_box_coverage_multisample.d.ts +18 -0
- package/src/shade/renderer/volumetrics/chunk_frustum_unit_box_coverage_multisample.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/chunk_frustum_unit_box_coverage_multisample.js +31 -23
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +5 -6
- package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
- package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +0 -213
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +0 -1468
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.d.ts +0 -82
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.js +0 -127
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.d.ts +0 -24
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.js +0 -29
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.d.ts +0 -12
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.js +0 -31
- package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.d.ts +0 -11
- package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.js +0 -21
- package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.d.ts +0 -29
- package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.js +0 -179
- package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.d.ts +0 -17
- package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.js +0 -107
- package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.d.ts +0 -65
- package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.js +0 -376
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts +0 -40
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.js +0 -301
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.d.ts +0 -19
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.js +0 -61
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts +0 -18
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.js +0 -102
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.d.ts +0 -15
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.js +0 -65
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.d.ts +0 -22
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.js +0 -136
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.d.ts +0 -20
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.js +0 -104
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.d.ts +0 -20
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.js +0 -80
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.d.ts +0 -18
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.js +0 -113
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.d.ts +0 -30
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.js +0 -146
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_cards.d.ts +0 -34
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_cards.d.ts.map +0 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +0 -31
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +0 -1
- 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
|
+
}
|