@woosh/meep-engine 3.25.0 → 3.27.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/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
- package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
- package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
- package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
- package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
- package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
- package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +66 -0
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.js +314 -20
- 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/physics/cloth/MEASUREMENTS.md +582 -0
- package/src/engine/physics/cloth/PLAN.md +330 -49
- 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/ClothInstance.d.ts +65 -7
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +72 -8
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +25 -4
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +75 -8
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +41 -4
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +207 -63
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +10 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +17 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +27 -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 +28 -3
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +75 -10
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +131 -12
- 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_write_back.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
- package/src/engine/physics/cloth/playground/collide_main.js +1 -1
- 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 +12 -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 +12 -2
- package/src/engine/physics/cloth/solver/cloth_step_instance.js +1 -1
- 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 +23 -9
- package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/AbstractClothWind.js +23 -9
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +7 -5
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/ClothAmbientWind.js +12 -9
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/ClothFluidWind.js +5 -2
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +7 -2
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/cloth_sample_air.js +12 -5
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/vgeo_runtime/README.md +167 -22
- package/src/shade/playground/vgeo_runtime/index.html +112 -62
- package/src/shade/playground/vgeo_runtime/main.js +660 -83
- package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
- package/src/shade/playground/vgeo_viewer/sample_asset.js +19 -2
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +73 -5
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +26 -15
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +5 -3
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +20 -0
- 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 +56 -9
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -0
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -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 +44 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -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 +55 -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 +202 -13
- 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 +147 -10
- package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +637 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +58 -28
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +77 -105
- package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +105 -22
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +47 -489
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1363 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +186 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +20 -8
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +580 -188
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
- 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 +12 -4
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
- package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
- 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 +7 -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 +7 -1
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +59 -4
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
- package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
- package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
- package/src/shade/renderer/view/GPUViewContext.js +21 -0
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
- package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
- package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { assert } from "../../../../../core/assert.js";
|
|
2
2
|
import { graph_read_buffer } from "../../../buffer/graph_read_buffer.js";
|
|
3
|
-
import { VGeoPageWant } from "../format/read/VGeoPageWant.js";
|
|
4
3
|
import { VGEO_CUT_STAT_COUNT } from "./layout/VGEO_CUT_STAT_COUNT.js";
|
|
5
4
|
import { VGEO_FEEDBACK_OFFSET } from "./layout/VGEO_FEEDBACK_OFFSET.js";
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} FrameGraph
|
|
8
|
+
* @typedef {import("./GPUVirtualGeometryRuntime.js").GPUVirtualGeometryRuntime} GPUVirtualGeometryRuntime
|
|
9
|
+
* @typedef {import("./VGeoResidency.js").VGeoResidency} VGeoResidency
|
|
10
|
+
* @typedef {import("./cut/vgeo_cut_feedback_layout.js").vgeo_cut_feedback_layout} vgeo_cut_feedback_layout
|
|
11
|
+
*/
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
14
|
* The other half of the loop: what the cut saw, coming back to the host.
|
|
@@ -14,20 +18,11 @@ import { VGEO_WANT_WORDS } from "./layout/VGEO_WANT_WORDS.js";
|
|
|
14
18
|
* feedback is skipped entirely** when saturated. A loop that insisted on a reading every frame
|
|
15
19
|
* would stall the frame it was reading, which is the failure the cap exists to prevent.
|
|
16
20
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* - **wants** — pages a clamped cluster could not reach, each naming the page it was discovered
|
|
23
|
-
* *through*. That second half is what resolves the byte range without a directory, and it is
|
|
24
|
-
* also the page format §10 asks to be pinned while its child is in flight.
|
|
25
|
-
*
|
|
26
|
-
* A want resolves to one of two very different things, and telling them apart is this class's real
|
|
27
|
-
* work. A page already in RAM is a **VRAM install** and no fetch at all — the bytes are here and
|
|
28
|
-
* the cut simply has not been given them. A page not in RAM is a fetch, handed to the residency
|
|
29
|
-
* manager with its priority so that it competes globally against every other asset's wants rather
|
|
30
|
-
* than within whichever reader asked first.
|
|
21
|
+
* This class is the transport and nothing else: it schedules the readback while the graph is still
|
|
22
|
+
* being built, closes the frame's own layout and frame number over it, keeps the counters the
|
|
23
|
+
* kernel wrote, and hands the words to {@link VGeoResidency.apply}. What a touch or a want means —
|
|
24
|
+
* which tier it lands on, what it costs, what is fetched and what is refused — is the residency's,
|
|
25
|
+
* in one place for both tiers (RUNTIME_PLAN_2026_09_14 §4.7).
|
|
31
26
|
*
|
|
32
27
|
* @author Alex Goldring
|
|
33
28
|
* @copyright Company Named Limited (c) 2026
|
|
@@ -39,7 +34,7 @@ export class VGeoFeedbackLoop {
|
|
|
39
34
|
#runtime;
|
|
40
35
|
|
|
41
36
|
/**
|
|
42
|
-
* @type {
|
|
37
|
+
* @type {VGeoResidency}
|
|
43
38
|
*/
|
|
44
39
|
#residency;
|
|
45
40
|
|
|
@@ -53,11 +48,6 @@ export class VGeoFeedbackLoop {
|
|
|
53
48
|
*/
|
|
54
49
|
#max_in_flight;
|
|
55
50
|
|
|
56
|
-
/**
|
|
57
|
-
* @type {number}
|
|
58
|
-
*/
|
|
59
|
-
#install_budget_bytes;
|
|
60
|
-
|
|
61
51
|
/**
|
|
62
52
|
* @type {number}
|
|
63
53
|
*/
|
|
@@ -74,121 +64,27 @@ export class VGeoFeedbackLoop {
|
|
|
74
64
|
*/
|
|
75
65
|
#stats = new Uint32Array(VGEO_CUT_STAT_COUNT);
|
|
76
66
|
|
|
77
|
-
/**
|
|
78
|
-
* @type {number}
|
|
79
|
-
*/
|
|
80
|
-
#last_want_count = 0;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @type {number}
|
|
84
|
-
*/
|
|
85
|
-
#last_touch_count = 0;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Page indices this loop has asked for and not yet heard back about, per reader.
|
|
89
|
-
*
|
|
90
|
-
* A page stays wanted for as long as it is missing, so the same want arrives every frame until
|
|
91
|
-
* the fetch lands. Without this the shared `ConcurrencyGate` accumulates one closure per frame
|
|
92
|
-
* per wanted page and the RAM budget is charged once per frame for the same bytes.
|
|
93
|
-
*
|
|
94
|
-
* @type {Map<VGeoContainerReader, Set<number>>}
|
|
95
|
-
*/
|
|
96
|
-
#in_flight_pages = new Map();
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* One per batch of fetches still running, so {@link abort} can stop all of them.
|
|
100
|
-
* @type {Set<AbortController>}
|
|
101
|
-
*/
|
|
102
|
-
#controllers = new Set();
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* @type {number}
|
|
106
|
-
*/
|
|
107
|
-
#max_wants_per_frame;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* @type {number}
|
|
111
|
-
*/
|
|
112
|
-
#deduped_wants = 0;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* @type {number}
|
|
116
|
-
*/
|
|
117
|
-
#dropped_wants = 0;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* @type {number}
|
|
121
|
-
*/
|
|
122
|
-
#failed_batches = 0;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Touches and wants naming a page row that was re-used between the cut and this reading.
|
|
126
|
-
* @type {number}
|
|
127
|
-
*/
|
|
128
|
-
#stale_records = 0;
|
|
129
|
-
|
|
130
67
|
/**
|
|
131
68
|
* @param {Object} options
|
|
132
69
|
* @param {GPUVirtualGeometryRuntime} options.runtime
|
|
133
|
-
* @param {
|
|
134
|
-
* @param {number} [options.max_in_flight] readbacks that may be outstanding at once
|
|
135
|
-
*
|
|
136
|
-
* @param {number} [options.max_wants_per_frame] pages one frame may newly ask to fetch, across
|
|
137
|
-
* every reader — see {@link #dispatch_frame}, which is where the "across every reader" is
|
|
138
|
-
* enforced; the rest are dropped and asked for again next frame, which is what a want is
|
|
139
|
-
* for
|
|
70
|
+
* @param {VGeoResidency} options.residency both tiers' owner
|
|
71
|
+
* @param {number} [options.max_in_flight] readbacks that may be outstanding at once; defaults
|
|
72
|
+
* to the residency's option
|
|
140
73
|
*/
|
|
141
|
-
constructor({
|
|
142
|
-
runtime,
|
|
143
|
-
residency,
|
|
144
|
-
max_in_flight = 2,
|
|
145
|
-
install_budget_bytes = 8 * 1024 * 1024,
|
|
146
|
-
max_wants_per_frame = 32,
|
|
147
|
-
}) {
|
|
74
|
+
constructor({ runtime, residency, max_in_flight = undefined }) {
|
|
148
75
|
assert.defined(runtime, 'runtime');
|
|
149
76
|
assert.defined(residency, 'residency');
|
|
150
77
|
|
|
151
78
|
this.#runtime = runtime;
|
|
152
79
|
this.#residency = residency;
|
|
153
|
-
this.#max_in_flight = max_in_flight;
|
|
154
|
-
this.#install_budget_bytes = install_budget_bytes;
|
|
155
|
-
this.#max_wants_per_frame = max_wants_per_frame;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Feedback records naming a page row that had been re-used by the time the reading landed.
|
|
160
|
-
* @returns {number}
|
|
161
|
-
*/
|
|
162
|
-
get stale_record_count() {
|
|
163
|
-
return this.#stale_records;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Wants this loop did not re-submit because the page was already being fetched.
|
|
168
|
-
* @returns {number}
|
|
169
|
-
*/
|
|
170
|
-
get deduped_want_count() {
|
|
171
|
-
return this.#deduped_wants;
|
|
80
|
+
this.#max_in_flight = max_in_flight ?? residency.options.max_readbacks_in_flight;
|
|
172
81
|
}
|
|
173
82
|
|
|
174
83
|
/**
|
|
175
|
-
*
|
|
176
|
-
* @returns {number}
|
|
84
|
+
* @returns {VGeoResidency}
|
|
177
85
|
*/
|
|
178
|
-
get
|
|
179
|
-
return this.#
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Batches every page of which the reader quarantined, plus any that rejected outright.
|
|
184
|
-
*
|
|
185
|
-
* A reader that has stopped answering is the one streaming failure a host can do something
|
|
186
|
-
* about, and it is the one thing a per-page quarantine cannot say on its own.
|
|
187
|
-
*
|
|
188
|
-
* @returns {number}
|
|
189
|
-
*/
|
|
190
|
-
get failed_batch_count() {
|
|
191
|
-
return this.#failed_batches;
|
|
86
|
+
get residency() {
|
|
87
|
+
return this.#residency;
|
|
192
88
|
}
|
|
193
89
|
|
|
194
90
|
/**
|
|
@@ -221,14 +117,22 @@ export class VGeoFeedbackLoop {
|
|
|
221
117
|
* @returns {number}
|
|
222
118
|
*/
|
|
223
119
|
get last_want_count() {
|
|
224
|
-
return this.#last_want_count;
|
|
120
|
+
return this.#residency.last_want_count;
|
|
225
121
|
}
|
|
226
122
|
|
|
227
123
|
/**
|
|
228
124
|
* @returns {number}
|
|
229
125
|
*/
|
|
230
126
|
get last_touch_count() {
|
|
231
|
-
return this.#last_touch_count;
|
|
127
|
+
return this.#residency.last_touch_count;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Records naming a page row that was refilled between the cut and the reading.
|
|
132
|
+
* @returns {number}
|
|
133
|
+
*/
|
|
134
|
+
get stale_record_count() {
|
|
135
|
+
return this.#residency.stale_record_count;
|
|
232
136
|
}
|
|
233
137
|
|
|
234
138
|
/**
|
|
@@ -240,20 +144,6 @@ export class VGeoFeedbackLoop {
|
|
|
240
144
|
read(graph) {
|
|
241
145
|
assert.defined(graph, 'graph');
|
|
242
146
|
|
|
243
|
-
/*
|
|
244
|
-
The RAM tier's clock, moved here rather than left to the host. `advance_frame` is what
|
|
245
|
-
carries the protect window forward, and without it `evict_to_budget` protects everything
|
|
246
|
-
and never drops a page — so the RAM tier is unbounded. Its only non-spec caller was the
|
|
247
|
-
playground (REVIEW_LEDGER M12), which is to say that in any real host the second tier of a
|
|
248
|
-
three-tier design was doing nothing at all.
|
|
249
|
-
|
|
250
|
-
Before the early returns below on purpose: a frame whose feedback is skipped is still a
|
|
251
|
-
frame, and a clock that only advanced on the frames the readback kept up with would make
|
|
252
|
-
the protect window a function of readback latency.
|
|
253
|
-
*/
|
|
254
|
-
this.#residency.advance_frame();
|
|
255
|
-
this.#residency.evict_to_budget();
|
|
256
|
-
|
|
257
147
|
const feedback = this.#runtime.feedback;
|
|
258
148
|
|
|
259
149
|
if (feedback === -1) {
|
|
@@ -268,27 +158,27 @@ export class VGeoFeedbackLoop {
|
|
|
268
158
|
|
|
269
159
|
/*
|
|
270
160
|
Closed over, not looked up again when the reading lands. `begin_frame` recomputes the
|
|
271
|
-
layout every frame out of the page-row high-water mark
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
read wants and touches out of the middle of the stamp region (REVIEW_LEDGER C5).
|
|
161
|
+
layout every frame out of the page-row high-water mark, which moves as pages install — so a
|
|
162
|
+
readback that lands a frame or two later and asked the runtime for "the" layout would
|
|
163
|
+
decode this frame's bytes with a later frame's bases (REVIEW_LEDGER C5).
|
|
275
164
|
*/
|
|
276
165
|
const layout = this.#runtime.feedback_layout;
|
|
277
166
|
|
|
278
167
|
/*
|
|
279
|
-
And the
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
168
|
+
And the frame this reading is about. A row is reused the moment it is freed and this
|
|
169
|
+
reading is at least a frame behind the cut that produced it, so a touch or a want naming
|
|
170
|
+
row 7 may be naming the page that *was* in row 7 (REVIEW_LEDGER M10). The pool stamps every
|
|
171
|
+
row with the frame whose flush publishes its occupant, and the residency compares that per
|
|
172
|
+
record against this number.
|
|
283
173
|
*/
|
|
284
|
-
const
|
|
174
|
+
const reading_frame = this.#runtime.pool.frame;
|
|
285
175
|
|
|
286
176
|
this.#in_flight++;
|
|
287
177
|
|
|
288
178
|
graph_read_buffer({ graph, buffer: feedback, offset: 0, size: layout.word_count * 4 })
|
|
289
179
|
.then(reference => {
|
|
290
180
|
try {
|
|
291
|
-
this.#apply(new Uint32Array(reference.getValue()), layout,
|
|
181
|
+
this.#apply(new Uint32Array(reference.getValue()), layout, reading_frame);
|
|
292
182
|
} finally {
|
|
293
183
|
reference.release();
|
|
294
184
|
}
|
|
@@ -306,365 +196,33 @@ export class VGeoFeedbackLoop {
|
|
|
306
196
|
return true;
|
|
307
197
|
}
|
|
308
198
|
|
|
309
|
-
/**
|
|
310
|
-
* @returns {Uint32Array} one generation per page row that could appear in this frame's feedback
|
|
311
|
-
*/
|
|
312
|
-
#snapshot_generations() {
|
|
313
|
-
const tables = this.#runtime.pool.tables;
|
|
314
|
-
|
|
315
|
-
const count = this.#runtime.pool.page_row_capacity;
|
|
316
|
-
|
|
317
|
-
const generations = new Uint32Array(count);
|
|
318
|
-
|
|
319
|
-
for (let row = 0; row < count; row++) {
|
|
320
|
-
generations[row] = tables.generation_of(row);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return generations;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Whether a page row still holds the page it held when the cut ran.
|
|
328
|
-
*
|
|
329
|
-
* @param {number} page_row
|
|
330
|
-
* @param {Uint32Array} generations
|
|
331
|
-
* @returns {boolean}
|
|
332
|
-
*/
|
|
333
|
-
#still_the_same_page(page_row, generations) {
|
|
334
|
-
if (page_row >= generations.length) {
|
|
335
|
-
// a row that did not exist when the graph was built cannot be one this cut named
|
|
336
|
-
return false;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return this.#runtime.pool.tables.generation_of(page_row) === generations[page_row];
|
|
340
|
-
}
|
|
341
|
-
|
|
342
199
|
/**
|
|
343
200
|
* @param {Uint32Array} words
|
|
344
201
|
* @param {ReturnType<vgeo_cut_feedback_layout>} layout the frame's own, not the current one
|
|
345
|
-
* @param {
|
|
202
|
+
* @param {number} reading_frame the frame this reading is about
|
|
346
203
|
*/
|
|
347
|
-
#apply(words, layout,
|
|
348
|
-
const pool = this.#runtime.pool;
|
|
349
|
-
|
|
204
|
+
#apply(words, layout, reading_frame) {
|
|
350
205
|
for (let i = 0; i < VGEO_CUT_STAT_COUNT; i++) {
|
|
351
206
|
this.#stats[i] = words[VGEO_FEEDBACK_OFFSET.STATS + i];
|
|
352
207
|
}
|
|
353
208
|
|
|
354
|
-
|
|
355
|
-
Clamped, because the count is an `atomicAdd` that ran past the capacity the kernel then
|
|
356
|
-
refused to write at. Reading it unclamped would read the words after the list, which are
|
|
357
|
-
whatever the pool's transient buffer held before this frame.
|
|
358
|
-
*/
|
|
359
|
-
const touch_count = Math.min(
|
|
360
|
-
words[VGEO_FEEDBACK_OFFSET.TOUCH_COUNT], layout.word_count - layout.touch_base
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
this.#last_touch_count = touch_count;
|
|
364
|
-
this.#last_want_count = Math.min(
|
|
365
|
-
words[VGEO_FEEDBACK_OFFSET.WANT_COUNT],
|
|
366
|
-
Math.floor((layout.touch_base - layout.want_base) / VGEO_WANT_WORDS)
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
for (let i = 0; i < touch_count; i++) {
|
|
370
|
-
const page_row = words[layout.touch_base + i];
|
|
371
|
-
|
|
372
|
-
const entry = pool.entry_of(page_row);
|
|
373
|
-
|
|
374
|
-
if (entry === undefined) {
|
|
375
|
-
// evicted between the cut and the reading; the stamp it would have taken is moot
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (!this.#still_the_same_page(page_row, generations)) {
|
|
380
|
-
/*
|
|
381
|
-
Evicted *and refilled* in between. Stamping now would tell both tiers' LRU that a
|
|
382
|
-
page nobody has drawn is the hottest thing in the cache, and it would do it at
|
|
383
|
-
exactly the moment a page was streaming in.
|
|
384
|
-
*/
|
|
385
|
-
this.#stale_records++;
|
|
386
|
-
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
pool.touch(page_row);
|
|
391
|
-
|
|
392
|
-
this.#residency.touch(
|
|
393
|
-
entry.reader, pool.tables.page_field(page_row, VGEO_PAGE_ROW_OFFSET.PAGE_INDEX)
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Wants that need bytes, per reader — the residency manager takes them a reader at a time
|
|
399
|
-
* because a reader is what owns a fetch, and orders them globally because a priority in
|
|
400
|
-
* pixels of error is comparable across assets by construction.
|
|
401
|
-
* @type {Map<VGeoContainerReader, VGeoPageWant[]>}
|
|
402
|
-
*/
|
|
403
|
-
const fetches = new Map();
|
|
404
|
-
|
|
405
|
-
let promoted = 0;
|
|
406
|
-
|
|
407
|
-
for (let i = 0; i < this.#last_want_count; i++) {
|
|
408
|
-
const base = layout.want_base + i * VGEO_WANT_WORDS;
|
|
409
|
-
|
|
410
|
-
const source_row = words[base];
|
|
411
|
-
const child_ref = words[base + 1];
|
|
412
|
-
const child_page_index = words[base + 2];
|
|
413
|
-
const priority = new Float32Array(new Uint32Array([words[base + 3]]).buffer)[0];
|
|
414
|
-
|
|
415
|
-
const entry = pool.entry_of(source_row);
|
|
416
|
-
|
|
417
|
-
if (entry === undefined) {
|
|
418
|
-
continue;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (!this.#still_the_same_page(source_row, generations)) {
|
|
422
|
-
/*
|
|
423
|
-
The row was reused between the cut and this reading, so the page index below and
|
|
424
|
-
the byte range the child table would give come from two different pages — a fetch
|
|
425
|
-
aimed at a page nobody asked for, charged to the RAM budget, at the priority of a
|
|
426
|
-
cluster in an unrelated part of the asset.
|
|
427
|
-
*/
|
|
428
|
-
this.#stale_records++;
|
|
429
|
-
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const reader = entry.reader;
|
|
434
|
-
|
|
435
|
-
const source_index = pool.tables.page_field(source_row, VGEO_PAGE_ROW_OFFSET.PAGE_INDEX);
|
|
436
|
-
|
|
437
|
-
const source = reader.page(source_index);
|
|
438
|
-
|
|
439
|
-
if (source === undefined || child_ref >= source.child_page_index.length) {
|
|
440
|
-
continue;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (reader.is_resident(child_page_index)) {
|
|
444
|
-
/*
|
|
445
|
-
The bytes are already in RAM, so this is not a fetch at all — the cut is clamping
|
|
446
|
-
because the page has not been promoted to VRAM yet. Budgeted per frame, because a
|
|
447
|
-
camera that suddenly wants a hundred pages should get them over several frames
|
|
448
|
-
rather than in one hitch.
|
|
449
|
-
*/
|
|
450
|
-
if (promoted < this.#install_budget_bytes) {
|
|
451
|
-
if (pool.install(reader, child_page_index) !== -1) {
|
|
452
|
-
promoted += source.child_decoded_size[child_ref];
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
continue;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
const want = new VGeoPageWant();
|
|
460
|
-
|
|
461
|
-
want.page_index = child_page_index;
|
|
462
|
-
want.frame_offset = source.child_frame_offset[child_ref];
|
|
463
|
-
want.fetch_size = source.child_fetch_size[child_ref];
|
|
464
|
-
want.decoded_size = source.child_decoded_size[child_ref];
|
|
465
|
-
want.priority = priority;
|
|
466
|
-
want.reference_count = 1;
|
|
467
|
-
|
|
468
|
-
const list = fetches.get(reader) ?? [];
|
|
469
|
-
|
|
470
|
-
list.push(want);
|
|
471
|
-
|
|
472
|
-
fetches.set(reader, list);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
this.#dispatch_frame(fetches);
|
|
209
|
+
this.#residency.apply(words, layout, reading_frame);
|
|
476
210
|
}
|
|
477
211
|
|
|
478
212
|
/**
|
|
479
|
-
*
|
|
480
|
-
* to the frame's limit.
|
|
481
|
-
*
|
|
482
|
-
* **Across every reader, which is what the option has always said and not what it did.**
|
|
483
|
-
* `max_wants_per_frame` was applied inside {@link #dispatch_wants}, once per reader, so a frame
|
|
484
|
-
* seeing eight streaming assets issued eight times the limit — the shape
|
|
485
|
-
* `VGeoResidencyManager`'s own doc records being measured at 48 concurrent range requests
|
|
486
|
-
* against a cap of 6, and the reason its gate is shared. One frame, one budget.
|
|
487
|
-
*
|
|
488
|
-
* Ranked across readers for the same reason the gate is shared: a want's priority is pixels of
|
|
489
|
-
* projected error past the threshold, which is comparable across assets by construction. So the
|
|
490
|
-
* frame's budget goes to the worst coarseness on screen wherever it came from, rather than to
|
|
491
|
-
* whichever reader this frame's touch list happened to name first.
|
|
492
|
-
*
|
|
493
|
-
* @param {Map<VGeoContainerReader, VGeoPageWant[]>} fetches
|
|
494
|
-
*/
|
|
495
|
-
#dispatch_frame(fetches) {
|
|
496
|
-
/**
|
|
497
|
-
* @type {{reader: VGeoContainerReader, want: VGeoPageWant}[]}
|
|
498
|
-
*/
|
|
499
|
-
const fresh = [];
|
|
500
|
-
|
|
501
|
-
for (const [reader, wants] of fetches) {
|
|
502
|
-
const in_flight = this.#in_flight_of(reader);
|
|
503
|
-
|
|
504
|
-
for (const want of wants) {
|
|
505
|
-
if (in_flight.has(want.page_index)) {
|
|
506
|
-
this.#deduped_wants++;
|
|
507
|
-
|
|
508
|
-
continue;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
fresh.push({ reader, want });
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (fresh.length === 0) {
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
fresh.sort((a, b) => b.want.priority - a.want.priority);
|
|
520
|
-
|
|
521
|
-
const batch = fresh.slice(0, this.#max_wants_per_frame);
|
|
522
|
-
|
|
523
|
-
this.#dropped_wants += fresh.length - batch.length;
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Back into per-reader lists, because a reader is what owns a fetch.
|
|
527
|
-
* @type {Map<VGeoContainerReader, VGeoPageWant[]>}
|
|
528
|
-
*/
|
|
529
|
-
const by_reader = new Map();
|
|
530
|
-
|
|
531
|
-
for (const { reader, want } of batch) {
|
|
532
|
-
const list = by_reader.get(reader) ?? [];
|
|
533
|
-
|
|
534
|
-
list.push(want);
|
|
535
|
-
|
|
536
|
-
by_reader.set(reader, list);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
for (const [reader, wants] of by_reader) {
|
|
540
|
-
this.#dispatch_wants(reader, wants);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* @param {VGeoContainerReader} reader
|
|
546
|
-
* @returns {Set<number>} page indices this loop has asked that reader for and not heard back
|
|
547
|
-
*/
|
|
548
|
-
#in_flight_of(reader) {
|
|
549
|
-
let in_flight = this.#in_flight_pages.get(reader);
|
|
550
|
-
|
|
551
|
-
if (in_flight === undefined) {
|
|
552
|
-
in_flight = new Set();
|
|
553
|
-
|
|
554
|
-
this.#in_flight_pages.set(reader, in_flight);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
return in_flight;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
/**
|
|
561
|
-
* Hand one reader's share of this frame's batch to the residency manager.
|
|
562
|
-
*
|
|
563
|
-
* This was `install_wants(...).catch(() => {})` and nothing else, which costs three things that
|
|
564
|
-
* compound rather than three separate ones. A page still wanted while its fetch is in flight is
|
|
565
|
-
* re-submitted **every frame**, so the shared `ConcurrencyGate` accumulates one stale closure
|
|
566
|
-
* per frame per wanted page and the RAM budget is charged for the same page over and over. A
|
|
567
|
-
* batch that is still running when the next arrives has no way to be told to stop. And an empty
|
|
568
|
-
* catch turns a reader that has quarantined every page it was asked for into silence
|
|
569
|
-
* (REVIEW_LEDGER M11).
|
|
570
|
-
*
|
|
571
|
-
* So: a page already in flight is not asked for again, the whole batch carries one
|
|
572
|
-
* `AbortSignal` that {@link abort} can pull, and a failure is counted and reported once rather
|
|
573
|
-
* than swallowed once per frame. The dedup and the frame's limit are {@link #dispatch_frame}'s,
|
|
574
|
-
* one level up, because both are properties of the frame rather than of a reader.
|
|
575
|
-
*
|
|
576
|
-
* @param {VGeoContainerReader} reader
|
|
577
|
-
* @param {VGeoPageWant[]} batch already deduped and inside this frame's limit
|
|
578
|
-
*/
|
|
579
|
-
#dispatch_wants(reader, batch) {
|
|
580
|
-
const in_flight = this.#in_flight_of(reader);
|
|
581
|
-
|
|
582
|
-
for (const want of batch) {
|
|
583
|
-
in_flight.add(want.page_index);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
const controller = new AbortController();
|
|
587
|
-
|
|
588
|
-
this.#controllers.add(controller);
|
|
589
|
-
|
|
590
|
-
this.#residency.install_wants(reader, batch, batch.length, controller.signal)
|
|
591
|
-
.then(() => {
|
|
592
|
-
if (controller.signal.aborted) {
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
/*
|
|
597
|
-
A failed fetch does not come back as a rejection. `VGeoResidencyManager` catches it
|
|
598
|
-
per page — the cut stands without any one page, which is the whole point of a
|
|
599
|
-
clamped cut — so a `.catch` here sees only a programming error, and the campaign
|
|
600
|
-
closed M11 with the reporting on exactly that branch. A reader that has quarantined
|
|
601
|
-
every page asked of it was therefore still silent (re-review 2026-09-12).
|
|
602
|
-
|
|
603
|
-
The reader's quarantine is where the fact lives, so that is what is read. Every
|
|
604
|
-
page of the batch quarantined is an asset that cannot be streamed at all, which is
|
|
605
|
-
the condition worth one line in the console; a page or two is ordinary attrition
|
|
606
|
-
and is on `VGeoResidencyManager.quarantined_page_count` for whoever is watching.
|
|
607
|
-
*/
|
|
608
|
-
let quarantined = 0;
|
|
609
|
-
|
|
610
|
-
for (const want of batch) {
|
|
611
|
-
if (reader.is_quarantined(want.page_index)) {
|
|
612
|
-
quarantined++;
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
if (quarantined < batch.length) {
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
this.#failed_batches++;
|
|
621
|
-
|
|
622
|
-
// once per batch, not once per frame per page: the dedup one level up is what makes
|
|
623
|
-
// that difference, and a reader that has quarantined everything asked of it is a
|
|
624
|
-
// fact somebody has to be able to see
|
|
625
|
-
console.warn(
|
|
626
|
-
`vgeo: every one of ${batch.length} page fetches was quarantined`
|
|
627
|
-
+ ` by ${reader.name ?? 'a reader'}`
|
|
628
|
-
);
|
|
629
|
-
})
|
|
630
|
-
.catch(error => {
|
|
631
|
-
if (controller.signal.aborted) {
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
this.#failed_batches++;
|
|
636
|
-
|
|
637
|
-
console.warn('vgeo: a batch of page fetches failed', error);
|
|
638
|
-
})
|
|
639
|
-
.finally(() => {
|
|
640
|
-
this.#controllers.delete(controller);
|
|
641
|
-
|
|
642
|
-
for (const want of batch) {
|
|
643
|
-
in_flight.delete(want.page_index);
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* Stop every fetch this loop started.
|
|
213
|
+
* Stop every fetch the residency has on the wire.
|
|
650
214
|
*
|
|
651
215
|
* @returns {void}
|
|
652
216
|
*/
|
|
653
217
|
abort() {
|
|
654
|
-
|
|
655
|
-
controller.abort();
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
this.#controllers.clear();
|
|
659
|
-
this.#in_flight_pages.clear();
|
|
218
|
+
this.#residency.abort();
|
|
660
219
|
}
|
|
661
220
|
|
|
662
221
|
/**
|
|
663
222
|
* Give up on this loop: the same as {@link abort}, under the name a host tears things down by.
|
|
664
223
|
*
|
|
665
224
|
* The loop owns no device resource, so there is nothing else to release — what it owns is
|
|
666
|
-
* outstanding *work
|
|
667
|
-
* transient control ("stop what is in flight, carry on") while a teardown is final.
|
|
225
|
+
* outstanding *work*.
|
|
668
226
|
*
|
|
669
227
|
* @returns {void}
|
|
670
228
|
*/
|