@woosh/meep-engine 3.28.0 → 3.30.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/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +14 -2
- package/src/core/binary/BitSet.d.ts +16 -0
- package/src/core/binary/BitSet.d.ts.map +1 -1
- package/src/core/binary/BitSet.js +159 -49
- package/src/core/binary/allocator/OffsetAllocator.d.ts +48 -0
- package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
- package/src/core/binary/allocator/OffsetAllocator.js +208 -9
- package/src/core/binary/compression/compress_bytes.d.ts +20 -0
- package/src/core/binary/compression/compress_bytes.d.ts.map +1 -0
- package/src/core/binary/compression/compress_bytes.js +35 -0
- package/src/core/binary/compression/decompress_bytes_into.d.ts +30 -0
- package/src/core/binary/compression/decompress_bytes_into.d.ts.map +1 -0
- package/src/core/binary/compression/decompress_bytes_into.js +87 -0
- package/src/core/binary/compression/deflate_decompress_bound.d.ts +27 -0
- package/src/core/binary/compression/deflate_decompress_bound.d.ts.map +1 -0
- package/src/core/binary/compression/deflate_decompress_bound.js +32 -0
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +14 -1
- package/src/core/cache/FrequencySketch.d.ts +3 -1
- package/src/core/cache/FrequencySketch.d.ts.map +1 -1
- package/src/core/cache/FrequencySketch.js +10 -4
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
- package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
- package/src/core/geom/3d/quadric/quadric_attribute_add.d.ts +24 -0
- package/src/core/geom/3d/quadric/quadric_attribute_add.d.ts.map +1 -0
- package/src/core/geom/3d/quadric/quadric_attribute_add.js +31 -0
- package/src/core/geom/3d/quadric/quadric_attribute_reduce.d.ts +46 -0
- package/src/core/geom/3d/quadric/quadric_attribute_reduce.d.ts.map +1 -0
- package/src/core/geom/3d/quadric/quadric_attribute_reduce.js +104 -0
- package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.d.ts +62 -0
- package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.d.ts.map +1 -0
- package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.js +158 -0
- package/src/core/geom/3d/quadric/quadric_attribute_size.d.ts +21 -0
- package/src/core/geom/3d/quadric/quadric_attribute_size.d.ts.map +1 -0
- package/src/core/geom/3d/quadric/quadric_attribute_size.js +24 -0
- package/src/core/geom/3d/quadric/quadric_attribute_solve.d.ts +34 -0
- package/src/core/geom/3d/quadric/quadric_attribute_solve.d.ts.map +1 -0
- package/src/core/geom/3d/quadric/quadric_attribute_solve.js +55 -0
- package/src/core/geom/3d/quadric/quadric_attribute_sub.d.ts +28 -0
- package/src/core/geom/3d/quadric/quadric_attribute_sub.d.ts.map +1 -0
- package/src/core/geom/3d/quadric/quadric_attribute_sub.js +35 -0
- package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.d.ts +15 -0
- package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.js +35 -0
- package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.d.ts +93 -0
- package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.js +128 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts +38 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +113 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +93 -17
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +930 -69
- package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.d.ts +22 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.js +46 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.d.ts +19 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.js +49 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
- package/src/core/graph/layout/layered/BoxLayoutOptions.d.ts +63 -0
- package/src/core/graph/layout/layered/BoxLayoutOptions.d.ts.map +1 -0
- package/src/core/graph/layout/layered/BoxLayoutOptions.js +80 -0
- package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/LayoutBoxGraph.d.ts +35 -0
- package/src/core/graph/layout/layered/LayoutBoxGraph.d.ts.map +1 -0
- package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/LayoutBoxGraph.js +53 -1
- package/src/core/graph/layout/layered/layout_assign_coordinates.d.ts.map +1 -0
- package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_coordinates.js +72 -68
- package/src/core/graph/layout/layered/layout_assign_layers.d.ts.map +1 -0
- package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_layers.js +4 -2
- package/src/core/graph/layout/layered/layout_break_cycles.d.ts.map +1 -0
- package/src/core/graph/layout/layered/layout_insert_lanes.d.ts.map +1 -0
- package/src/core/graph/layout/layered/layout_order_layers.d.ts.map +1 -0
- package/src/core/graph/layout/layered/layout_orient_links.d.ts.map +1 -0
- package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
- package/src/core/math/lookup/ParameterLookupTable.js +10 -5
- package/src/core/math/noise/sdnoise.d.ts.map +1 -1
- package/src/core/math/noise/sdnoise.js +16 -10
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +7 -51
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +8 -69
- package/src/core/model/node-graph/visual/layout/layout_build_problem.js +1 -1
- package/src/core/model/node-graph/visual/layout/layout_node_graph.js +6 -6
- package/src/core/model/node-graph/visual/layout/route_grid_build.js +1 -1
- package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
- package/src/core/model/object/ImmutableObjectPool.js +17 -7
- package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +95 -1
- package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
- package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
- package/src/core/process/task/task_find_dependency_cycle.js +81 -0
- package/src/core/wfc/WFCCellChoice.d.ts +17 -0
- package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
- package/src/core/wfc/WFCCellChoice.js +36 -0
- package/src/core/wfc/WFCLattice.d.ts +105 -0
- package/src/core/wfc/WFCLattice.d.ts.map +1 -0
- package/src/core/wfc/WFCLattice.js +235 -0
- package/src/core/wfc/WFCRuleTable.d.ts +172 -0
- package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
- package/src/core/wfc/WFCRuleTable.js +334 -0
- package/src/core/wfc/WFCState.d.ts +273 -0
- package/src/core/wfc/WFCState.d.ts.map +1 -0
- package/src/core/wfc/WFCState.js +552 -0
- package/src/core/wfc/WFCStatus.d.ts +11 -0
- package/src/core/wfc/WFCStatus.d.ts.map +1 -0
- package/src/core/wfc/WFCStatus.js +28 -0
- package/src/core/wfc/WFCTileWeights.d.ts +48 -0
- package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
- package/src/core/wfc/WFCTileWeights.js +86 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
- package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
- package/src/core/wfc/wfc_estimate_bytes.js +47 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
- package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
- package/src/core/wfc/wfc_solve.d.ts +21 -0
- package/src/core/wfc/wfc_solve.d.ts.map +1 -0
- package/src/core/wfc/wfc_solve.js +154 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
- package/src/core/wfc/wfc_state_assign.d.ts +11 -0
- package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_assign.js +36 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_ban_bits.js +81 -0
- package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
- package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_collapse.js +73 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
- package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
- package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_propagate.js +155 -0
- package/src/core/wfc/wfc_state_read.d.ts +11 -0
- package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_read.js +38 -0
- package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
- package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_restrict.js +39 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_set_eligible.js +49 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_undo_to.js +84 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
- package/src/core/wfc/wfc_words_per_cell.js +16 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +37 -14
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
- package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
- package/src/engine/ecs/guid/UUID.js +45 -17
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
- package/src/engine/graphics3/DebugDrawSystem.d.ts +7 -5
- package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DebugDrawSystem.js +206 -203
- package/src/engine/graphics3/DecalSystem.d.ts +4 -5
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +5 -5
- package/src/engine/graphics3/FogOfWarSystem.d.ts +7 -12
- package/src/engine/graphics3/FogOfWarSystem.d.ts.map +1 -1
- package/src/engine/graphics3/FogOfWarSystem.js +8 -12
- package/src/engine/graphics3/prefab/prefab_instantiate.js +230 -230
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
- package/src/engine/interpolation/Interpoland.d.ts +7 -1
- package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/Interpoland.js +8 -1
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +3 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
- package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/pose_interpoland.js +2 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
- package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
- package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
- package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
- package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
- package/src/format/image/avif/av1/util/round2.d.ts +19 -2
- package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
- package/src/format/image/avif/av1/util/round2.js +51 -27
- package/src/format/image/avif/heif/parse_avif_file.js +24 -0
- package/src/shade/RENDERER_CONTRACT.md +12 -7
- package/src/shade/playground/caldera/README.md +529 -0
- package/src/shade/playground/caldera/caldera_format.d.ts +151 -0
- package/src/shade/playground/caldera/caldera_format.d.ts.map +1 -0
- package/src/shade/playground/caldera/caldera_format.js +241 -0
- package/src/shade/playground/caldera/index.html +126 -0
- package/src/shade/playground/caldera/main.d.ts.map +1 -0
- package/src/shade/playground/caldera/main.js +1565 -0
- package/src/shade/playground/mesh_row_ceiling/README.md +85 -0
- package/src/shade/playground/mesh_row_ceiling/index.html +31 -0
- package/src/shade/playground/mesh_row_ceiling/main.d.ts +2 -0
- package/src/shade/playground/mesh_row_ceiling/main.d.ts.map +1 -0
- package/src/shade/playground/mesh_row_ceiling/main.js +389 -0
- package/src/shade/playground/vgeo_runtime/README.md +5 -3
- package/src/shade/playground/vgeo_runtime/main.js +3 -2
- package/src/shade/playground/vgeo_runtime/sample_asset.d.ts +3 -3
- package/src/shade/playground/vgeo_runtime/sample_asset.d.ts.map +1 -1
- package/src/shade/playground/vgeo_runtime/sample_asset.js +3 -3
- package/src/shade/playground/vgeo_scene/README.md +103 -24
- package/src/shade/playground/vgeo_scene/main.js +525 -24
- package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
- package/src/shade/renderer/GraphicsContext.js +6 -0
- package/src/shade/renderer/Renderer.d.ts +2 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +23 -0
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +100 -8
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
- package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +69 -33
- package/src/shade/renderer/extension/RenderExtension.d.ts +15 -18
- package/src/shade/renderer/extension/RenderExtension.d.ts.map +1 -1
- package/src/shade/renderer/extension/RenderExtension.js +15 -19
- package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts +5 -5
- package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts.map +1 -1
- package/src/shade/renderer/extension/RenderExtensionRegistry.js +29 -166
- package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/GPUGeometryManager.js +73 -16
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +18 -3
- package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +663 -0
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +100 -5
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +688 -81
- package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +540 -0
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +155 -64
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +76 -16
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +3 -3
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +448 -0
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +44 -7
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +48 -9
- package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.d.ts +40 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.js +24 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts +91 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.js +91 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.d.ts +24 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.js +25 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts +77 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.js +84 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts +19 -6
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.js +20 -7
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.d.ts +19 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.js +58 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.js +116 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +545 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts +16 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +110 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts +2 -27
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.js +120 -1564
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.d.ts +26 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.js +123 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.d.ts +26 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.js +78 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts +24 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.js +337 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts +29 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.js +147 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.d.ts +37 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.js +243 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts +29 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.js +117 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts +46 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +74 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +78 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts +12 -7
- package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.js +33 -11
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.d.ts +58 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.js +79 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.d.ts +39 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.js +68 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.d.ts +53 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.js +243 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +32 -7
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +243 -24
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts +12 -8
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.js +58 -50
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +5 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +13 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.d.ts +38 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.js +81 -0
- package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts +23 -5
- package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.js +28 -21
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set.js +1 -1
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.js +224 -60
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.js +17 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.js +19 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts +10 -1
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.js +103 -9
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts +14 -2
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.js +38 -14
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts +6 -2
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +27 -4
- package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.d.ts +32 -0
- package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.js +93 -0
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +20 -6
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +22 -8
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_corner.d.ts +16 -0
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_corner.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/attribute/{vgeo_layers_copy_vertex.js → vgeo_layers_copy_corner.js} +8 -8
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.d.ts +18 -7
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.js +19 -8
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.d.ts +3 -3
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.js +3 -3
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.d.ts +27 -0
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.js +97 -0
- package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.d.ts +7 -3
- package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.js +21 -11
- package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.d.ts +21 -0
- package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.js +41 -0
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +19 -1
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +20 -1
- package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.d.ts +25 -0
- package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.js +24 -0
- package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.d.ts +5 -0
- package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.js +5 -0
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.js +5 -0
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.d.ts +10 -3
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.js +37 -3
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +21 -13
- 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 +37 -13
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.d.ts +8 -2
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.js +14 -2
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +18 -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 +19 -1
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_OFFSET.js +6 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.d.ts +21 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.js +20 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.js +10 -1
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +1 -2
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +10 -3
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.js +43 -0
- package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts +4 -2
- package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +8 -4
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +2 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.d.ts +6 -4
- package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.js +6 -4
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +13 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +13 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +5 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +14 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.d.ts +4 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.js +53 -11
- 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 +7 -3
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts +12 -2
- 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 +111 -33
- package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts +6 -2
- 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 +112 -42
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts +2 -2
- 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 +51 -21
- package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +385 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +9 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
- 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 +34 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.js +18 -0
- 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 +47 -19
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +22 -4
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +7 -2
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +8 -3
- 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 +10 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +13 -11
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +13 -11
- 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 +4 -0
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
- 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 +3 -4
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +6 -2
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +90 -12
- package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts +22 -0
- package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.js +21 -0
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
- package/src/shade/renderer/particles/DESIGN.md +14 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +8 -2
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +13 -8
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +3 -6
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
- 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 +4 -12
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +0 -2
- 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 +4 -5
- 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 +5 -3
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.js +11 -4
- 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 +4 -3
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.js +3 -0
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +94 -90
- 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 +13 -5
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +96 -89
- package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.js +3 -1
- package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_two_way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_two_way.js +4 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +100 -89
- package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.js +31 -7
- 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 +1 -7
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +161 -153
- 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 +2 -7
- 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 +19 -2
- 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 +4 -8
- 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 +5 -8
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
- package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.d.ts +25 -0
- package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.js +24 -0
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +10 -0
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +30 -21
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
- package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
- package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipManager.js +22 -0
- package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipObserver.js +13 -3
- package/src/core/model/node-graph/visual/layout/LayoutBoxGraph.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/layout_assign_layers.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/layout_break_cycles.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/layout_orient_links.d.ts.map +0 -1
- package/src/shade/playground/vgeo_viewer/cut_geometry.d.ts +0 -61
- package/src/shade/playground/vgeo_viewer/cut_geometry.d.ts.map +0 -1
- package/src/shade/playground/vgeo_viewer/main.d.ts.map +0 -1
- package/src/shade/playground/vgeo_viewer/sample_asset.d.ts +0 -18
- package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +0 -1
- package/src/shade/playground/vgeo_viewer/select_cut.d.ts +0 -173
- package/src/shade/playground/vgeo_viewer/select_cut.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.d.ts +0 -52
- package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.d.ts +0 -24
- package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoLevel.d.ts +0 -32
- package/src/shade/renderer/geometry/virtual/build/VGeoLevel.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.d.ts +0 -59
- package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.d.ts +0 -44
- package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.d.ts +0 -20
- package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.d.ts +0 -73
- package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts +0 -13
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.d.ts +0 -12
- package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.d.ts +0 -36
- package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.d.ts +0 -13
- package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.d.ts +0 -19
- package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.d.ts +0 -29
- package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.d.ts +0 -31
- package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.d.ts +0 -18
- package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.d.ts +0 -14
- package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.d.ts +0 -12
- package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.d.ts +0 -14
- package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.d.ts +0 -11
- package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.d.ts +0 -46
- package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts +0 -22
- package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.d.ts +0 -29
- package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.d.ts +0 -9
- package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.d.ts +0 -10
- package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.d.ts +0 -15
- package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.d.ts +0 -16
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.d.ts.map +0 -1
- package/src/shade/renderer/loader/gltf/fix_up_material_sides.d.ts +0 -10
- package/src/shade/renderer/loader/gltf/fix_up_material_sides.d.ts.map +0 -1
- package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.d.ts +0 -17
- package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.d.ts.map +0 -1
- package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.d.ts +0 -3
- package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.d.ts.map +0 -1
- package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.d.ts +0 -8
- package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.d.ts.map +0 -1
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_coordinates.d.ts +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_layers.d.ts +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_break_cycles.d.ts +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_break_cycles.js +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_insert_lanes.d.ts +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_insert_lanes.js +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_order_layers.d.ts +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_order_layers.js +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_orient_links.d.ts +0 -0
- /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_orient_links.js +0 -0
- /package/src/shade/playground/{vgeo_viewer → caldera}/main.d.ts +0 -0
|
@@ -4,12 +4,8 @@ import {
|
|
|
4
4
|
allocator_run_size_for,
|
|
5
5
|
OffsetAllocator
|
|
6
6
|
} from "../../../../core/binary/allocator/OffsetAllocator.js";
|
|
7
|
-
import { BinaryBuffer } from "../../../../core/binary/BinaryBuffer.js";
|
|
8
|
-
import { platform_compute_endianness } from "../../../../core/binary/platform_compute_endianness.js";
|
|
9
7
|
import Signal from "../../../../core/events/signal/Signal.js";
|
|
10
8
|
import { MEGABYTE } from "../../../../core/science/units/memory/MEGABYTE.js";
|
|
11
|
-
import { read_wgsl_type_value } from "../../shader/type/serde/read_gpu_typed_buffer.js";
|
|
12
|
-
import { write_wgsl_type_value } from "../../shader/type/serde/write_gpu_typed_buffer.js";
|
|
13
9
|
import { inspect_gpu_buffer_typed } from "../../buffer/inspect_gpu_buffer_typed.js";
|
|
14
10
|
import {
|
|
15
11
|
BUFFER_INTRA_COPY_REGION_STRUCT,
|
|
@@ -50,6 +46,121 @@ const DEFAULT_DATA_CAPACITY = 32 * MEGABYTE;
|
|
|
50
46
|
*/
|
|
51
47
|
const ALLOCATION_LIMIT = 128 * 1024;
|
|
52
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Where a row's `address` sits, in words. The patch that places a batch adds the allocation offset
|
|
51
|
+
* to this word of every row and copies the rest as bytes — which is only right while the row is
|
|
52
|
+
* packed and the field is where the struct says (`GPUMeshletManager.spec.js` pins both).
|
|
53
|
+
* @type {number}
|
|
54
|
+
*/
|
|
55
|
+
const METADATA_ROW_WORDS = MESHLET_METADATA_STRUCT.aligned_size >>> 2;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The most records one {@link GPUMeshletManager#sweep} moves. A move is an O(1) slide in the
|
|
59
|
+
* allocator, four copy encodes, `meshlet_count` pairs in a patch table and one `changed`
|
|
60
|
+
* dispatch, so this bounds the main-thread cost of a sweep per frame by a count that does not
|
|
61
|
+
* grow with the resident set (COMPACTION_PLAN_2026_09_16 §3, §4.3).
|
|
62
|
+
* @type {number}
|
|
63
|
+
*/
|
|
64
|
+
export const MESHLET_SWEEP_MOVE_BUDGET = 64;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The most words one sweep copies, data and rows together — 4 MB of GPU copy through the staging
|
|
68
|
+
* buffer. Whichever of the two budgets is met first ends the call, but never before one move
|
|
69
|
+
* when one is possible: a single record larger than this still moves, once.
|
|
70
|
+
* @type {number}
|
|
71
|
+
*/
|
|
72
|
+
export const MESHLET_SWEEP_WORD_BUDGET = 1024 * 1024;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The most cursor steps one sweep takes, moves or not. A step that moves nothing — a hole the
|
|
76
|
+
* cursor was stepped back for that an allocation has since filled — is a link walk.
|
|
77
|
+
* @type {number}
|
|
78
|
+
*/
|
|
79
|
+
export const MESHLET_SWEEP_STEP_BUDGET = 4096;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* A removal that leaves at least this much of an arena free *in pieces* — free space less the
|
|
83
|
+
* largest free run — and at least an eighth of the arena that way, arms the sweep by itself.
|
|
84
|
+
*
|
|
85
|
+
* A sweep armed only by a refusal reclaims the space after the growth it could have prevented,
|
|
86
|
+
* and the next fill carves that tail before the next large arrival. Armed on scatter, the tail
|
|
87
|
+
* is clear by the time something needs it, at a cost bounded per frame as ever and proportional
|
|
88
|
+
* to the churn in total. Under a churn of one class the holes are recycled as fast as they are
|
|
89
|
+
* made and the scatter stays below the eighth; this is for a pool that thins.
|
|
90
|
+
* In words for the data arena; the row arena's floor is {@link MESHLET_SWEEP_SCATTER_MINIMUM_ROWS}.
|
|
91
|
+
* @type {number}
|
|
92
|
+
*/
|
|
93
|
+
export const MESHLET_SWEEP_SCATTER_MINIMUM_WORDS = 16 * 1024;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @type {number}
|
|
97
|
+
*/
|
|
98
|
+
export const MESHLET_SWEEP_SCATTER_MINIMUM_ROWS = 512;
|
|
99
|
+
const METADATA_ADDRESS_WORD = MESHLET_METADATA_STRUCT.fields.find(f => f.name === 'address').offset >>> 2;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* What the manager has done to its arenas, for a bench, a tour or an overlay to read without
|
|
103
|
+
* reaching inside. A rebuild is the O(all batches) event the compaction plan is about; a growth
|
|
104
|
+
* is the bounded alternative; the sweep counters are COMPACTION_PLAN_2026_09_16 §4.7's.
|
|
105
|
+
*/
|
|
106
|
+
class GPUMeshletManagerStats {
|
|
107
|
+
growths = 0;
|
|
108
|
+
rebuilds = 0;
|
|
109
|
+
moves = 0;
|
|
110
|
+
sweeps_armed = 0;
|
|
111
|
+
sweeps_completed = 0;
|
|
112
|
+
moves_last_sweep = 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* One arena's compaction state. An episode is armed by a fragmentation refusal and ended by the
|
|
117
|
+
* sweep reaching the arena's end or by a rebuild; `grew` says whether the episode has spent its
|
|
118
|
+
* one growth (plan §4.4).
|
|
119
|
+
*/
|
|
120
|
+
class ArenaSweep {
|
|
121
|
+
armed = false;
|
|
122
|
+
grew = false;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The used node the current pass considers next. {@link ALLOCATOR_NO_SPACE} when no pass is
|
|
126
|
+
* running.
|
|
127
|
+
* @type {number}
|
|
128
|
+
*/
|
|
129
|
+
cursor = ALLOCATOR_NO_SPACE;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Where the next pass starts: the used node after the lowest hole opened since the current
|
|
133
|
+
* pass went by it — or, with no pass running, since the arena was last packed. Kept by every
|
|
134
|
+
* removal, so a pass needs no walk to find its first hole. {@link ALLOCATOR_NO_SPACE} when
|
|
135
|
+
* nothing is known to be behind a hole.
|
|
136
|
+
*
|
|
137
|
+
* A pass does not step back for a hole opened below it: under a pool that thins fast, every
|
|
138
|
+
* removal would send the cursor back below the records it had just packed, and the pass
|
|
139
|
+
* would never reach the end. It finishes, then a second pass from here closes every hole the
|
|
140
|
+
* first one left behind in one walk — the holes gather into one bubble whichever pass slides
|
|
141
|
+
* over them.
|
|
142
|
+
* @type {number}
|
|
143
|
+
*/
|
|
144
|
+
restart = ALLOCATOR_NO_SPACE;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Records moved in the current episode.
|
|
148
|
+
* @type {number}
|
|
149
|
+
*/
|
|
150
|
+
moves = 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* One record's move in one arena, as the sweep recorded it: where the range was, where it is,
|
|
155
|
+
* both in that arena's elements.
|
|
156
|
+
*/
|
|
157
|
+
class ArenaMove {
|
|
158
|
+
/** @type {MeshletBatchAllocationRecord} */
|
|
159
|
+
record;
|
|
160
|
+
from = 0;
|
|
161
|
+
to = 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
53
164
|
class MeshletBatchAllocationRecord {
|
|
54
165
|
/**
|
|
55
166
|
* @type {Allocation}
|
|
@@ -123,10 +234,76 @@ export class GPUMeshletManager {
|
|
|
123
234
|
#device;
|
|
124
235
|
|
|
125
236
|
/**
|
|
126
|
-
*
|
|
237
|
+
* Node budget both allocators are built with; a rebuild re-picks the larger of this and twice
|
|
238
|
+
* the live batch count.
|
|
127
239
|
* @type {number}
|
|
128
240
|
*/
|
|
129
|
-
#
|
|
241
|
+
#allocation_limit = ALLOCATION_LIMIT;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* The state of the compaction of each arena (COMPACTION_PLAN_2026_09_16 §4.3–4.4).
|
|
245
|
+
* @type {ArenaSweep}
|
|
246
|
+
*/
|
|
247
|
+
#sweep_data = new ArenaSweep();
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @type {ArenaSweep}
|
|
251
|
+
*/
|
|
252
|
+
#sweep_metadata = new ArenaSweep();
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* What the sweep needs of an arena, gathered so the two are one code path: its sweep state,
|
|
256
|
+
* its live records by the allocator node that describes their range (a used node's index is
|
|
257
|
+
* stable until it is freed, and a freed one is immediately reused — so the map is kept by one
|
|
258
|
+
* release path and the sweep asserts on it), and how to read a record's range in it.
|
|
259
|
+
*/
|
|
260
|
+
#arena_data = {
|
|
261
|
+
sweep: this.#sweep_data,
|
|
262
|
+
/** @type {Map<number, MeshletBatchAllocationRecord>} */
|
|
263
|
+
records: new Map(),
|
|
264
|
+
allocator: () => this.#allocator_data,
|
|
265
|
+
/** @param {MeshletBatchAllocationRecord} record @returns {Allocation} */
|
|
266
|
+
allocation_of: record => record.data,
|
|
267
|
+
/** @param {MeshletBatchAllocationRecord} record @returns {number} true elements */
|
|
268
|
+
elements_of: record => record.data_size,
|
|
269
|
+
element_words: 1,
|
|
270
|
+
scatter_minimum: MESHLET_SWEEP_SCATTER_MINIMUM_WORDS,
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
#arena_metadata = {
|
|
274
|
+
sweep: this.#sweep_metadata,
|
|
275
|
+
/** @type {Map<number, MeshletBatchAllocationRecord>} */
|
|
276
|
+
records: new Map(),
|
|
277
|
+
allocator: () => this.#allocator_metadata,
|
|
278
|
+
/** @param {MeshletBatchAllocationRecord} record @returns {Allocation} */
|
|
279
|
+
allocation_of: record => record.metadata,
|
|
280
|
+
/** @param {MeshletBatchAllocationRecord} record @returns {number} true elements */
|
|
281
|
+
elements_of: record => record.meshlet_count,
|
|
282
|
+
element_words: METADATA_ROW_WORDS,
|
|
283
|
+
scatter_minimum: MESHLET_SWEEP_SCATTER_MINIMUM_ROWS,
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The command context the last {@link sweep} recorded moves into, while it has not finished.
|
|
288
|
+
* A recorded copy names the range a record left; an arrival placed there in the meantime is
|
|
289
|
+
* uploaded ahead of the copy, and a growth or rebuild destroys the buffer the copy names — so
|
|
290
|
+
* nothing may allocate, free, grow or rebuild until that context has been submitted
|
|
291
|
+
* (COMPACTION_PLAN_2026_09_16 §4.3.1, §5).
|
|
292
|
+
* @type {ShadeGPUCommandContext|null}
|
|
293
|
+
*/
|
|
294
|
+
#moving_ctx = null;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* @type {GPUMeshletManagerStats}
|
|
298
|
+
*/
|
|
299
|
+
#stats = new GPUMeshletManagerStats();
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* @returns {Readonly<GPUMeshletManagerStats>}
|
|
303
|
+
*/
|
|
304
|
+
get stats() {
|
|
305
|
+
return this.#stats;
|
|
306
|
+
}
|
|
130
307
|
|
|
131
308
|
/**
|
|
132
309
|
* Every live allocation, in the order it was made — which is the order a rebuild packs them in.
|
|
@@ -167,26 +344,32 @@ export class GPUMeshletManager {
|
|
|
167
344
|
* @param {GPUDevice} options.device
|
|
168
345
|
* @param {number} [options.initial_data_capacity] in bytes
|
|
169
346
|
* @param {number} [options.initial_metadata_capacity] in meshlets
|
|
347
|
+
* @param {number} [options.allocation_limit] node budget of each arena — the most ranges, live
|
|
348
|
+
* and free together, either can describe. Growth never raises it; a rebuild re-picks it.
|
|
170
349
|
*/
|
|
171
350
|
constructor({
|
|
172
351
|
device,
|
|
173
352
|
initial_data_capacity = DEFAULT_DATA_CAPACITY,
|
|
174
353
|
initial_metadata_capacity = DEFAULT_METADATA_CAPACITY,
|
|
354
|
+
allocation_limit = ALLOCATION_LIMIT,
|
|
175
355
|
}) {
|
|
176
356
|
assert.defined(device, 'device');
|
|
177
357
|
|
|
178
358
|
assert.isNonNegativeInteger(initial_data_capacity, 'initial_data_capacity');
|
|
179
359
|
assert.isNonNegativeInteger(initial_metadata_capacity, 'initial_metadata_capacity');
|
|
360
|
+
assert.isNonNegativeInteger(allocation_limit, 'allocation_limit');
|
|
180
361
|
|
|
181
362
|
assert.greaterThan(initial_data_capacity, 0, 'initial_data_capacity');
|
|
182
363
|
assert.greaterThan(initial_metadata_capacity, 0, 'initial_data_capacity');
|
|
364
|
+
assert.greaterThan(allocation_limit, 0, 'allocation_limit');
|
|
183
365
|
|
|
184
366
|
this.#device = device;
|
|
367
|
+
this.#allocation_limit = allocation_limit;
|
|
185
368
|
|
|
186
369
|
const data_buffer_size_words = Math.ceil(initial_data_capacity / 4);
|
|
187
370
|
|
|
188
|
-
this.#allocator_data = new OffsetAllocator(data_buffer_size_words,
|
|
189
|
-
this.#allocator_metadata = new OffsetAllocator(initial_metadata_capacity,
|
|
371
|
+
this.#allocator_data = new OffsetAllocator(data_buffer_size_words, allocation_limit);
|
|
372
|
+
this.#allocator_metadata = new OffsetAllocator(initial_metadata_capacity, allocation_limit);
|
|
190
373
|
|
|
191
374
|
this.#meshlet_data_buffer = device.createBuffer({
|
|
192
375
|
label: 'GPUMeshletManager/data',
|
|
@@ -203,6 +386,8 @@ export class GPUMeshletManager {
|
|
|
203
386
|
}
|
|
204
387
|
|
|
205
388
|
compact() {
|
|
389
|
+
this.#assert_not_moving();
|
|
390
|
+
|
|
206
391
|
this.#rebuild(
|
|
207
392
|
this.#meshlet_data_buffer.size >>> 2,
|
|
208
393
|
Math.ceil(this.#meshlet_metadata_buffer.size / MESHLET_METADATA_STRUCT.aligned_size)
|
|
@@ -218,8 +403,8 @@ export class GPUMeshletManager {
|
|
|
218
403
|
* re-patching, and no {@link MeshletBatchAllocationRecord#changed} fires. Compare {@link compact},
|
|
219
404
|
* which makes room by re-packing instead, and pays all three of those for every record it moves.
|
|
220
405
|
*
|
|
221
|
-
* Growing closes no holes
|
|
222
|
-
*
|
|
406
|
+
* Growing closes no holes: the holes it did not close are still there for the sweep, or a
|
|
407
|
+
* later {@link compact}, to close.
|
|
223
408
|
*
|
|
224
409
|
* The arena an allocator is asked for is {@link OffsetAllocator#grow_target_for}, not the
|
|
225
410
|
* shortfall: room for exactly `extra_data_size` can still be refused the allocation that asked
|
|
@@ -240,6 +425,8 @@ export class GPUMeshletManager {
|
|
|
240
425
|
return;
|
|
241
426
|
}
|
|
242
427
|
|
|
428
|
+
this.#assert_not_moving();
|
|
429
|
+
|
|
243
430
|
const device = this.#device;
|
|
244
431
|
|
|
245
432
|
const old_buffer_data = this.#meshlet_data_buffer;
|
|
@@ -337,6 +524,8 @@ export class GPUMeshletManager {
|
|
|
337
524
|
|
|
338
525
|
device.queue.submit([encoder.finish()]);
|
|
339
526
|
|
|
527
|
+
this.#stats.growths++;
|
|
528
|
+
|
|
340
529
|
if (new_buffer_data !== null) {
|
|
341
530
|
old_buffer_data.destroy();
|
|
342
531
|
|
|
@@ -351,8 +540,16 @@ export class GPUMeshletManager {
|
|
|
351
540
|
}
|
|
352
541
|
|
|
353
542
|
/**
|
|
354
|
-
*
|
|
355
|
-
*
|
|
543
|
+
* Place a batch's rows in the metadata buffer with every `address` made absolute.
|
|
544
|
+
*
|
|
545
|
+
* The rows a batch arrives with address its data relative to the batch; on the device they
|
|
546
|
+
* address the arena. The row is packed (`MESHLET_METADATA_STRUCT.size === aligned_size`) and
|
|
547
|
+
* the field is one word, so the patch is a byte copy of the batch's rows and one add per row.
|
|
548
|
+
* This used to be a struct read and a struct write per row through the generic serde, at
|
|
549
|
+
* ~20 µs a batch of 34 rows — which was most of what a rebuild cost per record, and what every
|
|
550
|
+
* page promotion paid (COMPACTION_PLAN_2026_09_16 §2.2).
|
|
551
|
+
*
|
|
552
|
+
* @param {ArrayBuffer} source_array_buffer the batch's rows, addresses relative to the batch
|
|
356
553
|
* @param {number} meshlet_count
|
|
357
554
|
* @param {number} data_offset_words
|
|
358
555
|
* @param {number} metadata_offset_index
|
|
@@ -365,29 +562,22 @@ export class GPUMeshletManager {
|
|
|
365
562
|
metadata_offset_index,
|
|
366
563
|
target_buffer
|
|
367
564
|
) {
|
|
368
|
-
const
|
|
369
|
-
temp_writer.setCapacity(meshlet_count * MESHLET_METADATA_STRUCT.size); // pre-allocate to avoid resizing
|
|
370
|
-
|
|
371
|
-
const source_reader = BinaryBuffer.fromArrayBuffer(source_array_buffer);
|
|
372
|
-
source_reader.endianness = platform_compute_endianness();
|
|
373
|
-
|
|
374
|
-
// Iterate over meshlets in the batch, patch the address, and write to temp buffer
|
|
375
|
-
for (let i = 0; i < meshlet_count; i++) {
|
|
376
|
-
const header = read_wgsl_type_value(source_reader, MESHLET_METADATA_STRUCT);
|
|
565
|
+
const word_count = meshlet_count * METADATA_ROW_WORDS;
|
|
377
566
|
|
|
378
|
-
|
|
379
|
-
|
|
567
|
+
// `metadata_buffer_original` is an ArrayBuffer from a BinaryBuffer, offset 0; a slice
|
|
568
|
+
// rather than a view because the batch keeps its rows relative for the next placement
|
|
569
|
+
const words = new Uint32Array(source_array_buffer.slice(0, word_count * 4));
|
|
380
570
|
|
|
381
|
-
|
|
571
|
+
for (let w = METADATA_ADDRESS_WORD; w < word_count; w += METADATA_ROW_WORDS) {
|
|
572
|
+
words[w] += data_offset_words;
|
|
382
573
|
}
|
|
383
574
|
|
|
384
|
-
// Upload
|
|
385
575
|
this.#device.queue.writeBuffer(
|
|
386
576
|
target_buffer,
|
|
387
577
|
metadata_offset_index * MESHLET_METADATA_STRUCT.aligned_size,
|
|
388
|
-
|
|
578
|
+
words.buffer,
|
|
389
579
|
0,
|
|
390
|
-
|
|
580
|
+
word_count * 4
|
|
391
581
|
);
|
|
392
582
|
}
|
|
393
583
|
|
|
@@ -417,7 +607,7 @@ export class GPUMeshletManager {
|
|
|
417
607
|
const record_count = records.size;
|
|
418
608
|
const new_allocator_data = new OffsetAllocator(
|
|
419
609
|
new_data_size,
|
|
420
|
-
Math.max(record_count * 2,
|
|
610
|
+
Math.max(record_count * 2, this.#allocation_limit)
|
|
421
611
|
);
|
|
422
612
|
|
|
423
613
|
const old_buffer_data = this.#meshlet_data_buffer;
|
|
@@ -429,7 +619,7 @@ export class GPUMeshletManager {
|
|
|
429
619
|
|
|
430
620
|
const new_allocator_metadata = new OffsetAllocator(
|
|
431
621
|
new_metadata_size,
|
|
432
|
-
Math.max(record_count * 2,
|
|
622
|
+
Math.max(record_count * 2, this.#allocation_limit)
|
|
433
623
|
);
|
|
434
624
|
|
|
435
625
|
const old_buffer_metadata = this.#meshlet_metadata_buffer;
|
|
@@ -445,11 +635,20 @@ export class GPUMeshletManager {
|
|
|
445
635
|
|
|
446
636
|
const moved_records = [];
|
|
447
637
|
|
|
448
|
-
|
|
638
|
+
const nodes_data = this.#arena_data.records;
|
|
639
|
+
const nodes_metadata = this.#arena_metadata.records;
|
|
640
|
+
|
|
641
|
+
nodes_data.clear();
|
|
642
|
+
nodes_metadata.clear();
|
|
643
|
+
|
|
644
|
+
// move data, in allocation order, which is the order the set keeps. Each range is the
|
|
645
|
+
// bin the record was placed in originally (see #allocate_data_and_metadata), which is
|
|
646
|
+
// also what makes sequential packing exact: a bin-sized request never falls in the gap
|
|
647
|
+
// between a remainder's size and the bin it is filed under.
|
|
449
648
|
for (const record of records) {
|
|
450
649
|
|
|
451
|
-
const new_allocation_data = new_allocator_data.allocate(record.data_size);
|
|
452
|
-
const new_allocation_metadata = new_allocator_metadata.allocate(record.meshlet_count);
|
|
650
|
+
const new_allocation_data = new_allocator_data.allocate(allocator_run_size_for(record.data_size));
|
|
651
|
+
const new_allocation_metadata = new_allocator_metadata.allocate(allocator_run_size_for(record.meshlet_count));
|
|
453
652
|
|
|
454
653
|
assert.notEqual(new_allocation_data.offset, ALLOCATOR_NO_SPACE);
|
|
455
654
|
assert.notEqual(new_allocation_metadata.offset, ALLOCATOR_NO_SPACE);
|
|
@@ -478,6 +677,9 @@ export class GPUMeshletManager {
|
|
|
478
677
|
record.data = new_allocation_data;
|
|
479
678
|
record.metadata = new_allocation_metadata;
|
|
480
679
|
|
|
680
|
+
nodes_data.set(new_allocation_data.metadata, record);
|
|
681
|
+
nodes_metadata.set(new_allocation_metadata.metadata, record);
|
|
682
|
+
|
|
481
683
|
if (metadata_record_moved) {
|
|
482
684
|
moved_records.push(record);
|
|
483
685
|
}
|
|
@@ -501,96 +703,170 @@ export class GPUMeshletManager {
|
|
|
501
703
|
this.#allocator_data = new_allocator_data;
|
|
502
704
|
this.#allocator_metadata = new_allocator_metadata;
|
|
503
705
|
|
|
504
|
-
//
|
|
505
|
-
this.#
|
|
706
|
+
// packed: whatever episode was running is over, and the nodes it was walking are gone
|
|
707
|
+
for (const sweep of [this.#sweep_data, this.#sweep_metadata]) {
|
|
708
|
+
sweep.armed = false;
|
|
709
|
+
sweep.grew = false;
|
|
710
|
+
sweep.cursor = ALLOCATOR_NO_SPACE;
|
|
711
|
+
sweep.restart = ALLOCATOR_NO_SPACE;
|
|
712
|
+
sweep.moves = 0;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
this.#stats.rebuilds++;
|
|
506
716
|
}
|
|
507
717
|
|
|
508
718
|
/**
|
|
509
719
|
* Allocate `data_size_words` in the data buffer and `meshlet_count`
|
|
510
|
-
* in the metadata buffer,
|
|
511
|
-
*
|
|
720
|
+
* in the metadata buffer, making room on refusal and trying again.
|
|
721
|
+
* Throws if the last attempt still can't satisfy both. The two
|
|
512
722
|
* allocations are kept in lockstep — partial successes are released
|
|
513
723
|
* before retrying so we never leak.
|
|
514
724
|
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
725
|
+
* Every request is rounded up to the bin it would be looked up from
|
|
726
|
+
* (`allocator_run_size_for`) before it reaches the allocator. The
|
|
727
|
+
* allocator files a freed run under the largest bin that fits inside
|
|
728
|
+
* it and looks a request up from the smallest bin that fits the
|
|
729
|
+
* request, so a hole left by a batch serves only requests a whole bin
|
|
730
|
+
* smaller than it — under a churn of near-uniform batches that was
|
|
731
|
+
* most refusals, and each refusal a rebuild. A range that is exactly
|
|
732
|
+
* a bin is filed under exactly the bin any request of its class is
|
|
733
|
+
* looked up from, and is consumed whole by one, leaving no splinter.
|
|
734
|
+
* The record keeps the true sizes; the arena reserves the bin
|
|
735
|
+
* (COMPACTION_PLAN_2026_09_16 §2.1, §4.1).
|
|
736
|
+
*
|
|
737
|
+
* What a refusal gets (plan §4.4). {@link grow} appends and moves
|
|
738
|
+
* nothing, so it is the answer to an arena that is short — and, once
|
|
739
|
+
* per sweep episode, to one that is merely fragmented: the growth
|
|
740
|
+
* leaves headroom, the holes stay, and the sweep closes them over the
|
|
741
|
+
* frames that follow. A second fragmentation refusal before the sweep
|
|
742
|
+
* has finished is the case growth would compound, so it gets the one
|
|
743
|
+
* {@link compact}, which is O(all batches) and now bounded by the row
|
|
744
|
+
* patch. The rebuild is also the last resort before the throw, for an
|
|
745
|
+
* arena the device will not let grow — and for one that is out of
|
|
746
|
+
* nodes, which no arena size answers and which a rebuild re-picks.
|
|
747
|
+
* Queued clone work is carried through any of these — {@link
|
|
748
|
+
* #pending_clones} names records, not addresses.
|
|
525
749
|
*
|
|
526
750
|
* @param {number} data_size_words
|
|
527
751
|
* @param {number} meshlet_count
|
|
528
752
|
* @returns {{data: Allocation, metadata: Allocation}}
|
|
529
753
|
*/
|
|
530
754
|
#allocate_data_and_metadata(data_size_words, meshlet_count) {
|
|
531
|
-
|
|
532
|
-
|
|
755
|
+
assert.isNonNegativeInteger(data_size_words, 'data_size_words');
|
|
756
|
+
assert.isNonNegativeInteger(meshlet_count, 'meshlet_count');
|
|
757
|
+
|
|
758
|
+
this.#assert_not_moving();
|
|
759
|
+
|
|
760
|
+
// An empty batch — a mesh with no triangles yet, a placeholder geometry — reserves one
|
|
761
|
+
// element rather than none: a zero-sized node has no place in a partition of the arena,
|
|
762
|
+
// and the sweep's head and cursor rules (plan §4.2) assume every node covers something.
|
|
763
|
+
const data_run = allocator_run_size_for(Math.max(1, data_size_words));
|
|
764
|
+
const metadata_run = allocator_run_size_for(Math.max(1, meshlet_count));
|
|
533
765
|
|
|
534
|
-
|
|
766
|
+
// attempt 0 grows; attempt 1 grows or rebuilds; attempt 2 rebuilds; attempt 3 is the last
|
|
767
|
+
const LAST_ATTEMPT = 3;
|
|
535
768
|
|
|
536
|
-
|
|
537
|
-
|
|
769
|
+
for (let attempt = 0; ; attempt++) {
|
|
770
|
+
|
|
771
|
+
const data_allocation = this.#allocator_data.allocate(data_run);
|
|
772
|
+
const metadata_allocation = this.#allocator_metadata.allocate(metadata_run);
|
|
538
773
|
|
|
539
774
|
const data_ok = data_allocation.offset !== ALLOCATOR_NO_SPACE;
|
|
540
775
|
const metadata_ok = metadata_allocation.offset !== ALLOCATOR_NO_SPACE;
|
|
541
776
|
|
|
542
777
|
if (data_ok && metadata_ok) {
|
|
543
|
-
|
|
778
|
+
return { data: data_allocation, metadata: metadata_allocation };
|
|
544
779
|
}
|
|
545
780
|
|
|
546
781
|
// release partial allocation
|
|
547
782
|
if (data_ok) {
|
|
548
783
|
this.#allocator_data.free(data_allocation);
|
|
549
|
-
|
|
550
|
-
data_allocation.offset = ALLOCATOR_NO_SPACE;
|
|
551
|
-
data_allocation.metadata = ALLOCATOR_NO_SPACE;
|
|
552
784
|
}
|
|
553
785
|
if (metadata_ok) {
|
|
554
786
|
this.#allocator_metadata.free(metadata_allocation);
|
|
787
|
+
}
|
|
555
788
|
|
|
556
|
-
|
|
557
|
-
|
|
789
|
+
if (attempt === LAST_ATTEMPT) {
|
|
790
|
+
throw new Error('Failed to allocate GPU memory for meshlet batch');
|
|
558
791
|
}
|
|
559
792
|
|
|
560
793
|
// An allocator holding enough free space for the request it just refused is one whose
|
|
561
|
-
// space is scattered
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
//
|
|
794
|
+
// space is scattered: with that much free and no run accepted there are at least two
|
|
795
|
+
// free nodes, so closing holes is what would help. Anything else is a shortfall.
|
|
796
|
+
// "Enough" is measured against the run the request is accepted from, or a packing
|
|
797
|
+
// could hand back the whole free space as one run and still be refused.
|
|
565
798
|
const data_is_fragmented = !data_ok
|
|
566
|
-
&& this.#allocator_data.freeStorage >=
|
|
799
|
+
&& this.#allocator_data.freeStorage >= data_run;
|
|
567
800
|
|
|
568
801
|
const metadata_is_fragmented = !metadata_ok
|
|
569
|
-
&& this.#allocator_metadata.freeStorage >=
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if (
|
|
574
|
-
this.#
|
|
575
|
-
|
|
576
|
-
|
|
802
|
+
&& this.#allocator_metadata.freeStorage >= metadata_run;
|
|
803
|
+
|
|
804
|
+
let rebuild = attempt === LAST_ATTEMPT - 1;
|
|
805
|
+
|
|
806
|
+
if (data_is_fragmented) {
|
|
807
|
+
rebuild ||= this.#sweep_data.grew;
|
|
808
|
+
|
|
809
|
+
this.#arm_sweep(this.#sweep_data, this.#allocator_data);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (metadata_is_fragmented) {
|
|
813
|
+
rebuild ||= this.#sweep_metadata.grew;
|
|
814
|
+
|
|
815
|
+
this.#arm_sweep(this.#sweep_metadata, this.#allocator_metadata);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (rebuild) {
|
|
577
819
|
this.compact();
|
|
578
820
|
|
|
579
821
|
continue;
|
|
580
822
|
}
|
|
581
823
|
|
|
582
|
-
|
|
583
|
-
|
|
824
|
+
if (data_is_fragmented) {
|
|
825
|
+
this.#sweep_data.grew = true;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (metadata_is_fragmented) {
|
|
829
|
+
this.#sweep_metadata.grew = true;
|
|
830
|
+
}
|
|
584
831
|
|
|
585
|
-
this.grow(
|
|
832
|
+
this.grow(data_ok ? 0 : data_run, metadata_ok ? 0 : metadata_run);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
586
835
|
|
|
836
|
+
/**
|
|
837
|
+
* Start a sweep of one arena, if one is not running. The cursor is kept up to date by every
|
|
838
|
+
* removal whether or not a sweep is running (plan §4.3), so arming is a flag.
|
|
839
|
+
*
|
|
840
|
+
* @param {ArenaSweep} sweep
|
|
841
|
+
* @param {OffsetAllocator} allocator
|
|
842
|
+
*/
|
|
843
|
+
#arm_sweep(sweep, allocator) {
|
|
844
|
+
if (sweep.armed) {
|
|
845
|
+
return;
|
|
587
846
|
}
|
|
588
847
|
|
|
589
|
-
|
|
590
|
-
|
|
848
|
+
sweep.armed = true;
|
|
849
|
+
sweep.grew = false;
|
|
850
|
+
sweep.moves = 0;
|
|
851
|
+
|
|
852
|
+
if (sweep.cursor === ALLOCATOR_NO_SPACE) {
|
|
853
|
+
// every hole comes from a removal, which records where the pass should start; the
|
|
854
|
+
// case of none known walks from the head, bounded by the step budget
|
|
855
|
+
sweep.cursor = sweep.restart !== ALLOCATOR_NO_SPACE ? sweep.restart : allocator.first_used_node();
|
|
856
|
+
sweep.restart = ALLOCATOR_NO_SPACE;
|
|
591
857
|
}
|
|
592
858
|
|
|
593
|
-
|
|
859
|
+
this.#stats.sweeps_armed++;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* @throws when a sweep's moves are recorded into a command context that has not finished
|
|
864
|
+
*/
|
|
865
|
+
#assert_not_moving() {
|
|
866
|
+
assert.ok(
|
|
867
|
+
this.#moving_ctx === null || this.#moving_ctx.finished,
|
|
868
|
+
'GPUMeshletManager: a sweep recorded moves into a command context that has not finished; an allocation, removal, growth or rebuild now would race the copies it recorded'
|
|
869
|
+
);
|
|
594
870
|
}
|
|
595
871
|
|
|
596
872
|
/**
|
|
@@ -621,13 +897,15 @@ export class GPUMeshletManager {
|
|
|
621
897
|
|
|
622
898
|
this.#records.add(record);
|
|
623
899
|
|
|
900
|
+
this.#arena_data.records.set(data.metadata, record);
|
|
901
|
+
this.#arena_metadata.records.set(metadata.metadata, record);
|
|
902
|
+
|
|
624
903
|
return record;
|
|
625
904
|
}
|
|
626
905
|
|
|
627
906
|
/**
|
|
628
907
|
* Release a batch allocation back to the data and metadata allocators. The GPU bytes are
|
|
629
|
-
* not cleared — the freed slices are
|
|
630
|
-
* deallocation bumps the compaction counter the allocator consults under pressure).
|
|
908
|
+
* not cleared — the freed slices are handed to whoever asks next, or closed by a sweep.
|
|
631
909
|
* Other batches' allocations are unaffected (the OffsetAllocator frees disjoint slices),
|
|
632
910
|
* so callers only need to ensure nothing still references this batch's metadata rows
|
|
633
911
|
* (the geometry table rebuild in {@link GPUGeometryManager} handles that).
|
|
@@ -643,17 +921,328 @@ export class GPUMeshletManager {
|
|
|
643
921
|
return false;
|
|
644
922
|
}
|
|
645
923
|
|
|
924
|
+
this.#assert_not_moving();
|
|
925
|
+
|
|
646
926
|
this.#cancel_pending_clones_naming(record);
|
|
647
927
|
|
|
648
|
-
this.#
|
|
649
|
-
this.#
|
|
928
|
+
this.#retire(this.#arena_data, record);
|
|
929
|
+
this.#retire(this.#arena_metadata, record);
|
|
650
930
|
|
|
651
931
|
this.#records.delete(record);
|
|
652
|
-
this.#deallocations_since_last_rebuild++;
|
|
653
932
|
|
|
654
933
|
return true;
|
|
655
934
|
}
|
|
656
935
|
|
|
936
|
+
/**
|
|
937
|
+
* Give a record's range in one arena back, keeping the sweep's pointers and the node map right.
|
|
938
|
+
*
|
|
939
|
+
* A freed node's index is immediately the merged free node's, and then the next allocation's;
|
|
940
|
+
* a pointer left on it would name another live record and never fail loudly. So a pointer on
|
|
941
|
+
* this node is moved to the used node after it before the free. And the hole this leaves is
|
|
942
|
+
* recorded for the sweep: if it is above the running pass's cursor the pass reaches it; if
|
|
943
|
+
* it is below — or no pass is running — the *restart* point is moved down to the used node
|
|
944
|
+
* after it when it is the lowest hole known, so the next pass starts there and closes it
|
|
945
|
+
* (COMPACTION_PLAN_2026_09_16 §4.3).
|
|
946
|
+
*
|
|
947
|
+
* @param {object} arena
|
|
948
|
+
* @param {MeshletBatchAllocationRecord} record
|
|
949
|
+
*/
|
|
950
|
+
#retire(arena, record) {
|
|
951
|
+
const sweep = arena.sweep;
|
|
952
|
+
const allocator = arena.allocator();
|
|
953
|
+
const allocation = arena.allocation_of(record);
|
|
954
|
+
const node = allocation.metadata;
|
|
955
|
+
|
|
956
|
+
const successor = allocator.next_used_node(node);
|
|
957
|
+
|
|
958
|
+
if (node === sweep.cursor) {
|
|
959
|
+
sweep.cursor = successor;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
if (node === sweep.restart) {
|
|
963
|
+
sweep.restart = successor;
|
|
964
|
+
} else if (this.#is_below(arena, allocation, sweep.cursor) && this.#is_below(arena, allocation, sweep.restart)) {
|
|
965
|
+
sweep.restart = successor;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
arena.records.delete(node);
|
|
969
|
+
|
|
970
|
+
allocator.free(allocation);
|
|
971
|
+
|
|
972
|
+
// Free space less the largest free run, both from the bins: O(1), and the largest run
|
|
973
|
+
// is bin-rounded down, which errs towards arming.
|
|
974
|
+
const report = allocator.storageReport();
|
|
975
|
+
const scattered = report.totalFreeSpace - report.largestFreeRegion;
|
|
976
|
+
|
|
977
|
+
if (scattered >= arena.scatter_minimum && scattered * 8 >= allocator.size) {
|
|
978
|
+
this.#arm_sweep(sweep, allocator);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Whether `allocation` sits below the record `pointer` names — or `pointer` names nothing,
|
|
984
|
+
* which counts as below: a hole with no pass or restart ahead of it is the lowest known.
|
|
985
|
+
*
|
|
986
|
+
* @param {object} arena
|
|
987
|
+
* @param {Allocation} allocation
|
|
988
|
+
* @param {number} pointer node index, or ALLOCATOR_NO_SPACE
|
|
989
|
+
* @returns {boolean}
|
|
990
|
+
*/
|
|
991
|
+
#is_below(arena, allocation, pointer) {
|
|
992
|
+
if (pointer === ALLOCATOR_NO_SPACE) {
|
|
993
|
+
return true;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
const record = arena.records.get(pointer);
|
|
997
|
+
|
|
998
|
+
assert.defined(record, 'record, a sweep pointer names a node no record holds');
|
|
999
|
+
|
|
1000
|
+
return allocation.offset < arena.allocation_of(record).offset;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* One budgeted step of the compaction of both arenas, recorded into `cmd_ctx`.
|
|
1005
|
+
*
|
|
1006
|
+
* Nothing happens unless a fragmentation refusal has armed a sweep (see
|
|
1007
|
+
* {@link #allocate_data_and_metadata}). Then, in each arena, the cursor walks up the used
|
|
1008
|
+
* ranges sliding each down over the free space before it — which gathers every hole passed
|
|
1009
|
+
* into one run just behind the cursor — until {@link MESHLET_SWEEP_MOVE_BUDGET} records or
|
|
1010
|
+
* {@link MESHLET_SWEEP_WORD_BUDGET} words have moved (never fewer than one when one can) or
|
|
1011
|
+
* {@link MESHLET_SWEEP_STEP_BUDGET} steps have been taken, across both arenas. The sweep is
|
|
1012
|
+
* done when the cursor reaches the arena's end: all free space is one run at the tail, and
|
|
1013
|
+
* the episode is over.
|
|
1014
|
+
*
|
|
1015
|
+
* A moved record's bytes — data and rows alike — go through a transient staging buffer in
|
|
1016
|
+
* two `copyBufferToBuffer`s: WebGPU refuses a same-buffer copy, the intra-copy shader the
|
|
1017
|
+
* clone flush uses is not overlap-safe, and a slide by less than a record's size overlaps.
|
|
1018
|
+
* Rows are copied rather than re-derived from the batch's bytes because the skinning bounds
|
|
1019
|
+
* chain writes into clone rows on the device every frame. A data move then patches the
|
|
1020
|
+
* moved rows' `address` with the clone flush's shader. Every move is recorded in cursor
|
|
1021
|
+
* order, so a record sliding into space another vacated earlier in the same call reads what
|
|
1022
|
+
* that record's copy already wrote out. `changed` fires once per moved record after the
|
|
1023
|
+
* whole batch is recorded, with the new offsets on the record.
|
|
1024
|
+
*
|
|
1025
|
+
* The renderer calls this once per frame, at the head of the frame, before
|
|
1026
|
+
* {@link update}, so the clone flush reads post-sweep offsets and every pass reads rows and
|
|
1027
|
+
* data that agree. Until `cmd_ctx` finishes the manager refuses to allocate, free, grow or
|
|
1028
|
+
* rebuild — a recorded copy names ranges that must stay what they are until it runs.
|
|
1029
|
+
*
|
|
1030
|
+
* @param {ShadeGPUCommandContext} cmd_ctx
|
|
1031
|
+
*/
|
|
1032
|
+
sweep(cmd_ctx) {
|
|
1033
|
+
assert.defined(cmd_ctx, 'cmd_ctx');
|
|
1034
|
+
|
|
1035
|
+
this.#assert_not_moving();
|
|
1036
|
+
|
|
1037
|
+
const budget = {
|
|
1038
|
+
moves: MESHLET_SWEEP_MOVE_BUDGET,
|
|
1039
|
+
words: MESHLET_SWEEP_WORD_BUDGET,
|
|
1040
|
+
steps: MESHLET_SWEEP_STEP_BUDGET,
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
const data_moves = this.#sweep_arena(this.#arena_data, budget);
|
|
1044
|
+
const metadata_moves = this.#sweep_arena(this.#arena_metadata, budget);
|
|
1045
|
+
|
|
1046
|
+
if (data_moves.length === 0 && metadata_moves.length === 0) {
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
this.#record_moves(cmd_ctx, data_moves, metadata_moves);
|
|
1051
|
+
|
|
1052
|
+
this.#moving_ctx = cmd_ctx;
|
|
1053
|
+
|
|
1054
|
+
const moved = new Set();
|
|
1055
|
+
|
|
1056
|
+
for (const move of data_moves) {
|
|
1057
|
+
moved.add(move.record);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
for (const move of metadata_moves) {
|
|
1061
|
+
moved.add(move.record);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
for (const record of moved) {
|
|
1065
|
+
record.changed.send0();
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* The sweep steps of one arena, within `budget` (which is spent across both arenas).
|
|
1071
|
+
*
|
|
1072
|
+
* @param {object} arena
|
|
1073
|
+
* @param {{moves: number, words: number, steps: number}} budget
|
|
1074
|
+
* @returns {ArenaMove[]}
|
|
1075
|
+
*/
|
|
1076
|
+
#sweep_arena(arena, budget) {
|
|
1077
|
+
const sweep = arena.sweep;
|
|
1078
|
+
|
|
1079
|
+
/** @type {ArenaMove[]} */
|
|
1080
|
+
const moves = [];
|
|
1081
|
+
|
|
1082
|
+
if (!sweep.armed) {
|
|
1083
|
+
return moves;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
const allocator = arena.allocator();
|
|
1087
|
+
|
|
1088
|
+
while (budget.moves > 0 && budget.words > 0 && budget.steps > 0) {
|
|
1089
|
+
const node = sweep.cursor;
|
|
1090
|
+
|
|
1091
|
+
if (node === ALLOCATOR_NO_SPACE) {
|
|
1092
|
+
if (sweep.restart !== ALLOCATOR_NO_SPACE) {
|
|
1093
|
+
// holes opened below this pass while it ran: another pass, from the lowest
|
|
1094
|
+
sweep.cursor = sweep.restart;
|
|
1095
|
+
sweep.restart = ALLOCATOR_NO_SPACE;
|
|
1096
|
+
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// the arena's end: all free space is one run at the tail
|
|
1101
|
+
sweep.armed = false;
|
|
1102
|
+
sweep.grew = false;
|
|
1103
|
+
|
|
1104
|
+
this.#stats.sweeps_completed++;
|
|
1105
|
+
this.#stats.moves_last_sweep = sweep.moves;
|
|
1106
|
+
|
|
1107
|
+
sweep.moves = 0;
|
|
1108
|
+
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
const record = arena.records.get(node);
|
|
1113
|
+
|
|
1114
|
+
assert.defined(record, 'record, the cursor names a node no record holds');
|
|
1115
|
+
|
|
1116
|
+
const allocation = arena.allocation_of(record);
|
|
1117
|
+
|
|
1118
|
+
assert.equal(allocation.metadata, node, 'allocation.metadata, the cursor names a node another record holds');
|
|
1119
|
+
|
|
1120
|
+
budget.steps--;
|
|
1121
|
+
|
|
1122
|
+
const delta = allocator.slide_down(node);
|
|
1123
|
+
|
|
1124
|
+
sweep.cursor = allocator.next_used_node(node);
|
|
1125
|
+
|
|
1126
|
+
if (delta === 0) {
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const move = new ArenaMove();
|
|
1131
|
+
|
|
1132
|
+
move.record = record;
|
|
1133
|
+
move.from = allocation.offset;
|
|
1134
|
+
move.to = allocation.offset - delta;
|
|
1135
|
+
|
|
1136
|
+
allocation.offset = move.to;
|
|
1137
|
+
|
|
1138
|
+
moves.push(move);
|
|
1139
|
+
|
|
1140
|
+
budget.moves--;
|
|
1141
|
+
budget.words -= arena.elements_of(record) * arena.element_words;
|
|
1142
|
+
|
|
1143
|
+
sweep.moves++;
|
|
1144
|
+
|
|
1145
|
+
this.#stats.moves++;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
return moves;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* The GPU side of a sweep step: the staged copies of every moved range, then the address
|
|
1153
|
+
* patch of every row whose data moved.
|
|
1154
|
+
*
|
|
1155
|
+
* One staging buffer sized to the largest move, reused from offset 0 by every copy: copies in
|
|
1156
|
+
* one command buffer are ordered. The patch table is built after the row copies from the
|
|
1157
|
+
* records' post-move row offsets, which is where the rows are by the time it runs.
|
|
1158
|
+
*
|
|
1159
|
+
* @param {ShadeGPUCommandContext} cmd_ctx
|
|
1160
|
+
* @param {ArenaMove[]} data_moves
|
|
1161
|
+
* @param {ArenaMove[]} metadata_moves
|
|
1162
|
+
*/
|
|
1163
|
+
#record_moves(cmd_ctx, data_moves, metadata_moves) {
|
|
1164
|
+
const data_buffer = this.#meshlet_data_buffer;
|
|
1165
|
+
const metadata_buffer = this.#meshlet_metadata_buffer;
|
|
1166
|
+
const row_bytes = MESHLET_METADATA_STRUCT.aligned_size;
|
|
1167
|
+
|
|
1168
|
+
let largest_bytes = 0;
|
|
1169
|
+
|
|
1170
|
+
for (const move of data_moves) {
|
|
1171
|
+
largest_bytes = Math.max(largest_bytes, move.record.data_size * 4);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
for (const move of metadata_moves) {
|
|
1175
|
+
largest_bytes = Math.max(largest_bytes, move.record.meshlet_count * row_bytes);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
if (largest_bytes > 0) {
|
|
1179
|
+
const stage = cmd_ctx.allocateTransientBuffer(
|
|
1180
|
+
GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
|
|
1181
|
+
largest_bytes
|
|
1182
|
+
);
|
|
1183
|
+
|
|
1184
|
+
for (const move of data_moves) {
|
|
1185
|
+
const bytes = move.record.data_size * 4;
|
|
1186
|
+
|
|
1187
|
+
if (bytes === 0) {
|
|
1188
|
+
continue;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
cmd_ctx.copyBufferToBuffer(data_buffer, move.from * 4, stage, 0, bytes);
|
|
1192
|
+
cmd_ctx.copyBufferToBuffer(stage, 0, data_buffer, move.to * 4, bytes);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
for (const move of metadata_moves) {
|
|
1196
|
+
const bytes = move.record.meshlet_count * row_bytes;
|
|
1197
|
+
|
|
1198
|
+
if (bytes === 0) {
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
cmd_ctx.copyBufferToBuffer(metadata_buffer, move.from * row_bytes, stage, 0, bytes);
|
|
1203
|
+
cmd_ctx.copyBufferToBuffer(stage, 0, metadata_buffer, move.to * row_bytes, bytes);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
let patch_count = 0;
|
|
1208
|
+
|
|
1209
|
+
for (const move of data_moves) {
|
|
1210
|
+
patch_count += move.record.meshlet_count;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
if (patch_count === 0) {
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
const patches = new Uint32Array(patch_count * 2);
|
|
1218
|
+
|
|
1219
|
+
let p = 0;
|
|
1220
|
+
|
|
1221
|
+
for (const move of data_moves) {
|
|
1222
|
+
const record = move.record;
|
|
1223
|
+
|
|
1224
|
+
// the same wrapping add as the clone flush: a move down is a negative delta
|
|
1225
|
+
const delta = (move.to - move.from) >>> 0;
|
|
1226
|
+
|
|
1227
|
+
for (let i = 0; i < record.meshlet_count; i++) {
|
|
1228
|
+
patches[p++] = record.metadata.offset + i;
|
|
1229
|
+
patches[p++] = delta;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
const patches_buffer = cmd_ctx.allocateTransientBufferAndLoad(patches.buffer, GPUBufferUsage.STORAGE);
|
|
1234
|
+
|
|
1235
|
+
shader_meshlet_metadata_address_patch.dispatchThreads({
|
|
1236
|
+
encoder: cmd_ctx,
|
|
1237
|
+
thread_count_x: patch_count,
|
|
1238
|
+
bindings: {
|
|
1239
|
+
meshlet_metadata: metadata_buffer,
|
|
1240
|
+
patches: patches_buffer,
|
|
1241
|
+
patch_count,
|
|
1242
|
+
},
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
|
|
657
1246
|
/**
|
|
658
1247
|
* Drop the queued clone copies that name `record`, because it is about to stop owning the
|
|
659
1248
|
* ranges they were going to read from or write to.
|
|
@@ -729,6 +1318,9 @@ export class GPUMeshletManager {
|
|
|
729
1318
|
|
|
730
1319
|
this.#records.add(record);
|
|
731
1320
|
|
|
1321
|
+
this.#arena_data.records.set(data.metadata, record);
|
|
1322
|
+
this.#arena_metadata.records.set(metadata.metadata, record);
|
|
1323
|
+
|
|
732
1324
|
// The queue names the two records rather than the addresses they
|
|
733
1325
|
// hold right now. Both are in `#records`, so a rebuild between
|
|
734
1326
|
// this call and the flush moves them and the flush still reads
|
|
@@ -922,6 +1514,21 @@ export class GPUMeshletManager {
|
|
|
922
1514
|
return result;
|
|
923
1515
|
}
|
|
924
1516
|
|
|
1517
|
+
/**
|
|
1518
|
+
* Bytes the arenas have handed out: every batch's range rounded to its bin, data and metadata
|
|
1519
|
+
* both. Above {@link gpu_memory_usage_occupied} by the quantization overhead — 3.4 % of data
|
|
1520
|
+
* and 3.9 % of rows on page-shaped batches, at most 12.5 % on any.
|
|
1521
|
+
*
|
|
1522
|
+
* @returns {number}
|
|
1523
|
+
*/
|
|
1524
|
+
get gpu_memory_usage_reserved() {
|
|
1525
|
+
const data = this.#allocator_data;
|
|
1526
|
+
const metadata = this.#allocator_metadata;
|
|
1527
|
+
|
|
1528
|
+
return (data.size - data.freeStorage) * 4
|
|
1529
|
+
+ (metadata.size - metadata.freeStorage) * MESHLET_METADATA_STRUCT.aligned_size;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
925
1532
|
get gpu_memory_usage() {
|
|
926
1533
|
let result = 0;
|
|
927
1534
|
|