@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,561 +1,678 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
*
|
|
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
|
-
* What
|
|
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
|
-
return
|
|
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
|
-
|
|
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
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
1
|
+
import {
|
|
2
|
+
VM_KIND,
|
|
3
|
+
VM_OP,
|
|
4
|
+
swizzle_selector,
|
|
5
|
+
vm_dest_width,
|
|
6
|
+
vm_f32_value,
|
|
7
|
+
vm_pack_instruction,
|
|
8
|
+
vm_register,
|
|
9
|
+
vm_with_width,
|
|
10
|
+
} from "../isa/ParticleVMISA.js";
|
|
11
|
+
import {
|
|
12
|
+
decode_particle_instructions,
|
|
13
|
+
particle_instruction_is_well_formed,
|
|
14
|
+
particle_read_slots,
|
|
15
|
+
} from "./particle_program_analysis.js";
|
|
16
|
+
|
|
17
|
+
/** @type {string} */
|
|
18
|
+
export const PARTICLE_PASS_FOLD_CONSTANTS = "fold_constants";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The opcodes whose result a known zero operand decides on its own — the ones
|
|
22
|
+
* `fold_multiply_by_zero` rewrites, and therefore the ones whose results the equivalence harness's
|
|
23
|
+
* reach mode has to follow. Stated once so the two cannot drift.
|
|
24
|
+
* @type {Set<number>}
|
|
25
|
+
*/
|
|
26
|
+
export const PARTICLE_ZERO_ABSORBING_OPS = new Set([VM_OP.MUL]);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Track what each register lane is known to hold, and rewrite the instructions that turn out not to
|
|
30
|
+
* need computing.
|
|
31
|
+
*
|
|
32
|
+
* Two things come out of this. Instructions whose every output lane is a known number become a
|
|
33
|
+
* `LOAD_CONST`, which usually makes everything feeding them dead. And instructions that are a known
|
|
34
|
+
* *shape* rather than a known value collapse: a `SELECT` whose condition is a compile-time mask is
|
|
35
|
+
* per-lane copying, and a multiply by one is a copy.
|
|
36
|
+
*
|
|
37
|
+
* The graph compiler emits both shapes constantly. It has no notion of a compile-time-known lane
|
|
38
|
+
* mask, so `graph/particle_graph_distributions.js` assembling `(cos, sin, 0)` out of a `select` on
|
|
39
|
+
* the literal `[0, 1, 0]` lowers to a broadcast, a second broadcast, a constant load and a `SELECT`
|
|
40
|
+
* — four instructions for what is one `MOV`, and this pass is what notices.
|
|
41
|
+
*
|
|
42
|
+
* ## What is not folded, and why
|
|
43
|
+
*
|
|
44
|
+
* A lane is tracked only while its value is FINITE. `NaN` and `±Inf` are dropped from the analysis
|
|
45
|
+
* rather than propagated, which removes at a stroke every rewrite that is right for ordinary numbers
|
|
46
|
+
* and wrong at the edges — `min(NaN, x)` is the reference's `NaN` and the GPU's anything, and a
|
|
47
|
+
* baked `NaN` constant is at the mercy of a driver that assumes there are none.
|
|
48
|
+
*
|
|
49
|
+
* Only operations both executors are obliged to round identically are evaluated here — see
|
|
50
|
+
* `foldable` in {@link ./particle_vm_semantics.js}. Folding `sin` would quietly hand the GPU the
|
|
51
|
+
* CPU's answer, so it happens only when a caller asks for it by name: see `fold_inexact` below.
|
|
52
|
+
*
|
|
53
|
+
* Every identity here is exact — `x * 1`, `x / 1` and `x - (+0)` are `x` for every value a register
|
|
54
|
+
* can hold — with one deliberate exception, below.
|
|
55
|
+
*
|
|
56
|
+
* ## Multiplying by zero: the one place this is not exact
|
|
57
|
+
*
|
|
58
|
+
* `x * 0` is `+0` for finite non-negative `x`, `-0` for finite negative `x`, and `NaN` for `±Inf`
|
|
59
|
+
* and `NaN`. Folding it to `+0` is therefore a fast-math relaxation rather than a rewrite, and it is
|
|
60
|
+
* on by default (`fold_multiply_by_zero`) because a particle effect essentially never needs the
|
|
61
|
+
* distinction and the shape it unlocks is everywhere.
|
|
62
|
+
*
|
|
63
|
+
* That shape is the lane mask. `graph/particle_graph_distributions.js` clears the lanes a disk has
|
|
64
|
+
* nothing to say about by multiplying through `[1, 1, 0]`, and the lowering has no way to know the
|
|
65
|
+
* result of that lane is a constant. With the fold it becomes one, the tail of the instruction is
|
|
66
|
+
* peeled off as a constant load, and the multiply, the mask's own load and the broadcast feeding it
|
|
67
|
+
* all go dead behind it.
|
|
68
|
+
*
|
|
69
|
+
* What it costs is not bounded by a shape — a substituted zero is read by whatever comes next, and
|
|
70
|
+
* a comparison or a division downstream can turn the difference into any number. The equivalence
|
|
71
|
+
* harness bounds its REACH instead: see `reached_by_zero_fold` in
|
|
72
|
+
* {@link ./particle_program_equivalence.js}. Switch the fold off
|
|
73
|
+
* (`{ fold_multiply_by_zero: false }`) and every pass in the
|
|
74
|
+
* optimizer is bit-exact again.
|
|
75
|
+
*
|
|
76
|
+
* ## `fold_inexact`: the transcendentals, off by default
|
|
77
|
+
*
|
|
78
|
+
* `{ fold_inexact: true }` also evaluates the operations whose two
|
|
79
|
+
* executors are allowed to round apart — `foldable_inexact` in
|
|
80
|
+
* {@link ./particle_vm_semantics.js}: the trigonometry and its inverses, `exp`, `log`, `pow`,
|
|
81
|
+
* `smoothstep`, `mix`, `mad` and `rsqrt`. That is HLSL's fast-math trade and it is worth naming
|
|
82
|
+
* rather than assuming: what is bought is a literal instead of a transcendental, and what is sold
|
|
83
|
+
* is the GPU's own last bits — `Math.sin` and a GPU's `sin` agree to about a part in 10^7, and
|
|
84
|
+
* with the fold on it is the CPU's answer that ships.
|
|
85
|
+
*
|
|
86
|
+
* It is off because that is not a trade the compiler gets to make on an author's behalf, and
|
|
87
|
+
* because there is nothing here to buy with it. The fold only fires where an argument is already a
|
|
88
|
+
* compile-time constant, and over all eighteen built-in groups — `curl4`, the simplex noises, the
|
|
89
|
+
* quaternion and sampling groups, 6,523 instructions optimized — turning it on changes not one
|
|
90
|
+
* instruction: every `sin` in the tree takes its argument from a `random`, an attribute or a
|
|
91
|
+
* builtin. On the fuzzer's programs, where the opcode mix is uniform and operands are often
|
|
92
|
+
* literals, it takes another 8.8% off what the default pipeline leaves (5,443 to 4,963 over 200
|
|
93
|
+
* programs). So the option is real and tested and worth having for a frontend that folds harder
|
|
94
|
+
* than this one — and on today's effects it is a switch with nothing behind it.
|
|
95
|
+
*
|
|
96
|
+
* What it does NOT do is turn a hardware `NaN` into a number. Only finite values are tracked, so
|
|
97
|
+
* `log` of zero, `asin` of two and `rsqrt` of a negative are all left alone by the same rule that
|
|
98
|
+
* leaves every other edge alone; the two operations whose reference spelling is defined where the
|
|
99
|
+
* hardware's is not — `pow` of a non-positive base and `smoothstep` with equal edges, both of which
|
|
100
|
+
* WGSL computes through a division or a `log2` that the reference does not — are refused in
|
|
101
|
+
* {@link evaluate} rather than relaxed. The relaxation is a rounding, and stays one.
|
|
102
|
+
*
|
|
103
|
+
* ## Operands
|
|
104
|
+
*
|
|
105
|
+
* A literal operand is a known value by construction, and a register operand's lanes are looked up
|
|
106
|
+
* through its swizzle — so a broadcast of a known register is known in every lane, and a `SELECT`
|
|
107
|
+
* between a register and a literal collapses to a `MOV` from whichever the mask picks, with the
|
|
108
|
+
* operand's kind and swizzle carried along.
|
|
109
|
+
*
|
|
110
|
+
* @type {import("./optimize_particle_program.js").ParticleOptimizerPass}
|
|
111
|
+
*/
|
|
112
|
+
export function pass_fold_constants(instructions, context) {
|
|
113
|
+
const decoded = decode_particle_instructions(instructions);
|
|
114
|
+
const slots = context.register_slots;
|
|
115
|
+
|
|
116
|
+
/** Whether a slot's value is known — and finite, which is the only kind that is tracked. */
|
|
117
|
+
const known = new Uint8Array(slots);
|
|
118
|
+
/** f32, so a tracked value is exactly the one the register would hold. */
|
|
119
|
+
const value = new Float32Array(slots);
|
|
120
|
+
|
|
121
|
+
const options = {
|
|
122
|
+
max_select_moves: 2,
|
|
123
|
+
fold_multiply_by_zero: true,
|
|
124
|
+
fold_inexact: false,
|
|
125
|
+
peel_constant_lanes: true,
|
|
126
|
+
...context,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/** @type {number[][]} */
|
|
130
|
+
const out = [];
|
|
131
|
+
|
|
132
|
+
let changed = false;
|
|
133
|
+
|
|
134
|
+
for (const instruction of decoded) {
|
|
135
|
+
const lanes = evaluate_lanes(instruction, known, value, options);
|
|
136
|
+
const replacement = rewrite(instruction, lanes, known, value, options);
|
|
137
|
+
|
|
138
|
+
if (replacement === null) {
|
|
139
|
+
out.push(instruction.words);
|
|
140
|
+
} else {
|
|
141
|
+
out.push(...replacement);
|
|
142
|
+
changed = true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
publish(instruction, lanes, known, value);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return changed ? out : null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* What each lane of the destination will hold, as far as it can be worked out here.
|
|
153
|
+
*
|
|
154
|
+
* @param {import("./particle_program_analysis.js").ParticleDecodedInstruction} instruction
|
|
155
|
+
* @param {Uint8Array} known
|
|
156
|
+
* @param {Float32Array} value
|
|
157
|
+
* @param {object} options
|
|
158
|
+
* @returns {Array<number|null>} one entry per destination lane; `null` where the value is not known
|
|
159
|
+
*/
|
|
160
|
+
function evaluate_lanes(instruction, known, value, options) {
|
|
161
|
+
if (instruction.write === null) {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const count = vm_dest_width(instruction.op, instruction.width);
|
|
166
|
+
/** @type {Array<number|null>} */
|
|
167
|
+
const lanes = new Array(count).fill(null);
|
|
168
|
+
|
|
169
|
+
if (instruction.op === VM_OP.LOAD_CONST) {
|
|
170
|
+
for (let lane = 0; lane < count; lane++) {
|
|
171
|
+
lanes[lane] = finite(options.constants[instruction.words[1] + lane]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return lanes;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (instruction.op === VM_OP.LOAD_ATTR) {
|
|
178
|
+
// Lanes past the component count are the zero an over-wide load is defined to read. The
|
|
179
|
+
// ones inside it are whatever the record holds, which is not knowable here.
|
|
180
|
+
for (let lane = instruction.words[2]; lane < count; lane++) {
|
|
181
|
+
lanes[lane] = 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return lanes;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Exact always; the ones the two executors may round apart only when the caller has asked for
|
|
188
|
+
// that trade by name.
|
|
189
|
+
const foldable = instruction.semantics.foldable
|
|
190
|
+
|| (options.fold_inexact && instruction.semantics.foldable_inexact);
|
|
191
|
+
|
|
192
|
+
if (!foldable) {
|
|
193
|
+
return lanes;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
for (let lane = 0; lane < count; lane++) {
|
|
197
|
+
/** @type {Array<number|undefined>} */
|
|
198
|
+
const inputs = [];
|
|
199
|
+
let complete = true;
|
|
200
|
+
|
|
201
|
+
for (const source of instruction.sources) {
|
|
202
|
+
const held = source_lane_value(source, lane, known, value);
|
|
203
|
+
|
|
204
|
+
if (held === null) {
|
|
205
|
+
complete = false;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
inputs[source.operand] = held;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (complete) {
|
|
213
|
+
lanes[lane] = finite(evaluate_particle_operation(instruction.op, inputs[0], inputs[1], inputs[2]));
|
|
214
|
+
} else if (options.fold_multiply_by_zero) {
|
|
215
|
+
lanes[lane] = absorbed_by_zero(instruction.op, inputs);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return lanes;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Zero as an absorbing element: a known zero on either side of a multiply gives zero, whatever the
|
|
224
|
+
* other operand turns out to be.
|
|
225
|
+
*
|
|
226
|
+
* This is the one thing here that is not true of every value a register can hold — `±Inf * 0` and
|
|
227
|
+
* `NaN * 0` are `NaN`, and a negative operand gives `-0` — and it is what the module comment above
|
|
228
|
+
* argues the trade for. A known `-0` absorbs as readily as a known `+0`: once the sign of the result
|
|
229
|
+
* is being given up, it is being given up either way.
|
|
230
|
+
*
|
|
231
|
+
* @param {number} op
|
|
232
|
+
* @param {Array<number|undefined>} inputs by operand slot, `undefined` where the value is unknown
|
|
233
|
+
* @returns {number|null}
|
|
234
|
+
*/
|
|
235
|
+
function absorbed_by_zero(op, inputs) {
|
|
236
|
+
if (!PARTICLE_ZERO_ABSORBING_OPS.has(op)) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return inputs[0] === 0 || inputs[1] === 0 ? 0 : null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* One lane of an operation, in the arithmetic the reference executes it in: `f32` operands, an
|
|
245
|
+
* `f64` computation, and the result rounded back to `f32` — which for a single correctly-rounded
|
|
246
|
+
* operation is the same number an `f32` machine produces.
|
|
247
|
+
*
|
|
248
|
+
* @param {number} op
|
|
249
|
+
* @param {number} a
|
|
250
|
+
* @param {number} b
|
|
251
|
+
* @param {number} c
|
|
252
|
+
* @returns {number}
|
|
253
|
+
*/
|
|
254
|
+
export function evaluate_particle_operation(op, a, b, c) {
|
|
255
|
+
switch (op) {
|
|
256
|
+
case VM_OP.MOV: return a;
|
|
257
|
+
case VM_OP.ADD: return Math.fround(a + b);
|
|
258
|
+
case VM_OP.SUB: return Math.fround(a - b);
|
|
259
|
+
case VM_OP.MUL: return Math.fround(a * b);
|
|
260
|
+
case VM_OP.DIV: return Math.fround(a / b);
|
|
261
|
+
// `Math.min(-0, 0)` is `-0` and WGSL's `min`, spelled `select(e1, e2, e2 < e1)`, is `0` —
|
|
262
|
+
// the one place these two executors are allowed to disagree bit for bit. Refusing the fold
|
|
263
|
+
// wherever a zero is involved closes it without pretending the rest of `min` is unreliable.
|
|
264
|
+
case VM_OP.MIN: return a === 0 || b === 0 ? NaN : Math.min(a, b);
|
|
265
|
+
case VM_OP.MAX: return a === 0 || b === 0 ? NaN : Math.max(a, b);
|
|
266
|
+
case VM_OP.CLAMP: return a === 0 || b === 0 || c === 0 ? NaN : Math.min(Math.max(a, b), c);
|
|
267
|
+
case VM_OP.NEG: return -a;
|
|
268
|
+
case VM_OP.ABS: return Math.abs(a);
|
|
269
|
+
case VM_OP.FLOOR: return Math.floor(a);
|
|
270
|
+
case VM_OP.FRACT: return Math.fround(a - Math.floor(a));
|
|
271
|
+
case VM_OP.SQRT: return Math.fround(Math.sqrt(a));
|
|
272
|
+
case VM_OP.STEP: return b < a ? 0 : 1;
|
|
273
|
+
case VM_OP.CMP_LT: return a < b ? 1 : 0;
|
|
274
|
+
case VM_OP.CMP_LE: return a <= b ? 1 : 0;
|
|
275
|
+
case VM_OP.CMP_GT: return a > b ? 1 : 0;
|
|
276
|
+
case VM_OP.CMP_GE: return a >= b ? 1 : 0;
|
|
277
|
+
case VM_OP.CMP_EQ: return a === b ? 1 : 0;
|
|
278
|
+
case VM_OP.SELECT: return c > 0.5 ? b : a;
|
|
279
|
+
|
|
280
|
+
// --- reached only under `fold_inexact` ---
|
|
281
|
+
//
|
|
282
|
+
// Each of these is spelled exactly as `../vm/ParticleVMReference.js` spells it, so the fold
|
|
283
|
+
// and the reference agree to the bit and it is the GPU that is allowed to differ. That is
|
|
284
|
+
// the whole of what the option trades; anything an executor could disagree about by more
|
|
285
|
+
// than a rounding is refused below rather than folded.
|
|
286
|
+
case VM_OP.MAD: return Math.fround(a * b + c);
|
|
287
|
+
case VM_OP.MIX: return Math.fround(a + (b - a) * c);
|
|
288
|
+
case VM_OP.SIN: return Math.fround(Math.sin(a));
|
|
289
|
+
case VM_OP.COS: return Math.fround(Math.cos(a));
|
|
290
|
+
case VM_OP.TAN: return Math.fround(Math.tan(a));
|
|
291
|
+
case VM_OP.ASIN: return Math.fround(Math.asin(a));
|
|
292
|
+
case VM_OP.ACOS: return Math.fround(Math.acos(a));
|
|
293
|
+
case VM_OP.EXP: return Math.fround(Math.exp(a));
|
|
294
|
+
case VM_OP.LOG: return Math.fround(Math.log(a));
|
|
295
|
+
// `1 / sqrt(a)` for `a <= 0` is an infinity or a `NaN`, and `finite` drops both — the same
|
|
296
|
+
// rule that keeps `SQRT` next door out of trouble, so there is nothing to say here.
|
|
297
|
+
case VM_OP.RSQRT: return Math.fround(1 / Math.sqrt(a));
|
|
298
|
+
// WGSL's `pow` is `exp2(e2 * log2(e1))`, which is a `NaN` for every base at or below zero
|
|
299
|
+
// — including `pow(0, 0)`, where JS says 1. A fold that turned the hardware's `NaN` into a
|
|
300
|
+
// number would not be a rounding, so the non-positive bases are not folded at all.
|
|
301
|
+
case VM_OP.POW: return a > 0 ? Math.fround(Math.pow(a, b)) : NaN;
|
|
302
|
+
// Equal edges divide by zero on the GPU; the reference answers 0 or 1 instead. Same
|
|
303
|
+
// argument as `pow`: refuse the case rather than ship the reference's answer for it.
|
|
304
|
+
case VM_OP.SMOOTHSTEP: {
|
|
305
|
+
if (a === b) {
|
|
306
|
+
return NaN;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const t = Math.min(Math.max((c - a) / (b - a), 0), 1);
|
|
310
|
+
|
|
311
|
+
return Math.fround(t * t * (3 - 2 * t));
|
|
312
|
+
}
|
|
313
|
+
// `atan2(0, 0)` is 0 in JS and left to the implementation in WGSL. Every other pair is an
|
|
314
|
+
// angle both agree on to a rounding.
|
|
315
|
+
case VM_OP.ATAN2: return a === 0 && b === 0 ? NaN : Math.fround(Math.atan2(a, b));
|
|
316
|
+
|
|
317
|
+
default: return NaN;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Only finite values are tracked. Dropping `NaN` and `±Inf` here is what keeps every rewrite below
|
|
323
|
+
* from having to restate its own edge cases.
|
|
324
|
+
*
|
|
325
|
+
* @param {number} x
|
|
326
|
+
* @returns {number|null}
|
|
327
|
+
*/
|
|
328
|
+
function finite(x) {
|
|
329
|
+
return Number.isFinite(x) ? Math.fround(x) : null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* What one lane of a source is known to hold: a literal is its own value, a register operand is
|
|
334
|
+
* whatever the analysis has tracked into the slot its swizzle names for that lane. `null` where the
|
|
335
|
+
* value is not known — or not finite, since only finite values are ever tracked.
|
|
336
|
+
*
|
|
337
|
+
* @param {import("./particle_program_analysis.js").ParticleOperandRun} source
|
|
338
|
+
* @param {number} lane output lane
|
|
339
|
+
* @param {Uint8Array} known
|
|
340
|
+
* @param {Float32Array} value
|
|
341
|
+
* @returns {number|null}
|
|
342
|
+
*/
|
|
343
|
+
function source_lane_value(source, lane, known, value) {
|
|
344
|
+
if (source.kind === VM_KIND.IMM) {
|
|
345
|
+
return finite(vm_f32_value(source.word));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// A scalar source feeds every lane from its first; everything else reads straight across.
|
|
349
|
+
const slot = source.base + swizzle_selector(source.pattern, source.lanes === 1 ? 0 : lane);
|
|
350
|
+
|
|
351
|
+
return slot < known.length && known[slot] ? value[slot] : null;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* A `MOV` of `width` lanes into `dst` from a source operand, from `first` lanes into it, keeping the
|
|
356
|
+
* source's kind: a copy of a register is that register read through the selectors those lanes use,
|
|
357
|
+
* a copy of a literal is that literal.
|
|
358
|
+
*
|
|
359
|
+
* @param {number} width
|
|
360
|
+
* @param {number} dst
|
|
361
|
+
* @param {import("./particle_program_analysis.js").ParticleOperandRun} source
|
|
362
|
+
* @param {number} [first]
|
|
363
|
+
* @returns {number[]}
|
|
364
|
+
*/
|
|
365
|
+
function move_from(width, dst, source, first = 0) {
|
|
366
|
+
if (source.kind === VM_KIND.IMM) {
|
|
367
|
+
return vm_pack_instruction(VM_OP.MOV, width, dst, [VM_KIND.IMM, VM_KIND.NONE, VM_KIND.NONE], [source.word, 0, 0]);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
let pattern = 0;
|
|
371
|
+
|
|
372
|
+
for (let lane = 0; lane < 4; lane++) {
|
|
373
|
+
pattern |= swizzle_selector(source.pattern, first + lane) << (2 * lane);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return vm_pack_instruction(
|
|
377
|
+
VM_OP.MOV, width, dst,
|
|
378
|
+
[VM_KIND.REG, VM_KIND.NONE, VM_KIND.NONE],
|
|
379
|
+
[vm_register(source.base, pattern), 0, 0]
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @param {import("./particle_program_analysis.js").ParticleDecodedInstruction} instruction
|
|
385
|
+
* @param {Array<number|null>} lanes
|
|
386
|
+
* @param {Uint8Array} known
|
|
387
|
+
* @param {Float32Array} value
|
|
388
|
+
*/
|
|
389
|
+
function publish(instruction, lanes, known, value) {
|
|
390
|
+
if (instruction.write === null) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
for (let lane = 0; lane < lanes.length; lane++) {
|
|
395
|
+
const slot = instruction.write.base + lane;
|
|
396
|
+
|
|
397
|
+
if (slot >= known.length) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
known[slot] = lanes[lane] === null ? 0 : 1;
|
|
402
|
+
value[slot] = lanes[lane] ?? 0;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* @param {import("./particle_program_analysis.js").ParticleDecodedInstruction} instruction
|
|
408
|
+
* @param {Array<number|null>} lanes
|
|
409
|
+
* @param {Uint8Array} known
|
|
410
|
+
* @param {Float32Array} value
|
|
411
|
+
* @param {object} options
|
|
412
|
+
* @returns {number[][]|null} what to emit instead, or `null` to keep the instruction
|
|
413
|
+
*/
|
|
414
|
+
function rewrite(instruction, lanes, known, value, options) {
|
|
415
|
+
if (instruction.semantics.side_effects) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const materialised = materialise(instruction, lanes, options);
|
|
420
|
+
|
|
421
|
+
if (materialised !== null) {
|
|
422
|
+
return materialised;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (instruction.op === VM_OP.SELECT) {
|
|
426
|
+
const collapsed = collapse_select(instruction, known, value, options.max_select_moves);
|
|
427
|
+
|
|
428
|
+
if (collapsed !== null) {
|
|
429
|
+
return collapsed;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const identity = collapse_identity(instruction, known, value);
|
|
434
|
+
|
|
435
|
+
if (identity !== null) {
|
|
436
|
+
return identity;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return options.peel_constant_lanes ? peel_constant_tail(instruction, lanes, options) : null;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Split an instruction whose trailing lanes turn out to be constants into the narrower instruction
|
|
444
|
+
* that computes the rest, plus one load for the tail.
|
|
445
|
+
*
|
|
446
|
+
* One instruction becomes two, which only pays for itself through what it frees: the narrowed
|
|
447
|
+
* instruction stops reading the upper lanes of its sources, and those are usually a broadcast, a
|
|
448
|
+
* mask, and the arithmetic that built them. A distribution's mask lane is exactly this shape.
|
|
449
|
+
*
|
|
450
|
+
* Only for opcodes that compute their result from registers. `LOAD_ATTR`'s lanes past its component
|
|
451
|
+
* count are already the zero it reads for free, and peeling those would be a load in place of
|
|
452
|
+
* nothing at all.
|
|
453
|
+
*
|
|
454
|
+
* @param {import("./particle_program_analysis.js").ParticleDecodedInstruction} instruction
|
|
455
|
+
* @param {Array<number|null>} lanes
|
|
456
|
+
* @param {object} options
|
|
457
|
+
* @returns {number[][]|null}
|
|
458
|
+
*/
|
|
459
|
+
function peel_constant_tail(instruction, lanes, options) {
|
|
460
|
+
if (
|
|
461
|
+
options.intern_constant === null
|
|
462
|
+
|| instruction.write === null
|
|
463
|
+
|| instruction.sources.length === 0
|
|
464
|
+
|| !instruction.semantics.narrowable
|
|
465
|
+
|| instruction.write.span !== instruction.operation_width
|
|
466
|
+
) {
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// The longest run of known lanes at the top, leaving at least one below it for the instruction
|
|
471
|
+
// to still be worth issuing — one that is constant all the way down was materialised above.
|
|
472
|
+
let first = lanes.length;
|
|
473
|
+
|
|
474
|
+
while (first > 0 && lanes[first - 1] !== null) {
|
|
475
|
+
first--;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (first === lanes.length || first < Math.max(1, instruction.meta.min_width)) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const narrowed = instruction.words.slice();
|
|
483
|
+
|
|
484
|
+
narrowed[0] = vm_with_width(narrowed[0], first);
|
|
485
|
+
|
|
486
|
+
const load = vm_pack_instruction(
|
|
487
|
+
VM_OP.LOAD_CONST, lanes.length - first, instruction.write.base + first,
|
|
488
|
+
[VM_KIND.NONE, VM_KIND.NONE, VM_KIND.NONE],
|
|
489
|
+
[options.intern_constant(lanes.slice(first)), 0, 0]
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
return particle_instruction_is_well_formed(narrowed) && particle_instruction_is_well_formed(load)
|
|
493
|
+
? [narrowed, load]
|
|
494
|
+
: null;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Replace an instruction whose every output lane is a known number with the load of that number.
|
|
499
|
+
*
|
|
500
|
+
* Neutral in instruction count on its own; the win is that it cuts the instruction loose from
|
|
501
|
+
* everything that fed it, which is usually then dead.
|
|
502
|
+
*
|
|
503
|
+
* @returns {number[][]|null}
|
|
504
|
+
*/
|
|
505
|
+
function materialise(instruction, lanes, options) {
|
|
506
|
+
if (
|
|
507
|
+
instruction.op === VM_OP.LOAD_CONST
|
|
508
|
+
|| options.intern_constant === null
|
|
509
|
+
|| lanes.length === 0
|
|
510
|
+
|| lanes.some(lane => lane === null)
|
|
511
|
+
) {
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// A reduction writes one lane whatever it reads, so the load that replaces it is one lane wide.
|
|
516
|
+
const words = vm_pack_instruction(
|
|
517
|
+
VM_OP.LOAD_CONST, lanes.length, instruction.write.base,
|
|
518
|
+
[VM_KIND.NONE, VM_KIND.NONE, VM_KIND.NONE],
|
|
519
|
+
[options.intern_constant(lanes), 0, 0]
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
return particle_instruction_is_well_formed(words) ? [words] : null;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* A `SELECT` whose condition is known lane by lane is not a choice, it is copying — and most of
|
|
527
|
+
* those copies are a register into itself.
|
|
528
|
+
*
|
|
529
|
+
* The replacement is capped at `max_select_moves` instructions: what pays for the split is the
|
|
530
|
+
* constant load feeding the condition going dead, so a mask that alternates lane by lane and needs
|
|
531
|
+
* a `MOV` for each run is not worth taking apart.
|
|
532
|
+
*
|
|
533
|
+
* The `SELECT` read every source before it wrote; the `MOV`s run one after another. So a copy is
|
|
534
|
+
* refused where a later one would read a slot an earlier one has already written — the case the
|
|
535
|
+
* split cannot express — and a run taken from the destination itself is a copy of a register into
|
|
536
|
+
* itself and is left out.
|
|
537
|
+
*
|
|
538
|
+
* @returns {number[][]|null}
|
|
539
|
+
*/
|
|
540
|
+
function collapse_select(instruction, known, value, max_select_moves) {
|
|
541
|
+
const [when_false, when_true, condition] = instruction.sources;
|
|
542
|
+
const width = instruction.operation_width;
|
|
543
|
+
/** @type {import("./particle_program_analysis.js").ParticleOperandRun[]} the source picked, per lane */
|
|
544
|
+
const chosen = new Array(width);
|
|
545
|
+
|
|
546
|
+
for (let lane = 0; lane < width; lane++) {
|
|
547
|
+
const mask = source_lane_value(condition, lane, known, value);
|
|
548
|
+
|
|
549
|
+
if (mask === null) {
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
chosen[lane] = mask > 0.5 ? when_true : when_false;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** @type {number[][]} */
|
|
557
|
+
const moves = [];
|
|
558
|
+
/** @type {Set<number>} slots the copies emitted so far have written */
|
|
559
|
+
const written = new Set();
|
|
560
|
+
|
|
561
|
+
for (let lane = 0; lane < width;) {
|
|
562
|
+
let end = lane + 1;
|
|
563
|
+
|
|
564
|
+
while (end < width && chosen[end] === chosen[lane]) {
|
|
565
|
+
end++;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const picked = chosen[lane];
|
|
569
|
+
const is_itself = picked.kind === VM_KIND.REG
|
|
570
|
+
&& particle_read_slots(picked, width).slice(lane, end).every((slot, i) => slot === instruction.write.base + lane + i);
|
|
571
|
+
|
|
572
|
+
if (!is_itself) {
|
|
573
|
+
const words = move_from(end - lane, instruction.write.base + lane, picked, lane);
|
|
574
|
+
|
|
575
|
+
if (!particle_instruction_is_well_formed(words)) {
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (picked.kind === VM_KIND.REG
|
|
580
|
+
&& particle_read_slots(picked, width).slice(lane, end).some(slot => written.has(slot))) {
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
moves.push(words);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
for (let slot = lane; slot < end; slot++) {
|
|
588
|
+
written.add(instruction.write.base + slot);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
lane = end;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return moves.length <= max_select_moves ? moves : null;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* The arithmetic identities that hold for every value a register can hold, not merely the ordinary
|
|
599
|
+
* ones.
|
|
600
|
+
*
|
|
601
|
+
* `x * 1`, `x / 1` and `x - (+0)` are `x` bit for bit — including `-0`, `±Inf` and `NaN` — so they
|
|
602
|
+
* are copies. `x + 0` is not: `-0 + 0` is `+0`. `x * 0` is not: it is `-0` for negative `x` and
|
|
603
|
+
* `NaN` for a non-finite one. The line is drawn at what is exactly true, because the record a
|
|
604
|
+
* program leaves is compared to the bit.
|
|
605
|
+
*
|
|
606
|
+
* `MAD` with a multiplier of one becomes an `ADD` for the same reason: `a * 1` is exact, so a
|
|
607
|
+
* contracted `fma(a, 1, c)` and a plain `a + c` are the same number.
|
|
608
|
+
*
|
|
609
|
+
* @returns {number[][]|null}
|
|
610
|
+
*/
|
|
611
|
+
function collapse_identity(instruction, known, value) {
|
|
612
|
+
const op = instruction.op;
|
|
613
|
+
const width = instruction.operation_width;
|
|
614
|
+
const sources = instruction.sources;
|
|
615
|
+
const is = (source, expected) => source !== undefined && all_lanes_are(source, width, expected, known, value);
|
|
616
|
+
|
|
617
|
+
/** Rebuild as a copy of one source, whatever kind it is and however it is swizzled. */
|
|
618
|
+
const copy_of = (source) => {
|
|
619
|
+
const words = move_from(width, instruction.write.base, source);
|
|
620
|
+
|
|
621
|
+
return particle_instruction_is_well_formed(words) ? [words] : null;
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
switch (op) {
|
|
625
|
+
case VM_OP.MUL:
|
|
626
|
+
if (is(sources[1], 1)) return copy_of(sources[0]);
|
|
627
|
+
if (is(sources[0], 1)) return copy_of(sources[1]);
|
|
628
|
+
return null;
|
|
629
|
+
|
|
630
|
+
case VM_OP.DIV:
|
|
631
|
+
return is(sources[1], 1) ? copy_of(sources[0]) : null;
|
|
632
|
+
|
|
633
|
+
case VM_OP.SUB:
|
|
634
|
+
// Positive zero only, which is what `Object.is` in `all_lanes_are` gets us: `x - (-0)`
|
|
635
|
+
// is `x + 0`, and that turns a `-0` into a `+0`.
|
|
636
|
+
return is(sources[1], 0) ? copy_of(sources[0]) : null;
|
|
637
|
+
|
|
638
|
+
case VM_OP.MAD: {
|
|
639
|
+
const add = (a, b) => {
|
|
640
|
+
const words = vm_pack_instruction(
|
|
641
|
+
VM_OP.ADD, width, instruction.write.base,
|
|
642
|
+
[a.kind, b.kind, VM_KIND.NONE],
|
|
643
|
+
[a.word, b.word, 0]
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
return particle_instruction_is_well_formed(words) ? [words] : null;
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
if (is(sources[1], 1)) return add(sources[0], sources[2]);
|
|
650
|
+
if (is(sources[0], 1)) return add(sources[1], sources[2]);
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
default:
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* @param {import("./particle_program_analysis.js").ParticleOperandRun} source
|
|
661
|
+
* @param {number} width
|
|
662
|
+
* @param {number} expected
|
|
663
|
+
* @param {Uint8Array} known
|
|
664
|
+
* @param {Float32Array} value
|
|
665
|
+
* @returns {boolean}
|
|
666
|
+
*/
|
|
667
|
+
function all_lanes_are(source, width, expected, known, value) {
|
|
668
|
+
for (let lane = 0; lane < width; lane++) {
|
|
669
|
+
const held = source_lane_value(source, lane, known, value);
|
|
670
|
+
|
|
671
|
+
// `Object.is`, so a `-0` never passes for the `+0` the identity actually needs.
|
|
672
|
+
if (held === null || !Object.is(held, expected)) {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return true;
|
|
678
|
+
}
|