@woosh/meep-engine 3.16.0 → 3.17.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/editor/particles/effect/ParticleEffectDocument.d.ts +21 -6
- package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
- package/editor/particles/effect/ParticleEffectDocument.js +38 -17
- package/editor/view/node-graph/NodeGraphClipboard.d.ts +186 -0
- package/editor/view/node-graph/NodeGraphClipboard.d.ts.map +1 -0
- package/editor/view/node-graph/NodeGraphClipboard.js +231 -0
- package/editor/view/node-graph/NodeGraphEditorView.d.ts +59 -1
- package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphEditorView.js +248 -5
- package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphView.js +84 -8
- package/editor/view/node-graph/actions/connection_bind_actions.d.ts +23 -0
- package/editor/view/node-graph/actions/connection_bind_actions.d.ts.map +1 -0
- package/editor/view/node-graph/actions/connection_bind_actions.js +39 -0
- package/editor/view/particles/effect/ParticleCodeEditorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleCodeEditorView.js +4 -3
- package/editor/view/particles/effect/ParticleCurveEditorView.d.ts +20 -0
- package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -0
- package/editor/view/particles/effect/ParticleCurveEditorView.js +574 -0
- package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleEmitterInspectorView.js +27 -1
- package/editor/view/particles/effect/ParticleGradientEditorView.d.ts +24 -0
- package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -0
- package/editor/view/particles/effect/ParticleGradientEditorView.js +472 -0
- package/editor/view/particles/effect/ParticleGraphEditorView.d.ts +5 -0
- package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleGraphEditorView.js +61 -31
- package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleNodeParametersView.js +33 -0
- package/editor/view/particles/effect/particle-editor.css +123 -35
- package/package.json +1 -1
- package/src/core/binary/allocator/OffsetAllocator.d.ts +25 -16
- package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
- package/src/core/binary/allocator/OffsetAllocator.js +10 -1
- package/src/core/collection/array/typed/float32_array_hash.d.ts +21 -0
- package/src/core/collection/array/typed/float32_array_hash.d.ts.map +1 -0
- package/src/core/collection/array/typed/float32_array_hash.js +38 -0
- package/src/core/graph/csr/CSRGraph.d.ts +8 -1
- package/src/core/graph/csr/CSRGraph.d.ts.map +1 -1
- package/src/core/graph/csr/CSRGraph.js +14 -6
- package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts +24 -0
- package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/LayoutProblem.js +27 -0
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +26 -0
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +28 -0
- package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts +92 -3
- package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/RouteGrid.js +405 -242
- package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts +50 -5
- package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/RouteSearch.js +160 -24
- package/src/core/model/node-graph/visual/layout/RouteSet.d.ts +7 -0
- package/src/core/model/node-graph/visual/layout/RouteSet.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/RouteSet.js +8 -0
- package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +9 -3
- package/src/core/model/node-graph/visual/layout/layout_build_problem.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_build_problem.js +7 -0
- package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts +9 -3
- package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_insert_lanes.js +17 -3
- package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts +9 -6
- package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_node_graph.js +49 -7
- package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts +11 -1
- package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_order_layers.js +135 -16
- package/src/core/model/node-graph/visual/layout/route_connections.d.ts +29 -0
- package/src/core/model/node-graph/visual/layout/route_connections.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/route_connections.js +716 -309
- package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts +3 -2
- package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/route_grid_build.js +7 -15
- package/src/core/model/node-graph/visual/layout/route_nudge.d.ts +6 -0
- package/src/core/model/node-graph/visual/layout/route_nudge.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/route_nudge.js +42 -13
- package/src/engine/animation/AnimationUtils.js +246 -246
- package/src/engine/animation/Animations.js +74 -74
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2078 -2078
- package/src/engine/ecs/EventType.d.ts +0 -1
- package/src/engine/ecs/EventType.js +1 -26
- package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +1 -1
- package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -1
- package/src/engine/ecs/ik/ik_write_local_rotation.js +3 -7
- package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
- package/src/engine/ecs/parent/EntityNode.js +4 -9
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +360 -364
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts +41 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts.map +1 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.js +40 -0
- package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +8 -0
- package/src/engine/ecs/transform/t64_announce_change.d.ts +10 -7
- package/src/engine/ecs/transform/t64_announce_change.d.ts.map +1 -1
- package/src/engine/ecs/transform/t64_announce_change.js +12 -12
- package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts +30 -0
- package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts.map +1 -0
- package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.js +29 -0
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +13 -21
- package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
- package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +4 -8
- package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
- package/src/engine/graphics3/LightSystem.js +4 -8
- package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
- package/src/engine/graphics3/MeshSystem.js +9 -19
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/ParticleEmitterSystem.js +4 -8
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
- package/src/engine/graphics3/ShadedGeometrySystem.js +4 -10
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts +1 -1
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +4 -8
- package/src/engine/intelligence/behavior/ecs/OrbitingBehavior.js +218 -218
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
- package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
- package/src/engine/sound/ecs/SoundListenerSystem.js +6 -8
- package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts +0 -4
- package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts.map +1 -1
- package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +5 -11
- package/src/shade/playground/particle_editor/README.md +43 -2
- package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
- package/src/shade/playground/particle_system/particle_prototype.js +4 -5
- package/src/shade/playground/particle_system/particle_scene.js +4 -4
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +13 -1
- package/src/shade/renderer/particles/DESIGN.md +104 -19
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +64 -50
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +176 -78
- package/src/shade/renderer/particles/ParticleConstants.d.ts +59 -23
- package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
- package/src/shade/renderer/particles/ParticleConstants.js +66 -23
- package/src/shade/renderer/particles/ParticleRenderMode.d.ts +19 -0
- package/src/shade/renderer/particles/ParticleRenderMode.d.ts.map +1 -0
- package/src/shade/renderer/particles/ParticleRenderMode.js +33 -0
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +167 -166
- package/src/shade/renderer/particles/data/particle_emitter_record.d.ts +37 -0
- package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -0
- package/src/shade/renderer/particles/data/particle_emitter_record.js +109 -0
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +3 -3
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +303 -303
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +18 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +152 -133
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +0 -11
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +720 -621
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/compile_particle_graph.js +8 -3
- package/src/shade/renderer/particles/graph/flatten_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/flatten_particle_graph.js +244 -213
- package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +6 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +294 -319
- package/src/shade/renderer/particles/graph/groups/particle_groups_noise.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_groups_noise.js +524 -517
- package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts +22 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.js +517 -0
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +185 -159
- package/src/shade/renderer/particles/graph/make_particle_group.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/make_particle_group.js +2 -20
- package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts +17 -0
- package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/particle_compare_ops.js +22 -0
- package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts +28 -8
- package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_graph_diagnostic.js +49 -25
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +40 -0
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_parameters.js +312 -234
- package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_presentation.js +59 -3
- package/src/shade/renderer/particles/graph/particle_ramp.d.ts +230 -0
- package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/particle_ramp.js +403 -0
- package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +7 -1
- package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/validate_particle_graph.js +66 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +23 -69
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +105 -262
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles_avboit.js +3 -2
- package/src/shade/renderer/particles/graph_particles_billboard.d.ts +37 -0
- package/src/shade/renderer/particles/graph_particles_billboard.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph_particles_billboard.js +93 -0
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts +51 -22
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/InstructionStream.js +98 -38
- package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +49 -8
- package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleProgram.js +95 -150
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +306 -64
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleVMISA.js +505 -136
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts +36 -12
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/particle_assembly.js +354 -139
- package/src/shade/renderer/particles/isa/validate_particle_program.d.ts +9 -0
- package/src/shade/renderer/particles/isa/validate_particle_program.d.ts.map +1 -0
- package/src/shade/renderer/particles/isa/validate_particle_program.js +128 -0
- package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +23 -0
- package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
- package/src/shade/renderer/particles/layout/ParticleLayout.js +68 -0
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts +77 -0
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +219 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts +83 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +283 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +133 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +334 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts +117 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +70 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts +97 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +462 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts +116 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +687 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +57 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +860 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts +115 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.js +264 -0
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +81 -42
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +477 -478
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +100 -0
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +236 -0
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +139 -59
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +764 -647
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +40 -7
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +376 -213
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts +30 -3
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +337 -223
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +24 -38
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +166 -206
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts +99 -0
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +313 -0
- package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts +3 -2
- package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_dedup_constants.js +198 -197
- package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts +19 -0
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +678 -561
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts +22 -0
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +221 -0
- package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +63 -72
- package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +87 -86
- package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_peephole.js +392 -271
- package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +361 -268
- package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts +4 -0
- package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/pass_schedule.js +244 -0
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +154 -151
- package/src/shade/renderer/particles/particle_test_fixtures.d.ts +20 -0
- package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +1 -1
- package/src/shade/renderer/particles/particle_test_fixtures.js +229 -203
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +99 -25
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/EmitterRegistry.js +438 -286
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +109 -0
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -0
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +127 -0
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +87 -102
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.js +184 -163
- package/src/shade/renderer/particles/runtime/ProgramArena.d.ts +26 -0
- package/src/shade/renderer/particles/runtime/ProgramArena.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +130 -0
- package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -0
- package/src/shade/renderer/particles/runtime/ProgramHeap.js +595 -0
- package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts +91 -0
- package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts.map +1 -0
- package/src/shade/renderer/particles/runtime/ProgramPlacement.js +106 -0
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +5 -2
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -19
- package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts +28 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.js +136 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts +35 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.js +133 -0
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts +18 -9
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +20 -80
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts +33 -0
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +114 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts +8 -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 +33 -101
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts +45 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +123 -0
- package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts +51 -0
- package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts.map +1 -0
- package/src/shade/renderer/particles/sort/graph_particle_sort.js +120 -0
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts +6 -0
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +16 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +4 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +261 -140
- package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/chunk_particle_vm.js +217 -255
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts +43 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts.map +1 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.js +55 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts +62 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts.map +1 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.js +86 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.js +32 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts +9 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.js +19 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/README.md +65 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.js +83 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.js +42 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts +31 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.js +80 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts +26 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.js +109 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts +38 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.js +129 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts +21 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.js +35 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts +19 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.js +28 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.js +22 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.js +59 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.js +74 -0
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts +34 -1
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +41 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -2
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +49 -10
- package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
- package/src/view/minimap/dom/MinimapCameraView.js +4 -9
- package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts +0 -15
- package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts +0 -45
- package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts +0 -24
- package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts +0 -19
- package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts.map +0 -1
- package/src/engine/ecs/transform/__probe.d.ts +0 -4
- package/src/engine/ecs/transform/__probe.d.ts.map +0 -1
- package/src/engine/ecs/util/hideEntityGracefully.d.ts +0 -9
- package/src/engine/ecs/util/hideEntityGracefully.d.ts.map +0 -1
- package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts +0 -27
- package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts.map +0 -1
- package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts +0 -14
- package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +0 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts +0 -156
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/Emitter.d.ts +0 -219
- package/src/shade/renderer/particles/runtime/Emitter.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts +0 -77
- package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/ProgramArena.js +0 -155
- package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts +0 -15
- package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts +0 -34
- package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts.map +0 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts +0 -32
- package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts.map +0 -1
|
@@ -1,647 +1,764 @@
|
|
|
1
|
-
import { CSRGraph } from "../../../../core/graph/csr/CSRGraph.js";
|
|
2
|
-
import { PARTICLE_VM_REGISTER_SLOTS } from "../ParticleConstants.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* @
|
|
42
|
-
* @
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* @
|
|
55
|
-
* @property {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* @
|
|
62
|
-
*
|
|
63
|
-
* @
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
*
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* @
|
|
280
|
-
* @
|
|
281
|
-
*/
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
*
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
* @param {number}
|
|
438
|
-
* @param {number}
|
|
439
|
-
* @
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
1
|
+
import { CSRGraph } from "../../../../core/graph/csr/CSRGraph.js";
|
|
2
|
+
import { PARTICLE_VM_REGISTER_SLOTS } from "../ParticleConstants.js";
|
|
3
|
+
import {
|
|
4
|
+
VM_ISA,
|
|
5
|
+
VM_KIND,
|
|
6
|
+
VM_MAX_WIDTH,
|
|
7
|
+
VM_OP,
|
|
8
|
+
VM_SWIZZLE_IDENTITY,
|
|
9
|
+
swizzle_selector,
|
|
10
|
+
vm_decode_dst,
|
|
11
|
+
vm_decode_kinds,
|
|
12
|
+
vm_decode_op,
|
|
13
|
+
vm_decode_width,
|
|
14
|
+
vm_dest_width,
|
|
15
|
+
vm_kinds_problem,
|
|
16
|
+
vm_operand_base,
|
|
17
|
+
vm_operand_pattern,
|
|
18
|
+
vm_operand_slot,
|
|
19
|
+
vm_operation_width,
|
|
20
|
+
vm_register,
|
|
21
|
+
vm_visit_operands,
|
|
22
|
+
} from "../isa/ParticleVMISA.js";
|
|
23
|
+
import { vm_semantics_of } from "./particle_vm_semantics.js";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The analysis every optimizer pass reads: instructions decoded into the operands they resolve and
|
|
27
|
+
* the run they write, the def-use graph over those, and per-lane liveness.
|
|
28
|
+
*
|
|
29
|
+
* Everything here is derived, never authoritative — the instruction words are. A pass rewrites
|
|
30
|
+
* words and the next one re-derives, which is why there is no incremental update path and no
|
|
31
|
+
* mutation of an analysis in place: the programs are at most
|
|
32
|
+
* {@link ../ParticleConstants.js PARTICLE_VM_MAX_INSTRUCTIONS} instructions over
|
|
33
|
+
* {@link PARTICLE_VM_REGISTER_SLOTS} slots, and re-deriving all of it is cheaper than keeping it
|
|
34
|
+
* honest.
|
|
35
|
+
*
|
|
36
|
+
* ## Lanes, not registers
|
|
37
|
+
*
|
|
38
|
+
* A register is one `f32` slot and a value of width `w` is a run of `w` of them, so nothing here is
|
|
39
|
+
* per-register: a value's producer is per (instruction, lane), and so is its liveness. Which slots a
|
|
40
|
+
* source reads is the operand's own business — its base and its swizzle, read at as many lanes as the
|
|
41
|
+
* opcode takes of it — and {@link particle_read_slots} is the one place that turns an operand into
|
|
42
|
+
* slots. The ISA's {@link vm_visit_operands} is the one place that says how many lanes that is.
|
|
43
|
+
*
|
|
44
|
+
* ## Kinds
|
|
45
|
+
*
|
|
46
|
+
* A source is a register run or a literal, by the kind bits its instruction carries. Only the first
|
|
47
|
+
* is a run of the file, so `reads` holds only those — every question about liveness, aliasing and
|
|
48
|
+
* dependency is a question about the file, and a literal whose bits happen to look like a slot index
|
|
49
|
+
* must never answer it. The passes that care what a source *is* rather than where it lives — folding,
|
|
50
|
+
* sharing, the copy rewrites — read `sources`, which lists every operand with its kind.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @typedef {object} ParticleOperandRun
|
|
55
|
+
* @property {number} operand which source slot this is, `0..2`; `-1` for the destination
|
|
56
|
+
* @property {number} kind a `VM_KIND`; `REG` for every entry of `reads` and for the write
|
|
57
|
+
* @property {number} word the operand word as encoded
|
|
58
|
+
* @property {number} base first register slot, or `-1` for a literal
|
|
59
|
+
* @property {number} pattern the swizzle the operand reads through, as `pack_swizzle` packs one; the
|
|
60
|
+
* identity for a write
|
|
61
|
+
* @property {number} lanes how many lanes the instruction reads of it — the operation's width, or one
|
|
62
|
+
* for a slot the ISA marks scalar; for the write, how many it writes
|
|
63
|
+
* @property {number} span consecutive slots the operand reaches from its base
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @typedef {object} ParticleDecodedInstruction
|
|
68
|
+
* @property {number} index position in the stream
|
|
69
|
+
* @property {number[]} words the four instruction words
|
|
70
|
+
* @property {number} op
|
|
71
|
+
* @property {number} width the encoded width field
|
|
72
|
+
* @property {number} dst the encoded destination register
|
|
73
|
+
* @property {number} kinds the three source kinds as one field, as word 0 carries them
|
|
74
|
+
* @property {number} operation_width lanes the operation spans, after the ISA's fixed-width rules
|
|
75
|
+
* @property {object} meta the {@link VM_ISA} entry
|
|
76
|
+
* @property {import("./particle_vm_semantics.js").ParticleOpSemantics} semantics
|
|
77
|
+
* @property {ParticleOperandRun|null} write destination run, or null when the opcode writes nothing
|
|
78
|
+
* @property {ParticleOperandRun[]} reads every register operand the instruction reads — the `REG` sources
|
|
79
|
+
* @property {ParticleOperandRun[]} sources every source operand, whatever its kind, in slot order
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Decode one instruction into the operands it resolves and the run it writes.
|
|
84
|
+
*
|
|
85
|
+
* @param {ArrayLike<number>} words the four words of a single instruction
|
|
86
|
+
* @param {number} [index]
|
|
87
|
+
* @returns {ParticleDecodedInstruction}
|
|
88
|
+
*/
|
|
89
|
+
export function decode_particle_instruction(words, index = 0) {
|
|
90
|
+
const word0 = words[0];
|
|
91
|
+
const op = vm_decode_op(word0);
|
|
92
|
+
const width = vm_decode_width(word0);
|
|
93
|
+
const meta = VM_ISA.get(op);
|
|
94
|
+
|
|
95
|
+
if (meta === undefined) {
|
|
96
|
+
throw new Error(`particle optimizer: unknown opcode ${op} at instruction ${index}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const dst = vm_decode_dst(word0);
|
|
100
|
+
const dest = vm_dest_width(op, width);
|
|
101
|
+
|
|
102
|
+
/** @type {ParticleOperandRun|null} */
|
|
103
|
+
const write = dest === 0
|
|
104
|
+
? null
|
|
105
|
+
: { operand: -1, kind: VM_KIND.REG, word: dst, base: dst, pattern: VM_SWIZZLE_IDENTITY, lanes: dest, span: dest };
|
|
106
|
+
|
|
107
|
+
/** @type {ParticleOperandRun[]} */
|
|
108
|
+
const sources = [];
|
|
109
|
+
|
|
110
|
+
vm_visit_operands(words, 0, ({ slot, kind, word, lanes, span }) => {
|
|
111
|
+
sources.push({
|
|
112
|
+
operand: slot,
|
|
113
|
+
kind,
|
|
114
|
+
word,
|
|
115
|
+
base: kind === VM_KIND.REG ? vm_operand_base(word) : -1,
|
|
116
|
+
pattern: kind === VM_KIND.REG ? vm_operand_pattern(word) : VM_SWIZZLE_IDENTITY,
|
|
117
|
+
lanes,
|
|
118
|
+
span,
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
index,
|
|
124
|
+
words: [words[0], words[1], words[2], words[3]],
|
|
125
|
+
op,
|
|
126
|
+
width,
|
|
127
|
+
dst,
|
|
128
|
+
kinds: vm_decode_kinds(word0),
|
|
129
|
+
operation_width: vm_operation_width(op, width),
|
|
130
|
+
meta,
|
|
131
|
+
semantics: vm_semantics_of(op),
|
|
132
|
+
write,
|
|
133
|
+
reads: sources.filter(source => source.kind === VM_KIND.REG),
|
|
134
|
+
sources,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {ArrayLike<ArrayLike<number>>} instructions four-word tuples
|
|
140
|
+
* @returns {ParticleDecodedInstruction[]}
|
|
141
|
+
*/
|
|
142
|
+
export function decode_particle_instructions(instructions) {
|
|
143
|
+
const out = new Array(instructions.length);
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < instructions.length; i++) {
|
|
146
|
+
out[i] = decode_particle_instruction(instructions[i], i);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The slots a register operand reads, one per lane read — in lane order, and a slot appears once per
|
|
154
|
+
* lane that reads it, so a broadcast lists the same slot several times.
|
|
155
|
+
*
|
|
156
|
+
* @param {ParticleOperandRun} read a `REG` run
|
|
157
|
+
* @param {number} [lanes] how many lanes to read; the operand's own count when left out
|
|
158
|
+
* @returns {number[]}
|
|
159
|
+
*/
|
|
160
|
+
export function particle_read_slots(read, lanes = read.lanes) {
|
|
161
|
+
const slots = new Array(lanes);
|
|
162
|
+
|
|
163
|
+
for (let lane = 0; lane < lanes; lane++) {
|
|
164
|
+
slots[lane] = read.base + swizzle_selector(read.pattern, lane);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return slots;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Whether an instruction fits the register file: its kinds agree with its opcode, and every run it
|
|
172
|
+
* touches ends inside the file.
|
|
173
|
+
*
|
|
174
|
+
* There is no aliasing rule to check. Every executor resolves every source before it writes the
|
|
175
|
+
* destination, so a source may overlap the destination in any way and mean what it held before the
|
|
176
|
+
* instruction — which is also what lets a pass move a base or fold a swizzle without asking how the
|
|
177
|
+
* result sits against the other operands.
|
|
178
|
+
*
|
|
179
|
+
* @param {ArrayLike<number>} words the four words of a single instruction
|
|
180
|
+
* @returns {boolean}
|
|
181
|
+
*/
|
|
182
|
+
export function particle_instruction_is_well_formed(words) {
|
|
183
|
+
if (vm_kinds_problem(words, 0) !== null) {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const decoded = decode_particle_instruction(words);
|
|
188
|
+
const runs = decoded.write === null ? decoded.reads : [decoded.write, ...decoded.reads];
|
|
189
|
+
|
|
190
|
+
for (const run of runs) {
|
|
191
|
+
if (run.base < 0 || run.base + run.span > PARTICLE_VM_REGISTER_SLOTS) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Def-use over the instruction stream: an edge `i -> j` says instruction `j` reads a slot
|
|
201
|
+
* instruction `i` last wrote.
|
|
202
|
+
*
|
|
203
|
+
* Straight-line code with no control flow, so "last wrote" is exact rather than a may-reach
|
|
204
|
+
* approximation: one forward scan of a slot-indexed table finds every producer. The result is a
|
|
205
|
+
* {@link CSRGraph} because that is what the rest of the engine walks — `edge_addresses` /
|
|
206
|
+
* `adjacency` directly, without a per-vertex closure — and because dead-code elimination is then a
|
|
207
|
+
* reachability question over it rather than a bespoke container.
|
|
208
|
+
*
|
|
209
|
+
* A read of a slot nothing has written yet has no producer and contributes no edge: the register
|
|
210
|
+
* file starts zeroed on both executors, so such a read is a constant, not a dependency.
|
|
211
|
+
*
|
|
212
|
+
* @param {ParticleDecodedInstruction[]} decoded
|
|
213
|
+
* @param {number} [register_slots]
|
|
214
|
+
* @returns {CSRGraph} vertices are instructions; vertex `i`'s adjacency lists its consumers
|
|
215
|
+
*/
|
|
216
|
+
export function build_particle_def_use_graph(decoded, register_slots = PARTICLE_VM_REGISTER_SLOTS) {
|
|
217
|
+
const count = decoded.length;
|
|
218
|
+
const degree = new Uint32Array(count + 1);
|
|
219
|
+
/** @type {number[][]} consumer lists, gathered before the CSR is sized */
|
|
220
|
+
const edges = [];
|
|
221
|
+
|
|
222
|
+
const producer = new Int32Array(register_slots).fill(-1);
|
|
223
|
+
|
|
224
|
+
for (let i = 0; i < count; i++) {
|
|
225
|
+
const instruction = decoded[i];
|
|
226
|
+
/** @type {Set<number>} one edge per producing instruction, however many lanes it feeds */
|
|
227
|
+
const sources = new Set();
|
|
228
|
+
|
|
229
|
+
for (const read of instruction.reads) {
|
|
230
|
+
for (const slot of particle_read_slots(read)) {
|
|
231
|
+
const from = slot < register_slots ? producer[slot] : -1;
|
|
232
|
+
|
|
233
|
+
if (from >= 0) {
|
|
234
|
+
sources.add(from);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
for (const from of sources) {
|
|
240
|
+
edges.push([from, i]);
|
|
241
|
+
degree[from]++;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (instruction.write !== null) {
|
|
245
|
+
for (let lane = 0; lane < instruction.write.span; lane++) {
|
|
246
|
+
const slot = instruction.write.base + lane;
|
|
247
|
+
|
|
248
|
+
if (slot < register_slots) {
|
|
249
|
+
producer[slot] = i;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const graph = new CSRGraph(count, edges.length);
|
|
256
|
+
const addresses = graph.edge_addresses;
|
|
257
|
+
|
|
258
|
+
for (let i = 0; i < count; i++) {
|
|
259
|
+
addresses[i + 1] = addresses[i] + degree[i];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const cursor = addresses.slice(0, count);
|
|
263
|
+
|
|
264
|
+
for (const [from, to] of edges) {
|
|
265
|
+
graph.adjacency[cursor[from]++] = to;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
graph.edge_weights.fill(1);
|
|
269
|
+
|
|
270
|
+
return graph;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* @typedef {object} ParticleLaneAnalysis
|
|
275
|
+
* @property {Uint8Array} keep per instruction: whether it has to survive — it runs, and either it
|
|
276
|
+
* has an effect beyond its destination or something reads a lane it writes
|
|
277
|
+
* @property {Int32Array} width per instruction: the width field it could carry, once the lanes
|
|
278
|
+
* nothing reads are dropped. Equal to the encoded one wherever narrowing is not allowed.
|
|
279
|
+
* @property {Uint8Array} live_lanes per instruction: bitmask of destination lanes read later
|
|
280
|
+
* @property {number} halt_index index of the first `HALT`, or `-1`
|
|
281
|
+
*/
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Backward per-lane liveness: which lanes of each instruction's destination anything downstream
|
|
285
|
+
* actually reads, and therefore how narrow the instruction could be and whether it is needed at all.
|
|
286
|
+
*
|
|
287
|
+
* Registers do not outlive a section — both executors start a particle with a zeroed file — so the
|
|
288
|
+
* walk starts with nothing live and everything a program means has already been written to the
|
|
289
|
+
* record, the kill flag or the RNG by the time it ends.
|
|
290
|
+
*
|
|
291
|
+
* Narrowing is decided inside the same backward pass rather than after it, because an instruction's
|
|
292
|
+
* reads follow its width: a narrowed copy reads fewer lanes of its source, which is what makes the
|
|
293
|
+
* value above it dead. Deciding both at once reaches that fixed point in one sweep.
|
|
294
|
+
*
|
|
295
|
+
* @param {ParticleDecodedInstruction[]} decoded
|
|
296
|
+
* @param {number} [register_slots]
|
|
297
|
+
* @returns {ParticleLaneAnalysis}
|
|
298
|
+
*/
|
|
299
|
+
export function analyze_particle_lanes(decoded, register_slots = PARTICLE_VM_REGISTER_SLOTS) {
|
|
300
|
+
const count = decoded.length;
|
|
301
|
+
const keep = new Uint8Array(count);
|
|
302
|
+
const width = new Int32Array(count);
|
|
303
|
+
const live_lanes = new Uint8Array(count);
|
|
304
|
+
|
|
305
|
+
let halt_index = -1;
|
|
306
|
+
|
|
307
|
+
for (let i = 0; i < count; i++) {
|
|
308
|
+
width[i] = decoded[i].width;
|
|
309
|
+
|
|
310
|
+
if (halt_index < 0 && decoded[i].op === VM_OP.HALT) {
|
|
311
|
+
halt_index = i;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// A HALT returns, so nothing past the first one runs — and nothing past it can make a value live.
|
|
316
|
+
const last = halt_index >= 0 ? halt_index : count - 1;
|
|
317
|
+
const live = new Uint8Array(register_slots);
|
|
318
|
+
|
|
319
|
+
for (let i = last; i >= 0; i--) {
|
|
320
|
+
const instruction = decoded[i];
|
|
321
|
+
const semantics = instruction.semantics;
|
|
322
|
+
|
|
323
|
+
let mask = 0;
|
|
324
|
+
let highest_live = -1;
|
|
325
|
+
|
|
326
|
+
if (instruction.write !== null) {
|
|
327
|
+
for (let lane = 0; lane < instruction.write.span; lane++) {
|
|
328
|
+
if (live[instruction.write.base + lane]) {
|
|
329
|
+
mask |= 1 << lane;
|
|
330
|
+
highest_live = lane;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
live_lanes[i] = mask;
|
|
336
|
+
|
|
337
|
+
if (!semantics.side_effects && highest_live < 0) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
keep[i] = 1;
|
|
342
|
+
|
|
343
|
+
// Only the lanes below the highest live one have to be computed. Lanes are a contiguous run
|
|
344
|
+
// from zero, so a live lane 2 holds the width at 3 however dead lanes 0 and 1 are.
|
|
345
|
+
if (
|
|
346
|
+
semantics.narrowable
|
|
347
|
+
&& highest_live >= 0
|
|
348
|
+
&& instruction.write !== null
|
|
349
|
+
&& instruction.write.span === instruction.operation_width
|
|
350
|
+
) {
|
|
351
|
+
width[i] = Math.max(highest_live + 1, instruction.meta.min_width);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const operation_width = vm_operation_width(instruction.op, width[i]);
|
|
355
|
+
|
|
356
|
+
if (instruction.write !== null) {
|
|
357
|
+
const span = vm_dest_width(instruction.op, width[i]);
|
|
358
|
+
|
|
359
|
+
for (let lane = 0; lane < span; lane++) {
|
|
360
|
+
live[instruction.write.base + lane] = 0;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
for (const read of instruction.reads) {
|
|
365
|
+
for (const slot of particle_read_slots(read, particle_lanes_read_at(instruction, read, operation_width))) {
|
|
366
|
+
if (slot < register_slots) {
|
|
367
|
+
live[slot] = 1;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return { keep, width, live_lanes, halt_index };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* The most slots alive at once anywhere in the section — what a perfect allocator would need, and
|
|
378
|
+
* the one measure of an instruction order the scheduling pass is for.
|
|
379
|
+
*
|
|
380
|
+
* A slot is alive between a write and a later read of it; a read at the instruction that overwrites
|
|
381
|
+
* the slot counts for the value above, since every executor reads its sources before it writes.
|
|
382
|
+
* `HALT` is not special here: what follows one is dead code, and counting it can only overstate.
|
|
383
|
+
*
|
|
384
|
+
* @param {ParticleDecodedInstruction[]} decoded
|
|
385
|
+
* @param {number} [register_slots]
|
|
386
|
+
* @returns {number}
|
|
387
|
+
*/
|
|
388
|
+
export function particle_peak_live_slots(decoded, register_slots = PARTICLE_VM_REGISTER_SLOTS) {
|
|
389
|
+
const live = new Uint8Array(register_slots);
|
|
390
|
+
|
|
391
|
+
let alive = 0;
|
|
392
|
+
let peak = 0;
|
|
393
|
+
|
|
394
|
+
for (let i = decoded.length - 1; i >= 0; i--) {
|
|
395
|
+
const instruction = decoded[i];
|
|
396
|
+
|
|
397
|
+
if (instruction.write !== null) {
|
|
398
|
+
for (let lane = 0; lane < instruction.write.span; lane++) {
|
|
399
|
+
const slot = instruction.write.base + lane;
|
|
400
|
+
|
|
401
|
+
if (slot < register_slots && live[slot]) {
|
|
402
|
+
live[slot] = 0;
|
|
403
|
+
alive--;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
for (const read of instruction.reads) {
|
|
409
|
+
for (const slot of particle_read_slots(read)) {
|
|
410
|
+
if (slot >= 0 && slot < register_slots && !live[slot]) {
|
|
411
|
+
live[slot] = 1;
|
|
412
|
+
alive++;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
peak = Math.max(peak, alive);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return peak;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* How many lanes of a source an instruction reads once it is narrowed to `operation_width`: one for a
|
|
425
|
+
* slot the ISA marks scalar, the width for everything else.
|
|
426
|
+
*
|
|
427
|
+
* @param {ParticleDecodedInstruction} instruction
|
|
428
|
+
* @param {ParticleOperandRun} read
|
|
429
|
+
* @param {number} operation_width
|
|
430
|
+
* @returns {number}
|
|
431
|
+
*/
|
|
432
|
+
function particle_lanes_read_at(instruction, read, operation_width) {
|
|
433
|
+
return instruction.meta.scalar_operands.includes(read.operand) ? 1 : operation_width;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* @param {number} base_a
|
|
438
|
+
* @param {number} span_a
|
|
439
|
+
* @param {number} base_b
|
|
440
|
+
* @param {number} span_b
|
|
441
|
+
* @returns {boolean} whether the two runs share a slot
|
|
442
|
+
*/
|
|
443
|
+
export function particle_runs_overlap(base_a, span_a, base_b, span_b) {
|
|
444
|
+
return base_a < base_b + span_b && base_b < base_a + span_a;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Whether anything in `[from, to)` reads or writes any slot of a run.
|
|
449
|
+
*
|
|
450
|
+
* What a pass moving an instruction has to ask: a value that nothing in the gap looks at or
|
|
451
|
+
* disturbs can be produced anywhere in that gap. A read is taken at its whole span, which is at
|
|
452
|
+
* least what it touches.
|
|
453
|
+
*
|
|
454
|
+
* @param {ParticleDecodedInstruction[]} decoded
|
|
455
|
+
* @param {number} from inclusive
|
|
456
|
+
* @param {number} to exclusive
|
|
457
|
+
* @param {number} base
|
|
458
|
+
* @param {number} span
|
|
459
|
+
* @returns {boolean}
|
|
460
|
+
*/
|
|
461
|
+
export function particle_run_is_touched_between(decoded, from, to, base, span) {
|
|
462
|
+
for (let i = from; i < to; i++) {
|
|
463
|
+
const instruction = decoded[i];
|
|
464
|
+
|
|
465
|
+
if (instruction.write !== null
|
|
466
|
+
&& particle_runs_overlap(instruction.write.base, instruction.write.span, base, span)) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
for (const read of instruction.reads) {
|
|
471
|
+
if (particle_runs_overlap(read.base, read.span, base, span)) {
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Whether anything in `[from, to)` writes any slot of a run — the weaker question, for a pass that
|
|
482
|
+
* needs a value to still be where it was but does not mind who has looked at it in between.
|
|
483
|
+
*
|
|
484
|
+
* @param {ParticleDecodedInstruction[]} decoded
|
|
485
|
+
* @param {number} from inclusive
|
|
486
|
+
* @param {number} to exclusive
|
|
487
|
+
* @param {number} base
|
|
488
|
+
* @param {number} span
|
|
489
|
+
* @returns {boolean}
|
|
490
|
+
*/
|
|
491
|
+
export function particle_run_is_written_between(decoded, from, to, base, span) {
|
|
492
|
+
for (let i = from; i < to; i++) {
|
|
493
|
+
const instruction = decoded[i];
|
|
494
|
+
|
|
495
|
+
if (instruction.write !== null
|
|
496
|
+
&& particle_runs_overlap(instruction.write.base, instruction.write.span, base, span)) {
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Whether every slot of a run is overwritten — or the section ends — before anything reads it again.
|
|
506
|
+
*
|
|
507
|
+
* A run that is dead from `index` onwards belongs to nobody, so the instruction that filled it may
|
|
508
|
+
* be retargeted, folded into its consumer, or dropped.
|
|
509
|
+
*
|
|
510
|
+
* @param {ParticleDecodedInstruction[]} decoded
|
|
511
|
+
* @param {number} index the instruction after which to look
|
|
512
|
+
* @param {number} base
|
|
513
|
+
* @param {number} span
|
|
514
|
+
* @returns {boolean}
|
|
515
|
+
*/
|
|
516
|
+
export function particle_run_is_dead_after(decoded, index, base, span) {
|
|
517
|
+
const pending = new Set();
|
|
518
|
+
|
|
519
|
+
for (let lane = 0; lane < span; lane++) {
|
|
520
|
+
pending.add(base + lane);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
for (let i = index + 1; i < decoded.length && pending.size > 0; i++) {
|
|
524
|
+
const instruction = decoded[i];
|
|
525
|
+
|
|
526
|
+
// Nothing past a HALT runs, so nothing past it can want the value.
|
|
527
|
+
if (instruction.op === VM_OP.HALT) {
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
for (const read of instruction.reads) {
|
|
532
|
+
for (const slot of particle_read_slots(read)) {
|
|
533
|
+
if (pending.has(slot)) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (instruction.write !== null) {
|
|
540
|
+
for (let lane = 0; lane < instruction.write.span; lane++) {
|
|
541
|
+
pending.delete(instruction.write.base + lane);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Which value each register slot holds, as a number, and where that value was first computed.
|
|
551
|
+
*
|
|
552
|
+
* Two passes ask questions that turn out to be the same question underneath. "Is this register still
|
|
553
|
+
* the copy it was?" and "has this expression already been evaluated?" both reduce to comparing value
|
|
554
|
+
* numbers, and both need a copy to carry its source's number across rather than minting a new one —
|
|
555
|
+
* otherwise a value moved between registers stops being recognisable as itself.
|
|
556
|
+
*
|
|
557
|
+
* Numbers are minted per write and inherited by `MOV`, the one opcode that moves a value without
|
|
558
|
+
* changing it — through whatever swizzle its source carries, so a broadcast's lanes all hold one
|
|
559
|
+
* number and a permutation's hold the source's in the permuted order. Because a number is never
|
|
560
|
+
* reused, a slot overwritten since simply fails to match, and there is no invalidation step to get
|
|
561
|
+
* wrong.
|
|
562
|
+
*/
|
|
563
|
+
export class ParticleValueNumbering {
|
|
564
|
+
/**
|
|
565
|
+
* @param {number} [slots]
|
|
566
|
+
*/
|
|
567
|
+
constructor(slots = PARTICLE_VM_REGISTER_SLOTS) {
|
|
568
|
+
/** @type {number} */
|
|
569
|
+
this.slots = slots;
|
|
570
|
+
/** @type {Int32Array} the value in each slot */
|
|
571
|
+
this.value_id = new Int32Array(slots);
|
|
572
|
+
/** @type {Int32Array} the slot each value was first computed in */
|
|
573
|
+
this.home = new Int32Array(slots);
|
|
574
|
+
/** @type {Int32Array} which publish computed the value in each slot; `-1` for the reset's zero */
|
|
575
|
+
this.producer = new Int32Array(slots).fill(-1);
|
|
576
|
+
/** @type {number} */
|
|
577
|
+
this.next_id = slots;
|
|
578
|
+
/** @type {number} publishes so far, which is what names a producer */
|
|
579
|
+
this.published = 0;
|
|
580
|
+
|
|
581
|
+
// The file starts zeroed on both executors, but every slot is given a DISTINCT number: they
|
|
582
|
+
// hold equal values, not the same value, and nothing is gained by conflating them.
|
|
583
|
+
for (let slot = 0; slot < slots; slot++) {
|
|
584
|
+
this.value_id[slot] = slot;
|
|
585
|
+
this.home[slot] = slot;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* @param {number} base
|
|
591
|
+
* @param {number} span
|
|
592
|
+
* @returns {number[]|null} the numbers in that run, or `null` if it leaves the file
|
|
593
|
+
*/
|
|
594
|
+
ids_of(base, span) {
|
|
595
|
+
if (base < 0 || base + span > this.slots) {
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const ids = new Array(span);
|
|
600
|
+
|
|
601
|
+
for (let lane = 0; lane < span; lane++) {
|
|
602
|
+
ids[lane] = this.value_id[base + lane];
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return ids;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* The numbers a register operand reads, one per lane, through its swizzle.
|
|
610
|
+
*
|
|
611
|
+
* @param {ParticleOperandRun} read a `REG` run
|
|
612
|
+
* @returns {number[]|null} `null` if a lane reaches outside the file
|
|
613
|
+
*/
|
|
614
|
+
ids_read(read) {
|
|
615
|
+
const slots = particle_read_slots(read);
|
|
616
|
+
|
|
617
|
+
if (slots.some(slot => slot < 0 || slot >= this.slots)) {
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return slots.map(slot => this.value_id[slot]);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* @param {number} base
|
|
626
|
+
* @param {number[]} ids
|
|
627
|
+
* @returns {boolean} whether that run still holds exactly those values
|
|
628
|
+
*/
|
|
629
|
+
holds(base, ids) {
|
|
630
|
+
if (base < 0 || base + ids.length > this.slots) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
for (let lane = 0; lane < ids.length; lane++) {
|
|
635
|
+
if (this.value_id[base + lane] !== ids[lane]) {
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* The register operand that reads the same values from where they were first computed.
|
|
645
|
+
*
|
|
646
|
+
* Lane by lane, the value a read sees has a home slot; if every home still holds its value and
|
|
647
|
+
* the homes fit in the four slots a swizzle can reach from one base, the read can be redirected
|
|
648
|
+
* there. That is how a copy is read through, a broadcast folds into the consumer's swizzle, and a
|
|
649
|
+
* value moved between registers stays recognisable as itself.
|
|
650
|
+
*
|
|
651
|
+
* Every lane has to come from ONE instruction. Two producers' results side by side could be named
|
|
652
|
+
* by one swizzled operand too, but folding them there would leave both producers where they are;
|
|
653
|
+
* forwarding one of them into the copy's slot deletes the copy outright, and that is the rewrite
|
|
654
|
+
* the copy-propagation pass wants to have the chance to make.
|
|
655
|
+
*
|
|
656
|
+
* @param {ParticleOperandRun} read a `REG` run
|
|
657
|
+
* @returns {number} a register operand word, or `-1` when the values are not all at home, come from
|
|
658
|
+
* more than one producer, or their homes do not fit one operand
|
|
659
|
+
*/
|
|
660
|
+
origin_of_read(read) {
|
|
661
|
+
const slots = particle_read_slots(read);
|
|
662
|
+
const homes = new Array(slots.length);
|
|
663
|
+
|
|
664
|
+
let low = Infinity;
|
|
665
|
+
let high = -Infinity;
|
|
666
|
+
let producer = null;
|
|
667
|
+
|
|
668
|
+
for (let lane = 0; lane < slots.length; lane++) {
|
|
669
|
+
const slot = slots[lane];
|
|
670
|
+
|
|
671
|
+
if (slot < 0 || slot >= this.slots) {
|
|
672
|
+
return -1;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const home = this.home[slot];
|
|
676
|
+
|
|
677
|
+
if (this.value_id[home] !== this.value_id[slot]) {
|
|
678
|
+
return -1;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (producer !== null && this.producer[slot] !== producer) {
|
|
682
|
+
return -1;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
producer = this.producer[slot];
|
|
686
|
+
homes[lane] = home;
|
|
687
|
+
low = Math.min(low, home);
|
|
688
|
+
high = Math.max(high, home);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (high - low >= VM_MAX_WIDTH) {
|
|
692
|
+
return -1;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
let pattern = 0;
|
|
696
|
+
|
|
697
|
+
for (let lane = 0; lane < VM_MAX_WIDTH; lane++) {
|
|
698
|
+
// Lanes past the read are the identity: they are not read, and the canonical spelling
|
|
699
|
+
// wants them so.
|
|
700
|
+
const selector = lane < homes.length ? homes[lane] - low : lane;
|
|
701
|
+
|
|
702
|
+
pattern |= (selector & 3) << (2 * lane);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return vm_register(low, pattern);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Record what an instruction leaves in its destination.
|
|
710
|
+
*
|
|
711
|
+
* Takes the words as they will be EMITTED rather than as they were read, because a pass may have
|
|
712
|
+
* moved a source or rewritten the opcode by the time it gets here — the state has to describe
|
|
713
|
+
* the program that will run.
|
|
714
|
+
*
|
|
715
|
+
* @param {ArrayLike<number>} words the four words of a single instruction
|
|
716
|
+
*/
|
|
717
|
+
publish(words) {
|
|
718
|
+
const instruction = decode_particle_instruction(words);
|
|
719
|
+
|
|
720
|
+
if (instruction.write === null) {
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const base = instruction.write.base;
|
|
725
|
+
const span = instruction.write.span;
|
|
726
|
+
const publish = this.published++;
|
|
727
|
+
|
|
728
|
+
/** Gathered before anything is written: a source may alias the destination. */
|
|
729
|
+
const lanes = new Array(span);
|
|
730
|
+
|
|
731
|
+
if (instruction.semantics.broadcasts) {
|
|
732
|
+
// One value in every lane, so lane `i` is a copy of lane 0 and traces back to it — which
|
|
733
|
+
// is what lets a consumer read the scalar instead of the widened form.
|
|
734
|
+
const id = this.next_id++;
|
|
735
|
+
|
|
736
|
+
lanes.fill({ id, home: base, producer: publish });
|
|
737
|
+
} else {
|
|
738
|
+
// A copy carries values only from a REGISTER source. A literal is a value the file never
|
|
739
|
+
// held, so a MOV from one mints — and its word is not the slot it would otherwise be
|
|
740
|
+
// read as.
|
|
741
|
+
const source = instruction.op === VM_OP.MOV && instruction.sources[0].kind === VM_KIND.REG
|
|
742
|
+
? instruction.sources[0]
|
|
743
|
+
: null;
|
|
744
|
+
|
|
745
|
+
for (let lane = 0; lane < span; lane++) {
|
|
746
|
+
const from = source === null ? -1 : vm_operand_slot(source.word, lane);
|
|
747
|
+
|
|
748
|
+
lanes[lane] = from >= 0 && from < this.slots
|
|
749
|
+
? { id: this.value_id[from], home: this.home[from], producer: this.producer[from] }
|
|
750
|
+
: { id: this.next_id++, home: base + lane, producer: publish };
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
for (let lane = 0; lane < span; lane++) {
|
|
755
|
+
const slot = base + lane;
|
|
756
|
+
|
|
757
|
+
if (slot < this.slots) {
|
|
758
|
+
this.value_id[slot] = lanes[lane].id;
|
|
759
|
+
this.home[slot] = lanes[lane].home;
|
|
760
|
+
this.producer[slot] = lanes[lane].producer;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|