@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
|
@@ -7,40 +7,72 @@
|
|
|
7
7
|
*
|
|
8
8
|
* ## Encoding
|
|
9
9
|
*
|
|
10
|
-
* Every instruction is
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
10
|
+
* Every instruction is {@link PARTICLE_VM_INSTRUCTION_WORDS} `u32` words — the size of one
|
|
11
|
+
* `vec4<u32>`, so the four loads that fetch it are one 16-byte load by the time a shader compiler is
|
|
12
|
+
* done with them:
|
|
13
|
+
*
|
|
14
|
+
* [ op | width << 8 | kinds << 16 | dst << 24, s0, s1, s2 ]
|
|
15
|
+
*
|
|
16
|
+
* Word 0 packs the opcode (bits 0..7), the lane count the operation spans (8..10), the kind of each
|
|
17
|
+
* source (two bits per slot at 16..21) and the destination register (24..31). The other three words
|
|
18
|
+
* are the sources. Registers hold single floats, so a `vec3` value is three consecutive slots and an
|
|
19
|
+
* `ADD` with width 3 adds three lanes; widths are what stop every value costing four registers.
|
|
20
|
+
*
|
|
21
|
+
* ## Operands
|
|
22
|
+
*
|
|
23
|
+
* A source word means what its kind says — see {@link VM_KIND}:
|
|
24
|
+
*
|
|
25
|
+
* - `NONE`: not an operand the VM resolves — an unused slot, or a raw field the opcode reads for
|
|
26
|
+
* itself: an attribute offset, a component count, a builtin id, a curve handle, a pool index.
|
|
27
|
+
* - `REG`: a register operand. Bits 0..7 are the first slot, bits 8..15 a swizzle — see below.
|
|
28
|
+
* - `IMM`: the word IS the `f32` bit pattern of a literal, read in every lane. A scalar or a
|
|
29
|
+
* lane-uniform vector costs no register and no load; only a vector whose lanes differ still goes
|
|
30
|
+
* through the pool with `LOAD_CONST`.
|
|
31
|
+
*
|
|
32
|
+
* The kinds exist so the interpreter can resolve every source the same way, before the opcode runs
|
|
33
|
+
* and without consulting a table: it reads the kind, gathers the lanes, and the opcode body sees
|
|
34
|
+
* three four-lane values whatever they came from. A kind is encoding, not an opcode mode.
|
|
35
|
+
*
|
|
36
|
+
* ## Swizzles
|
|
37
|
+
*
|
|
38
|
+
* Every register operand carries a swizzle: four two-bit lane selectors in bits 8..15, packed as
|
|
39
|
+
* {@link pack_swizzle} packs them, and stored XOR the identity pattern `.xyzw`
|
|
40
|
+
* ({@link VM_SWIZZLE_IDENTITY}). That choice is what makes a bare slot index a register operand:
|
|
41
|
+
* with a zero swizzle byte lane `c` reads slot `base + c`, the run as it lies, and `r5.xxxx` is the
|
|
42
|
+
* same word with the selectors that name lane 0 four times. Lane `c` of an operand reads slot
|
|
43
|
+
* `base + selector[c]`, so an operand reaches as far into the file as its widest selector below the
|
|
44
|
+
* instruction's width — never further, whatever the selectors above the width say.
|
|
45
|
+
*
|
|
46
|
+
* Swizzles are why there is no `SWIZZLE` opcode and no `SCALE`: a permutation or a broadcast is a
|
|
47
|
+
* `MOV` whose source is swizzled, and a vector times a scalar is `MUL v, s.xxxx`. Both were
|
|
48
|
+
* opcodes that existed to do what an operand can now say for itself, which is the direction the
|
|
49
|
+
* ISA takes whenever it can — see {@link VM_OP} for the holes they left.
|
|
50
|
+
*
|
|
51
|
+
* ## Resolution before execution
|
|
52
|
+
*
|
|
53
|
+
* The interpreter reads every source lane before it writes any destination lane. Operands may
|
|
54
|
+
* therefore overlap the destination in any way — `MOV.2 r0, r0.yx` swaps two slots in place — and
|
|
55
|
+
* there is no aliasing rule for a program to break. The reductions write one lane whatever they
|
|
56
|
+
* read (see {@link VM_DEST}); a few opcodes fix their lane count (see {@link VM_WIDTH}).
|
|
57
|
+
*
|
|
58
|
+
* There is no control flow: conditionals are `CMP` + `SELECT` and destruction is `KILL`, which
|
|
59
|
+
* keeps the interpreter a flat `switch` inside a bounded loop.
|
|
30
60
|
*/
|
|
31
61
|
|
|
62
|
+
/** Words per instruction. Four, so an instruction is one `vec4<u32>` fetch. @type {number} */
|
|
63
|
+
export const PARTICLE_VM_INSTRUCTION_WORDS = 4;
|
|
64
|
+
|
|
32
65
|
/**
|
|
33
|
-
* Operand slot roles
|
|
66
|
+
* Operand slot roles: what an opcode reads a source slot as. Used for assembler validation,
|
|
67
|
+
* disassembly and for deriving each slot's {@link VM_KIND}.
|
|
34
68
|
* @enum {string}
|
|
35
69
|
*/
|
|
36
70
|
export const VM_OPERAND = {
|
|
37
71
|
/** unused slot (must be 0) */
|
|
38
72
|
NONE: "none",
|
|
39
|
-
/**
|
|
73
|
+
/** a register operand — a slot with a swizzle, or a literal */
|
|
40
74
|
REG: "reg",
|
|
41
|
-
/**
|
|
42
|
-
DST: "dst",
|
|
43
|
-
/** constant-pool index */
|
|
75
|
+
/** constant-pool word index */
|
|
44
76
|
CONST: "const",
|
|
45
77
|
/** attribute word offset within the record */
|
|
46
78
|
ATTR_OFFSET: "attr_offset",
|
|
@@ -50,8 +82,6 @@ export const VM_OPERAND = {
|
|
|
50
82
|
BUILTIN: "builtin",
|
|
51
83
|
/** curve handle (row index into the animation-curve table) */
|
|
52
84
|
CURVE: "curve",
|
|
53
|
-
/** packed swizzle pattern: four 2-bit lane selectors, lane i in bits `[2i, 2i+2)` */
|
|
54
|
-
SWIZZLE: "swizzle",
|
|
55
85
|
};
|
|
56
86
|
|
|
57
87
|
/**
|
|
@@ -99,7 +129,8 @@ export const VM_BUILTIN_COMPONENTS = Object.freeze({
|
|
|
99
129
|
});
|
|
100
130
|
|
|
101
131
|
/**
|
|
102
|
-
* Opcodes. Numbers are stable wire values — never renumber, only append.
|
|
132
|
+
* Opcodes. Numbers are stable wire values — never renumber, only append. 19 was `SCALE` and 45 was
|
|
133
|
+
* `SWIZZLE`; both are spelled by an operand swizzle now and the numbers stay unused.
|
|
103
134
|
* @enum {number}
|
|
104
135
|
*/
|
|
105
136
|
export const VM_OP = {
|
|
@@ -121,7 +152,6 @@ export const VM_OP = {
|
|
|
121
152
|
MAX: 16,
|
|
122
153
|
MIX: 17,
|
|
123
154
|
CLAMP: 18,
|
|
124
|
-
SCALE: 19,
|
|
125
155
|
|
|
126
156
|
NEG: 20,
|
|
127
157
|
ABS: 21,
|
|
@@ -135,13 +165,17 @@ export const VM_OP = {
|
|
|
135
165
|
POW: 29,
|
|
136
166
|
STEP: 30,
|
|
137
167
|
SMOOTHSTEP: 31,
|
|
168
|
+
RSQRT: 32,
|
|
169
|
+
TAN: 33,
|
|
170
|
+
ASIN: 34,
|
|
171
|
+
ACOS: 35,
|
|
172
|
+
ATAN2: 36,
|
|
138
173
|
|
|
139
174
|
DOT: 40,
|
|
140
175
|
CROSS: 41,
|
|
141
176
|
LENGTH: 42,
|
|
142
177
|
NORMALIZE: 43,
|
|
143
178
|
DISTANCE: 44,
|
|
144
|
-
SWIZZLE: 45,
|
|
145
179
|
|
|
146
180
|
CMP_LT: 50,
|
|
147
181
|
CMP_LE: 51,
|
|
@@ -183,65 +217,304 @@ export const VM_DEST = {
|
|
|
183
217
|
};
|
|
184
218
|
|
|
185
219
|
/**
|
|
186
|
-
* Widest an operation may be. Registers hold scalars; four is what a `vec4` value needs and what
|
|
187
|
-
*
|
|
220
|
+
* Widest an operation may be. Registers hold scalars; four is what a `vec4` value needs and what a
|
|
221
|
+
* two-bit lane selector can address.
|
|
188
222
|
* @type {number}
|
|
189
223
|
*/
|
|
190
224
|
export const VM_MAX_WIDTH = 4;
|
|
191
225
|
|
|
226
|
+
// --- word 0 -----------------------------------------------------------------------------------
|
|
227
|
+
|
|
228
|
+
/** Mask selecting the opcode out of word 0. @type {number} */
|
|
229
|
+
export const VM_OP_MASK = 0xff;
|
|
230
|
+
|
|
231
|
+
/** Bit position of the width field in word 0. @type {number} */
|
|
232
|
+
export const VM_WIDTH_SHIFT = 8;
|
|
233
|
+
|
|
234
|
+
/** Mask selecting the width out of word 0, once shifted down. @type {number} */
|
|
235
|
+
export const VM_WIDTH_MASK = 0x7;
|
|
236
|
+
|
|
192
237
|
/**
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
238
|
+
* What a source word means. Wire values; never renumber.
|
|
239
|
+
* @enum {number}
|
|
240
|
+
*/
|
|
241
|
+
export const VM_KIND = {
|
|
242
|
+
/** not an operand: an unused slot, or a raw field the opcode reads itself */
|
|
243
|
+
NONE: 0,
|
|
244
|
+
/** a register operand: base slot in bits 0..7, swizzle in bits 8..15 */
|
|
245
|
+
REG: 1,
|
|
246
|
+
/** the `f32` bit pattern of a literal, read in every lane */
|
|
247
|
+
IMM: 2,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Bit position of the first source's kind in word 0. Source `n` has its two kind bits at
|
|
252
|
+
* `VM_KIND_SHIFT + 2n`, so the three together are bits 16..21.
|
|
200
253
|
* @type {number}
|
|
201
254
|
*/
|
|
202
|
-
export const
|
|
255
|
+
export const VM_KIND_SHIFT = 16;
|
|
203
256
|
|
|
204
|
-
/**
|
|
205
|
-
export const
|
|
257
|
+
/** Bits per kind field. @type {number} */
|
|
258
|
+
export const VM_KIND_BITS = 2;
|
|
206
259
|
|
|
207
|
-
/** Mask selecting
|
|
208
|
-
export const
|
|
260
|
+
/** Mask selecting one kind field, once shifted down. @type {number} */
|
|
261
|
+
export const VM_KIND_MASK = 0x3;
|
|
262
|
+
|
|
263
|
+
/** Mask selecting all three kind fields, once shifted down by {@link VM_KIND_SHIFT}. @type {number} */
|
|
264
|
+
const VM_KINDS_MASK = 0x3f;
|
|
265
|
+
|
|
266
|
+
/** Bit position of the destination register in word 0. @type {number} */
|
|
267
|
+
export const VM_DST_SHIFT = 24;
|
|
268
|
+
|
|
269
|
+
/** Mask selecting the destination register out of word 0, once shifted down. @type {number} */
|
|
270
|
+
export const VM_DST_MASK = 0xff;
|
|
209
271
|
|
|
210
272
|
/**
|
|
211
|
-
* Pack
|
|
273
|
+
* Pack word 0.
|
|
274
|
+
*
|
|
212
275
|
* @param {number} op
|
|
213
276
|
* @param {number} width lane count, `0..4`
|
|
277
|
+
* @param {number} dst destination register, `0..255`
|
|
278
|
+
* @param {number} kinds the three source kinds as one field — see {@link vm_pack_kinds}
|
|
214
279
|
* @returns {number}
|
|
215
280
|
*/
|
|
216
|
-
export function vm_encode_word0(op, width) {
|
|
217
|
-
return (
|
|
281
|
+
export function vm_encode_word0(op, width, dst, kinds) {
|
|
282
|
+
return (
|
|
283
|
+
(op & VM_OP_MASK)
|
|
284
|
+
| ((width & VM_WIDTH_MASK) << VM_WIDTH_SHIFT)
|
|
285
|
+
| ((kinds & VM_KINDS_MASK) << VM_KIND_SHIFT)
|
|
286
|
+
| ((dst & VM_DST_MASK) << VM_DST_SHIFT)
|
|
287
|
+
) >>> 0;
|
|
218
288
|
}
|
|
219
289
|
|
|
220
290
|
/**
|
|
221
|
-
* @
|
|
222
|
-
*
|
|
291
|
+
* The three source kinds as the one field {@link vm_encode_word0} takes.
|
|
292
|
+
*
|
|
293
|
+
* @param {number} s0
|
|
294
|
+
* @param {number} s1
|
|
295
|
+
* @param {number} s2
|
|
296
|
+
* @returns {number}
|
|
223
297
|
*/
|
|
298
|
+
export function vm_pack_kinds(s0, s1, s2) {
|
|
299
|
+
return (
|
|
300
|
+
(s0 & VM_KIND_MASK)
|
|
301
|
+
| ((s1 & VM_KIND_MASK) << VM_KIND_BITS)
|
|
302
|
+
| ((s2 & VM_KIND_MASK) << (2 * VM_KIND_BITS))
|
|
303
|
+
) >>> 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** @param {number} word0 @returns {number} opcode */
|
|
224
307
|
export function vm_decode_op(word0) {
|
|
225
308
|
return word0 & VM_OP_MASK;
|
|
226
309
|
}
|
|
227
310
|
|
|
311
|
+
/** @param {number} word0 @returns {number} lane count */
|
|
312
|
+
export function vm_decode_width(word0) {
|
|
313
|
+
return (word0 >>> VM_WIDTH_SHIFT) & VM_WIDTH_MASK;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** @param {number} word0 @returns {number} destination register */
|
|
317
|
+
export function vm_decode_dst(word0) {
|
|
318
|
+
return (word0 >>> VM_DST_SHIFT) & VM_DST_MASK;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** @param {number} word0 @returns {number} the three source kinds as one field */
|
|
322
|
+
export function vm_decode_kinds(word0) {
|
|
323
|
+
return (word0 >>> VM_KIND_SHIFT) & VM_KINDS_MASK;
|
|
324
|
+
}
|
|
325
|
+
|
|
228
326
|
/**
|
|
229
327
|
* @param {number} word0
|
|
230
|
-
* @
|
|
328
|
+
* @param {number} slot source slot, `0..2`
|
|
329
|
+
* @returns {number} a {@link VM_KIND}
|
|
231
330
|
*/
|
|
232
|
-
export function
|
|
233
|
-
return (word0
|
|
331
|
+
export function vm_decode_kind(word0, slot) {
|
|
332
|
+
return (word0 >>> (VM_KIND_SHIFT + slot * VM_KIND_BITS)) & VM_KIND_MASK;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** @returns {number} word 0 with its width replaced */
|
|
336
|
+
export function vm_with_width(word0, width) {
|
|
337
|
+
return ((word0 & ~(VM_WIDTH_MASK << VM_WIDTH_SHIFT)) | ((width & VM_WIDTH_MASK) << VM_WIDTH_SHIFT)) >>> 0;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** @returns {number} word 0 with its destination replaced */
|
|
341
|
+
export function vm_with_dst(word0, dst) {
|
|
342
|
+
return ((word0 & ~(VM_DST_MASK << VM_DST_SHIFT)) | ((dst & VM_DST_MASK) << VM_DST_SHIFT)) >>> 0;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** @returns {number} word 0 with one source's kind replaced */
|
|
346
|
+
export function vm_with_kind(word0, slot, kind) {
|
|
347
|
+
const shift = VM_KIND_SHIFT + slot * VM_KIND_BITS;
|
|
348
|
+
|
|
349
|
+
return ((word0 & ~(VM_KIND_MASK << shift)) | ((kind & VM_KIND_MASK) << shift)) >>> 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// --- register operands ------------------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Pack a swizzle pattern from four lane selectors: selector `i` in bits `[2i, 2i+2)`, values
|
|
356
|
+
* 0=x, 1=y, 2=z, 3=w.
|
|
357
|
+
*
|
|
358
|
+
* @param {number} x
|
|
359
|
+
* @param {number} y
|
|
360
|
+
* @param {number} z
|
|
361
|
+
* @param {number} w
|
|
362
|
+
* @returns {number}
|
|
363
|
+
*/
|
|
364
|
+
export function pack_swizzle(x, y, z, w) {
|
|
365
|
+
return (x & 3) | ((y & 3) << 2) | ((z & 3) << 4) | ((w & 3) << 6);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @param {number} pattern
|
|
370
|
+
* @param {number} lane
|
|
371
|
+
* @returns {number} the lane the pattern selects for output lane `lane`
|
|
372
|
+
*/
|
|
373
|
+
export function swizzle_selector(pattern, lane) {
|
|
374
|
+
return (pattern >>> (2 * lane)) & 3;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** The pattern that reads a run as it lies: `.xyzw`. @type {number} */
|
|
378
|
+
export const VM_SWIZZLE_IDENTITY = pack_swizzle(0, 1, 2, 3);
|
|
379
|
+
|
|
380
|
+
/** The pattern that reads lane 0 in every lane: `.xxxx`. @type {number} */
|
|
381
|
+
export const VM_SWIZZLE_BROADCAST = pack_swizzle(0, 0, 0, 0);
|
|
382
|
+
|
|
383
|
+
/** Mask selecting the base slot out of a register operand word. @type {number} */
|
|
384
|
+
export const VM_OPERAND_BASE_MASK = 0xff;
|
|
385
|
+
|
|
386
|
+
/** Bit position of the swizzle byte in a register operand word. @type {number} */
|
|
387
|
+
export const VM_OPERAND_SWIZZLE_SHIFT = 8;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* A register operand word: a base slot read through a pattern.
|
|
391
|
+
*
|
|
392
|
+
* The pattern is stored XOR {@link VM_SWIZZLE_IDENTITY}, so the identity is a zero byte and a bare
|
|
393
|
+
* slot index is the run at that slot. Nothing else about the word depends on that choice; read the
|
|
394
|
+
* pattern back with {@link vm_operand_pattern} rather than the bits.
|
|
395
|
+
*
|
|
396
|
+
* @param {number} base first register slot
|
|
397
|
+
* @param {number} [pattern] a packed swizzle; the run as it lies when left out
|
|
398
|
+
* @returns {number}
|
|
399
|
+
*/
|
|
400
|
+
export function vm_register(base, pattern = VM_SWIZZLE_IDENTITY) {
|
|
401
|
+
return ((base & VM_OPERAND_BASE_MASK) | (((pattern ^ VM_SWIZZLE_IDENTITY) & 0xff) << VM_OPERAND_SWIZZLE_SHIFT)) >>> 0;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/** @param {number} word a register operand @returns {number} its base slot */
|
|
405
|
+
export function vm_operand_base(word) {
|
|
406
|
+
return word & VM_OPERAND_BASE_MASK;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** @param {number} word a register operand @returns {number} its swizzle, as {@link pack_swizzle} packs one */
|
|
410
|
+
export function vm_operand_pattern(word) {
|
|
411
|
+
return ((word >>> VM_OPERAND_SWIZZLE_SHIFT) & 0xff) ^ VM_SWIZZLE_IDENTITY;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* @param {number} word a register operand
|
|
416
|
+
* @param {number} lane
|
|
417
|
+
* @returns {number} the slot lane `lane` of the operand reads
|
|
418
|
+
*/
|
|
419
|
+
export function vm_operand_slot(word, lane) {
|
|
420
|
+
return vm_operand_base(word) + swizzle_selector(vm_operand_pattern(word), lane);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** @returns {number} the operand moved to another base, keeping its swizzle */
|
|
424
|
+
export function vm_operand_with_base(word, base) {
|
|
425
|
+
return vm_register(base, vm_operand_pattern(word));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* How far into the file a register operand reaches when `lanes` lanes of it are read: one past the
|
|
430
|
+
* widest selector among them. The selectors above `lanes` are never read and do not count.
|
|
431
|
+
*
|
|
432
|
+
* @param {number} word a register operand
|
|
433
|
+
* @param {number} lanes how many lanes the instruction reads of it
|
|
434
|
+
* @returns {number}
|
|
435
|
+
*/
|
|
436
|
+
export function vm_operand_span(word, lanes) {
|
|
437
|
+
const pattern = vm_operand_pattern(word);
|
|
438
|
+
|
|
439
|
+
let span = 1;
|
|
440
|
+
|
|
441
|
+
for (let lane = 0; lane < lanes; lane++) {
|
|
442
|
+
span = Math.max(span, swizzle_selector(pattern, lane) + 1);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return span;
|
|
234
446
|
}
|
|
235
447
|
|
|
236
448
|
/**
|
|
237
|
-
* The
|
|
449
|
+
* The canonical spelling of a register operand read at `lanes` lanes: the base is the lowest slot
|
|
450
|
+
* any lane reads, and selectors above the lanes read are the identity, since they name nothing. So
|
|
451
|
+
* `r0.yz` is `r1`, `r0.zy` is `r1.yx`, and a broadcast of lane 3 is the run at lane 3 — one
|
|
452
|
+
* spelling per meaning, which is what lets two instructions be compared word for word.
|
|
238
453
|
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
454
|
+
* @param {number} word a register operand
|
|
455
|
+
* @param {number} lanes how many lanes the instruction reads of it
|
|
456
|
+
* @returns {number}
|
|
457
|
+
*/
|
|
458
|
+
export function vm_canonical_register(word, lanes) {
|
|
459
|
+
const pattern = vm_operand_pattern(word);
|
|
460
|
+
|
|
461
|
+
let lowest = lanes > 0 ? 3 : 0;
|
|
462
|
+
|
|
463
|
+
for (let lane = 0; lane < lanes; lane++) {
|
|
464
|
+
lowest = Math.min(lowest, swizzle_selector(pattern, lane));
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
let canonical = 0;
|
|
468
|
+
|
|
469
|
+
for (let lane = 0; lane < VM_MAX_WIDTH; lane++) {
|
|
470
|
+
const selector = lane < lanes ? swizzle_selector(pattern, lane) - lowest : lane;
|
|
471
|
+
|
|
472
|
+
canonical |= selector << (2 * lane);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return vm_register(vm_operand_base(word) + lowest, canonical);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// --- immediates -------------------------------------------------------------------------------
|
|
479
|
+
|
|
480
|
+
/** Scratch for converting between a literal and its bits. */
|
|
481
|
+
const F32_SCRATCH = new Float32Array(1);
|
|
482
|
+
|
|
483
|
+
/** @type {Uint32Array} the same four bytes */
|
|
484
|
+
const U32_SCRATCH = new Uint32Array(F32_SCRATCH.buffer);
|
|
485
|
+
|
|
486
|
+
/** @param {number} value @returns {number} the `f32` bit pattern the value rounds to */
|
|
487
|
+
export function vm_f32_bits(value) {
|
|
488
|
+
F32_SCRATCH[0] = value;
|
|
489
|
+
|
|
490
|
+
return U32_SCRATCH[0];
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** @param {number} bits @returns {number} the `f32` those bits are */
|
|
494
|
+
export function vm_f32_value(bits) {
|
|
495
|
+
U32_SCRATCH[0] = bits;
|
|
496
|
+
|
|
497
|
+
return F32_SCRATCH[0];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* A literal source operand, as `InstructionStream.emit` takes one in a source slot.
|
|
502
|
+
*
|
|
503
|
+
* @param {number} value
|
|
504
|
+
* @returns {{kind: number, word: number}}
|
|
505
|
+
*/
|
|
506
|
+
export function vm_immediate(value) {
|
|
507
|
+
return { kind: VM_KIND.IMM, word: vm_f32_bits(value) };
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// --- the opcode table -------------------------------------------------------------------------
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Widths are read out of the opcode's metadata; see {@link VM_ISA}.
|
|
241
514
|
*
|
|
242
515
|
* @param {number} op
|
|
243
516
|
* @param {number} width the instruction's width field
|
|
244
|
-
* @returns {number}
|
|
517
|
+
* @returns {number} the lane count the opcode actually operates on
|
|
245
518
|
*/
|
|
246
519
|
export function vm_operation_width(op, width) {
|
|
247
520
|
const meta = VM_ISA.get(op);
|
|
@@ -278,23 +551,22 @@ export function vm_dest_width(op, width) {
|
|
|
278
551
|
}
|
|
279
552
|
}
|
|
280
553
|
|
|
281
|
-
const D = VM_OPERAND.DST;
|
|
282
554
|
const R = VM_OPERAND.REG;
|
|
283
555
|
const _ = VM_OPERAND.NONE;
|
|
284
556
|
|
|
285
557
|
/**
|
|
286
|
-
* Per-opcode metadata: mnemonic
|
|
558
|
+
* Per-opcode metadata: mnemonic, whether it writes a destination, and the role of each source slot.
|
|
287
559
|
*
|
|
288
560
|
* Keyed by opcode number. Used by the assembler for validation/disassembly and by the parity
|
|
289
561
|
* meta-test to enforce that every opcode is handled by both executors.
|
|
290
|
-
* @type {Map<number, {name: string, dst: boolean, operands: [string, string, string]}>}
|
|
562
|
+
* @type {Map<number, {name: string, dst: boolean, operands: [string, string, string], width: string, dest: string, default_width: number, min_width: number, scalar_operands: number[]}>}
|
|
291
563
|
*/
|
|
292
564
|
export const VM_ISA = new Map();
|
|
293
565
|
|
|
294
566
|
/**
|
|
295
567
|
* @param {number} op
|
|
296
568
|
* @param {string} name
|
|
297
|
-
* @param {boolean} dst
|
|
569
|
+
* @param {boolean} dst whether the opcode writes a destination register
|
|
298
570
|
* @param {string} [s0]
|
|
299
571
|
* @param {string} [s1]
|
|
300
572
|
* @param {string} [s2]
|
|
@@ -311,7 +583,7 @@ function def(op, name, dst, s0 = _, s1 = _, s2 = _, options = {}) {
|
|
|
311
583
|
}
|
|
312
584
|
|
|
313
585
|
const width = options.width ?? VM_WIDTH.VARIABLE;
|
|
314
|
-
const dest = options.dest ??
|
|
586
|
+
const dest = dst ? (options.dest ?? VM_DEST.WIDTH) : VM_DEST.NONE;
|
|
315
587
|
|
|
316
588
|
let default_width = options.default_width ?? VM_MAX_WIDTH;
|
|
317
589
|
|
|
@@ -340,12 +612,12 @@ def(VM_OP.NOP, "NOP", false, _, _, _, { width: VM_WIDTH.NONE });
|
|
|
340
612
|
def(VM_OP.MOV, "MOV", true, R);
|
|
341
613
|
def(VM_OP.LOAD_CONST, "LOAD_CONST", true, VM_OPERAND.CONST);
|
|
342
614
|
def(VM_OP.LOAD_ATTR, "LOAD_ATTR", true, VM_OPERAND.ATTR_OFFSET, VM_OPERAND.COMP);
|
|
343
|
-
//
|
|
344
|
-
// cannot write lanes the
|
|
345
|
-
def(VM_OP.STORE_ATTR, "STORE_ATTR",
|
|
615
|
+
// The value to store is an ordinary source — a register run or a literal — and the width must equal
|
|
616
|
+
// the component count, since a store cannot write lanes the value does not have.
|
|
617
|
+
def(VM_OP.STORE_ATTR, "STORE_ATTR", false, R, VM_OPERAND.ATTR_OFFSET, VM_OPERAND.COMP);
|
|
346
618
|
def(VM_OP.LOAD_BUILTIN, "LOAD_BUILTIN", true, VM_OPERAND.BUILTIN);
|
|
347
|
-
//
|
|
348
|
-
def(VM_OP.KILL, "KILL",
|
|
619
|
+
// The condition is one lane of an ordinary source.
|
|
620
|
+
def(VM_OP.KILL, "KILL", false, R, _, _, { width: VM_WIDTH.ONE });
|
|
349
621
|
|
|
350
622
|
def(VM_OP.ADD, "ADD", true, R, R);
|
|
351
623
|
def(VM_OP.SUB, "SUB", true, R, R);
|
|
@@ -356,7 +628,6 @@ def(VM_OP.MIN, "MIN", true, R, R);
|
|
|
356
628
|
def(VM_OP.MAX, "MAX", true, R, R);
|
|
357
629
|
def(VM_OP.MIX, "MIX", true, R, R, R);
|
|
358
630
|
def(VM_OP.CLAMP, "CLAMP", true, R, R, R);
|
|
359
|
-
def(VM_OP.SCALE, "SCALE", true, R, R, _, { scalar_operands: [1] });
|
|
360
631
|
|
|
361
632
|
def(VM_OP.NEG, "NEG", true, R);
|
|
362
633
|
def(VM_OP.ABS, "ABS", true, R);
|
|
@@ -370,18 +641,23 @@ def(VM_OP.LOG, "LOG", true, R);
|
|
|
370
641
|
def(VM_OP.POW, "POW", true, R, R);
|
|
371
642
|
def(VM_OP.STEP, "STEP", true, R, R);
|
|
372
643
|
def(VM_OP.SMOOTHSTEP, "SMOOTHSTEP", true, R, R, R);
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
644
|
+
def(VM_OP.RSQRT, "RSQRT", true, R);
|
|
645
|
+
def(VM_OP.TAN, "TAN", true, R);
|
|
646
|
+
def(VM_OP.ASIN, "ASIN", true, R);
|
|
647
|
+
def(VM_OP.ACOS, "ACOS", true, R);
|
|
648
|
+
// `atan2(y, x)`: the angle of the point, with the quadrant the signs put it in — so the first
|
|
649
|
+
// source is the one a plot puts on the vertical axis, as it is in every shading language.
|
|
650
|
+
def(VM_OP.ATAN2, "ATAN2", true, R, R);
|
|
651
|
+
|
|
652
|
+
// The reductions read `width` lanes and write one. Whatever wants the result wider reads it through
|
|
653
|
+
// an `.xxxx` swizzle, which is what tracking widths is for.
|
|
377
654
|
def(VM_OP.DOT, "DOT", true, R, R, _, { dest: VM_DEST.ONE, default_width: 3 });
|
|
378
|
-
// A cross product is three lanes wide. It may be asked for a fourth, which it writes as zero
|
|
379
|
-
//
|
|
655
|
+
// A cross product is three lanes wide. It may be asked for a fourth, which it writes as zero, but
|
|
656
|
+
// never for fewer, so `min_width` is a floor rather than a fix.
|
|
380
657
|
def(VM_OP.CROSS, "CROSS", true, R, R, _, { default_width: 3, min_width: 3 });
|
|
381
658
|
def(VM_OP.LENGTH, "LENGTH", true, R, _, _, { dest: VM_DEST.ONE, default_width: 3 });
|
|
382
659
|
def(VM_OP.NORMALIZE, "NORMALIZE", true, R, _, _, { default_width: 3 });
|
|
383
660
|
def(VM_OP.DISTANCE, "DISTANCE", true, R, R, _, { dest: VM_DEST.ONE, default_width: 3 });
|
|
384
|
-
def(VM_OP.SWIZZLE, "SWIZZLE", true, R, VM_OPERAND.SWIZZLE);
|
|
385
661
|
|
|
386
662
|
def(VM_OP.CMP_LT, "CMP_LT", true, R, R);
|
|
387
663
|
def(VM_OP.CMP_LE, "CMP_LE", true, R, R);
|
|
@@ -390,108 +666,201 @@ def(VM_OP.CMP_GE, "CMP_GE", true, R, R);
|
|
|
390
666
|
def(VM_OP.CMP_EQ, "CMP_EQ", true, R, R);
|
|
391
667
|
def(VM_OP.SELECT, "SELECT", true, R, R, R);
|
|
392
668
|
|
|
393
|
-
// One independent uniform draw in `[0, 1)` per lane, and nothing else
|
|
394
|
-
//
|
|
395
|
-
// this draw that a program can write for itself: with its constants hoisted, a unit sphere is ten
|
|
396
|
-
// instructions and a unit disk seven. There is no principled place to stop adding distributions, so
|
|
397
|
-
// the ISA does not start. Which means the draw count is now plainly `width`, rather than a per-mode
|
|
398
|
-
// rule a reader has to look up.
|
|
669
|
+
// One independent uniform draw in `[0, 1)` per lane, and nothing else: a shaped distribution is
|
|
670
|
+
// arithmetic a program writes over this draw — see ../graph/particle_graph_distributions.js.
|
|
399
671
|
def(VM_OP.RANDOM, "RANDOM", true);
|
|
400
672
|
// `t` is one lane; the sampled value fills the destination's width.
|
|
401
673
|
def(VM_OP.CURVE, "CURVE", true, VM_OPERAND.CURVE, R, _, { scalar_operands: [1] });
|
|
402
674
|
|
|
675
|
+
// --- packing an instruction ---------------------------------------------------------------------
|
|
676
|
+
|
|
403
677
|
/**
|
|
678
|
+
* The four words of an instruction, with every register operand in its canonical spelling.
|
|
679
|
+
*
|
|
680
|
+
* Both the assembler's `InstructionStream.emit` and the assembly parser build instructions here, so
|
|
681
|
+
* the one encoding rule that is a choice rather than a fact — how a swizzle is spelled — is made in
|
|
682
|
+
* one place: selectors above the lanes an operand is read at are the identity, and a run of
|
|
683
|
+
* consecutive selectors is the identity at a higher base. Two instructions that mean the same thing
|
|
684
|
+
* then have the same words, which is what lets the optimizer compare them.
|
|
685
|
+
*
|
|
404
686
|
* @param {number} op
|
|
405
|
-
* @
|
|
687
|
+
* @param {number} width lane count, `0..4`
|
|
688
|
+
* @param {number} dst destination register
|
|
689
|
+
* @param {number[]} kinds a {@link VM_KIND} per source slot
|
|
690
|
+
* @param {number[]} sources the three source words
|
|
691
|
+
* @returns {number[]}
|
|
406
692
|
*/
|
|
407
|
-
export function
|
|
693
|
+
export function vm_pack_instruction(op, width, dst, kinds, sources) {
|
|
408
694
|
const meta = VM_ISA.get(op);
|
|
409
|
-
|
|
695
|
+
const operation_width = vm_operation_width(op, width);
|
|
696
|
+
const words = [vm_encode_word0(op, width, dst, vm_pack_kinds(kinds[0], kinds[1], kinds[2])), 0, 0, 0];
|
|
697
|
+
|
|
698
|
+
for (let slot = 0; slot < 3; slot++) {
|
|
699
|
+
const word = sources[slot] >>> 0;
|
|
700
|
+
|
|
701
|
+
words[1 + slot] = kinds[slot] === VM_KIND.REG && meta !== undefined
|
|
702
|
+
? vm_canonical_register(word, meta.scalar_operands.includes(slot) ? 1 : operation_width)
|
|
703
|
+
: word;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return words;
|
|
410
707
|
}
|
|
411
708
|
|
|
412
709
|
/**
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* @param {number}
|
|
416
|
-
* @
|
|
417
|
-
* @param {number} z
|
|
418
|
-
* @param {number} w
|
|
419
|
-
* @returns {number}
|
|
710
|
+
* An encoded instruction, re-spelled canonically — what a pass wants after it has moved an operand.
|
|
711
|
+
*
|
|
712
|
+
* @param {ArrayLike<number>} words the four words of a single instruction
|
|
713
|
+
* @returns {number[]}
|
|
420
714
|
*/
|
|
421
|
-
export function
|
|
422
|
-
|
|
715
|
+
export function vm_repack_instruction(words) {
|
|
716
|
+
const word0 = words[0];
|
|
717
|
+
|
|
718
|
+
return vm_pack_instruction(
|
|
719
|
+
vm_decode_op(word0),
|
|
720
|
+
vm_decode_width(word0),
|
|
721
|
+
vm_decode_dst(word0),
|
|
722
|
+
[vm_decode_kind(word0, 0), vm_decode_kind(word0, 1), vm_decode_kind(word0, 2)],
|
|
723
|
+
[words[1], words[2], words[3]]
|
|
724
|
+
);
|
|
423
725
|
}
|
|
424
726
|
|
|
727
|
+
// --- reading an instruction ---------------------------------------------------------------------
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* @typedef {object} ParticleVMOperand
|
|
731
|
+
* @property {number} slot source slot, `0..2`
|
|
732
|
+
* @property {number} kind a {@link VM_KIND}, never `NONE`
|
|
733
|
+
* @property {number} word the source word as encoded
|
|
734
|
+
* @property {number} lanes how many lanes the instruction reads of it: the operation's width, or one
|
|
735
|
+
* for a slot the ISA marks scalar
|
|
736
|
+
* @property {number} span register slots the operand reaches from its base, for a register; `0` for a
|
|
737
|
+
* literal
|
|
738
|
+
*/
|
|
739
|
+
|
|
425
740
|
/**
|
|
426
|
-
*
|
|
427
|
-
* the
|
|
741
|
+
* Visit every source operand of an instruction — every slot whose kind is not `NONE` — with how
|
|
742
|
+
* many lanes the opcode reads of it and how far into the file it reaches.
|
|
428
743
|
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
744
|
+
* The rules for the reach are not uniform and live here rather than in each caller: a source is
|
|
745
|
+
* read as wide as the operation runs unless the ISA marks that slot scalar, and a register operand
|
|
746
|
+
* reaches as far as its widest selector among the lanes read.
|
|
432
747
|
*
|
|
433
|
-
* @param {number}
|
|
434
|
-
* @
|
|
748
|
+
* @param {ArrayLike<number>} words an instruction stream
|
|
749
|
+
* @param {number} base index of the instruction's first word
|
|
750
|
+
* @param {function(ParticleVMOperand):void} visit the one object is reused between calls; copy it
|
|
751
|
+
* to keep it
|
|
435
752
|
*/
|
|
436
|
-
export function
|
|
437
|
-
|
|
753
|
+
export function vm_visit_operands(words, base, visit) {
|
|
754
|
+
const word0 = words[base];
|
|
755
|
+
const op = vm_decode_op(word0);
|
|
756
|
+
const meta = VM_ISA.get(op);
|
|
438
757
|
|
|
439
|
-
|
|
440
|
-
|
|
758
|
+
if (meta === undefined) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const operation_width = vm_operation_width(op, vm_decode_width(word0));
|
|
763
|
+
const operand = { slot: 0, kind: 0, word: 0, lanes: 0, span: 0 };
|
|
764
|
+
|
|
765
|
+
for (let slot = 0; slot < 3; slot++) {
|
|
766
|
+
const kind = vm_decode_kind(word0, slot);
|
|
441
767
|
|
|
442
|
-
if (
|
|
443
|
-
|
|
768
|
+
if (kind === VM_KIND.NONE) {
|
|
769
|
+
continue;
|
|
444
770
|
}
|
|
445
|
-
}
|
|
446
771
|
|
|
447
|
-
|
|
772
|
+
const word = words[base + 1 + slot];
|
|
773
|
+
const lanes = meta.scalar_operands.includes(slot) ? 1 : operation_width;
|
|
774
|
+
|
|
775
|
+
operand.slot = slot;
|
|
776
|
+
operand.kind = kind;
|
|
777
|
+
operand.word = word;
|
|
778
|
+
operand.lanes = lanes;
|
|
779
|
+
operand.span = kind === VM_KIND.REG ? vm_operand_span(word, lanes) : 0;
|
|
780
|
+
visit(operand);
|
|
781
|
+
}
|
|
448
782
|
}
|
|
449
783
|
|
|
450
784
|
/**
|
|
451
|
-
* Visit every register
|
|
452
|
-
* slots it reaches
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
* of the file it touches: a `vec3` at r0 occupies r0, r1 and r2. Anyone sizing a register file or
|
|
456
|
-
* bounds-checking one needs the reach rather than the base, and the rules for it are not uniform —
|
|
457
|
-
* so they live here, in one place, instead of being re-derived by each caller until they disagree:
|
|
458
|
-
*
|
|
459
|
-
* - a destination reaches as far as the opcode writes, which for the reductions is one lane;
|
|
460
|
-
* - a source reaches as far as the operation runs, unless the ISA marks that slot scalar;
|
|
461
|
-
* - a `SWIZZLE` source reaches as far as its pattern names, which the width cannot tell you;
|
|
462
|
-
* - the source `STORE_ATTR` and `KILL` keep in the destination slot reaches as far as they read.
|
|
785
|
+
* Visit every run of the register file an instruction touches, as the slot it starts at and how
|
|
786
|
+
* many consecutive slots it reaches: the destination as far as the opcode writes, and each register
|
|
787
|
+
* source as far as its selectors read. What anyone sizing or bounds-checking the file wants; a
|
|
788
|
+
* literal is not a run of the file and is not visited.
|
|
463
789
|
*
|
|
464
790
|
* @param {ArrayLike<number>} words an instruction stream
|
|
465
791
|
* @param {number} base index of the instruction's first word
|
|
466
|
-
* @param {function(number, number):void} visit called `(slot, span)` per
|
|
792
|
+
* @param {function(number, number):void} visit called `(slot, span)` per run
|
|
467
793
|
*/
|
|
468
|
-
export function
|
|
794
|
+
export function vm_visit_register_runs(words, base, visit) {
|
|
469
795
|
const word0 = words[base];
|
|
470
796
|
const op = vm_decode_op(word0);
|
|
471
|
-
const
|
|
797
|
+
const dest = vm_dest_width(op, vm_decode_width(word0));
|
|
472
798
|
|
|
473
|
-
if (
|
|
474
|
-
|
|
799
|
+
if (dest > 0) {
|
|
800
|
+
visit(vm_decode_dst(word0), dest);
|
|
475
801
|
}
|
|
476
802
|
|
|
477
|
-
|
|
478
|
-
|
|
803
|
+
vm_visit_operands(words, base, (operand) => {
|
|
804
|
+
if (operand.kind === VM_KIND.REG) {
|
|
805
|
+
visit(vm_operand_base(operand.word), operand.span);
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
}
|
|
479
809
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
810
|
+
/**
|
|
811
|
+
* Whether the kind bits of an instruction agree with what its opcode reads: a register-role slot
|
|
812
|
+
* carries a register or a literal, every other slot carries nothing. Both the assembler and
|
|
813
|
+
* `ParticleProgram.validate` ask here rather than each restating the rule.
|
|
814
|
+
*
|
|
815
|
+
* @param {ArrayLike<number>} words an instruction stream
|
|
816
|
+
* @param {number} base index of the instruction's first word
|
|
817
|
+
* @returns {string|null} what is wrong, or `null` when nothing is
|
|
818
|
+
*/
|
|
819
|
+
export function vm_kinds_problem(words, base) {
|
|
820
|
+
const word0 = words[base];
|
|
821
|
+
const meta = VM_ISA.get(vm_decode_op(word0));
|
|
822
|
+
|
|
823
|
+
if (meta === undefined) {
|
|
824
|
+
return null;
|
|
484
825
|
}
|
|
485
826
|
|
|
486
827
|
for (let slot = 0; slot < 3; slot++) {
|
|
487
|
-
|
|
488
|
-
|
|
828
|
+
const kind = vm_decode_kind(word0, slot);
|
|
829
|
+
const role = meta.operands[slot];
|
|
830
|
+
|
|
831
|
+
if (kind > VM_KIND.IMM) {
|
|
832
|
+
return `s${slot} has operand kind ${kind}, which the ISA does not define`;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (role === VM_OPERAND.REG && kind === VM_KIND.NONE) {
|
|
836
|
+
return `s${slot} of ${meta.name} must be a register or a literal`;
|
|
489
837
|
}
|
|
490
838
|
|
|
491
|
-
|
|
492
|
-
?
|
|
493
|
-
|
|
839
|
+
if (role !== VM_OPERAND.REG && kind !== VM_KIND.NONE) {
|
|
840
|
+
return `s${slot} of ${meta.name} is ${role === VM_OPERAND.NONE ? "unused" : `a ${role}`} and has no kind`;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
return null;
|
|
845
|
+
}
|
|
494
846
|
|
|
495
|
-
|
|
847
|
+
/**
|
|
848
|
+
* The kinds an opcode's sources carry when every register-role slot holds a register: the default
|
|
849
|
+
* an assembler starts from, before any literal is marked.
|
|
850
|
+
*
|
|
851
|
+
* @param {number} op
|
|
852
|
+
* @returns {number} a kinds field for {@link vm_encode_word0}
|
|
853
|
+
*/
|
|
854
|
+
export function vm_register_kinds(op) {
|
|
855
|
+
const meta = VM_ISA.get(op);
|
|
856
|
+
|
|
857
|
+
if (meta === undefined) {
|
|
858
|
+
return 0;
|
|
496
859
|
}
|
|
860
|
+
|
|
861
|
+
return vm_pack_kinds(
|
|
862
|
+
meta.operands[0] === R ? VM_KIND.REG : VM_KIND.NONE,
|
|
863
|
+
meta.operands[1] === R ? VM_KIND.REG : VM_KIND.NONE,
|
|
864
|
+
meta.operands[2] === R ? VM_KIND.REG : VM_KIND.NONE
|
|
865
|
+
);
|
|
497
866
|
}
|