@woosh/meep-engine 3.24.0 → 3.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +59 -0
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.js +285 -0
- package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
- package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
- package/src/engine/graphics3/PickingSystem.d.ts +3 -3
- package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
- package/src/engine/graphics3/PickingSystem.js +52 -55
- package/src/engine/graphics3/shader_picking_gather.d.ts +40 -0
- package/src/engine/graphics3/shader_picking_gather.d.ts.map +1 -0
- package/src/engine/graphics3/shader_picking_gather.js +120 -0
- package/src/engine/physics/cloth/MEASUREMENTS.md +1632 -0
- package/src/engine/physics/cloth/PLAN.md +738 -95
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
- package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts +52 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.js +70 -0
- package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts +12 -3
- package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothDynamics.js +340 -331
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +101 -29
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +110 -31
- package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts +84 -0
- package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.js +141 -0
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +71 -81
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +135 -856
- package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts +48 -0
- package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothWorkerCore.js +107 -0
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +323 -0
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothWorld.js +1248 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +192 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +578 -0
- package/src/engine/physics/cloth/ecs/cloth.worker.d.ts +2 -0
- package/src/engine/physics/cloth/ecs/cloth.worker.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth.worker.js +12 -0
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_build_rows.js +2 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +85 -3
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +366 -271
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +95 -12
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +170 -27
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
- package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts +29 -0
- package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_worker_protocol.js +78 -0
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
- package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts +17 -0
- package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/makeClothWorker.js +18 -0
- package/src/engine/physics/cloth/playground/README.md +73 -2
- package/src/engine/physics/cloth/playground/collide_main.js +1 -1
- package/src/engine/physics/cloth/playground/wind.html +166 -0
- package/src/engine/physics/cloth/playground/wind_build.d.ts +81 -0
- package/src/engine/physics/cloth/playground/wind_build.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/wind_build.js +141 -0
- package/src/engine/physics/cloth/playground/wind_main.d.ts +2 -0
- package/src/engine/physics/cloth/playground/wind_main.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/wind_main.js +681 -0
- package/src/engine/physics/cloth/solver/ClothState.d.ts +134 -79
- package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/ClothState.js +273 -12
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +45 -2
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.js +46 -2
- package/src/engine/physics/cloth/solver/cloth_step.d.ts +21 -2
- package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step.js +173 -4
- package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +40 -0
- package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_step_instance.js +284 -0
- package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts +107 -0
- package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_wind_accelerate.js +263 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
- package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +102 -0
- package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -0
- package/src/engine/physics/cloth/wind/AbstractClothWind.js +114 -0
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +87 -0
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -0
- package/src/engine/physics/cloth/wind/ClothAmbientWind.js +185 -0
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +79 -0
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -0
- package/src/engine/physics/cloth/wind/ClothFluidWind.js +213 -0
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +106 -0
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -0
- package/src/engine/physics/cloth/wind/cloth_sample_air.js +297 -0
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
- package/src/shade/device/mock/texture_copy.js +28 -0
- package/src/shade/playground/vgeo_runtime/README.md +94 -0
- package/src/shade/playground/vgeo_runtime/index.html +62 -0
- package/src/shade/playground/vgeo_runtime/main.d.ts +2 -0
- package/src/shade/playground/vgeo_runtime/main.d.ts.map +1 -0
- package/src/shade/playground/vgeo_runtime/main.js +399 -0
- package/src/shade/playground/vgeo_viewer/sample_asset.js +1 -1
- package/src/shade/renderer/camera/Camera.d.ts +14 -0
- package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
- package/src/shade/renderer/camera/Camera.js +7 -1
- package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.js +16 -1
- package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/GPUGeometryManager.js +29 -9
- package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts +10 -0
- package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts.map +1 -1
- package/src/shade/renderer/geometry/GPUGeometryMetadata.js +13 -0
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +46 -18
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +70 -22
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +97 -19
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +12 -2
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +14 -3
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts +2 -2
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +124 -6
- package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.js +53 -0
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +8 -1
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +8 -1
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts +16 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.js +15 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts +54 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.js +53 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +13 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +14 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +100 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +113 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.js +5 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +108 -0
- package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +23 -0
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +40 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +228 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +932 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +176 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +425 -0
- package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +241 -0
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +574 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +120 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +674 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +287 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +976 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +42 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +96 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.js +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +83 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +160 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +255 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +80 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +144 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +530 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +39 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +54 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts +41 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.js +56 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts +49 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +328 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +10 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +51 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +12 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +99 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +7 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +27 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts +7 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.js +35 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.js +14 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +7 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +36 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +10 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts +11 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.js +54 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts +11 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.js +10 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts +7 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.js +30 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.js +12 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +11 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +61 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.js +12 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.js +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts +23 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +70 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +25 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +35 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +41 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +32 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +138 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +9 -0
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +12 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +12 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +10 -0
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +18 -0
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +647 -594
- package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
- package/src/shade/renderer/scene/rows/GPUSceneRows.js +22 -0
- package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts +35 -0
- package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.js +91 -0
- package/src/engine/graphics3/instantiate_scene_bundle.d.ts +0 -54
- package/src/engine/graphics3/instantiate_scene_bundle.d.ts.map +0 -1
- package/src/engine/graphics3/shade_node_to_entity_composition.d.ts +0 -39
- package/src/engine/graphics3/shade_node_to_entity_composition.d.ts.map +0 -1
- package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts +0 -35
- package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts.map +0 -1
- package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts +0 -96
- package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts.map +0 -1
- package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts +0 -20
- package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts.map +0 -1
- package/src/shade/renderer/animation/skin_bind_transform.d.ts +0 -25
- package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +0 -1
- package/src/shade/renderer/animation/skin_frame_defect.d.ts +0 -34
- package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +0 -1
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts +0 -24
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +0 -1
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +0 -70
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +0 -1
- package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts +0 -96
- package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts.map +0 -1
- package/src/shade/renderer/scene/InstanceBatch.d.ts +0 -92
- package/src/shade/renderer/scene/InstanceBatch.d.ts.map +0 -1
- package/src/shade/renderer/scene/Mesh.d.ts +0 -55
- package/src/shade/renderer/scene/Mesh.d.ts.map +0 -1
- package/src/shade/renderer/scene/Node3D.d.ts +0 -159
- package/src/shade/renderer/scene/Node3D.d.ts.map +0 -1
- package/src/shade/renderer/scene/Node3DDirtyList.d.ts +0 -59
- package/src/shade/renderer/scene/Node3DDirtyList.d.ts.map +0 -1
- package/src/shade/renderer/scene/SceneNodeBinding.d.ts +0 -52
- package/src/shade/renderer/scene/SceneNodeBinding.d.ts.map +0 -1
- package/src/shade/renderer/scene/SkinnedMesh.d.ts +0 -27
- package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +0 -1
- package/src/shade/renderer/scene/TransformAuthority.d.ts +0 -19
- package/src/shade/renderer/scene/TransformAuthority.d.ts.map +0 -1
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import { atomic_u32, u32 } from "../../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
|
+
import { WebGPUArray } from "../../../../shader/type/WebGPUArray.js";
|
|
3
|
+
import { CodeChunk } from "../../../../shader/compiler/CodeChunk.js";
|
|
4
|
+
import { ComputeShader } from "../../../../shader/ComputeShader.js";
|
|
5
|
+
import { ShaderResourceSetDescriptor } from "../../../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
6
|
+
import { COLLECTION_U32_STRUCT_READ } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
|
|
7
|
+
import { COLLECTION_U32_STRUCT_WRITE } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_WRITE.js";
|
|
8
|
+
import { MESHLET_COLLECTION_WRITE_STRUCT } from "../../../../rasterize/MESHLET_COLLECTION_WRITE_STRUCT.js";
|
|
9
|
+
import { MESHLET_DEFINITION_STRUCT } from "../../../meshlet/encoding/MESHLET_DEFINITION_STRUCT.js";
|
|
10
|
+
import { VGEO_CLUSTER_ROW_OFFSET } from "../layout/VGEO_CLUSTER_ROW_OFFSET.js";
|
|
11
|
+
import { VGEO_CUT_STAT } from "../layout/VGEO_CUT_STAT.js";
|
|
12
|
+
import { VGEO_FEEDBACK_OFFSET } from "../layout/VGEO_FEEDBACK_OFFSET.js";
|
|
13
|
+
import { VGEO_GROUP_FLAG_SELECTABLE } from "../layout/VGEO_GROUP_FLAG_SELECTABLE.js";
|
|
14
|
+
import { VGEO_GROUP_ROW_OFFSET } from "../layout/VGEO_GROUP_ROW_OFFSET.js";
|
|
15
|
+
import { VGEO_INSTANCE_OFFSET } from "../layout/VGEO_INSTANCE_OFFSET.js";
|
|
16
|
+
import { VGEO_NODE_ROW_OFFSET } from "../layout/VGEO_NODE_ROW_OFFSET.js";
|
|
17
|
+
import { VGEO_NO_CHILD_PAGE } from "../layout/VGEO_NO_CHILD_PAGE.js";
|
|
18
|
+
import { VGEO_PAGE_ROW_NONE } from "../layout/VGEO_PAGE_ROW_NONE.js";
|
|
19
|
+
import { VGEO_PAGE_ROW_OFFSET } from "../layout/VGEO_PAGE_ROW_OFFSET.js";
|
|
20
|
+
import { VGEO_QUEUE_TARGET_GROUP_BIT } from "../layout/VGEO_QUEUE_TARGET_GROUP_BIT.js";
|
|
21
|
+
import { VGEO_WANT_WORDS } from "../layout/VGEO_WANT_WORDS.js";
|
|
22
|
+
import { chunk_vgeo_cut_access } from "./chunk_vgeo_cut_access.js";
|
|
23
|
+
import { VGEO_CUT_FLAG_CULL } from "./VGEO_CUT_FLAG_CULL.js";
|
|
24
|
+
import { VGEO_CUT_PARAMS_STRUCT } from "./VGEO_CUT_PARAMS_STRUCT.js";
|
|
25
|
+
import { VGEO_CUT_WORKGROUP_SIZE } from "./VGEO_CUT_WORKGROUP_SIZE.js";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* One wavefront of the virtual-geometry cut — the pass design §7 calls for, and the reason every
|
|
29
|
+
* structure under it exists.
|
|
30
|
+
*
|
|
31
|
+
* ## The rule
|
|
32
|
+
*
|
|
33
|
+
* A cluster is drawn iff
|
|
34
|
+
*
|
|
35
|
+
* > `own group selectable AND project(parent) > tau AND (project(self) <= tau OR child group not
|
|
36
|
+
* > selectable)`
|
|
37
|
+
*
|
|
38
|
+
* which is design §4's per-cluster form **plus its first term**. That term is not decoration, and
|
|
39
|
+
* omitting it — as §4's own wording does, because §4 was written for a traversal that gets it for
|
|
40
|
+
* free — double-draws: a group that is resident but not yet selectable has clusters satisfying the
|
|
41
|
+
* rest of the rule while their coarse stand-in is drawn over the same surface, a few microns apart,
|
|
42
|
+
* with the depth buffer choosing between them. That reads as corrupt geometry rather than as a
|
|
43
|
+
* missing page, which is what makes it hard to attribute and worth stating first.
|
|
44
|
+
*
|
|
45
|
+
* ## The shape
|
|
46
|
+
*
|
|
47
|
+
* A wavefront BFS, ping-ponged through two queues, one lane per item. Not persistent threads over
|
|
48
|
+
* an MPMC queue: WebGPU guarantees no forward progress across workgroups, so a consumer waiting on
|
|
49
|
+
* a producer in another workgroup is waiting without a bound.
|
|
50
|
+
*
|
|
51
|
+
* An item is a **node visit** or a **group-chunk visit**, distinguished by one bit of `target`. A
|
|
52
|
+
* node tests its metric and either enqueues its children or, being a leaf, enqueues bounded chunks
|
|
53
|
+
* of its groups' clusters. Chunks exist because a node leaf covers up to four groups of up to 4096
|
|
54
|
+
* clusters each (format §11.5) — legal input, and 16,384 iterations in the lane that popped it if
|
|
55
|
+
* the leaf walked them itself.
|
|
56
|
+
*
|
|
57
|
+
* Descent crosses a page boundary by enqueueing the child page's **node 0**: uniform items, one
|
|
58
|
+
* kernel, no special case for "entering a page". `SAME_PAGE` needs no special case either, because
|
|
59
|
+
* the CPU resolved it to this page's own index at install, so it looks up a page that is trivially
|
|
60
|
+
* resident and falls through to the only question it was really asking — is that group selectable.
|
|
61
|
+
*
|
|
62
|
+
* ## Why page-granular dedup is enough, and why it is necessary
|
|
63
|
+
*
|
|
64
|
+
* The page DAG is many-parented — 82 of 91 pages of a measured 98k sphere have more than one parent
|
|
65
|
+
* — so an undeduped descent would visit a page once per parent and draw its whole cut that many
|
|
66
|
+
* times. The claim is one bit per (instance, resident page), which is affordable. Cluster-granular
|
|
67
|
+
* dedup is what this avoids: the resident cluster count is exactly the number design §4 is trying
|
|
68
|
+
* not to pay per frame.
|
|
69
|
+
*
|
|
70
|
+
* Visiting a cluster the descent "should not" have reached costs only the test, because the
|
|
71
|
+
* predicate is a pure function of the row and gives the same answer from every direction. Missing
|
|
72
|
+
* one costs a hole. That asymmetry is the whole design:
|
|
73
|
+
*
|
|
74
|
+
* - **No cluster is drawn twice.** It is evaluated once per page visit, and the claim makes that at
|
|
75
|
+
* most once per instance.
|
|
76
|
+
* - **No cluster the flat rule would draw is missed.** If `project(C.parent) > tau`, then any
|
|
77
|
+
* parent cluster `P` of `C`'s group has `project(P.self) = project(C.parent) > tau` — every
|
|
78
|
+
* cluster of a group shares the consuming step's sphere and error — and monotonicity gives
|
|
79
|
+
* `project(P.parent) >= project(P.self)`, so `P` satisfies the predicate's first half and by
|
|
80
|
+
* induction its page is visited. `P` fails `project(self) <= tau`, so it either enqueues `C`'s
|
|
81
|
+
* page or clamps, and it clamps only when `C`'s group is not selectable, in which case `C` must
|
|
82
|
+
* not be drawn. Neither cull intervenes: a node's sphere contains `P.parent_sphere` and its
|
|
83
|
+
* `max_parent_error` is at least `P.parent_error`, so the LOD cull cannot fire, and the frustum
|
|
84
|
+
* cull fires only where `C` is off-screen anyway.
|
|
85
|
+
*
|
|
86
|
+
* ## Bounds
|
|
87
|
+
*
|
|
88
|
+
* Every append is checked and every overflow is counted, and they all degrade in one direction —
|
|
89
|
+
* coarser or missing, never doubled. The exception worth knowing is `QUEUE_DROPPED`: a dropped item
|
|
90
|
+
* is a subtree never descended, and the parent that would have stood in over it was not drawn
|
|
91
|
+
* either, so that one is a hole.
|
|
92
|
+
*
|
|
93
|
+
* ## Bindings
|
|
94
|
+
*
|
|
95
|
+
* Eight storage buffers against the engine's floor of ten (RUNTIME_PLAN §4.9), and the page table
|
|
96
|
+
* is not one of them: a page's header is the first words of its own arena slot, so `vg_page_field`
|
|
97
|
+
* is an offset into a buffer this kernel already binds rather than a second buffer to bind and keep
|
|
98
|
+
* coherent.
|
|
99
|
+
*
|
|
100
|
+
* @author Alex Goldring
|
|
101
|
+
* @copyright Company Named Limited (c) 2026
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
105
|
+
|
|
106
|
+
resources.createGroup()
|
|
107
|
+
.addUniform("params", VGEO_CUT_PARAMS_STRUCT)
|
|
108
|
+
// per geometry, `total_pages` words: container page index -> page row, or VGEO_PAGE_ROW_NONE
|
|
109
|
+
.addStorageBuffer("vg_lookup", WebGPUArray.from(u32), false)
|
|
110
|
+
// one fixed-stride slot per VRAM-resident page:
|
|
111
|
+
// [page header][node rows][group rows][cluster rows]
|
|
112
|
+
.addStorageBuffer("vg_arena", WebGPUArray.from(u32), false)
|
|
113
|
+
;
|
|
114
|
+
|
|
115
|
+
resources.createGroup()
|
|
116
|
+
.addStorageBuffer("instances", WebGPUArray.from(u32), false)
|
|
117
|
+
.addStorageBuffer("queue_in", COLLECTION_U32_STRUCT_READ, false)
|
|
118
|
+
.addStorageBuffer("queue_out", COLLECTION_U32_STRUCT_WRITE, true)
|
|
119
|
+
;
|
|
120
|
+
|
|
121
|
+
resources.createGroup()
|
|
122
|
+
// one bit per (instance, page ordinal); cleared per invocation because each expansion site
|
|
123
|
+
// sees a different instance set
|
|
124
|
+
.addStorageBuffer("claim", WebGPUArray.from(atomic_u32), true)
|
|
125
|
+
// header, stats, touch and want stamps, then the two lists — one per frame, shared by every
|
|
126
|
+
// view and bucket, which is what dedups a touch across them
|
|
127
|
+
.addStorageBuffer("feedback", WebGPUArray.from(atomic_u32), true)
|
|
128
|
+
// the same collection the static mesh expansion appends to, read downstream by the HZB meshlet
|
|
129
|
+
// filter and the indirect draw with no knowledge that virtual geometry exists
|
|
130
|
+
.addStorageBuffer("out_meshlets", MESHLET_COLLECTION_WRITE_STRUCT, true)
|
|
131
|
+
;
|
|
132
|
+
|
|
133
|
+
const body = CodeChunk.from(
|
|
134
|
+
//language=WGSL
|
|
135
|
+
`
|
|
136
|
+
const VG_QUEUE_GROUP_BIT = ${VGEO_QUEUE_TARGET_GROUP_BIT}u;
|
|
137
|
+
const VG_PAGE_ROW_NONE = ${VGEO_PAGE_ROW_NONE}u;
|
|
138
|
+
const VG_NO_CHILD_PAGE = ${VGEO_NO_CHILD_PAGE}u;
|
|
139
|
+
const VG_GROUP_SELECTABLE = ${VGEO_GROUP_FLAG_SELECTABLE}u;
|
|
140
|
+
const VG_WANT_WORDS = ${VGEO_WANT_WORDS}u;
|
|
141
|
+
|
|
142
|
+
fn vg_stat(slot: u32, amount: u32) {
|
|
143
|
+
atomicAdd(&feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + slot], amount);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Reserve count slots of the next wavefront.
|
|
148
|
+
*
|
|
149
|
+
* The count is allowed to run past capacity — the prepare pass clamps it before it becomes a
|
|
150
|
+
* dispatch — so every write against the returned base is bounds-checked here as well.
|
|
151
|
+
*/
|
|
152
|
+
fn vg_queue_reserve(count: u32) -> u32 {
|
|
153
|
+
return atomicAdd(&queue_out.count, count);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
fn vg_queue_write(slot: u32, instance_slot: u32, page_row: u32, visit: u32, first_cluster: u32) {
|
|
157
|
+
if (slot >= params.queue_capacity) {
|
|
158
|
+
vg_stat(${VGEO_CUT_STAT.QUEUE_DROPPED}u, 1u);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let base = slot * 4u;
|
|
163
|
+
|
|
164
|
+
queue_out.elements[base] = instance_slot;
|
|
165
|
+
queue_out.elements[base + 1u] = page_row;
|
|
166
|
+
queue_out.elements[base + 2u] = visit;
|
|
167
|
+
queue_out.elements[base + 3u] = first_cluster;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Claim a page for one instance, and touch it if the claim was won.
|
|
172
|
+
*
|
|
173
|
+
* The claim is what makes "at most one draw record per (instance, cluster)" true, so an instance
|
|
174
|
+
* whose slice of the bitmask does not fit is refused upstream rather than run unclaimed.
|
|
175
|
+
*/
|
|
176
|
+
fn vg_claim_page(instance_base: u32, page_row: u32) -> bool {
|
|
177
|
+
let ordinal = vg_page_field(page_row, ${VGEO_PAGE_ROW_OFFSET.ORDINAL}u);
|
|
178
|
+
|
|
179
|
+
if (ordinal >= instances[instance_base + ${VGEO_INSTANCE_OFFSET.ORDINAL_CAPACITY}u]) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
let bit = instances[instance_base + ${VGEO_INSTANCE_OFFSET.CLAIM_BASE}u] + ordinal;
|
|
184
|
+
|
|
185
|
+
let word = bit >> 5u;
|
|
186
|
+
|
|
187
|
+
if (word >= params.claim_word_count) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let mask = 1u << (bit & 31u);
|
|
192
|
+
|
|
193
|
+
if ((atomicOr(&claim[word], mask) & mask) != 0u) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
vg_stat(${VGEO_CUT_STAT.PAGES}u, 1u);
|
|
198
|
+
|
|
199
|
+
vg_touch_page(page_row);
|
|
200
|
+
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Record that this page was selected from this frame — design §6's eviction key.
|
|
206
|
+
*
|
|
207
|
+
* LRU on last-*touched*, never on last-wanted: stamping at fetch time freezes the stamp of exactly
|
|
208
|
+
* the pages that are on screen and evicts them, which is the classic fallback-chain bug the virtual
|
|
209
|
+
* texture cache already keys on touch to avoid.
|
|
210
|
+
*
|
|
211
|
+
* Deduped across every view and bucket of the frame by one stamp word per page row, because the
|
|
212
|
+
* feedback buffer is per frame rather than per invocation.
|
|
213
|
+
*/
|
|
214
|
+
fn vg_touch_page(page_row: u32) {
|
|
215
|
+
if (atomicExchange(&feedback[params.touch_stamp_base + page_row], 1u) != 0u) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
let slot = atomicAdd(&feedback[${VGEO_FEEDBACK_OFFSET.TOUCH_COUNT}u], 1u);
|
|
220
|
+
|
|
221
|
+
if (slot >= params.touch_capacity) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
atomicStore(&feedback[params.touch_base + slot], page_row);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Ask for the page a clamped cluster could not reach.
|
|
230
|
+
*
|
|
231
|
+
* Deduped on the child page, so a hundred clusters clamped against one page produce one request.
|
|
232
|
+
* The record names the page the want was discovered **through** as well as the page wanted: the
|
|
233
|
+
* source page's child table holds the exact byte range at child_ref, so the fetch costs one
|
|
234
|
+
* round trip and no metadata request, and it is also the page format §10 asks to be pinned while
|
|
235
|
+
* the child is in flight — which nothing but the cut can name, since the format stores parent counts
|
|
236
|
+
* rather than parent references.
|
|
237
|
+
*
|
|
238
|
+
* Priority is the first writer's projected error rather than the maximum over all of them. Taking a
|
|
239
|
+
* true maximum needs the record's slot, and a later writer cannot read that slot without waiting
|
|
240
|
+
* for the first writer to publish it. It is pixels of error either way, comparable across assets,
|
|
241
|
+
* and VGeoResidencyManager maxes across frames.
|
|
242
|
+
*/
|
|
243
|
+
fn vg_want(source_page_row: u32, child_ref: u32, child_page_index: u32, lookup_base: u32, projected: f32) {
|
|
244
|
+
let stamp = params.want_stamp_base + lookup_base + child_page_index;
|
|
245
|
+
|
|
246
|
+
if (atomicExchange(&feedback[stamp], 1u) != 0u) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let slot = atomicAdd(&feedback[${VGEO_FEEDBACK_OFFSET.WANT_COUNT}u], 1u);
|
|
251
|
+
|
|
252
|
+
if (slot >= params.want_capacity) {
|
|
253
|
+
vg_stat(${VGEO_CUT_STAT.WANTS_DROPPED}u, 1u);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let base = params.want_base + slot * VG_WANT_WORDS;
|
|
258
|
+
|
|
259
|
+
atomicStore(&feedback[base], source_page_row);
|
|
260
|
+
atomicStore(&feedback[base + 1u], child_ref);
|
|
261
|
+
atomicStore(&feedback[base + 2u], child_page_index);
|
|
262
|
+
atomicStore(&feedback[base + 3u], bitcast<u32>(projected));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Emit one draw record — the existing record type, into the existing collection.
|
|
267
|
+
*
|
|
268
|
+
* meshlet_base + local cluster is a row of the meshlet **metadata** pool, which is where a page
|
|
269
|
+
* install put this page's synthesized rows. Downstream reads meshlet_metadata[meshlet.index]
|
|
270
|
+
* exactly as it does for a static mesh, which is the whole of what makes the seam one call.
|
|
271
|
+
*/
|
|
272
|
+
fn vg_draw(page_row: u32, cluster: u32, mesh_index: u32) {
|
|
273
|
+
let slot = atomicAdd(&out_meshlets.count, 1u);
|
|
274
|
+
|
|
275
|
+
if (slot >= params.meshlet_capacity) {
|
|
276
|
+
vg_stat(${VGEO_CUT_STAT.MESHLETS_DROPPED}u, 1u);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let meshlet = vg_page_field(page_row, ${VGEO_PAGE_ROW_OFFSET.MESHLET_BASE}u) + cluster;
|
|
281
|
+
|
|
282
|
+
out_meshlets.elements[slot] = ${MESHLET_DEFINITION_STRUCT.wgsl_ref}(meshlet, mesh_index);
|
|
283
|
+
|
|
284
|
+
vg_stat(${VGEO_CUT_STAT.DRAWN}u, 1u);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
fn vg_group_selectable(page_row: u32, group: u32) -> bool {
|
|
288
|
+
let row = vg_group_base(page_row) + group * VG_GROUP_ROW_WORDS;
|
|
289
|
+
|
|
290
|
+
return (vg_arena[row + ${VGEO_GROUP_ROW_OFFSET.FLAGS}u] & VG_GROUP_SELECTABLE) != 0u;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* A node: cull, then descend or hand off.
|
|
295
|
+
*/
|
|
296
|
+
fn vg_visit_node(instance_slot: u32, instance_base: u32, page_row: u32, node: u32) {
|
|
297
|
+
let row = vg_node_base(page_row) + node * VG_NODE_ROW_WORDS;
|
|
298
|
+
|
|
299
|
+
let sphere = vg_sphere_at(row + ${VGEO_NODE_ROW_OFFSET.SPHERE}u);
|
|
300
|
+
|
|
301
|
+
if ((params.flags & ${VGEO_CUT_FLAG_CULL}u) != 0u
|
|
302
|
+
&& vg_sphere_outside_frustum(instance_base, sphere)) {
|
|
303
|
+
vg_stat(${VGEO_CUT_STAT.CULLED_FRUSTUM}u, 1u);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
let eye = vg_instance_eye(instance_base);
|
|
308
|
+
let k = vg_instance_f32(instance_base, ${VGEO_INSTANCE_OFFSET.PROJECTION_K}u);
|
|
309
|
+
|
|
310
|
+
/*
|
|
311
|
+
Format §6.2's load-bearing field. A cluster draws only while project(parent) > tau, so if the
|
|
312
|
+
*largest* parent error under this node still projects to no more than tau, nothing under it can
|
|
313
|
+
be drawn and the whole subtree goes. The node's sphere is the union of the covered clusters'
|
|
314
|
+
parent spheres, so the projection is conservative in both terms.
|
|
315
|
+
*/
|
|
316
|
+
if (vg_project(vg_arena_f32(row + ${VGEO_NODE_ROW_OFFSET.MAX_PARENT_ERROR}u), sphere, eye, k)
|
|
317
|
+
<= params.tau) {
|
|
318
|
+
vg_stat(${VGEO_CUT_STAT.CULLED_LOD}u, 1u);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let child_first = vg_arena[row + ${VGEO_NODE_ROW_OFFSET.CHILD_FIRST}u];
|
|
323
|
+
let child_word = vg_arena[row + ${VGEO_NODE_ROW_OFFSET.CHILD_COUNT_AND_FLAGS}u];
|
|
324
|
+
|
|
325
|
+
let child_count = child_word & VG_NODE_CHILD_COUNT_MASK;
|
|
326
|
+
|
|
327
|
+
if ((child_word & VG_NODE_LEAF_BIT) == 0u) {
|
|
328
|
+
let slot = vg_queue_reserve(child_count);
|
|
329
|
+
|
|
330
|
+
for (var i = 0u; i < child_count; i = i + 1u) {
|
|
331
|
+
vg_queue_write(slot + i, instance_slot, page_row, child_first + i, 0u);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// A leaf's children are groups. Hand them off in bounded chunks rather than walking them here:
|
|
338
|
+
// four groups of four thousand clusters is legal input and would be one lane's whole life.
|
|
339
|
+
let group_base = vg_group_base(page_row);
|
|
340
|
+
|
|
341
|
+
var total = 0u;
|
|
342
|
+
|
|
343
|
+
for (var i = 0u; i < child_count; i = i + 1u) {
|
|
344
|
+
let members = vg_arena[
|
|
345
|
+
group_base + (child_first + i) * VG_GROUP_ROW_WORDS
|
|
346
|
+
+ ${VGEO_GROUP_ROW_OFFSET.CLUSTER_COUNT}u
|
|
347
|
+
];
|
|
348
|
+
|
|
349
|
+
total = total + (members + params.cluster_chunk - 1u) / params.cluster_chunk;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
var slot = vg_queue_reserve(total);
|
|
353
|
+
|
|
354
|
+
for (var i = 0u; i < child_count; i = i + 1u) {
|
|
355
|
+
let group = child_first + i;
|
|
356
|
+
|
|
357
|
+
let members = vg_arena[
|
|
358
|
+
group_base + group * VG_GROUP_ROW_WORDS + ${VGEO_GROUP_ROW_OFFSET.CLUSTER_COUNT}u
|
|
359
|
+
];
|
|
360
|
+
|
|
361
|
+
var first = 0u;
|
|
362
|
+
|
|
363
|
+
while (first < members) {
|
|
364
|
+
vg_queue_write(slot, instance_slot, page_row, group | VG_QUEUE_GROUP_BIT, first);
|
|
365
|
+
|
|
366
|
+
slot = slot + 1u;
|
|
367
|
+
first = first + params.cluster_chunk;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* A run of one group's clusters: the rule, cluster by cluster.
|
|
374
|
+
*/
|
|
375
|
+
fn vg_visit_group(
|
|
376
|
+
instance_slot: u32,
|
|
377
|
+
instance_base: u32,
|
|
378
|
+
page_row: u32,
|
|
379
|
+
group: u32,
|
|
380
|
+
first_cluster: u32
|
|
381
|
+
) {
|
|
382
|
+
/*
|
|
383
|
+
The own-group term. A group that is resident but not selectable draws nothing at all — its
|
|
384
|
+
coarser selectable ancestors are already covering that surface, and drawing both is the
|
|
385
|
+
double-draw this whole runtime is arranged to avoid.
|
|
386
|
+
*/
|
|
387
|
+
if (!vg_group_selectable(page_row, group)) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
let group_row = vg_group_base(page_row) + group * VG_GROUP_ROW_WORDS;
|
|
392
|
+
|
|
393
|
+
let members = vg_arena[group_row + ${VGEO_GROUP_ROW_OFFSET.CLUSTER_COUNT}u];
|
|
394
|
+
let cluster_first = vg_arena[group_row + ${VGEO_GROUP_ROW_OFFSET.CLUSTER_FIRST}u];
|
|
395
|
+
|
|
396
|
+
let last = min(first_cluster + params.cluster_chunk, members);
|
|
397
|
+
|
|
398
|
+
let cluster_base = vg_cluster_base(page_row);
|
|
399
|
+
|
|
400
|
+
let eye = vg_instance_eye(instance_base);
|
|
401
|
+
let k = vg_instance_f32(instance_base, ${VGEO_INSTANCE_OFFSET.PROJECTION_K}u);
|
|
402
|
+
let mesh_index = instances[instance_base + ${VGEO_INSTANCE_OFFSET.MESH_INDEX}u];
|
|
403
|
+
let lookup_base = instances[instance_base + ${VGEO_INSTANCE_OFFSET.LOOKUP_WORD_OFFSET}u];
|
|
404
|
+
|
|
405
|
+
for (var i = first_cluster; i < last; i = i + 1u) {
|
|
406
|
+
let cluster = cluster_first + i;
|
|
407
|
+
|
|
408
|
+
let row = cluster_base + cluster * VG_CLUSTER_ROW_WORDS;
|
|
409
|
+
|
|
410
|
+
vg_stat(${VGEO_CUT_STAT.CLUSTERS_TESTED}u, 1u);
|
|
411
|
+
|
|
412
|
+
let parent_projected = vg_project(
|
|
413
|
+
vg_arena_f32(row + ${VGEO_CLUSTER_ROW_OFFSET.PARENT_ERROR}u),
|
|
414
|
+
vg_sphere_at(row + ${VGEO_CLUSTER_ROW_OFFSET.PARENT_SPHERE}u),
|
|
415
|
+
eye, k
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
if (parent_projected <= params.tau) {
|
|
419
|
+
// something coarser is covering this surface; this cluster is below the cut
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let self_projected = vg_project(
|
|
424
|
+
vg_arena_f32(row + ${VGEO_CLUSTER_ROW_OFFSET.SELF_ERROR}u),
|
|
425
|
+
vg_sphere_at(row + ${VGEO_CLUSTER_ROW_OFFSET.SELF_SPHERE}u),
|
|
426
|
+
eye, k
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
let child_page_index = vg_arena[row + ${VGEO_CLUSTER_ROW_OFFSET.CHILD_PAGE_INDEX}u];
|
|
430
|
+
|
|
431
|
+
if (self_projected <= params.tau || child_page_index == VG_NO_CHILD_PAGE) {
|
|
432
|
+
vg_draw(page_row, cluster, mesh_index);
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
let child_page_row = vg_lookup[lookup_base + child_page_index];
|
|
437
|
+
|
|
438
|
+
if (child_page_row == VG_PAGE_ROW_NONE) {
|
|
439
|
+
/*
|
|
440
|
+
The clamp. Drawing this cluster is not a fallback for a missing one — it is the correct
|
|
441
|
+
coarser surface over exactly the region the missing page would have refined, which is
|
|
442
|
+
what makes an arriving cut watertight at every moment rather than only at the end.
|
|
443
|
+
*/
|
|
444
|
+
vg_draw(page_row, cluster, mesh_index);
|
|
445
|
+
|
|
446
|
+
vg_stat(${VGEO_CUT_STAT.CLAMPED}u, 1u);
|
|
447
|
+
|
|
448
|
+
vg_want(
|
|
449
|
+
page_row,
|
|
450
|
+
vg_arena[row + ${VGEO_CLUSTER_ROW_OFFSET.CHILD_REF}u],
|
|
451
|
+
child_page_index,
|
|
452
|
+
lookup_base,
|
|
453
|
+
self_projected
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
let child_group = vg_arena[row + ${VGEO_CLUSTER_ROW_OFFSET.CHILD_GROUP}u];
|
|
460
|
+
|
|
461
|
+
if (!vg_group_selectable(child_page_row, child_group)) {
|
|
462
|
+
/*
|
|
463
|
+
The bytes are here and the group is still waiting on a page holding one of its *other*
|
|
464
|
+
parents, so there is nothing to fetch from this cluster. Another cluster in this same
|
|
465
|
+
cut is clamped directly against that page and wants it — monotonicity puts every
|
|
466
|
+
ancestor of a cluster projecting above tau above tau as well.
|
|
467
|
+
*/
|
|
468
|
+
vg_draw(page_row, cluster, mesh_index);
|
|
469
|
+
|
|
470
|
+
vg_stat(${VGEO_CUT_STAT.CLAMPED}u, 1u);
|
|
471
|
+
vg_stat(${VGEO_CUT_STAT.CLAMPED_ON_ACTIVATION}u, 1u);
|
|
472
|
+
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (vg_claim_page(instance_base, child_page_row)) {
|
|
477
|
+
let slot = vg_queue_reserve(1u);
|
|
478
|
+
|
|
479
|
+
vg_queue_write(slot, instance_slot, child_page_row, 0u, 0u);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
@compute @workgroup_size(${VGEO_CUT_WORKGROUP_SIZE})
|
|
485
|
+
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
|
|
486
|
+
let item = global_id.x;
|
|
487
|
+
|
|
488
|
+
if (item == 0u && queue_in.count > 0u) {
|
|
489
|
+
/*
|
|
490
|
+
One per wavefront that actually ran. The descent is a fixed number of indirect dispatches
|
|
491
|
+
of zero workgroups once the work runs out, so this is the only way to know how deep it
|
|
492
|
+
went — and reaching the iteration budget is what turns RUNTIME_PLAN §4.7's measured depth
|
|
493
|
+
of about 48 from a fact into an assumption.
|
|
494
|
+
*/
|
|
495
|
+
vg_stat(${VGEO_CUT_STAT.WAVEFRONTS}u, 1u);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (item >= queue_in.count) {
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
let base = item * 4u;
|
|
503
|
+
|
|
504
|
+
let instance_slot = queue_in.elements[base];
|
|
505
|
+
let page_row = queue_in.elements[base + 1u];
|
|
506
|
+
let visit = queue_in.elements[base + 2u];
|
|
507
|
+
let first_cluster = queue_in.elements[base + 3u];
|
|
508
|
+
|
|
509
|
+
vg_stat(${VGEO_CUT_STAT.ITEMS}u, 1u);
|
|
510
|
+
|
|
511
|
+
let instance_base = instance_slot * VG_INSTANCE_WORDS;
|
|
512
|
+
|
|
513
|
+
if ((visit & VG_QUEUE_GROUP_BIT) != 0u) {
|
|
514
|
+
vg_visit_group(
|
|
515
|
+
instance_slot, instance_base, page_row, visit & ~VG_QUEUE_GROUP_BIT, first_cluster
|
|
516
|
+
);
|
|
517
|
+
} else {
|
|
518
|
+
vg_visit_node(instance_slot, instance_base, page_row, visit);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
`, [
|
|
522
|
+
chunk_vgeo_cut_access,
|
|
523
|
+
MESHLET_DEFINITION_STRUCT.declaration_chunk,
|
|
524
|
+
]);
|
|
525
|
+
|
|
526
|
+
export const shader_vgeo_cut_traverse = ComputeShader.from({
|
|
527
|
+
label: "VGeo cut traverse",
|
|
528
|
+
body,
|
|
529
|
+
resources,
|
|
530
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where each region of the feedback buffer starts, for one frame's worth of cutting.
|
|
3
|
+
*
|
|
4
|
+
* One function rather than two agreeing conventions: the pass that creates the buffer and the
|
|
5
|
+
* params block that tells the kernel where to write both come from here, and so does anything that
|
|
6
|
+
* reads it back. A layout computed twice is a layout that drifts, and the way it drifts is a want
|
|
7
|
+
* list written over a stamp region, which reads as wants that never resolve.
|
|
8
|
+
*
|
|
9
|
+
* The stamps are the reason the buffer is per **frame** rather than per invocation: a page touched
|
|
10
|
+
* from two buckets is one touch, and a page wanted by two views is one want. Being cleared exactly
|
|
11
|
+
* once, at creation, is what makes a plain flag enough and saves carrying a frame counter through
|
|
12
|
+
* every comparison.
|
|
13
|
+
*
|
|
14
|
+
* @param {Object} options
|
|
15
|
+
* @param {number} options.page_row_capacity one touch stamp per page-table row
|
|
16
|
+
* @param {number} options.lookup_word_count one want stamp per lookup word, so a want's stamp is
|
|
17
|
+
* its geometry's lookup offset plus the child page index — which is the whole reason the page
|
|
18
|
+
* lookup has its own buffer and its own allocator
|
|
19
|
+
* @param {number} options.want_capacity records
|
|
20
|
+
* @param {number} options.touch_capacity records
|
|
21
|
+
* @returns {{touch_stamp_base: number, want_stamp_base: number, want_base: number,
|
|
22
|
+
* touch_base: number, word_count: number}}
|
|
23
|
+
*
|
|
24
|
+
* @author Alex Goldring
|
|
25
|
+
* @copyright Company Named Limited (c) 2026
|
|
26
|
+
*/
|
|
27
|
+
export function vgeo_cut_feedback_layout({ page_row_capacity, lookup_word_count, want_capacity, touch_capacity, }: {
|
|
28
|
+
page_row_capacity: number;
|
|
29
|
+
lookup_word_count: number;
|
|
30
|
+
want_capacity: number;
|
|
31
|
+
touch_capacity: number;
|
|
32
|
+
}): {
|
|
33
|
+
touch_stamp_base: number;
|
|
34
|
+
want_stamp_base: number;
|
|
35
|
+
want_base: number;
|
|
36
|
+
touch_base: number;
|
|
37
|
+
word_count: number;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=vgeo_cut_feedback_layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vgeo_cut_feedback_layout.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH;IAZ2B,iBAAiB,EAAjC,MAAM;IACU,iBAAiB,EAAjC,MAAM;IAGU,aAAa,EAA7B,MAAM;IACU,cAAc,EAA9B,MAAM;IACJ;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAClF,UAAgB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAC,CA4B7C"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { assert } from "../../../../../../core/assert.js";
|
|
2
|
+
import { VGEO_FEEDBACK_OFFSET } from "../layout/VGEO_FEEDBACK_OFFSET.js";
|
|
3
|
+
import { VGEO_WANT_WORDS } from "../layout/VGEO_WANT_WORDS.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Where each region of the feedback buffer starts, for one frame's worth of cutting.
|
|
7
|
+
*
|
|
8
|
+
* One function rather than two agreeing conventions: the pass that creates the buffer and the
|
|
9
|
+
* params block that tells the kernel where to write both come from here, and so does anything that
|
|
10
|
+
* reads it back. A layout computed twice is a layout that drifts, and the way it drifts is a want
|
|
11
|
+
* list written over a stamp region, which reads as wants that never resolve.
|
|
12
|
+
*
|
|
13
|
+
* The stamps are the reason the buffer is per **frame** rather than per invocation: a page touched
|
|
14
|
+
* from two buckets is one touch, and a page wanted by two views is one want. Being cleared exactly
|
|
15
|
+
* once, at creation, is what makes a plain flag enough and saves carrying a frame counter through
|
|
16
|
+
* every comparison.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} options
|
|
19
|
+
* @param {number} options.page_row_capacity one touch stamp per page-table row
|
|
20
|
+
* @param {number} options.lookup_word_count one want stamp per lookup word, so a want's stamp is
|
|
21
|
+
* its geometry's lookup offset plus the child page index — which is the whole reason the page
|
|
22
|
+
* lookup has its own buffer and its own allocator
|
|
23
|
+
* @param {number} options.want_capacity records
|
|
24
|
+
* @param {number} options.touch_capacity records
|
|
25
|
+
* @returns {{touch_stamp_base: number, want_stamp_base: number, want_base: number,
|
|
26
|
+
* touch_base: number, word_count: number}}
|
|
27
|
+
*
|
|
28
|
+
* @author Alex Goldring
|
|
29
|
+
* @copyright Company Named Limited (c) 2026
|
|
30
|
+
*/
|
|
31
|
+
export function vgeo_cut_feedback_layout({
|
|
32
|
+
page_row_capacity,
|
|
33
|
+
lookup_word_count,
|
|
34
|
+
want_capacity,
|
|
35
|
+
touch_capacity,
|
|
36
|
+
}) {
|
|
37
|
+
assert.isNonNegativeInteger(page_row_capacity, 'page_row_capacity');
|
|
38
|
+
assert.isNonNegativeInteger(lookup_word_count, 'lookup_word_count');
|
|
39
|
+
assert.isNonNegativeInteger(want_capacity, 'want_capacity');
|
|
40
|
+
assert.isNonNegativeInteger(touch_capacity, 'touch_capacity');
|
|
41
|
+
|
|
42
|
+
const touch_stamp_base = VGEO_FEEDBACK_OFFSET.HEADER_WORDS;
|
|
43
|
+
const want_stamp_base = touch_stamp_base + page_row_capacity;
|
|
44
|
+
const want_base = want_stamp_base + lookup_word_count;
|
|
45
|
+
const touch_base = want_base + want_capacity * VGEO_WANT_WORDS;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
touch_stamp_base,
|
|
49
|
+
want_stamp_base,
|
|
50
|
+
want_base,
|
|
51
|
+
touch_base,
|
|
52
|
+
word_count: touch_base + touch_capacity,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The seam, at a call site that does not want to know whether this scene has virtual geometry in it.
|
|
3
|
+
*
|
|
4
|
+
* Four rasterization paths call `graph_expand_meshes_to_meshlets`, and each of them gains exactly
|
|
5
|
+
* one line. That line has to be a no-op in the overwhelmingly common case — a scene of ordinary
|
|
6
|
+
* meshes — and it has to be a no-op *cheaply*: not a cut over an empty instance list, but no passes
|
|
7
|
+
* at all, because a wavefront is sixty-odd dispatches whose only output would be zero.
|
|
8
|
+
*
|
|
9
|
+
* The frame check is the second half of that. A runtime exists from the moment somebody enables it,
|
|
10
|
+
* but its feedback buffer exists only between `begin_frame` and `end_frame`; a path that runs
|
|
11
|
+
* outside a frame — a shadow view built before the main pass opens one, say — skips rather than
|
|
12
|
+
* writing into a resource that is not there.
|
|
13
|
+
*
|
|
14
|
+
* **And the graph check is the third.** `GPUSceneShadowmapContext` records through
|
|
15
|
+
* `graph_rasterize_scene_fast_raw`, which carries this seam, on a `FrameGraph` of its own — so a
|
|
16
|
+
* cube or tetra face inside an open frame would run a whole cut, at the *main camera's* projection
|
|
17
|
+
* scale, writing into a resource handle that belongs to another graph. Design §4 pins one cut per
|
|
18
|
+
* view and RUNTIME_PLAN §9 scopes shadow cuts out of v1; a graph that is not the one the frame was
|
|
19
|
+
* opened on is therefore not a graph this seam belongs in (REVIEW_LEDGER M13). When shadow views do
|
|
20
|
+
* get cuts, they get their own `begin_frame` and their own τ, and this check is what makes that a
|
|
21
|
+
* change rather than a discovery.
|
|
22
|
+
*
|
|
23
|
+
* @param {Object} options
|
|
24
|
+
* @param {FrameGraph} options.graph
|
|
25
|
+
* @param {number} options.input_meshes
|
|
26
|
+
* @param {number} options.output_meshlets
|
|
27
|
+
* @param {GPUViewContext} options.view
|
|
28
|
+
* @param {GPUCollectionLimits} options.limits
|
|
29
|
+
* @returns {number} `output_meshlets`, cut records appended or not
|
|
30
|
+
*
|
|
31
|
+
* @author Alex Goldring
|
|
32
|
+
* @copyright Company Named Limited (c) 2026
|
|
33
|
+
*/
|
|
34
|
+
export function graph_vgeo_expand_if_enabled({ graph, input_meshes, output_meshlets, view, limits, }: {
|
|
35
|
+
graph: FrameGraph;
|
|
36
|
+
input_meshes: number;
|
|
37
|
+
output_meshlets: number;
|
|
38
|
+
view: GPUViewContext;
|
|
39
|
+
limits: GPUCollectionLimits;
|
|
40
|
+
}): number;
|
|
41
|
+
//# sourceMappingURL=graph_vgeo_expand_if_enabled.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph_vgeo_expand_if_enabled.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;IAV+B,KAAK;IACT,YAAY,EAA5B,MAAM;IACU,eAAe,EAA/B,MAAM;IACkB,IAAI;IACC,MAAM;IACjC,MAAM,CAyBlB"}
|