@woosh/meep-engine 3.24.0 → 3.25.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/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 +1050 -0
- package/src/engine/physics/cloth/PLAN.md +411 -49
- 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 +36 -22
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +38 -23
- 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 +51 -82
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +81 -869
- 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 +286 -0
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothWorld.js +1104 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +182 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +562 -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 +58 -0
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +341 -271
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +20 -2
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +39 -15
- 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/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/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_solver_constants.d.ts +33 -0
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.js +34 -0
- 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/wind/AbstractClothWind.d.ts +88 -0
- package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -0
- package/src/engine/physics/cloth/wind/AbstractClothWind.js +100 -0
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +85 -0
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -0
- package/src/engine/physics/cloth/wind/ClothAmbientWind.js +182 -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 +210 -0
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +101 -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 +290 -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
|
@@ -250,18 +250,32 @@ export class GPUGeometryManager {
|
|
|
250
250
|
metadata.allocated = false;
|
|
251
251
|
metadata.index = this.__last_geometry_index++;
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
if (geometry.isVirtualGeometry === true) {
|
|
254
|
+
/*
|
|
255
|
+
A virtual geometry has no meshlets to allocate and no tree to trace. Everything it
|
|
256
|
+
draws comes from a cut selected per view per frame, out of pages
|
|
257
|
+
`GPUVirtualGeometryPool` installed into the *shared* meshlet pool — so its clusters are
|
|
258
|
+
in the same buffers as everything else, and only the route to them differs.
|
|
254
259
|
|
|
255
|
-
|
|
260
|
+
The row still carries the source's bounds and triangle count, which is what
|
|
261
|
+
instance-level culling reads and what makes a VG instance an ordinary instance
|
|
262
|
+
everywhere above this line.
|
|
263
|
+
*/
|
|
264
|
+
metadata.vg_row = geometry.vg_row;
|
|
265
|
+
} else {
|
|
266
|
+
const meshlets = geometry.meshlets;
|
|
256
267
|
|
|
257
|
-
|
|
258
|
-
metadata.meshlets.changed.add(() => {
|
|
268
|
+
metadata.meshlets = this.#meshlets.add_batch(meshlets);
|
|
259
269
|
|
|
260
|
-
//
|
|
270
|
+
// watch for data migration
|
|
271
|
+
metadata.meshlets.changed.add(() => {
|
|
261
272
|
|
|
262
|
-
|
|
273
|
+
// TODO need to handle this properly
|
|
263
274
|
|
|
264
|
-
|
|
275
|
+
console.warn('Meshlet GPU address changed.')
|
|
276
|
+
|
|
277
|
+
});
|
|
278
|
+
}
|
|
265
279
|
|
|
266
280
|
this.#geometries.set(geometry, metadata);
|
|
267
281
|
|
|
@@ -634,8 +648,14 @@ export class GPUGeometryManager {
|
|
|
634
648
|
index_count: indexCount,
|
|
635
649
|
bounding_sphere: geometry.bounding_sphere,
|
|
636
650
|
bounding_box: geometry.bounding_box,
|
|
637
|
-
|
|
638
|
-
|
|
651
|
+
/*
|
|
652
|
+
Zero and zero for a virtual geometry, and the zero count is load-bearing rather than
|
|
653
|
+
defensive: `shader_meshes_to_meshlet_counts` reads it and therefore contributes nothing
|
|
654
|
+
for a VG instance without knowing what one is.
|
|
655
|
+
*/
|
|
656
|
+
meshlets_address: g_meta.meshlets?.metadata.offset ?? 0,
|
|
657
|
+
meshlets_count: g_meta.meshlets?.meshlet_count ?? 0,
|
|
658
|
+
vg_row: g_meta.vg_row,
|
|
639
659
|
}, GEOMETRY_METADATA_STRUCT, metadata.buffer, offset);
|
|
640
660
|
|
|
641
661
|
}
|
|
@@ -24,6 +24,16 @@ export class GPUGeometryMetadata {
|
|
|
24
24
|
* @type {number}
|
|
25
25
|
*/
|
|
26
26
|
references: number;
|
|
27
|
+
/**
|
|
28
|
+
* Row in `GPUVirtualGeometryPool`'s geometry table, or {@link VGEO_GEOMETRY_ROW_NONE}.
|
|
29
|
+
*
|
|
30
|
+
* Set for a {@link VirtualGeometry} and for nothing else. It travels into the GPU row so a pass
|
|
31
|
+
* handed a list of visible instances can tell a virtual one from a static one — which is the
|
|
32
|
+
* whole of the seam, on this side of it.
|
|
33
|
+
*
|
|
34
|
+
* @type {number}
|
|
35
|
+
*/
|
|
36
|
+
vg_row: number;
|
|
27
37
|
allocated: boolean;
|
|
28
38
|
}
|
|
29
39
|
export type MeshletGeometry = import("./MeshletGeometry.js").MeshletGeometry;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GPUGeometryMetadata.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/geometry/GPUGeometryMetadata.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GPUGeometryMetadata.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/geometry/GPUGeometryMetadata.js"],"names":[],"mappings":"AAEA;;GAEG;AAEH;IACI;;OAEG;IACH,UAFU,eAAe,CAEjB;IAER;;;OAGG;IACH,OAFU,MAAM,CAEN;IAEV;;OAEG;IACH,uCAAS;IAET;;;;;;;OAOG;IACH,YAFU,MAAM,CAED;IAEf;;;;;;;;OAQG;IACH,QAFU,MAAM,CAEgB;IAEhC,mBAAkB;CACrB;8BA1CY,OAAO,sBAAsB,EAAE,eAAe"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { VGEO_GEOMETRY_ROW_NONE } from "./virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @typedef {import("./MeshletGeometry.js").MeshletGeometry} MeshletGeometry
|
|
3
5
|
*/
|
|
@@ -29,5 +31,16 @@ export class GPUGeometryMetadata {
|
|
|
29
31
|
*/
|
|
30
32
|
references = 0;
|
|
31
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Row in `GPUVirtualGeometryPool`'s geometry table, or {@link VGEO_GEOMETRY_ROW_NONE}.
|
|
36
|
+
*
|
|
37
|
+
* Set for a {@link VirtualGeometry} and for nothing else. It travels into the GPU row so a pass
|
|
38
|
+
* handed a list of visible instances can tell a virtual one from a static one — which is the
|
|
39
|
+
* whole of the seam, on this side of it.
|
|
40
|
+
*
|
|
41
|
+
* @type {number}
|
|
42
|
+
*/
|
|
43
|
+
vg_row = VGEO_GEOMETRY_ROW_NONE;
|
|
44
|
+
|
|
32
45
|
allocated = false;
|
|
33
46
|
}
|
|
@@ -18,9 +18,16 @@ rather than baked in.
|
|
|
18
18
|
implements the *mechanics* of §10 — cold start, one fetch per page from the byte range its parent
|
|
19
19
|
wrote down, want dedup, activation, eviction, and the mandatory reject rules of §4 and §5. It
|
|
20
20
|
implements none of the *policy*: no fetch scheduler, no budgets, no touch-LRU, no quarantine, and
|
|
21
|
-
the pinning rules are left to whoever manages residency.
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
the pinning rules are left to whoever manages residency.
|
|
22
|
+
|
|
23
|
+
It decodes the **node table** (§6.1) — the GPU cut pass is the consumer that was predicted here and
|
|
24
|
+
it arrived; the node metric's `max_parent_error` is what lets a whole subtree be skipped without
|
|
25
|
+
touching a cluster. It decodes the **child-table traversal metric** (§5, §6.2) as well, because a
|
|
26
|
+
reader that decodes two thirds of a structure is worse than one that decodes all of it — but no
|
|
27
|
+
consumer reads it, and `runtime/RUNTIME_PLAN.md` §4.8 says why: at the moment a want is emitted, the
|
|
28
|
+
per-cluster test the cut has already passed is strictly tighter than any page-level test, so the
|
|
29
|
+
page-level one can never reject anything. Its consumer is prefetch, which is a later campaign.
|
|
30
|
+
|
|
24
31
|
`shade/playground/vgeo_viewer/` drives the reader end to end, and its `select_cut.js` is a CPU
|
|
25
32
|
reference traversal of the cut rule this format was shaped around.
|
|
26
33
|
|
|
@@ -115,7 +122,7 @@ All u64/u128 fields are naturally 8-byte aligned.
|
|
|
115
122
|
| 10 | u8 | hash_algo | 0 = xxHash3; readers MUST reject unknown values |
|
|
116
123
|
| 11 | u8 | reserved | |
|
|
117
124
|
| 12 | u32 | feature_flags_required | readers MUST reject any unknown set bit |
|
|
118
|
-
| 16 | u32 | feature_flags_ignorable | readers MUST ignore unknown set bits |
|
|
125
|
+
| 16 | u32 | feature_flags_ignorable | readers MUST ignore unknown set bits; bit 0 = every page is within `nominal_page_size` (§11.14) |
|
|
119
126
|
| 20 | u32 | payload_encoding | 1 = `SHADE_MESHLET_V1` (§8); readers MUST reject unknown values |
|
|
120
127
|
| 24 | [u8; 16] | asset_id | xxh3-128 of the whole file with every **derived checksum field** zeroed (see below); stored low64 LE at bytes 0–7, high64 LE at bytes 8–15 |
|
|
121
128
|
| 40 | u32 | vertex_attribute_mask | advisory attribute presence (§8 bit table) |
|
|
@@ -127,7 +134,7 @@ All u64/u128 fields are naturally 8-byte aligned.
|
|
|
127
134
|
| 76 | u32 | root_page_decoded_size | RAM admission for the always-resident set, known from the header alone |
|
|
128
135
|
| 80 | u64 | directory_offset | also the exact end of the frame region |
|
|
129
136
|
| 88 | u64 | dir_block_checksums_offset | `ceil(total_pages / 128)` × u64 |
|
|
130
|
-
| 96 | u32 | nominal_page_size |
|
|
137
|
+
| 96 | u32 | nominal_page_size | bytes a decoded page may come to; a **hard bound** when bit 0 of `feature_flags_ignorable` is set (§11.14), advisory otherwise |
|
|
131
138
|
| 100 | u16 | reserved | |
|
|
132
139
|
| 102 | u8 | level_count | levels `0..level_count-1` |
|
|
133
140
|
| 103 | u8 | reserved | |
|
|
@@ -492,8 +499,8 @@ about a scene and not about a container.
|
|
|
492
499
|
always-resident set is small: invariant §11.7 puts exactly one root cluster in the file and the
|
|
493
500
|
assembler gives the root page the complete topmost level, so a measured root page is one cluster —
|
|
494
501
|
1,732 B and 1,472 B on two torus builds, header and level table included coming to about 2.4 KB.
|
|
495
|
-
A prefix past that is speculation about the *next* band, and at the
|
|
496
|
-
|
|
502
|
+
A prefix past that is speculation about the *next* band, and at the 64 KiB default page size it
|
|
503
|
+
buys about one page. `VGeoReadOptions.head_prefix_bytes` therefore defaults to 64 KiB rather
|
|
497
504
|
than the 256 KiB it did, and the reader **releases the prefix** the first time a read falls
|
|
498
505
|
outside it (`VGeoContainerReader.release_head`, and `head_bytes` to see it). Measured, at the old
|
|
499
506
|
default a 256 KiB prefix over a 22 MB container covered 105 of its 4,000 pages and served nothing
|
|
@@ -537,12 +544,14 @@ about a scene and not about a container.
|
|
|
537
544
|
child installs — known at queue time, purely local. Arrivals verify the
|
|
538
545
|
identity-seeded frame checksum; activation makes any arrival order safe beyond that.
|
|
539
546
|
The reader dedups in-flight fetches by page index but pins nothing.
|
|
540
|
-
Still open, and
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
547
|
+
Still open, and the blocker named here is gone. It was that a `VGeoPageWant` carried the page it
|
|
548
|
+
named and not the page it was *discovered through*, so neither the reader nor the manager could
|
|
549
|
+
identify P — the format stores parent counts rather than parent references, deliberately, so
|
|
550
|
+
nothing below the cut can name one. The cut says it: a want record is
|
|
551
|
+
`(source_page_row, child_ref, child_page_index, priority)` and the source row is P. Nothing pins
|
|
552
|
+
anything yet, and that is the whole of what remains. It is an efficiency item and not a
|
|
553
|
+
correctness one — evicting P while its child is on the wire wastes the fetch, because the child
|
|
554
|
+
installs non-selectable and activation is safe at every arrival order.
|
|
546
555
|
- **Eviction** *(mechanics shipped in the reader, policy shipped above it)*: within each residency tier, a page is
|
|
547
556
|
evictable only while it has no resident child pages in that tier — checked against its own
|
|
548
557
|
child table (`SAME_PAGE` references never pin). Leaves-first order emerges from the rule;
|
|
@@ -619,8 +628,12 @@ about a scene and not about a container.
|
|
|
619
628
|
lives within bands — the within-band spatial curve (§12) is what carries fetch
|
|
620
629
|
locality and must be chosen with that as a criterion. Fetching through small unwanted
|
|
621
630
|
gaps is permitted under an implementation waste threshold.
|
|
622
|
-
- *(shipped)*
|
|
623
|
-
|
|
631
|
+
- *(shipped)* Take a page's *actual* size from child tables (traversal), frames (prefix scan), or
|
|
632
|
+
the directory (special tasks) — never from `nominal_page_size`, which is an upper bound and not a
|
|
633
|
+
size. The bound itself may be relied on, and only when bit 0 of `feature_flags_ignorable` is set:
|
|
634
|
+
then no page exceeds it (§11.14) and a reader may size fixed-stride page slots against it. A
|
|
635
|
+
reader that depends on that MUST check the bit and refuse a container without it — containers
|
|
636
|
+
written before the bound existed carry a `nominal_page_size` that pages ran over.
|
|
624
637
|
- *(shipped)* **Nothing a runtime holds may be able to read the whole file.** The whole-file audit
|
|
625
638
|
(§11, every checksum, the directory against a frame scan) and the install-every-page sweep are in
|
|
626
639
|
`format/read/tool/` as `vgeo_audit_container` and `vgeo_install_all_pages`, not on the reader —
|
|
@@ -672,8 +685,7 @@ clustering and simplification dominate regardless.
|
|
|
672
685
|
design §3 grouping is adaptive from ~4). `parent_cluster_count` equals the exact
|
|
673
686
|
number of clusters (across all pages, `SAME_PAGE` included) whose
|
|
674
687
|
`child_ref/child_group` name this group; it is 0 exactly for the root page's
|
|
675
|
-
topmost-level groups.
|
|
676
|
-
`nominal_page_size`; the hard bound is the frame's u32 `stored_size`.
|
|
688
|
+
topmost-level groups.
|
|
677
689
|
6. `1 ≤ triangle_count ≤ 128`, `3 ≤ vertex_count ≤ 128` (Shade meshlet limits);
|
|
678
690
|
`total_clusters ≥ 1`; `source_vertex_count ≥ 3`, `source_face_count ≥ 1`.
|
|
679
691
|
7. Error/sphere monotonicity per design §4; `self_error = 0` and `child_ref = NO_CHILD`
|
|
@@ -709,6 +721,18 @@ clustering and simplification dominate regardless.
|
|
|
709
721
|
13. `root_page_offset = align16(256 + 32 · level_count)`; the level table's `cluster_count` and
|
|
710
722
|
`group_count` columns sum to `total_clusters` and `total_groups`; every level holds at least
|
|
711
723
|
one cluster and one group; `min_error ≤ max_error`, both finite and ≥ 0.
|
|
724
|
+
14. **Page size is a bound.** When bit 0 of `feature_flags_ignorable` is set, every page's
|
|
725
|
+
`decoded_size` is ≤ `nominal_page_size`, and `nominal_page_size` is non-zero. The bit is what a
|
|
726
|
+
reader checks; unset, `nominal_page_size` is the advisory build parameter it used to be and
|
|
727
|
+
nothing here applies.
|
|
728
|
+
|
|
729
|
+
The bound is what makes a page slot a fixed stride in VRAM — a slot address is a multiply, with
|
|
730
|
+
no allocator, no growth path and no address migration behind it (design §6). It costs the
|
|
731
|
+
internal fragmentation of each band's last page, measured at about 9% of a page across a
|
|
732
|
+
254-page build, and it is kept by splitting a band into more pages. What it cannot be kept by is
|
|
733
|
+
splitting a **group**: §11.1 makes a group atomic to its page. So a build whose clusters group
|
|
734
|
+
into more bytes than a page holds has no layout, and the builder refuses it naming the page size
|
|
735
|
+
that would work, rather than writing a page over the size the header states.
|
|
712
736
|
|
|
713
737
|
## 12. Open
|
|
714
738
|
|
|
@@ -717,7 +741,11 @@ clustering and simplification dominate regardless.
|
|
|
717
741
|
the tables) is a per-frame `codec` id away and costs no reader that already handles a
|
|
718
742
|
mixture. The quantized-position `payload_encoding` is the other half of the same
|
|
719
743
|
question, and would take most of what LZ4 currently finds.
|
|
720
|
-
- Default `nominal_page_size
|
|
744
|
+
- ~~Default `nominal_page_size`~~ — 64 KiB, `VGEO_DEFAULT_PAGE_SIZE`: one page size rather than
|
|
745
|
+
Nanite's two, set between hiding fetch latency and paying for it in response time and in VRAM per
|
|
746
|
+
resident page on a low-end device, with a floor at the largest group a build produces. Provisional
|
|
747
|
+
— reopen it on a device measurement, and when quantization lands, since that moves what a cluster
|
|
748
|
+
costs.
|
|
721
749
|
- Spatial ordering curve within a level band (Morton over group centroids is the
|
|
722
750
|
default candidate; chosen with fetch-coalescing locality as an explicit criterion,
|
|
723
751
|
§10).
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
# Virtual Geometry — Design
|
|
2
2
|
|
|
3
|
-
Status: **builder, container and
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Status: **builder, container, reader and GPU runtime implemented; the runtime is under review and
|
|
4
|
+
not shippable** — see [runtime/REVIEW_LEDGER.md](./runtime/REVIEW_LEDGER.md), which found seven
|
|
5
|
+
critical defects including one that breaks §4's no-double-draw guarantee on the ordinary streaming
|
|
6
|
+
path. §10's M1 is written below as closed; treat it as *built and not yet trustworthy*. This document pins only what
|
|
7
|
+
is certain; everything else is listed explicitly under *Open*. Runtime home is this directory
|
|
8
|
+
(`shade/renderer/geometry/virtual/`, mirroring `texture/virtual/`); builder lives with
|
|
9
|
+
`core/geom/3d/topology/struct/binary/` and `core/graph/metis/`.
|
|
7
10
|
|
|
8
11
|
What exists, in the order a newcomer meets it: `build/` turns a `Geometry` into a cluster DAG,
|
|
9
12
|
`format/` writes and validates the `.vgeo` container ([VGEO_FORMAT.md](./VGEO_FORMAT.md)),
|
|
10
|
-
`format/read/` reads one back a page at a time with residency and activation,
|
|
11
|
-
`
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
`format/read/` reads one back a page at a time with residency and activation, `residency/` owns the
|
|
14
|
+
RAM tier's budget, and `runtime/` is everything §7 describes — the selection buffer, the compute cut
|
|
15
|
+
pass, the VRAM page pool, the feedback loop, and the seam through which VG instances enter the
|
|
16
|
+
meshlet pipeline ([runtime/RUNTIME_PLAN.md](./runtime/RUNTIME_PLAN.md)).
|
|
17
|
+
|
|
18
|
+
Two playgrounds prove two different things and it is worth not confusing them.
|
|
19
|
+
`shade/playground/vgeo_viewer/` puts a clamped **CPU** cut of a streaming container on screen
|
|
20
|
+
through Shade's direct geometry path — it proves the DAG, the format and the clamp, and by
|
|
21
|
+
construction it proves nothing about the engine. `shade/playground/vgeo_runtime/` puts an ordinary
|
|
22
|
+
`Mesh` in an ordinary `Scene` and draws it entirely from a **GPU** cut through the meshlet
|
|
23
|
+
pipeline — it proves the seam and nothing about the DAG. §10 says which milestone that leaves us
|
|
24
|
+
in, and the order the work actually arrived in.
|
|
17
25
|
|
|
18
26
|
## 1. What and why
|
|
19
27
|
|
|
@@ -317,7 +325,10 @@ Pinned:
|
|
|
317
325
|
fill in M2, never from these nominals.
|
|
318
326
|
- **Immutable and content-addressed** (`hash(output bytes)` in header and filename):
|
|
319
327
|
perfect HTTP caching, CDN-friendly, no invalidation protocol.
|
|
320
|
-
- **Fetch unit = size-bounded page** (
|
|
328
|
+
- **Fetch unit = size-bounded page** (64 KiB, `VGEO_DEFAULT_PAGE_SIZE` — **one** page size, against
|
|
329
|
+
Nanite's two, traded off between hiding fetch latency and both response time and VRAM per
|
|
330
|
+
resident page on a low-end device; this section's "order hundreds of KB" was a first-principles
|
|
331
|
+
guess and is superseded, see the constant's own note), fetched by
|
|
321
332
|
HTTP **single-range** requests and **independently decodable**: a group never spans
|
|
322
333
|
pages; a page carries whole groups with payloads in (near-)upload-ready encoded form.
|
|
323
334
|
- **Pages carry the DAG, fetchably**: each cluster record stores its two (sphere, error)
|
|
@@ -348,7 +359,7 @@ Pinned:
|
|
|
348
359
|
- **Coarse-first layout**: pages ordered so a plain prefix read of the file yields a
|
|
349
360
|
complete coarse asset — progressive load without a feedback loop.
|
|
350
361
|
|
|
351
|
-
Open:
|
|
362
|
+
Open: a denser page codec than LZ4, if quantization leaves one worth having;
|
|
352
363
|
per-attribute quantization widths (cluster-local grids); relationship to
|
|
353
364
|
`MeshletGeometrySerializationAdapter` (extend vs parallel).
|
|
354
365
|
|
|
@@ -376,6 +387,13 @@ Pinned:
|
|
|
376
387
|
intent is **fixed-size page-slot allocation** (no compaction, no CPU metadata mirror,
|
|
377
388
|
no transient 2× rebuild), plus propagation of address migration to every consumer —
|
|
378
389
|
the existing `GPUGeometryManager` TODO becomes load-bearing under churn.
|
|
390
|
+
|
|
391
|
+
What that rests on is the container, and it now holds: FORMAT §11.14 makes
|
|
392
|
+
`nominal_page_size` a bound no page exceeds, announced by a feature bit a pool can require.
|
|
393
|
+
Before that it was an advisory number the builder itself broke — 13 of 40 pages over it on a
|
|
394
|
+
measured build — and a fixed stride sized against it would have been a slot overrun. A pool
|
|
395
|
+
taking the guarantee is entitled to one slot size and nothing else: it refuses a container
|
|
396
|
+
built at a different page size rather than carrying a size-class table for it.
|
|
379
397
|
- **Activation invariant (closure without dependency metadata)**: a group is
|
|
380
398
|
*selectable* iff **all** of its parent-cluster references are live — each referencing
|
|
381
399
|
cluster's page installed and that cluster's own group selectable (per-group reference
|
|
@@ -565,6 +583,14 @@ canonicalizing them is a preprocessor's job).
|
|
|
565
583
|
and the reports behind it. `cone_reserved` stays a zeroed reserved field (format §7). This is
|
|
566
584
|
the one entry here that is not a "v1" qualifier.
|
|
567
585
|
- Skinned / morphing / WPO meshes through the VG path (static geometry only).
|
|
586
|
+
- **Non-opaque VG instances.** The cut runs beside the mesh→meshlet expansion of the *opaque*
|
|
587
|
+
rasterization paths, and the transparent and alpha-tested bucket path
|
|
588
|
+
(`prepare_meshlet_draw_commands_by_material`) has no seam: it is handed a scene and an optional
|
|
589
|
+
camera resource rather than a view context, where a cut needs the camera's uniform buffer to put
|
|
590
|
+
each instance into object space. A VG instance with a non-opaque material therefore expands to
|
|
591
|
+
zero meshlets and draws nothing at all. `GPUSceneRows.attach_mesh` says so out loud when one is
|
|
592
|
+
attached, because this bullet is the authority for it and did not exist while the code was citing
|
|
593
|
+
it.
|
|
568
594
|
- Compute/software rasterization — WebGPU lacks portable 64-bit atomics; the hardware
|
|
569
595
|
raster path through the existing pipeline is the only raster path. Deferred G-buffer
|
|
570
596
|
shading already bounds the overshading cost of small triangles.
|
|
@@ -597,13 +623,31 @@ is the piece still missing, and M1 is where the work now starts.
|
|
|
597
623
|
which was M2's job; τ-sweep watertightness as a spec (`build/vgeo_cut.spec.js` counts edges
|
|
598
624
|
used by one triangle instead of two, at a spread of thresholds, and wants zero); the
|
|
599
625
|
group-boundary polyline guarantee, enforced by the builder rather than merely validated.
|
|
600
|
-
**
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
(
|
|
626
|
+
**Done since**: the expansion seam. `runtime/graph_vgeo_expand_instances_to_meshlets` runs beside
|
|
627
|
+
`graph_expand_meshes_to_meshlets` at each of the three opaque call sites and appends into the same
|
|
628
|
+
collection, so a VG instance enters through a VG-shaped door and everything past the expansion is
|
|
629
|
+
untouched. `shade/playground/vgeo_runtime/` is that, on screen.
|
|
630
|
+
**Still not done**: flip validation (§2, extension 3).
|
|
631
|
+
- **M1 — GPU cut** — **done**: selection buffer + compute cut pass; wants/touches readback wired.
|
|
632
|
+
`runtime/` holds all of it and [runtime/RUNTIME_PLAN.md](./runtime/RUNTIME_PLAN.md) is its design.
|
|
633
|
+
Acceptance was parity with M0 and selection cost measured, and both were taken:
|
|
634
|
+
|
|
635
|
+
*Parity* is `runtime/cut/vgeo_cut_agreement.spec.js` — the kernels run under the WGSL emulator
|
|
636
|
+
against a real container and their drawn cluster **multiset** is held to exactly what
|
|
637
|
+
`vgeo_select_cut` selects, over seven cameras and four thresholds, fully resident and with pages
|
|
638
|
+
withheld, one instance and two. Multiset rather than set because a duplicate is the failure that
|
|
639
|
+
reads as corrupt geometry rather than as a missing page.
|
|
640
|
+
|
|
641
|
+
*Measured*, on an nvidia/lovelace adapter, a 13-page torus opened holding only its root page and
|
|
642
|
+
streamed entirely by the cut's own wants: 50 drawn clusters at τ=0.5 down to 8 at τ=16, monotone,
|
|
643
|
+
visiting 9 pages down to 5, clamping to zero as pages arrive, dropping nothing. Half the frames
|
|
644
|
+
skip feedback entirely under a two-deep readback cap, which is the virtual-texture contract and
|
|
645
|
+
costs streaming latency rather than pixels.
|
|
646
|
+
|
|
647
|
+
The flat-vs-hierarchy decision data is *not* what M1 produced, and §7 already says why: §4 pinned
|
|
648
|
+
the traversal and the question stopped being a measurement to take. What the cut measures instead
|
|
649
|
+
is that the hierarchy's own accelerator is sound — the node metric's `max_parent_error` cull fires
|
|
650
|
+
across the whole agreement sweep and changes not one selected cluster.
|
|
607
651
|
- **M2 — format + streaming** — *the RAM tier landed early*: `.vgeo` container, pager,
|
|
608
652
|
residency tiers with the §6 invariants (page-slot pool, address-migration propagation,
|
|
609
653
|
occlusion-aware wants, touch-LRU, in-flight pinning), budgets, eviction. Position
|
|
@@ -613,8 +657,12 @@ is the piece still missing, and M1 is where the work now starts.
|
|
|
613
657
|
**Done ahead of M1**: the container and its validator; the RAM-tier pager with residency,
|
|
614
658
|
activation and eviction (`format/read/`); TTFP, which is header + level table + root page and
|
|
615
659
|
measured to hold on a 27M-triangle asset; the page codec, chosen on measurement (§5).
|
|
616
|
-
**
|
|
617
|
-
|
|
660
|
+
**Done with M1**: the VRAM page pool (`runtime/GPUVirtualGeometryPool`) with a byte budget and
|
|
661
|
+
touch-LRU under a protect window, and the want record now naming the page it was discovered
|
|
662
|
+
*through* — which is what in-flight pinning was blocked on, since the format stores parent counts
|
|
663
|
+
rather than parent references and nothing below the cut could name that page.
|
|
664
|
+
**Still M2's**: address-migration propagation, occlusion-aware wants, the in-flight pin itself,
|
|
665
|
+
and position quantization.
|
|
618
666
|
- **M3 — hardening**: prefetch, disk page store decision, budget defaults, low-limit
|
|
619
667
|
adapters (τ fallback), stress on CAD-class input; browser builder-harness proof
|
|
620
668
|
(build a mid-size asset in-tab).
|
|
@@ -6,10 +6,11 @@ This file holds what is *next*, and — more usefully — the reasoning and the
|
|
|
6
6
|
ideas that are accepted but not yet scheduled, so that picking one up does not mean
|
|
7
7
|
rediscovering it.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
The GPU runtime is **built** — `runtime/`, and
|
|
10
|
+
[runtime/RUNTIME_PLAN.md](./runtime/RUNTIME_PLAN.md) is its design and its adversarial review. The
|
|
11
|
+
cut runs on the device, the VRAM tier holds pages under a budget, wants and touches come back
|
|
12
|
+
through a readback, and a VG instance enters the meshlet pipeline through a door of its own. §3's
|
|
13
|
+
items are no longer blocked on "a runtime"; each names what it is actually waiting for now.
|
|
13
14
|
|
|
14
15
|
Items carry their provenance. `[M §x]` is a section of
|
|
15
16
|
[MICRON_COMPARISON_2026_08_20.md](./MICRON_COMPARISON_2026_08_20.md), the review of the
|
|
@@ -78,11 +79,43 @@ accepted-and-waiting one.
|
|
|
78
79
|
meshlet pipeline — so it proves the DAG and the format, and proves nothing about the engine
|
|
79
80
|
seam.
|
|
80
81
|
|
|
82
|
+
- **The GPU runtime** — `runtime/`, and [runtime/RUNTIME_PLAN.md](./runtime/RUNTIME_PLAN.md) for the
|
|
83
|
+
design and the adversarial review that reshaped it. The cut is a wavefront BFS over the page DAG
|
|
84
|
+
with a per-cluster predicate at the leaves, and that combination is the whole design: the
|
|
85
|
+
hierarchy decides which clusters to *look at*, the predicate decides whether to *draw* them, and
|
|
86
|
+
because the predicate is a pure function of one row, a page visited twice costs a duplicate record
|
|
87
|
+
rather than a wrong answer — so dedup is one bit per (instance, resident page) and never per
|
|
88
|
+
cluster, which is the number design §4 is trying not to pay.
|
|
89
|
+
|
|
90
|
+
Three things the review found, in descending order of how much they cost to rediscover:
|
|
91
|
+
|
|
92
|
+
- **Design §4's per-cluster rule double-draws as written.** A group that is resident but not
|
|
93
|
+
selectable has clusters satisfying it while their coarse stand-in is drawn over the same
|
|
94
|
+
surface. The rule needs an *own group selectable* term that a traversal gets for free and an
|
|
95
|
+
evaluator does not. §6 states the fact without stating it as a term of the rule, because §4 was
|
|
96
|
+
written for a traversal.
|
|
97
|
+
- **Page size decides whether that state is even reachable.** At the 8 KB pages
|
|
98
|
+
`select_cut.spec.js` uses, a torus puts exactly one group in every page — so a blocked group is
|
|
99
|
+
a blocked page, no page is ever mixed, and no page is ever entered twice. Measured: 40 pages
|
|
100
|
+
withheld one at a time and 60 random residency subsets produced *no* mixed page. At 64 KB the
|
|
101
|
+
median page holds eight groups and it is ordinary. A spec for anything about mixed selectability
|
|
102
|
+
has to be written at a page size that produces it.
|
|
103
|
+
- **Every bound degrades in one direction.** A full meshlet collection drops records; a claim
|
|
104
|
+
allocation that does not fit drops the *instance*, because an instance run unclaimed draws its
|
|
105
|
+
whole cut once per parent page that reaches it.
|
|
106
|
+
|
|
107
|
+
Held against mutation: removing the own-group term, the claim, the child selectability check or
|
|
108
|
+
the parent projection each turns the agreement suite red. Proved on a device in
|
|
109
|
+
`playground/vgeo_runtime/` — a 13-page container opened holding only its root page, streamed to 9
|
|
110
|
+
by its own wants, 50 drawn clusters at τ=0.5 falling monotonically to 8 at τ=16, clamping to zero,
|
|
111
|
+
dropping nothing.
|
|
112
|
+
|
|
81
113
|
## 2. Next
|
|
82
114
|
|
|
83
115
|
§2.1 and §2.2 both landed. They are kept because their notes are the reasoning behind decisions
|
|
84
|
-
that are now only visible in code, and rediscovering them is the expensive part.
|
|
85
|
-
|
|
116
|
+
that are now only visible in code, and rediscovering them is the expensive part. §2.3 **half**
|
|
117
|
+
closed, and the half that did not is the more interesting one — read it before building a
|
|
118
|
+
prefetch.
|
|
86
119
|
|
|
87
120
|
### 2.1 A partitioning fallback for when METIS fails `[M §3.3]`, `[V §3.2]` — LANDED
|
|
88
121
|
|
|
@@ -204,7 +237,7 @@ instance count first and from fan-out immediately after — measured out-degree
|
|
|
204
237
|
the middle bands of the 98k sphere. It bites only for a single instance in close-up, and only
|
|
205
238
|
for the first few bands, which are also the cheapest to walk.
|
|
206
239
|
|
|
207
|
-
### 2.3
|
|
240
|
+
### 2.3 The node tree has a reader; the child-table metric still does not — LANDED (half)
|
|
208
241
|
|
|
209
242
|
§2.2 built both, and the format specifies both: every child-table entry carries the child page's
|
|
210
243
|
LOD-metric sphere and error range (VGEO_FORMAT §5, §6.2), and every page carries a fanout-4 tree
|
|
@@ -231,13 +264,36 @@ What it buys when the pass arrives, and what to hold it to:
|
|
|
231
264
|
Neither is measurable until there is a GPU traversal to measure, which is the honest reason it
|
|
232
265
|
has waited.
|
|
233
266
|
|
|
234
|
-
|
|
267
|
+
**What happened when the traversal arrived**, and it is not what this section predicted.
|
|
268
|
+
|
|
269
|
+
*Below the page*, the node tree has its reader. `runtime/cut/shader_vgeo_cut_traverse` descends it,
|
|
270
|
+
tests each node's sphere and `max_parent_error`, and discards a region rather than a cluster. The
|
|
271
|
+
cull fires across the whole agreement sweep and changes not one selected cluster, which is what
|
|
272
|
+
sound means for an accelerator. The 0.3%–1.6% of asset size is earning something now.
|
|
273
|
+
|
|
274
|
+
*Before the fetch*, the child-table metric **still has no reader, and now for a reason rather than
|
|
275
|
+
for want of a consumer.** Held against the cut, it buys nothing. A want is emitted from a cluster
|
|
276
|
+
that has already passed `project(parent) > τ` and `project(self) > τ`; the child page's metric
|
|
277
|
+
covers that cluster's child group among others, so its `max_parent_error` is at least that group's
|
|
278
|
+
`parent_error` and its sphere contains that group's `parent_sphere` — and the projection is monotone
|
|
279
|
+
in both. The page-level test is therefore **always** above τ at exactly the moment the question is
|
|
280
|
+
asked. It cannot reject what a per-cluster test has just accepted, because the per-cluster test is
|
|
281
|
+
strictly tighter. The frustum half dies the same way: the cluster's own `self_sphere` is a tighter
|
|
282
|
+
test than the child page's union sphere, available locally, for free.
|
|
283
|
+
|
|
284
|
+
Where the copy *is* load-bearing is **prefetch** — ranking and bounding pages nobody has asked for
|
|
285
|
+
yet, which by definition has no cluster-level evidence to be tighter than. `min_self_error` is in
|
|
286
|
+
the same position: it ranks a want and the cut never asks it anything. So the field is not dead, it
|
|
287
|
+
is early, and the thing it is early for is §3's territory rather than the cut's. Anyone building a
|
|
288
|
+
prefetch should start here.
|
|
235
289
|
|
|
236
|
-
|
|
237
|
-
waiting on all of it; a CPU traversal and a RAM-tier pager now exist (§1), so what each item is
|
|
238
|
-
actually blocked on is named individually.
|
|
290
|
+
## 3. Was waiting on a GPU runtime
|
|
239
291
|
|
|
240
|
-
|
|
292
|
+
Accepted, documented here so the reasoning is not lost. "Waiting on a runtime" used to mean waiting
|
|
293
|
+
on all of it; the runtime exists now (`runtime/`), so §3.1 has landed with it and the rest name what
|
|
294
|
+
they are actually waiting for.
|
|
295
|
+
|
|
296
|
+
### 3.1 Object-space refinement `[M §2.7]` — LANDED
|
|
241
297
|
|
|
242
298
|
`RefinementSpec.build` in `Micron/render/refinement/RefinementSpec.js`: multiply the camera's
|
|
243
299
|
view-projection by the instance transform once, derive the frustum planes from the result,
|
|
@@ -245,10 +301,17 @@ and run every cull and error test in **object space** against untransformed clus
|
|
|
245
301
|
One matrix multiply per instance instead of transforming every cluster's bounds to world
|
|
246
302
|
space. With thousands of instances sharing one geometry that difference is the entire cost.
|
|
247
303
|
|
|
248
|
-
**
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
304
|
+
**Landed** with the cut. `runtime/cut/shader_vgeo_cut_collect` is the one place a VG transform is
|
|
305
|
+
touched: it multiplies the camera's view-projection by the instance transform, extracts the frustum
|
|
306
|
+
from the result, inverts the transform once for the eye, and writes both into the instance record.
|
|
307
|
+
Every cull and error test downstream runs against untransformed cluster bounds.
|
|
308
|
+
|
|
309
|
+
One thing fell out that `RefinementSpec.build` never had to face, because object space is not free
|
|
310
|
+
when an instance is scaled: error and distance are **both** object-space, so a *uniform* scale
|
|
311
|
+
cancels out of `r_e · k / d` exactly and needs no term at all. A non-uniform one does not, and the
|
|
312
|
+
correction is the ratio of the largest axis scale to the smallest — conservative, so it over-refines
|
|
313
|
+
rather than under-refines, and exactly 1 for every instance that is not stretched. Worth knowing
|
|
314
|
+
before anyone adds a scale term that does nothing in the common case.
|
|
252
315
|
|
|
253
316
|
### 3.2 Proxy geometry from a DAG cut `[M §2.6]`
|
|
254
317
|
|
|
@@ -282,6 +345,16 @@ choice belongs to the view, not to the geometry.
|
|
|
282
345
|
|
|
283
346
|
### 3.4 GPU-driven allocation `[V §4.3]`
|
|
284
347
|
|
|
348
|
+
**Narrower now, and the runtime says exactly how much.** A VG page is one arena allocation holding
|
|
349
|
+
its node, group and cluster rows back to back, and an eviction frees one allocation and writes one
|
|
350
|
+
lookup word. Nothing inside a resident page can move, growth appends through `OffsetAllocator#grow`
|
|
351
|
+
and relocates nothing, and no address migrates. What VG's churn *does* still reach is
|
|
352
|
+
`GPUMeshletManager`: a page install is an `add_batch` and an eviction a `remove_batch`, so the holes
|
|
353
|
+
accumulate in that pool and closing them is still a CPU-side rebuild with the unhandled
|
|
354
|
+
address-migration TODO downstream of it. Pages are near-uniform in size, so a hole is usually
|
|
355
|
+
re-usable by the next install — which narrows the problem without closing it, and is the reason this
|
|
356
|
+
is still an item rather than an incident.
|
|
357
|
+
|
|
285
358
|
Worth pursuing **beyond virtual geometry** — this is a GPU-driven engine and CPU-side
|
|
286
359
|
allocation for GPU-resident data is a standing mismatch.
|
|
287
360
|
|
|
@@ -384,9 +457,14 @@ attacked:
|
|
|
384
457
|
`MICRON_PATCH_SIZE_MAX × 3` vertices with occupancy in a BitSet: no allocator, no
|
|
385
458
|
fragmentation, no address migration, at the cost of internal fragmentation proportional to
|
|
386
459
|
`1 − fill`. **Declined: pages already are the compaction mechanism.** A page is fixed-size
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
460
|
+
and carries whole groups; the lever to pull is page waste, by keeping clusters full — which
|
|
461
|
+
§1's cluster-count target and repack are for — not by giving up variable-size allocation.
|
|
462
|
+
|
|
463
|
+
*(2026-09-12: "by construction" was the original wording and it was not true — the builder
|
|
464
|
+
overran `nominal_page_size` whenever a group did not fit, and the format told readers not to
|
|
465
|
+
assume the number at all. It is true now, by enforcement rather than by construction:
|
|
466
|
+
FORMAT §11.14, the builder refusing a page size no group fits, and the validator behind it.
|
|
467
|
+
The conclusion this bullet reaches is unchanged; the premise had to be made real first.)*
|
|
390
468
|
- **Shape-aware greedy leaf clustering** `[M §2.8]`. Micron grows leaf patches with a heap
|
|
391
469
|
scored on perimeter change, added-neighbour count, and "open face freedom" — how many of a
|
|
392
470
|
candidate face's neighbours are about to be stranded
|
|
@@ -48,8 +48,18 @@ export class VGeoBuildOptions {
|
|
|
48
48
|
*/
|
|
49
49
|
weld_ratio: number;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
51
|
+
* Decoded bytes per page, as a **hard cap**: no page of the asset exceeds it, and the container
|
|
52
|
+
* says so with a feature bit a runtime can require (`VGEO_FORMAT.md` §11.14). That is what makes
|
|
53
|
+
* a page slot a fixed stride on the device — a slot address is a multiply, with no allocator, no
|
|
54
|
+
* growth path and no address migration behind it.
|
|
55
|
+
*
|
|
56
|
+
* The cap is kept by splitting bands into more pages, which costs only the internal
|
|
57
|
+
* fragmentation of the last page of each band — measured at about 9% on a 254-page build. The
|
|
58
|
+
* one thing it cannot do is split a group: `VGEO_FORMAT.md` §11.1 makes a group atomic to its
|
|
59
|
+
* page and the whole activation invariant rests on that. So a build whose clusters group into
|
|
60
|
+
* more bytes than a page holds **throws**, naming the page size that would work, and the remedy
|
|
61
|
+
* is that page size rather than anything about the mesh.
|
|
62
|
+
*
|
|
53
63
|
* @type {number}
|
|
54
64
|
*/
|
|
55
65
|
nominal_page_size: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VGeoBuildOptions.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VGeoBuildOptions.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH;IACI;;;;;;;;;;OAUG;IACH,OAFU,MAAM,CAEO;IAEvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,YAFU,MAAM,CAEE;IAElB;;;;;;;;;;;;;;OAcG;IACH,mBAFU,MAAM,CAE2B;IAE3C;;OAEG;IACH,eAFU,gBAAgB,CAEa;CAC1C;iCA1EgC,uBAAuB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { VGEO_CODEC_LZ4 } from "../format/frame/VGEO_CODEC_LZ4.js";
|
|
2
|
+
import { VGEO_DEFAULT_PAGE_SIZE } from "../format/page/VGEO_DEFAULT_PAGE_SIZE.js";
|
|
2
3
|
import { VGeoLevelOptions } from "./VGeoLevelOptions.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -53,11 +54,21 @@ export class VGeoBuildOptions {
|
|
|
53
54
|
weld_ratio = 1e-5;
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
57
|
+
* Decoded bytes per page, as a **hard cap**: no page of the asset exceeds it, and the container
|
|
58
|
+
* says so with a feature bit a runtime can require (`VGEO_FORMAT.md` §11.14). That is what makes
|
|
59
|
+
* a page slot a fixed stride on the device — a slot address is a multiply, with no allocator, no
|
|
60
|
+
* growth path and no address migration behind it.
|
|
61
|
+
*
|
|
62
|
+
* The cap is kept by splitting bands into more pages, which costs only the internal
|
|
63
|
+
* fragmentation of the last page of each band — measured at about 9% on a 254-page build. The
|
|
64
|
+
* one thing it cannot do is split a group: `VGEO_FORMAT.md` §11.1 makes a group atomic to its
|
|
65
|
+
* page and the whole activation invariant rests on that. So a build whose clusters group into
|
|
66
|
+
* more bytes than a page holds **throws**, naming the page size that would work, and the remedy
|
|
67
|
+
* is that page size rather than anything about the mesh.
|
|
68
|
+
*
|
|
58
69
|
* @type {number}
|
|
59
70
|
*/
|
|
60
|
-
nominal_page_size =
|
|
71
|
+
nominal_page_size = VGEO_DEFAULT_PAGE_SIZE;
|
|
61
72
|
|
|
62
73
|
/**
|
|
63
74
|
* @type {VGeoLevelOptions}
|