@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
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a program's structural invariants (opcodes known, operand kinds consistent with the
|
|
3
|
+
* opcode, register runs in range, instruction budget, constant references in range). Throws on the
|
|
4
|
+
* first problem. Intended for tests and asset ingestion, not the hot path.
|
|
5
|
+
*
|
|
6
|
+
* @param {import("./ParticleProgram.js").ParticleProgram} program
|
|
7
|
+
*/
|
|
8
|
+
export function validate_particle_program(program: import("./ParticleProgram.js").ParticleProgram): void;
|
|
9
|
+
//# sourceMappingURL=validate_particle_program.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate_particle_program.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/isa/validate_particle_program.js"],"names":[],"mappings":"AAkBA;;;;;;GAMG;AACH,mDAFW,OAAO,sBAAsB,EAAE,eAAe,QAWxD"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import {
|
|
3
|
+
PARTICLE_RECORD_WORD_COUNT,
|
|
4
|
+
PARTICLE_VM_INSTRUCTION_WORDS,
|
|
5
|
+
PARTICLE_VM_MAX_INSTRUCTIONS,
|
|
6
|
+
} from "../ParticleConstants.js";
|
|
7
|
+
import {
|
|
8
|
+
VM_ISA,
|
|
9
|
+
VM_MAX_WIDTH,
|
|
10
|
+
VM_OP,
|
|
11
|
+
VM_WIDTH,
|
|
12
|
+
vm_decode_op,
|
|
13
|
+
vm_decode_width,
|
|
14
|
+
vm_kinds_problem,
|
|
15
|
+
vm_operation_width,
|
|
16
|
+
vm_visit_register_runs,
|
|
17
|
+
} from "./ParticleVMISA.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validate a program's structural invariants (opcodes known, operand kinds consistent with the
|
|
21
|
+
* opcode, register runs in range, instruction budget, constant references in range). Throws on the
|
|
22
|
+
* first problem. Intended for tests and asset ingestion, not the hot path.
|
|
23
|
+
*
|
|
24
|
+
* @param {import("./ParticleProgram.js").ParticleProgram} program
|
|
25
|
+
*/
|
|
26
|
+
export function validate_particle_program(program) {
|
|
27
|
+
const constant_word_count = program.constant_word_count;
|
|
28
|
+
const register_count = program.register_count;
|
|
29
|
+
|
|
30
|
+
validate_stream(program.init, "init", constant_word_count, register_count);
|
|
31
|
+
validate_stream(program.update, "update", constant_word_count, register_count);
|
|
32
|
+
|
|
33
|
+
assert.lessThanOrEqual(program.init_instruction_count, PARTICLE_VM_MAX_INSTRUCTIONS, "init exceeds instruction budget");
|
|
34
|
+
assert.lessThanOrEqual(program.update_instruction_count, PARTICLE_VM_MAX_INSTRUCTIONS, "update exceeds instruction budget");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* There is no aliasing rule between an instruction's operands: the interpreter reads every source
|
|
39
|
+
* lane before it writes any destination lane, so a source may overlap the destination in any way
|
|
40
|
+
* and mean what it says.
|
|
41
|
+
*
|
|
42
|
+
* @param {Uint32Array} words
|
|
43
|
+
* @param {string} label
|
|
44
|
+
* @param {number} constant_word_count
|
|
45
|
+
* @param {number} register_count
|
|
46
|
+
*/
|
|
47
|
+
function validate_stream(words, label, constant_word_count, register_count) {
|
|
48
|
+
const instruction_count = words.length / PARTICLE_VM_INSTRUCTION_WORDS;
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < instruction_count; i++) {
|
|
51
|
+
const base = i * PARTICLE_VM_INSTRUCTION_WORDS;
|
|
52
|
+
const word0 = words[base];
|
|
53
|
+
const op = vm_decode_op(word0);
|
|
54
|
+
const width = vm_decode_width(word0);
|
|
55
|
+
const meta = VM_ISA.get(op);
|
|
56
|
+
|
|
57
|
+
if (meta === undefined) {
|
|
58
|
+
throw new Error(`${label}[${i}]: unknown opcode ${op}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (meta.width !== VM_WIDTH.NONE) {
|
|
62
|
+
assert.greaterThanOrEqual(
|
|
63
|
+
width,
|
|
64
|
+
meta.min_width,
|
|
65
|
+
`${label}[${i}] (${meta.name}): width must be >= ${meta.min_width}`
|
|
66
|
+
);
|
|
67
|
+
assert.lessThanOrEqual(width, VM_MAX_WIDTH, `${label}[${i}] (${meta.name}): width must be <= ${VM_MAX_WIDTH}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const kinds_problem = vm_kinds_problem(words, base);
|
|
71
|
+
|
|
72
|
+
if (kinds_problem !== null) {
|
|
73
|
+
throw new Error(`${label}[${i}] (${meta.name}): ${kinds_problem}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Every register operand names a RUN of slots, and a run that overshoots the file reads
|
|
77
|
+
// whatever the next value holds rather than failing — so the bound is on its end.
|
|
78
|
+
vm_visit_register_runs(words, base, (slot, span) => {
|
|
79
|
+
assert.lessThanOrEqual(
|
|
80
|
+
slot + span,
|
|
81
|
+
register_count,
|
|
82
|
+
`${label}[${i}] (${meta.name}): register range [${slot}, ${slot + span}) exceeds the `
|
|
83
|
+
+ `${register_count}-slot register file`
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const operation_width = vm_operation_width(op, width);
|
|
88
|
+
|
|
89
|
+
if (op === VM_OP.LOAD_CONST) {
|
|
90
|
+
// The load reads one word per lane, so the whole run has to be inside the pool.
|
|
91
|
+
const first = words[base + 1];
|
|
92
|
+
|
|
93
|
+
assert.lessThanOrEqual(
|
|
94
|
+
first + operation_width,
|
|
95
|
+
constant_word_count,
|
|
96
|
+
`${label}[${i}] (LOAD_CONST): words [${first}, ${first + operation_width}) exceed the `
|
|
97
|
+
+ `${constant_word_count}-word constant pool`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Attribute accesses must stay inside one record. An out-of-range offset is NOT caught by
|
|
102
|
+
// GPU robustness — record_base + offset lands inside the pool buffer, silently reading or
|
|
103
|
+
// corrupting the NEXT PARTICLE'S record.
|
|
104
|
+
if (op === VM_OP.LOAD_ATTR || op === VM_OP.STORE_ATTR) {
|
|
105
|
+
const first = op === VM_OP.LOAD_ATTR ? 1 : 2;
|
|
106
|
+
const offset = words[base + first];
|
|
107
|
+
const components = words[base + first + 1];
|
|
108
|
+
|
|
109
|
+
assert.greaterThanOrEqual(components, 1, `${label}[${i}] (${meta.name}): component count must be >= 1`);
|
|
110
|
+
assert.lessThanOrEqual(components, 4, `${label}[${i}] (${meta.name}): component count must be <= 4`);
|
|
111
|
+
assert.lessThanOrEqual(
|
|
112
|
+
offset + components,
|
|
113
|
+
PARTICLE_RECORD_WORD_COUNT,
|
|
114
|
+
`${label}[${i}] (${meta.name}): attribute access [${offset}, ${offset + components}) exceeds the ${PARTICLE_RECORD_WORD_COUNT}-word record`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// A store writes one record word per lane, so it cannot be asked for more words than
|
|
118
|
+
// the value holds — the extra ones would come out of the next value.
|
|
119
|
+
if (op === VM_OP.STORE_ATTR) {
|
|
120
|
+
assert.equal(
|
|
121
|
+
width,
|
|
122
|
+
components,
|
|
123
|
+
`${label}[${i}] (STORE_ATTR): width ${width} must equal the component count ${components}`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -71,5 +71,28 @@ export class ParticleLayout {
|
|
|
71
71
|
* @returns {number} component count of the attribute
|
|
72
72
|
*/
|
|
73
73
|
componentsOf(name: string): number;
|
|
74
|
+
/**
|
|
75
|
+
* Structural equality: the same attributes, by name, at the same offsets, the same width, and
|
|
76
|
+
* tagged the same. Two layouts that compare equal describe one particle record — a program
|
|
77
|
+
* compiled against either reads and writes the same words.
|
|
78
|
+
*
|
|
79
|
+
* Declaration order is not compared separately because it cannot differ without an offset
|
|
80
|
+
* differing: attributes are packed sequentially in the order they were declared.
|
|
81
|
+
*
|
|
82
|
+
* @param {ParticleLayout} other
|
|
83
|
+
* @returns {boolean}
|
|
84
|
+
*/
|
|
85
|
+
equals(other: ParticleLayout): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Hash over everything {@link ParticleLayout#equals} compares.
|
|
88
|
+
*
|
|
89
|
+
* Per-attribute hashes are summed rather than folded in iteration order. A `Map` iterates in
|
|
90
|
+
* insertion order and equal layouts are built in the same order, so a fold would agree — but a
|
|
91
|
+
* commutative combine says outright that the hash is of a set of attributes, and holds even if
|
|
92
|
+
* a layout is ever built by some other route.
|
|
93
|
+
*
|
|
94
|
+
* @returns {number} int32
|
|
95
|
+
*/
|
|
96
|
+
hash(): number;
|
|
74
97
|
}
|
|
75
98
|
//# sourceMappingURL=ParticleLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParticleLayout.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/layout/ParticleLayout.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ParticleLayout.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/layout/ParticleLayout.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IAcI;;;;OAIG;IACH,wBAJW,MAAM;QAAC,MAAM,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,EAyClE;IAtDD;;;OAGG;IACH,YAFU,IAAI,MAAM,EAAE;QAAC,MAAM,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAC,SAAS,CAAA;KAAC,CAAC,CAE1E;IAEvB;;;OAGG;IACH,aAFU,MAAM,CAE8B;IA8C9C;;;OAGG;IACH,UAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,UAHW,MAAM,GACJ;QAAC,MAAM,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAC,CAQ9D;IAED;;;OAGG;IACH,eAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,mBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;;;OAUG;IACH,cAHW,cAAc,GACZ,OAAO,CA8BnB;IAED;;;;;;;;;OASG;IACH,QAFa,MAAM,CAclB;CACJ"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { hash_mix2 } from "../../../../core/math/hash/hash_mix2.js";
|
|
3
|
+
import { hash_mix3 } from "../../../../core/math/hash/hash_mix3.js";
|
|
4
|
+
import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
|
|
2
5
|
import {
|
|
3
6
|
PARTICLE_RECORD_USER_WORD_START,
|
|
4
7
|
PARTICLE_RECORD_WORD_COUNT,
|
|
@@ -120,4 +123,69 @@ export class ParticleLayout {
|
|
|
120
123
|
componentsOf(name) {
|
|
121
124
|
return this.get(name).components;
|
|
122
125
|
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Structural equality: the same attributes, by name, at the same offsets, the same width, and
|
|
129
|
+
* tagged the same. Two layouts that compare equal describe one particle record — a program
|
|
130
|
+
* compiled against either reads and writes the same words.
|
|
131
|
+
*
|
|
132
|
+
* Declaration order is not compared separately because it cannot differ without an offset
|
|
133
|
+
* differing: attributes are packed sequentially in the order they were declared.
|
|
134
|
+
*
|
|
135
|
+
* @param {ParticleLayout} other
|
|
136
|
+
* @returns {boolean}
|
|
137
|
+
*/
|
|
138
|
+
equals(other) {
|
|
139
|
+
if (this === other) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const attributes = this.attributes;
|
|
144
|
+
|
|
145
|
+
if (attributes.size !== other.attributes.size) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
for (const [name, attribute] of attributes) {
|
|
150
|
+
const candidate = other.attributes.get(name);
|
|
151
|
+
|
|
152
|
+
if (candidate === undefined) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
candidate.offset !== attribute.offset
|
|
158
|
+
|| candidate.components !== attribute.components
|
|
159
|
+
|| candidate.type !== attribute.type
|
|
160
|
+
) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Hash over everything {@link ParticleLayout#equals} compares.
|
|
170
|
+
*
|
|
171
|
+
* Per-attribute hashes are summed rather than folded in iteration order. A `Map` iterates in
|
|
172
|
+
* insertion order and equal layouts are built in the same order, so a fold would agree — but a
|
|
173
|
+
* commutative combine says outright that the hash is of a set of attributes, and holds even if
|
|
174
|
+
* a layout is ever built by some other route.
|
|
175
|
+
*
|
|
176
|
+
* @returns {number} int32
|
|
177
|
+
*/
|
|
178
|
+
hash() {
|
|
179
|
+
let hash = this.attributes.size;
|
|
180
|
+
|
|
181
|
+
for (const [name, attribute] of this.attributes) {
|
|
182
|
+
hash = (hash + hash_mix3(
|
|
183
|
+
computeStringHash(name),
|
|
184
|
+
hash_mix2(attribute.offset, attribute.components),
|
|
185
|
+
computeStringHash(attribute.type)
|
|
186
|
+
)) | 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return hash;
|
|
190
|
+
}
|
|
123
191
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} ParticleVectorOptimizerResult
|
|
3
|
+
* @property {ParticleProgram} program
|
|
4
|
+
* @property {boolean} rewritten whether the returned program is the optimized one
|
|
5
|
+
* @property {number} instructions what the optimized program cost, before `keep_better` had its say
|
|
6
|
+
* @property {number} registers likewise
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @param {ParticleProgram} program
|
|
10
|
+
* @param {object} [options] see {@link optimize_particle_program_vector_result}
|
|
11
|
+
* @returns {ParticleProgram}
|
|
12
|
+
*/
|
|
13
|
+
export function optimize_particle_program_vector(program: ParticleProgram, options?: object): ParticleProgram;
|
|
14
|
+
/**
|
|
15
|
+
* @param {ParticleProgram} program
|
|
16
|
+
* @param {object} [options]
|
|
17
|
+
* @param {number} [options.register_slots] size of the register file to optimize against
|
|
18
|
+
* @param {boolean} [options.fold_inexact] fold what the two executors may round apart
|
|
19
|
+
* @param {boolean} [options.fold_multiply_by_zero] a known zero absorbs a multiply
|
|
20
|
+
* @param {boolean} [options.compact_registers] finish with the first optimizer's register allocator
|
|
21
|
+
* @param {boolean} [options.keep_better] return what was given when the rewrite is bigger
|
|
22
|
+
* @param {number[]} [options.share_windows] see {@link PARTICLE_VECTOR_SHARE_WINDOWS}
|
|
23
|
+
* @returns {ParticleVectorOptimizerResult}
|
|
24
|
+
*/
|
|
25
|
+
export function optimize_particle_program_vector_result(program: ParticleProgram, { register_slots, fold_inexact, fold_multiply_by_zero, compact_registers, keep_better, share_windows, }?: {
|
|
26
|
+
register_slots?: number;
|
|
27
|
+
fold_inexact?: boolean;
|
|
28
|
+
fold_multiply_by_zero?: boolean;
|
|
29
|
+
compact_registers?: boolean;
|
|
30
|
+
keep_better?: boolean;
|
|
31
|
+
share_windows?: number[];
|
|
32
|
+
}): ParticleVectorOptimizerResult;
|
|
33
|
+
/**
|
|
34
|
+
* The optimizer, over a graph whose values are VECTORS.
|
|
35
|
+
*
|
|
36
|
+
* The second optimizer, beside `../optimize_particle_program.js`'s pass pipeline. `ParticleProgram`
|
|
37
|
+
* in and out, flat options, and it is what the editor and the runtime get.
|
|
38
|
+
*
|
|
39
|
+
* There was a third, over a graph whose values were single LANES, and it was retired once this one
|
|
40
|
+
* beat it everywhere: making a value one lane buys lane-exact rewriting and costs the vectorisation
|
|
41
|
+
* the frontend had already done, and the second turns out to be worth more than the first on this
|
|
42
|
+
* machine. The argument and the measurements survive in `./particle_vector_graph.js`, because they
|
|
43
|
+
* are the reason this file is shaped the way it is and not an accident of it.
|
|
44
|
+
*
|
|
45
|
+
* The stages are lift, rewrite, extract, lower. With a vector as the unit there is no
|
|
46
|
+
* re-vectorisation to do, so what would otherwise be eight hundred lines of superword grouping and
|
|
47
|
+
* lane-order search is a hundred that say "one value, one instruction".
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* How much sharing to try, in order, until the program fits the register file.
|
|
51
|
+
*
|
|
52
|
+
* A rung says how far back a value may have been computed and still be reused rather than
|
|
53
|
+
* recomputed. Unbounded is the honest first try, and it is what `curl3` and `curl4` cannot afford:
|
|
54
|
+
* unbounded sharing puts them at 61 and 103 slots against a file of 48, where sharing nothing at all
|
|
55
|
+
* puts them at 32 and 39. Between those lies the trade, and where a given program sits in it is not
|
|
56
|
+
* something a constant can know.
|
|
57
|
+
*
|
|
58
|
+
* @type {number[]}
|
|
59
|
+
*/
|
|
60
|
+
export const PARTICLE_VECTOR_SHARE_WINDOWS: number[];
|
|
61
|
+
export type ParticleVectorOptimizerResult = {
|
|
62
|
+
program: ParticleProgram;
|
|
63
|
+
/**
|
|
64
|
+
* whether the returned program is the optimized one
|
|
65
|
+
*/
|
|
66
|
+
rewritten: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* what the optimized program cost, before `keep_better` had its say
|
|
69
|
+
*/
|
|
70
|
+
instructions: number;
|
|
71
|
+
/**
|
|
72
|
+
* likewise
|
|
73
|
+
*/
|
|
74
|
+
registers: number;
|
|
75
|
+
};
|
|
76
|
+
import { ParticleProgram } from "../../isa/ParticleProgram.js";
|
|
77
|
+
//# sourceMappingURL=optimize_particle_program_vector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimize_particle_program_vector.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js"],"names":[],"mappings":"AA4CA;;;;;;GAMG;AAEH;;;;GAIG;AACH,0DAJW,eAAe,YACf,MAAM,GACJ,eAAe,CAI3B;AAED;;;;;;;;;;GAUG;AACH,iEAVW,eAAe;IAEE,cAAc,GAA/B,MAAM;IACY,YAAY,GAA9B,OAAO;IACW,qBAAqB,GAAvC,OAAO;IACW,iBAAiB,GAAnC,OAAO;IACW,WAAW,GAA7B,OAAO;IACY,aAAa,GAAhC,MAAM,EAAE;IACN,6BAA6B,CAwCzC;AAhGD;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;;;;GAUG;AACH,4CAFU,MAAM,EAAE,CAEqE;;aAIzE,eAAe;;;;eACf,OAAO;;;;kBACP,MAAM;;;;eACN,MAAM;;gCA9CY,8BAA8B"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { assert } from "../../../../../core/assert.js";
|
|
2
|
+
import { PARTICLE_VM_INSTRUCTION_WORDS, PARTICLE_VM_REGISTER_SLOTS } from "../../ParticleConstants.js";
|
|
3
|
+
import { ParticleAssembler } from "../../isa/ParticleAssembler.js";
|
|
4
|
+
import { ParticleProgram } from "../../isa/ParticleProgram.js";
|
|
5
|
+
import { optimize_particle_section, stream_from_words } from "../optimize_particle_program.js";
|
|
6
|
+
import { PARTICLE_PASS_ALLOCATE_REGISTERS } from "../pass_allocate_registers.js";
|
|
7
|
+
import { PARTICLE_PASS_PACK_REGISTERS } from "../pass_pack_registers.js";
|
|
8
|
+
import { extract_particle_values } from "./particle_vector_extract.js";
|
|
9
|
+
import { lower_particle_values } from "./particle_vector_lower.js";
|
|
10
|
+
import { ParticleVectorGraph, PV } from "./particle_vector_graph.js";
|
|
11
|
+
import { lift_particle_vector_section } from "./particle_vector_lift.js";
|
|
12
|
+
import { pack_particle_vectors } from "./particle_vector_pack.js";
|
|
13
|
+
import { particle_vector_rules } from "./particle_vector_rules.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The optimizer, over a graph whose values are VECTORS.
|
|
17
|
+
*
|
|
18
|
+
* The second optimizer, beside `../optimize_particle_program.js`'s pass pipeline. `ParticleProgram`
|
|
19
|
+
* in and out, flat options, and it is what the editor and the runtime get.
|
|
20
|
+
*
|
|
21
|
+
* There was a third, over a graph whose values were single LANES, and it was retired once this one
|
|
22
|
+
* beat it everywhere: making a value one lane buys lane-exact rewriting and costs the vectorisation
|
|
23
|
+
* the frontend had already done, and the second turns out to be worth more than the first on this
|
|
24
|
+
* machine. The argument and the measurements survive in `./particle_vector_graph.js`, because they
|
|
25
|
+
* are the reason this file is shaped the way it is and not an accident of it.
|
|
26
|
+
*
|
|
27
|
+
* The stages are lift, rewrite, extract, lower. With a vector as the unit there is no
|
|
28
|
+
* re-vectorisation to do, so what would otherwise be eight hundred lines of superword grouping and
|
|
29
|
+
* lane-order search is a hundred that say "one value, one instruction".
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* How much sharing to try, in order, until the program fits the register file.
|
|
34
|
+
*
|
|
35
|
+
* A rung says how far back a value may have been computed and still be reused rather than
|
|
36
|
+
* recomputed. Unbounded is the honest first try, and it is what `curl3` and `curl4` cannot afford:
|
|
37
|
+
* unbounded sharing puts them at 61 and 103 slots against a file of 48, where sharing nothing at all
|
|
38
|
+
* puts them at 32 and 39. Between those lies the trade, and where a given program sits in it is not
|
|
39
|
+
* something a constant can know.
|
|
40
|
+
*
|
|
41
|
+
* @type {number[]}
|
|
42
|
+
*/
|
|
43
|
+
export const PARTICLE_VECTOR_SHARE_WINDOWS = Object.freeze([Infinity, 256, 64, 16, 4]);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @typedef {object} ParticleVectorOptimizerResult
|
|
47
|
+
* @property {ParticleProgram} program
|
|
48
|
+
* @property {boolean} rewritten whether the returned program is the optimized one
|
|
49
|
+
* @property {number} instructions what the optimized program cost, before `keep_better` had its say
|
|
50
|
+
* @property {number} registers likewise
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {ParticleProgram} program
|
|
55
|
+
* @param {object} [options] see {@link optimize_particle_program_vector_result}
|
|
56
|
+
* @returns {ParticleProgram}
|
|
57
|
+
*/
|
|
58
|
+
export function optimize_particle_program_vector(program, options = {}) {
|
|
59
|
+
return optimize_particle_program_vector_result(program, options).program;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {ParticleProgram} program
|
|
64
|
+
* @param {object} [options]
|
|
65
|
+
* @param {number} [options.register_slots] size of the register file to optimize against
|
|
66
|
+
* @param {boolean} [options.fold_inexact] fold what the two executors may round apart
|
|
67
|
+
* @param {boolean} [options.fold_multiply_by_zero] a known zero absorbs a multiply
|
|
68
|
+
* @param {boolean} [options.compact_registers] finish with the first optimizer's register allocator
|
|
69
|
+
* @param {boolean} [options.keep_better] return what was given when the rewrite is bigger
|
|
70
|
+
* @param {number[]} [options.share_windows] see {@link PARTICLE_VECTOR_SHARE_WINDOWS}
|
|
71
|
+
* @returns {ParticleVectorOptimizerResult}
|
|
72
|
+
*/
|
|
73
|
+
export function optimize_particle_program_vector_result(program, {
|
|
74
|
+
register_slots = PARTICLE_VM_REGISTER_SLOTS,
|
|
75
|
+
fold_inexact = false,
|
|
76
|
+
fold_multiply_by_zero = true,
|
|
77
|
+
compact_registers = true,
|
|
78
|
+
keep_better = true,
|
|
79
|
+
share_windows = PARTICLE_VECTOR_SHARE_WINDOWS,
|
|
80
|
+
} = {}) {
|
|
81
|
+
assert.ok(program instanceof ParticleProgram, "program must be a ParticleProgram");
|
|
82
|
+
assert.lessThanOrEqual(register_slots, PARTICLE_VM_REGISTER_SLOTS, "register_slots exceeds the VM register file");
|
|
83
|
+
|
|
84
|
+
const assembler = new ParticleAssembler();
|
|
85
|
+
const intern_constant = values => assembler.constant(...values);
|
|
86
|
+
const rules = particle_vector_rules({ fold_inexact, fold_multiply_by_zero });
|
|
87
|
+
const shared = { program, register_slots, intern_constant, rules, share_windows };
|
|
88
|
+
|
|
89
|
+
const init = rebuild_section(program.init, shared);
|
|
90
|
+
const update = rebuild_section(program.update, shared);
|
|
91
|
+
|
|
92
|
+
if (init === null || update === null) {
|
|
93
|
+
return unchanged(program);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const rebuilt = new ParticleProgram({
|
|
97
|
+
init: init.toWords(),
|
|
98
|
+
update: update.toWords(),
|
|
99
|
+
constants: new Float32Array(assembler.constants),
|
|
100
|
+
register_count: Math.max(init.register_count, update.register_count),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const finished = compact_registers ? compact(rebuilt, register_slots) : rebuilt;
|
|
104
|
+
const instructions = finished.init_instruction_count + finished.update_instruction_count;
|
|
105
|
+
|
|
106
|
+
if (keep_better && !is_better(finished, program)) {
|
|
107
|
+
return { ...unchanged(program), instructions, registers: finished.register_count };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { program: finished, rewritten: true, instructions, registers: finished.register_count };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** @param {ParticleProgram} program @returns {ParticleVectorOptimizerResult} */
|
|
114
|
+
function unchanged(program) {
|
|
115
|
+
return {
|
|
116
|
+
program,
|
|
117
|
+
rewritten: false,
|
|
118
|
+
instructions: program.init_instruction_count + program.update_instruction_count,
|
|
119
|
+
registers: program.register_count,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {ParticleProgram} rebuilt
|
|
125
|
+
* @param {ParticleProgram} original
|
|
126
|
+
* @returns {boolean}
|
|
127
|
+
*/
|
|
128
|
+
function is_better(rebuilt, original) {
|
|
129
|
+
const after = rebuilt.init_instruction_count + rebuilt.update_instruction_count;
|
|
130
|
+
const before = original.init_instruction_count + original.update_instruction_count;
|
|
131
|
+
|
|
132
|
+
return after !== before ? after < before : rebuilt.register_count < original.register_count;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* What a literal costs. Below an instruction, because most become an operand; above nothing, so that
|
|
137
|
+
* a fold is not preferred over a value that was going to be computed anyway.
|
|
138
|
+
*
|
|
139
|
+
* @param {import("./particle_vector_graph.js").ParticleVectorNode} node
|
|
140
|
+
* @returns {number}
|
|
141
|
+
*/
|
|
142
|
+
function node_cost(node) {
|
|
143
|
+
return node.op === PV.CONST ? 0.5 : 1;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @param {Uint32Array} words one section
|
|
148
|
+
* @param {object} params
|
|
149
|
+
* @returns {import("../../isa/InstructionStream.js").InstructionStream|null}
|
|
150
|
+
*/
|
|
151
|
+
function rebuild_section(words, { program, register_slots, intern_constant, rules, share_windows }) {
|
|
152
|
+
const tuples = to_tuples(words);
|
|
153
|
+
|
|
154
|
+
// Widest sharing first, and less of it only where the result will not fit. Reusing a value rather
|
|
155
|
+
// than recomputing it saves an instruction and costs however long it now has to be held, and
|
|
156
|
+
// whether that is a good trade is not a question about the pair — it is a question about whether
|
|
157
|
+
// the whole program still fits. So it is answered by trying.
|
|
158
|
+
for (const share_window of share_windows) {
|
|
159
|
+
const graph = new ParticleVectorGraph({ ...rules, share_window });
|
|
160
|
+
const section = lift_particle_vector_section(graph, tuples, {
|
|
161
|
+
constants: program.constants,
|
|
162
|
+
register_slots,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (section === null) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Every draw is a root whether or not anything reads it: the state at the end counts them.
|
|
170
|
+
const roots = [
|
|
171
|
+
...section.stores.map(store => store.place.value),
|
|
172
|
+
...section.kills.map(kill => kill.value),
|
|
173
|
+
...section.draws,
|
|
174
|
+
];
|
|
175
|
+
const extraction = extract_particle_values(graph, roots, { node_cost });
|
|
176
|
+
const packing = pack_particle_vectors(graph, section, extraction);
|
|
177
|
+
const lowered = lower_particle_values(packing, { register_slots, intern_constant });
|
|
178
|
+
|
|
179
|
+
if (lowered !== null) {
|
|
180
|
+
return lowered.stream;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param {ParticleProgram} program
|
|
189
|
+
* @param {number} register_slots
|
|
190
|
+
* @returns {ParticleProgram}
|
|
191
|
+
*/
|
|
192
|
+
function compact(program, register_slots) {
|
|
193
|
+
const options = {
|
|
194
|
+
passes: [PARTICLE_PASS_ALLOCATE_REGISTERS, PARTICLE_PASS_PACK_REGISTERS],
|
|
195
|
+
register_slots,
|
|
196
|
+
constants: program.constants,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const init = optimize_particle_section(stream_from_words(program.init), options);
|
|
200
|
+
const update = optimize_particle_section(stream_from_words(program.update), options);
|
|
201
|
+
|
|
202
|
+
return new ParticleProgram({
|
|
203
|
+
init: init.toWords(),
|
|
204
|
+
update: update.toWords(),
|
|
205
|
+
constants: program.constants,
|
|
206
|
+
register_count: Math.max(init.register_count, update.register_count),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** @param {Uint32Array} words @returns {number[][]} */
|
|
211
|
+
function to_tuples(words) {
|
|
212
|
+
const tuples = [];
|
|
213
|
+
|
|
214
|
+
for (let base = 0; base < words.length; base += PARTICLE_VM_INSTRUCTION_WORDS) {
|
|
215
|
+
tuples.push(Array.from(words.subarray(base, base + PARTICLE_VM_INSTRUCTION_WORDS)));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return tuples;
|
|
219
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Choose one node per class — the instruction-count half of the optimizer.
|
|
3
|
+
*
|
|
4
|
+
* Most classes hold one node and there is nothing to choose. The ones that hold two are where a
|
|
5
|
+
* rewrite's worth was not local: `a * b + c` as a `MAD` costs one instruction and as `MUL` then
|
|
6
|
+
* `ADD` costs two, but the `MAD` only SAVES one if nothing else reads the product. So the cost that
|
|
7
|
+
* matters is the DAG cost — every distinct node counted once, which is exactly the instruction count
|
|
8
|
+
* — and not the tree cost, which would count a shared subexpression once per reader and talk itself
|
|
9
|
+
* into duplicating work.
|
|
10
|
+
*
|
|
11
|
+
* ## Why this is a greedy and not an exact solver
|
|
12
|
+
*
|
|
13
|
+
* DAG-cost extraction is NP-hard in general (reduction from minimum set cover), and the literature's
|
|
14
|
+
* answer at this scale is an ILP. That would mean a solver, and there is no solver in this tree and
|
|
15
|
+
* no appetite for vendoring one. What is here instead is the standard two-step: a bottom-up
|
|
16
|
+
* relaxation to a consistent choice, then hill-climbing on the classes that actually have a choice,
|
|
17
|
+
* each flip scored by re-measuring the whole reachable set.
|
|
18
|
+
*
|
|
19
|
+
* ## The climb does nothing today, and that is worth saying
|
|
20
|
+
*
|
|
21
|
+
* With the one alternative there is — `MAD` beside `MUL` then `ADD` — the seed is already optimal,
|
|
22
|
+
* and it was measured to be: over the whole effect corpus, switching the climb off changes neither an
|
|
23
|
+
* instruction nor a slot. The reason is that a `MAD` is never WORSE than the pair. Choosing it costs
|
|
24
|
+
* one instruction and leaves the product to be counted only if something else still reads it, so its
|
|
25
|
+
* DAG cost is at most the pair's, and the bottom-up relaxation — which prefers it on tree cost, where
|
|
26
|
+
* it is strictly cheaper — lands on the answer without help.
|
|
27
|
+
*
|
|
28
|
+
* The climb stays because the seed's agreement is a property of THAT rule and not of the pipeline. A
|
|
29
|
+
* rule whose alternative is dearer where it is shared — a fused operation that costs more than one
|
|
30
|
+
* instruction, an operation with a wider destination — has a tree cost that says the wrong thing, and
|
|
31
|
+
* the climb is what corrects it. `./particle_vector_extract.spec.js` exercises exactly that, through the
|
|
32
|
+
* `node_cost` the caller may pass, so the machinery is held to its purpose rather than to the one
|
|
33
|
+
* rule that happens not to need it.
|
|
34
|
+
*
|
|
35
|
+
* The relaxation is also what keeps extraction honest about cycles. A class can only be given a cost
|
|
36
|
+
* through nodes whose children already have one, so a node that could only be reached through its own
|
|
37
|
+
* class never gets a finite cost and is never chosen, whatever the rules did.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* What a node costs. Everything is one instruction except a literal, which is usually an operand
|
|
41
|
+
* rather than an instruction — priced below one so that folding is preferred, and above zero so that
|
|
42
|
+
* a fold is not preferred over a value that was already going to be computed anyway.
|
|
43
|
+
*
|
|
44
|
+
* @param {import("./particle_vector_graph.js").ParticleVectorNode} node
|
|
45
|
+
* @returns {number}
|
|
46
|
+
*/
|
|
47
|
+
export function particle_vector_node_cost(node: import("./particle_vector_graph.js").ParticleVectorNode): number;
|
|
48
|
+
/**
|
|
49
|
+
* @typedef {object} ParticleValueExtraction
|
|
50
|
+
* @property {Map<number, number>} choice per class, the node chosen for it
|
|
51
|
+
* @property {number[]} order the demanded classes, every class after the ones it reads
|
|
52
|
+
* @property {number} cost the DAG cost of that choice
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* @param {import("./particle_vector_graph.js").ParticleVectorGraph} graph
|
|
56
|
+
* @param {number[]} roots classes the program has to compute
|
|
57
|
+
* @param {object} [options]
|
|
58
|
+
* @param {function(import("./particle_vector_graph.js").ParticleVectorNode): number} [options.node_cost]
|
|
59
|
+
* @param {number} [options.max_rounds] hill-climbing sweeps over the classes that have a choice
|
|
60
|
+
* @param {number} [options.max_evaluations] flips to score before settling for what is in hand; a
|
|
61
|
+
* guard so a pathological program cannot make extraction the slow part of a build
|
|
62
|
+
* @returns {ParticleValueExtraction}
|
|
63
|
+
*/
|
|
64
|
+
export function extract_particle_values(graph: import("./particle_vector_graph.js").ParticleVectorGraph, roots: number[], { node_cost, max_rounds, max_evaluations, }?: {
|
|
65
|
+
node_cost?: (arg0: import("./particle_vector_graph.js").ParticleVectorNode) => number;
|
|
66
|
+
max_rounds?: number;
|
|
67
|
+
max_evaluations?: number;
|
|
68
|
+
}): ParticleValueExtraction;
|
|
69
|
+
export type ParticleValueExtraction = {
|
|
70
|
+
/**
|
|
71
|
+
* per class, the node chosen for it
|
|
72
|
+
*/
|
|
73
|
+
choice: Map<number, number>;
|
|
74
|
+
/**
|
|
75
|
+
* the demanded classes, every class after the ones it reads
|
|
76
|
+
*/
|
|
77
|
+
order: number[];
|
|
78
|
+
/**
|
|
79
|
+
* the DAG cost of that choice
|
|
80
|
+
*/
|
|
81
|
+
cost: number;
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=particle_vector_extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"particle_vector_extract.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;GAOG;AACH,gDAHW,OAAO,4BAA4B,EAAE,kBAAkB,GACrD,MAAM,CAIlB;AAED;;;;;GAKG;AAEH;;;;;;;;;GASG;AACH,+CATW,OAAO,4BAA4B,EAAE,mBAAmB,SACxD,MAAM,EAAE;IAE4E,SAAS,UAApF,OAAO,4BAA4B,EAAE,kBAAkB,KAAG,MAAM;IACxD,UAAU,GAA3B,MAAM;IACW,eAAe,GAAhC,MAAM;IAEJ,uBAAuB,CA0DnC;;;;;YAvEa,IAAI,MAAM,EAAE,MAAM,CAAC;;;;WACnB,MAAM,EAAE;;;;UACR,MAAM"}
|