@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,478 +1,477 @@
|
|
|
1
|
-
import { assert } from "../../../../core/assert.js";
|
|
2
|
-
import { PARTICLE_VM_INSTRUCTION_WORDS, PARTICLE_VM_REGISTER_SLOTS } from "../ParticleConstants.js";
|
|
3
|
-
import { InstructionStream } from "../isa/InstructionStream.js";
|
|
4
|
-
import { ParticleAssembler } from "../isa/ParticleAssembler.js";
|
|
5
|
-
import { ParticleProgram } from "../isa/ParticleProgram.js";
|
|
6
|
-
import { VM_OP, vm_decode_op
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
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
|
-
*
|
|
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
|
-
* @type {
|
|
95
|
-
*/
|
|
96
|
-
export const
|
|
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
|
-
export
|
|
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
|
-
* @param {number[]
|
|
169
|
-
* @param {
|
|
170
|
-
* @param {
|
|
171
|
-
* @param {
|
|
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
|
-
* @param {
|
|
253
|
-
* @param {
|
|
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
|
-
|
|
302
|
-
|
|
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
|
-
|
|
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
|
-
|
|
438
|
-
|
|
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
|
-
}
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { PARTICLE_VM_INSTRUCTION_WORDS, PARTICLE_VM_REGISTER_SLOTS } from "../ParticleConstants.js";
|
|
3
|
+
import { InstructionStream } from "../isa/InstructionStream.js";
|
|
4
|
+
import { ParticleAssembler } from "../isa/ParticleAssembler.js";
|
|
5
|
+
import { ParticleProgram } from "../isa/ParticleProgram.js";
|
|
6
|
+
import { VM_OP, vm_decode_op } from "../isa/ParticleVMISA.js";
|
|
7
|
+
import { PARTICLE_PASS_ALLOCATE_REGISTERS, pass_allocate_registers } from "./pass_allocate_registers.js";
|
|
8
|
+
import { PARTICLE_PASS_DEAD_CODE, pass_eliminate_dead_code } from "./pass_eliminate_dead_code.js";
|
|
9
|
+
import {
|
|
10
|
+
PARTICLE_PASS_DEDUP_CONSTANTS,
|
|
11
|
+
pass_dedup_constants,
|
|
12
|
+
visit_particle_constant_reads,
|
|
13
|
+
} from "./pass_dedup_constants.js";
|
|
14
|
+
import { PARTICLE_PASS_FOLD_CONSTANTS, pass_fold_constants } from "./pass_fold_constants.js";
|
|
15
|
+
import { PARTICLE_PASS_INLINE_CONSTANTS, pass_inline_constants } from "./pass_inline_constants.js";
|
|
16
|
+
import { PARTICLE_PASS_NARROW_WIDTHS, pass_narrow_widths } from "./pass_narrow_widths.js";
|
|
17
|
+
import { PARTICLE_PASS_PACK_REGISTERS, pass_pack_registers } from "./pass_pack_registers.js";
|
|
18
|
+
import { PARTICLE_PASS_PEEPHOLE, pass_peephole } from "./pass_peephole.js";
|
|
19
|
+
import { PARTICLE_PASS_PROPAGATE_COPIES, pass_propagate_copies } from "./pass_propagate_copies.js";
|
|
20
|
+
import { PARTICLE_PASS_SHARE_SUBEXPRESSIONS, pass_share_subexpressions } from "./pass_share_subexpressions.js";
|
|
21
|
+
import { PARTICLE_PASS_SCHEDULE, pass_schedule } from "./pass_schedule.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Binary-level optimizer for particle VM programs: a {@link ParticleProgram} in, one out.
|
|
25
|
+
*
|
|
26
|
+
* {@link optimize_particle_program} is the entry point and its options are FLAT — the passes to run
|
|
27
|
+
* as a list of names, and every rewrite a caller might want to name as an option of its own. Which
|
|
28
|
+
* pass implements a rewrite is this file's business and not the caller's, so
|
|
29
|
+
* `{ fold_multiply_by_zero: false }` asks for exact arithmetic without naming the pass that would
|
|
30
|
+
* otherwise round. {@link ./dag/optimize_particle_program_vector.js the graph optimizer} has the
|
|
31
|
+
* same shape, so a caller can hold both and choose between them.
|
|
32
|
+
*
|
|
33
|
+
* It runs over a compiled {@link InstructionStream} rather than inside any one frontend, because
|
|
34
|
+
* there is more than one frontend — the node-graph compiler, the assembly text pane in the editor,
|
|
35
|
+
* and whatever comes next — and the same waste appears in all of them. The node compiler lowers a
|
|
36
|
+
* value at a time and has no way to know that the broadcast it just emitted will be read one lane
|
|
37
|
+
* wide; a pass over the finished stream can simply look.
|
|
38
|
+
*
|
|
39
|
+
* ## Shape
|
|
40
|
+
*
|
|
41
|
+
* Passes are ordinary functions from an instruction array to a new one, with `null` for "changed
|
|
42
|
+
* nothing". All but one never reorder: every pass rewrites an instruction in place or drops it,
|
|
43
|
+
* which is what makes the ordering constraints — `RANDOM`'s draw sequence, `STORE_ATTR`/`LOAD_ATTR`
|
|
44
|
+
* aliasing — hold structurally rather than by each pass remembering them. The one that does,
|
|
45
|
+
* `pass_schedule`, moves nothing across an instruction with side effects, which keeps the same
|
|
46
|
+
* constraints structural for it.
|
|
47
|
+
*
|
|
48
|
+
* The pipeline sweeps the enabled passes in order until a whole sweep changes nothing or
|
|
49
|
+
* `max_iterations` sweeps have run, then schedules, allocates and packs the register file — and
|
|
50
|
+
* sweeps again if that changed anything, since a reordered program is one the passes have not seen.
|
|
51
|
+
* Passes that pay to repeat on their own take their own `max_iterations`, so effort is the
|
|
52
|
+
* caller's to spend.
|
|
53
|
+
*
|
|
54
|
+
* ## What must not change
|
|
55
|
+
*
|
|
56
|
+
* A program's meaning is the record it leaves, the kill flag it sets, and the RNG state it ends on.
|
|
57
|
+
* Every pass here preserves all three to the bit, with one deliberate exception: folding `x * 0` to
|
|
58
|
+
* `+0` gives up the sign of that zero, and gives up `NaN` where something upstream overflowed. That
|
|
59
|
+
* substitution is made in a register, so what it does to the record is whatever the instructions
|
|
60
|
+
* below it do with a zero — which is not bounded, and is why the harness holds the fold to the
|
|
61
|
+
* record words a multiply can REACH rather than to a shape. It is on by default — see the argument
|
|
62
|
+
* in `pass_fold_constants.js` — and `{ fold_multiply_by_zero: false }`
|
|
63
|
+
* takes the optimizer back to bit-identical. `optimize_particle_program.spec.js` and the
|
|
64
|
+
* differential harness beside it hold both settings to their respective promises, over the real
|
|
65
|
+
* distribution compositions, the hand-written spec programs and randomly generated ones.
|
|
66
|
+
*
|
|
67
|
+
* Two further rewrites change the arithmetic and are off unless a caller names them:
|
|
68
|
+
* `fuse_multiply_add`, which is a rounding the reference can see, and `fold_inexact`, which is a
|
|
69
|
+
* rounding only a GPU can see — the fast-math fold of the transcendentals and `rsqrt`. Each is
|
|
70
|
+
* argued where it lives.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @callback ParticleOptimizerPass
|
|
75
|
+
* @param {number[][]} instructions five-word tuples, in program order
|
|
76
|
+
* @param {ParticleOptimizerContext} context
|
|
77
|
+
* @returns {number[][]|null} the rewritten stream, or `null` when the pass changed nothing
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @typedef {object} ParticleOptimizerContext
|
|
82
|
+
* @property {ArrayLike<number>} constants the shared constant pool, one float per word
|
|
83
|
+
* @property {((values: number[]) => number)|null} intern_constant interns a run of constants and
|
|
84
|
+
* returns its first word index — {@link ../isa/ParticleAssembler.js}'s `constant`. Without it a
|
|
85
|
+
* pass can read the pool but not add to it, which only costs it the folds that need a new literal.
|
|
86
|
+
* @property {number} register_slots size of the register file
|
|
87
|
+
* @property {number} max_iterations how many times this pass may repeat itself
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The passes, in the order a sweep runs them. `final` passes run once, after the sweeps settle.
|
|
92
|
+
* A pass marked `enabled: false` runs only when a caller switches it on by name.
|
|
93
|
+
*
|
|
94
|
+
* @type {Array<{name: string, run: ParticleOptimizerPass, max_iterations: number, final?: boolean, enabled?: boolean}>}
|
|
95
|
+
*/
|
|
96
|
+
export const PARTICLE_OPTIMIZER_PASSES = [
|
|
97
|
+
{ name: PARTICLE_PASS_DEAD_CODE, run: pass_eliminate_dead_code, max_iterations: 1 },
|
|
98
|
+
{ name: PARTICLE_PASS_NARROW_WIDTHS, run: pass_narrow_widths, max_iterations: 1 },
|
|
99
|
+
{ name: PARTICLE_PASS_FOLD_CONSTANTS, run: pass_fold_constants, max_iterations: 1 },
|
|
100
|
+
// Before sharing, and after the folds that intern new literals: two loads of one value are the
|
|
101
|
+
// same subexpression only once they name the same pool word.
|
|
102
|
+
{ name: PARTICLE_PASS_DEDUP_CONSTANTS, run: pass_dedup_constants, max_iterations: 1 },
|
|
103
|
+
{ name: PARTICLE_PASS_SHARE_SUBEXPRESSIONS, run: pass_share_subexpressions, max_iterations: 1 },
|
|
104
|
+
{ name: PARTICLE_PASS_PROPAGATE_COPIES, run: pass_propagate_copies, max_iterations: 3 },
|
|
105
|
+
{ name: PARTICLE_PASS_PEEPHOLE, run: pass_peephole, max_iterations: 1 },
|
|
106
|
+
// Last in the sweep: every pass above reasons about constants as loads into registers, and
|
|
107
|
+
// once a constant is an operand of its consumer there is nothing left for them to see. This is
|
|
108
|
+
// where the literal kind pays — a third of the simulate pass on a constant-heavy effect, see
|
|
109
|
+
// ../vm/chunk_particle_vm.js — so it is on like the rest.
|
|
110
|
+
{ name: PARTICLE_PASS_INLINE_CONSTANTS, run: pass_inline_constants, max_iterations: 1 },
|
|
111
|
+
// Once the instructions have settled, their order: a value that lives no longer than it must
|
|
112
|
+
// is a slot the allocator below can give back.
|
|
113
|
+
{ name: PARTICLE_PASS_SCHEDULE, run: pass_schedule, max_iterations: 1, final: true },
|
|
114
|
+
// Allocation packs after every placement itself, so packing on its own is what runs when the
|
|
115
|
+
// allocator is switched off — and a no-op after it.
|
|
116
|
+
{ name: PARTICLE_PASS_ALLOCATE_REGISTERS, run: pass_allocate_registers, max_iterations: 1, final: true },
|
|
117
|
+
{ name: PARTICLE_PASS_PACK_REGISTERS, run: pass_pack_registers, max_iterations: 1, final: true },
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The passes that run unless the caller names a different set. For bisecting, and for measuring what
|
|
122
|
+
* each pass is worth; the rewrites that change the ARITHMETIC rather than the program are flat
|
|
123
|
+
* options instead of passes, so that this stays a list of what to run and not a list of what to
|
|
124
|
+
* trust. `fold_multiply_by_zero` is on, `fuse_multiply_add` and `fold_inexact` are off, and each is
|
|
125
|
+
* argued where it lives.
|
|
126
|
+
*
|
|
127
|
+
* @type {ReadonlyArray<string>}
|
|
128
|
+
*/
|
|
129
|
+
export const PARTICLE_OPTIMIZER_DEFAULT_PASSES = Object.freeze(
|
|
130
|
+
PARTICLE_OPTIMIZER_PASSES.filter(pass => pass.enabled !== false).map(pass => pass.name)
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* How many times the whole pass list may sweep before the optimizer gives up on reaching a fixed
|
|
135
|
+
* point. Passes feed each other — folding a `SELECT` makes a broadcast dead, deleting it lets the
|
|
136
|
+
* value above narrow — so one sweep is never enough. Two settle every program in this tree and
|
|
137
|
+
* three settle the worst of a hundred generated ones; the budget is well clear of that, because a
|
|
138
|
+
* program that ran out of sweeps would be a program whose optimization depended on the budget.
|
|
139
|
+
*
|
|
140
|
+
* @type {number}
|
|
141
|
+
*/
|
|
142
|
+
export const PARTICLE_OPTIMIZER_DEFAULT_ITERATIONS = 8;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Optimize one section of a particle program.
|
|
146
|
+
*
|
|
147
|
+
* The options are flat, and the ones that are not about the pipeline itself are handed to every pass
|
|
148
|
+
* — each takes the ones it knows and ignores the rest, which is why a rewrite like
|
|
149
|
+
* `fold_multiply_by_zero` is named here rather than buried under the pass that happens to implement
|
|
150
|
+
* it. A caller asking for exact arithmetic should not have to know which pass would otherwise round.
|
|
151
|
+
*
|
|
152
|
+
* @param {InstructionStream} stream
|
|
153
|
+
* @param {object} [options]
|
|
154
|
+
* @param {ArrayLike<number>} [options.constants] the shared constant pool; without it the passes
|
|
155
|
+
* that reason about literal values do nothing
|
|
156
|
+
* @param {function(number[]): number} [options.intern_constant] adds a run to that pool
|
|
157
|
+
* @param {ReadonlyArray<string>} [options.passes] the passes to run, defaulting to
|
|
158
|
+
* {@link PARTICLE_OPTIMIZER_DEFAULT_PASSES}; see {@link particle_passes_except}
|
|
159
|
+
* @param {number} [options.max_iterations] sweeps of the whole pass list
|
|
160
|
+
* @param {boolean} [options.speculate] whether to try lane peeling both ways and keep the better
|
|
161
|
+
* program; on unless told otherwise. Off makes the pipeline a straight run of its passes, which is
|
|
162
|
+
* what a caller measuring one pass in isolation wants.
|
|
163
|
+
* @param {number} [options.register_slots]
|
|
164
|
+
* @param {boolean} [options.fold_multiply_by_zero] a known zero absorbs a multiply
|
|
165
|
+
* @param {boolean} [options.fold_inexact] fold what the two executors may round apart
|
|
166
|
+
* @param {boolean} [options.peel_constant_lanes] split a lane whose value is known off its
|
|
167
|
+
* instruction
|
|
168
|
+
* @param {number} [options.max_select_moves] how many copies folding a `SELECT` may cost
|
|
169
|
+
* @param {boolean} [options.fuse_multiply_add] fuse where the rounding may differ
|
|
170
|
+
* @param {boolean} [options.fuse_exact_multiply_add] fuse where it cannot
|
|
171
|
+
* @param {boolean} [options.merge_constant_loads] join adjacent pool loads into one run
|
|
172
|
+
* @param {boolean} [options.merge_moves] join adjacent copies into one
|
|
173
|
+
* @returns {InstructionStream} a fresh stream, whose `register_count` is re-derived from what the
|
|
174
|
+
* optimized instructions actually touch
|
|
175
|
+
*/
|
|
176
|
+
export function optimize_particle_section(stream, {
|
|
177
|
+
constants = [],
|
|
178
|
+
intern_constant = null,
|
|
179
|
+
register_slots = PARTICLE_VM_REGISTER_SLOTS,
|
|
180
|
+
passes = PARTICLE_OPTIMIZER_DEFAULT_PASSES,
|
|
181
|
+
max_iterations = PARTICLE_OPTIMIZER_DEFAULT_ITERATIONS,
|
|
182
|
+
speculate = true,
|
|
183
|
+
...settings
|
|
184
|
+
} = {}) {
|
|
185
|
+
assert.ok(stream instanceof InstructionStream, "stream must be an InstructionStream");
|
|
186
|
+
assert.isNonNegativeInteger(max_iterations, "max_iterations");
|
|
187
|
+
|
|
188
|
+
/** @type {number[][]} */
|
|
189
|
+
const instructions = stream.instructions.map(words => words.slice());
|
|
190
|
+
const enabled = new Set(passes);
|
|
191
|
+
const base_context = { ...settings, constants, intern_constant, register_slots };
|
|
192
|
+
|
|
193
|
+
const speculative = to_stream(run_pipeline(instructions, base_context, enabled, max_iterations));
|
|
194
|
+
|
|
195
|
+
if (speculate === false || !enabled.has(PARTICLE_PASS_FOLD_CONSTANTS) || settings.peel_constant_lanes === false) {
|
|
196
|
+
return speculative;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Peeling a constant tail off an instruction always costs one instruction where it fires, and
|
|
200
|
+
// pays only through what dies above it — a mask's load, the broadcast feeding it, the arithmetic
|
|
201
|
+
// that built them. Whether that cascade happens is not a local question, and a heuristic for it
|
|
202
|
+
// would be wrong on somebody's effect. So the pipeline is run both ways and the better program
|
|
203
|
+
// kept; these are at most a few hundred instructions and settling one twice costs nothing worth
|
|
204
|
+
// measuring.
|
|
205
|
+
const conservative = to_stream(
|
|
206
|
+
run_pipeline(instructions, { ...base_context, peel_constant_lanes: false }, enabled, max_iterations)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
return better_of(conservative, speculative);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Sweep the enabled passes to a fixed point, then the closing ones to theirs — and round again
|
|
214
|
+
* while the closing passes keep finding something.
|
|
215
|
+
*
|
|
216
|
+
* The two halves feed each other. A schedule frees slots the allocator then reuses, and an
|
|
217
|
+
* allocated file constrains the next schedule; and a program in a new order is a program the sweep
|
|
218
|
+
* passes have not seen — a copy whose original is now intact until the read, two loads that are now
|
|
219
|
+
* adjacent. Each closing acceptance shrinks the file or its peak, so the rounds are bounded by the
|
|
220
|
+
* file's size, and a program that comes back unchanged from a round is one a second run of the
|
|
221
|
+
* optimizer would also leave alone.
|
|
222
|
+
*
|
|
223
|
+
* @param {number[][]} instructions
|
|
224
|
+
* @param {object} base_context
|
|
225
|
+
* @param {Set<string>} enabled
|
|
226
|
+
* @param {number} max_iterations sweeps of the pass list per round
|
|
227
|
+
* @returns {number[][]}
|
|
228
|
+
*/
|
|
229
|
+
function run_pipeline(instructions, base_context, enabled, max_iterations) {
|
|
230
|
+
const running = PARTICLE_OPTIMIZER_PASSES.filter(pass => enabled.has(pass.name));
|
|
231
|
+
const sweep = running.filter(pass => pass.final !== true);
|
|
232
|
+
const closing = running.filter(pass => pass.final === true);
|
|
233
|
+
|
|
234
|
+
let current = instructions;
|
|
235
|
+
|
|
236
|
+
for (let round = 0; round < 2 * base_context.register_slots; round++) {
|
|
237
|
+
current = run_to_fixed_point(sweep, current, base_context, max_iterations);
|
|
238
|
+
|
|
239
|
+
const closed = run_to_fixed_point(closing, current, base_context, 2 * base_context.register_slots);
|
|
240
|
+
|
|
241
|
+
if (closed === current) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
current = closed;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return current;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @param {Array<{name: string, run: ParticleOptimizerPass, max_iterations: number}>} passes
|
|
253
|
+
* @param {number[][]} instructions
|
|
254
|
+
* @param {object} base_context
|
|
255
|
+
* @param {number} max_iterations
|
|
256
|
+
* @returns {number[][]} the settled stream — `instructions` itself when nothing changed
|
|
257
|
+
*/
|
|
258
|
+
function run_to_fixed_point(passes, instructions, base_context, max_iterations) {
|
|
259
|
+
let current = instructions;
|
|
260
|
+
|
|
261
|
+
for (let iteration = 0; iteration < max_iterations; iteration++) {
|
|
262
|
+
let changed = false;
|
|
263
|
+
|
|
264
|
+
for (const pass of passes) {
|
|
265
|
+
const result = pass.run(current, { ...base_context, max_iterations: pass.max_iterations });
|
|
266
|
+
|
|
267
|
+
if (result !== null) {
|
|
268
|
+
current = result;
|
|
269
|
+
changed = true;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (!changed) {
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return current;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Fewer instructions wins; a tie goes to the smaller register file, and a tie there to the
|
|
283
|
+
* speculative one, whose instructions are the narrower of the two.
|
|
284
|
+
*
|
|
285
|
+
* @param {InstructionStream} conservative
|
|
286
|
+
* @param {InstructionStream} speculative
|
|
287
|
+
* @returns {InstructionStream}
|
|
288
|
+
*/
|
|
289
|
+
function better_of(conservative, speculative) {
|
|
290
|
+
if (conservative.instruction_count !== speculative.instruction_count) {
|
|
291
|
+
return conservative.instruction_count < speculative.instruction_count ? conservative : speculative;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return conservative.register_count < speculative.register_count ? conservative : speculative;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* The default passes with these ones left out — what a caller turning ONE pass off wants, without
|
|
299
|
+
* having to write down the ten it is keeping.
|
|
300
|
+
*
|
|
301
|
+
* @param {...string} names
|
|
302
|
+
* @returns {string[]}
|
|
303
|
+
*/
|
|
304
|
+
export function particle_passes_except(...names) {
|
|
305
|
+
return PARTICLE_OPTIMIZER_DEFAULT_PASSES.filter(name => !names.includes(name));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Optimize a compiled program: `ParticleProgram` in, `ParticleProgram` out.
|
|
310
|
+
*
|
|
311
|
+
* The entry point, and the same shape
|
|
312
|
+
* {@link ./dag/optimize_particle_program_vector.js the graph optimizer} has — one program in, one
|
|
313
|
+
* out, flat options — so that a caller can hold both and choose.
|
|
314
|
+
*
|
|
315
|
+
* Both sections are optimized against one constant pool, which is shared and may grow: a folded
|
|
316
|
+
* expression needs somewhere to put its literal. It is interned through a
|
|
317
|
+
* {@link ParticleAssembler}, which is the code that already knows how to reuse a run anywhere in the
|
|
318
|
+
* pool rather than only one on a boundary.
|
|
319
|
+
*
|
|
320
|
+
* @param {ParticleProgram} program
|
|
321
|
+
* @param {object} [options] as {@link optimize_particle_section}, minus the pool it supplies itself
|
|
322
|
+
* @returns {ParticleProgram}
|
|
323
|
+
*/
|
|
324
|
+
export function optimize_particle_program(program, options = {}) {
|
|
325
|
+
assert.ok(program instanceof ParticleProgram, "program must be a ParticleProgram");
|
|
326
|
+
|
|
327
|
+
const assembler = new ParticleAssembler();
|
|
328
|
+
|
|
329
|
+
assembler.constants = Array.from(program.constants);
|
|
330
|
+
|
|
331
|
+
const shared = {
|
|
332
|
+
...options,
|
|
333
|
+
constants: assembler.constants,
|
|
334
|
+
intern_constant: (values) => assembler.constant(...values),
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const init = optimize_particle_section(stream_from_words(program.init), shared);
|
|
338
|
+
const update = optimize_particle_section(stream_from_words(program.update), shared);
|
|
339
|
+
|
|
340
|
+
const init_words = init.toWords();
|
|
341
|
+
const update_words = update.toWords();
|
|
342
|
+
|
|
343
|
+
// Last, and here rather than in a pass: which pool words are dead is a question about the whole
|
|
344
|
+
// program, and a pass sees one section. Running it before the sections settled would be wrong
|
|
345
|
+
// twice over — the folds are still interning, and the speculation below has not yet thrown away
|
|
346
|
+
// the run whose literals are the dead ones.
|
|
347
|
+
const constants = sweep_particle_constants(
|
|
348
|
+
[init_words, update_words],
|
|
349
|
+
assembler.constants,
|
|
350
|
+
(options.passes ?? PARTICLE_OPTIMIZER_DEFAULT_PASSES).includes(PARTICLE_PASS_DEDUP_CONSTANTS)
|
|
351
|
+
&& options.sweep !== false
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
return new ParticleProgram({
|
|
355
|
+
init: init_words,
|
|
356
|
+
update: update_words,
|
|
357
|
+
constants,
|
|
358
|
+
register_count: Math.max(init.register_count, update.register_count),
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Drop the pool words no section loads any more, and move the loads onto what is left.
|
|
364
|
+
*
|
|
365
|
+
* Marking is per word rather than per run, and that is what makes compaction safe for runs that
|
|
366
|
+
* overlap — a scalar sharing the leading word of a `vec4` is something the assembler deliberately
|
|
367
|
+
* produces. Every word of a live run is marked, and compaction keeps marked words in order, so a run
|
|
368
|
+
* whose words were consecutive still is; only its base moves.
|
|
369
|
+
*
|
|
370
|
+
* @param {Uint32Array[]} sections instruction words, rewritten in place
|
|
371
|
+
* @param {ArrayLike<number>} constants the shared pool
|
|
372
|
+
* @param {boolean} enabled
|
|
373
|
+
* @returns {Float32Array} the pool the sections now address
|
|
374
|
+
*/
|
|
375
|
+
function sweep_particle_constants(sections, constants, enabled) {
|
|
376
|
+
if (!enabled) {
|
|
377
|
+
return new Float32Array(constants);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const live = new Uint8Array(constants.length);
|
|
381
|
+
|
|
382
|
+
let well_formed = true;
|
|
383
|
+
|
|
384
|
+
for (const words of sections) {
|
|
385
|
+
visit_particle_constant_reads(instruction_tuples(words), (index, base, span) => {
|
|
386
|
+
if (base < 0 || base + span > constants.length) {
|
|
387
|
+
// Out of the pool already. Compacting under it would turn a program that fails
|
|
388
|
+
// validation into one that fails it somewhere else, so nothing is touched.
|
|
389
|
+
well_formed = false;
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
for (let i = 0; i < span; i++) {
|
|
394
|
+
live[base + i] = 1;
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (!well_formed) {
|
|
400
|
+
return new Float32Array(constants);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** @type {number[]} */
|
|
404
|
+
const kept = [];
|
|
405
|
+
|
|
406
|
+
/** @type {Int32Array} old word index -> new one; only meaningful where `live` */
|
|
407
|
+
const remap = new Int32Array(constants.length);
|
|
408
|
+
|
|
409
|
+
for (let i = 0; i < constants.length; i++) {
|
|
410
|
+
remap[i] = kept.length;
|
|
411
|
+
|
|
412
|
+
if (live[i] === 1) {
|
|
413
|
+
kept.push(constants[i]);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (kept.length !== constants.length) {
|
|
418
|
+
for (const words of sections) {
|
|
419
|
+
for (let base = 0; base < words.length; base += PARTICLE_VM_INSTRUCTION_WORDS) {
|
|
420
|
+
if (vm_decode_op(words[base]) === VM_OP.LOAD_CONST) {
|
|
421
|
+
words[base + 1] = remap[words[base + 1]];
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return new Float32Array(kept);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* A packed section as the four-word tuples the pass helpers read.
|
|
432
|
+
*
|
|
433
|
+
* @param {Uint32Array} words
|
|
434
|
+
* @returns {Uint32Array[]} views, so nothing is copied
|
|
435
|
+
*/
|
|
436
|
+
function instruction_tuples(words) {
|
|
437
|
+
const out = [];
|
|
438
|
+
|
|
439
|
+
for (let base = 0; base < words.length; base += PARTICLE_VM_INSTRUCTION_WORDS) {
|
|
440
|
+
out.push(words.subarray(base, base + PARTICLE_VM_INSTRUCTION_WORDS));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return out;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* @param {Uint32Array} words a packed instruction section
|
|
448
|
+
* @returns {InstructionStream}
|
|
449
|
+
*/
|
|
450
|
+
export function stream_from_words(words) {
|
|
451
|
+
const out = new InstructionStream();
|
|
452
|
+
|
|
453
|
+
for (let base = 0; base < words.length; base += PARTICLE_VM_INSTRUCTION_WORDS) {
|
|
454
|
+
out.emitWords(words.subarray(base, base + PARTICLE_VM_INSTRUCTION_WORDS));
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return out;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Re-emit into a fresh stream, so the register high-water mark is the optimized program's rather
|
|
462
|
+
* than the one it was built from. A file that shrank is itself part of the win — it is the
|
|
463
|
+
* interpreter's dominant register cost (see the occupancy note in `vm/chunk_particle_vm.js`) — and
|
|
464
|
+
* carrying the old count forward would hide it.
|
|
465
|
+
*
|
|
466
|
+
* @param {number[][]} instructions
|
|
467
|
+
* @returns {InstructionStream}
|
|
468
|
+
*/
|
|
469
|
+
function to_stream(instructions) {
|
|
470
|
+
const out = new InstructionStream();
|
|
471
|
+
|
|
472
|
+
for (const words of instructions) {
|
|
473
|
+
out.emitWords(words);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return out;
|
|
477
|
+
}
|