@woosh/meep-engine 3.16.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/editor/particles/effect/ParticleEffectDocument.d.ts +21 -6
- package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
- package/editor/particles/effect/ParticleEffectDocument.js +38 -17
- package/editor/view/node-graph/NodeGraphClipboard.d.ts +186 -0
- package/editor/view/node-graph/NodeGraphClipboard.d.ts.map +1 -0
- package/editor/view/node-graph/NodeGraphClipboard.js +231 -0
- package/editor/view/node-graph/NodeGraphEditorView.d.ts +59 -1
- package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphEditorView.js +248 -5
- package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphView.js +84 -8
- package/editor/view/node-graph/actions/connection_bind_actions.d.ts +23 -0
- package/editor/view/node-graph/actions/connection_bind_actions.d.ts.map +1 -0
- package/editor/view/node-graph/actions/connection_bind_actions.js +39 -0
- package/editor/view/particles/effect/ParticleCodeEditorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleCodeEditorView.js +4 -3
- package/editor/view/particles/effect/ParticleCurveEditorView.d.ts +20 -0
- package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -0
- package/editor/view/particles/effect/ParticleCurveEditorView.js +574 -0
- package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleEmitterInspectorView.js +27 -1
- package/editor/view/particles/effect/ParticleGradientEditorView.d.ts +24 -0
- package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -0
- package/editor/view/particles/effect/ParticleGradientEditorView.js +472 -0
- package/editor/view/particles/effect/ParticleGraphEditorView.d.ts +5 -0
- package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleGraphEditorView.js +61 -31
- package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleNodeParametersView.js +33 -0
- package/editor/view/particles/effect/particle-editor.css +123 -35
- package/package.json +1 -1
- package/src/core/binary/allocator/OffsetAllocator.d.ts +25 -16
- package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
- package/src/core/binary/allocator/OffsetAllocator.js +10 -1
- package/src/core/collection/array/typed/float32_array_hash.d.ts +21 -0
- package/src/core/collection/array/typed/float32_array_hash.d.ts.map +1 -0
- package/src/core/collection/array/typed/float32_array_hash.js +38 -0
- package/src/core/graph/csr/CSRGraph.d.ts +8 -1
- package/src/core/graph/csr/CSRGraph.d.ts.map +1 -1
- package/src/core/graph/csr/CSRGraph.js +14 -6
- package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts +24 -0
- package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/LayoutProblem.js +27 -0
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +26 -0
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +28 -0
- package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts +92 -3
- package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/RouteGrid.js +405 -242
- package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts +50 -5
- package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/RouteSearch.js +160 -24
- package/src/core/model/node-graph/visual/layout/RouteSet.d.ts +7 -0
- package/src/core/model/node-graph/visual/layout/RouteSet.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/RouteSet.js +8 -0
- package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +9 -3
- package/src/core/model/node-graph/visual/layout/layout_build_problem.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_build_problem.js +7 -0
- package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts +9 -3
- package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_insert_lanes.js +17 -3
- package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts +9 -6
- package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_node_graph.js +49 -7
- package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts +11 -1
- package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/layout_order_layers.js +135 -16
- package/src/core/model/node-graph/visual/layout/route_connections.d.ts +29 -0
- package/src/core/model/node-graph/visual/layout/route_connections.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/route_connections.js +716 -309
- package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts +3 -2
- package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/route_grid_build.js +7 -15
- package/src/core/model/node-graph/visual/layout/route_nudge.d.ts +6 -0
- package/src/core/model/node-graph/visual/layout/route_nudge.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/layout/route_nudge.js +42 -13
- package/src/engine/animation/AnimationUtils.js +246 -246
- package/src/engine/animation/Animations.js +74 -74
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2078 -2078
- package/src/engine/ecs/EventType.d.ts +0 -1
- package/src/engine/ecs/EventType.js +1 -26
- package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +1 -1
- package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -1
- package/src/engine/ecs/ik/ik_write_local_rotation.js +3 -7
- package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
- package/src/engine/ecs/parent/EntityNode.js +4 -9
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +360 -364
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts +41 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts.map +1 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.js +40 -0
- package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +8 -0
- package/src/engine/ecs/transform/t64_announce_change.d.ts +10 -7
- package/src/engine/ecs/transform/t64_announce_change.d.ts.map +1 -1
- package/src/engine/ecs/transform/t64_announce_change.js +12 -12
- package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts +30 -0
- package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts.map +1 -0
- package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.js +29 -0
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +13 -21
- package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
- package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +4 -8
- package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
- package/src/engine/graphics3/LightSystem.js +4 -8
- package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
- package/src/engine/graphics3/MeshSystem.js +9 -19
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/ParticleEmitterSystem.js +4 -8
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
- package/src/engine/graphics3/ShadedGeometrySystem.js +4 -10
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts +1 -1
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +4 -8
- package/src/engine/intelligence/behavior/ecs/OrbitingBehavior.js +218 -218
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
- package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
- package/src/engine/sound/ecs/SoundListenerSystem.js +6 -8
- package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts +0 -4
- package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts.map +1 -1
- package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +5 -11
- package/src/shade/playground/particle_editor/README.md +43 -2
- package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
- package/src/shade/playground/particle_system/particle_prototype.js +4 -5
- package/src/shade/playground/particle_system/particle_scene.js +4 -4
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +13 -1
- package/src/shade/renderer/particles/DESIGN.md +104 -19
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +64 -50
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +176 -78
- package/src/shade/renderer/particles/ParticleConstants.d.ts +59 -23
- package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
- package/src/shade/renderer/particles/ParticleConstants.js +66 -23
- package/src/shade/renderer/particles/ParticleRenderMode.d.ts +19 -0
- package/src/shade/renderer/particles/ParticleRenderMode.d.ts.map +1 -0
- package/src/shade/renderer/particles/ParticleRenderMode.js +33 -0
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +167 -166
- package/src/shade/renderer/particles/data/particle_emitter_record.d.ts +37 -0
- package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -0
- package/src/shade/renderer/particles/data/particle_emitter_record.js +109 -0
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +3 -3
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +303 -303
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +18 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +152 -133
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +0 -11
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +720 -621
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/compile_particle_graph.js +8 -3
- package/src/shade/renderer/particles/graph/flatten_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/flatten_particle_graph.js +244 -213
- package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +6 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +294 -319
- package/src/shade/renderer/particles/graph/groups/particle_groups_noise.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_groups_noise.js +524 -517
- package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts +22 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.js +517 -0
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +185 -159
- package/src/shade/renderer/particles/graph/make_particle_group.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/make_particle_group.js +2 -20
- package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts +17 -0
- package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/particle_compare_ops.js +22 -0
- package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts +28 -8
- package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_graph_diagnostic.js +49 -25
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +40 -0
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_parameters.js +312 -234
- package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_presentation.js +59 -3
- package/src/shade/renderer/particles/graph/particle_ramp.d.ts +230 -0
- package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/particle_ramp.js +403 -0
- package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +7 -1
- package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/validate_particle_graph.js +66 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +23 -69
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +105 -262
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles_avboit.js +3 -2
- package/src/shade/renderer/particles/graph_particles_billboard.d.ts +37 -0
- package/src/shade/renderer/particles/graph_particles_billboard.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph_particles_billboard.js +93 -0
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts +51 -22
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/InstructionStream.js +98 -38
- package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +49 -8
- package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleProgram.js +95 -150
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +306 -64
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleVMISA.js +505 -136
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts +36 -12
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/particle_assembly.js +354 -139
- package/src/shade/renderer/particles/isa/validate_particle_program.d.ts +9 -0
- package/src/shade/renderer/particles/isa/validate_particle_program.d.ts.map +1 -0
- package/src/shade/renderer/particles/isa/validate_particle_program.js +128 -0
- package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +23 -0
- package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
- package/src/shade/renderer/particles/layout/ParticleLayout.js +68 -0
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts +77 -0
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +219 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts +83 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +283 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +133 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +334 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts +117 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +70 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts +97 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +462 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts +116 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +687 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +57 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +860 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts +115 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.js +264 -0
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +81 -42
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +477 -478
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +100 -0
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +236 -0
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +139 -59
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +764 -647
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +40 -7
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +376 -213
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts +30 -3
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +337 -223
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +24 -38
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +166 -206
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts +99 -0
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +313 -0
- package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts +3 -2
- package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_dedup_constants.js +198 -197
- package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts +19 -0
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +678 -561
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts +22 -0
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +221 -0
- package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +63 -72
- package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +87 -86
- package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_peephole.js +392 -271
- package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +361 -268
- package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts +4 -0
- package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -0
- package/src/shade/renderer/particles/optimizer/pass_schedule.js +244 -0
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +154 -151
- package/src/shade/renderer/particles/particle_test_fixtures.d.ts +20 -0
- package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +1 -1
- package/src/shade/renderer/particles/particle_test_fixtures.js +229 -203
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +99 -25
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/EmitterRegistry.js +438 -286
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +109 -0
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -0
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +127 -0
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +87 -102
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.js +184 -163
- package/src/shade/renderer/particles/runtime/ProgramArena.d.ts +26 -0
- package/src/shade/renderer/particles/runtime/ProgramArena.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +130 -0
- package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -0
- package/src/shade/renderer/particles/runtime/ProgramHeap.js +595 -0
- package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts +91 -0
- package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts.map +1 -0
- package/src/shade/renderer/particles/runtime/ProgramPlacement.js +106 -0
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +5 -2
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -19
- package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts +28 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.js +136 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts +35 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.js +133 -0
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts +18 -9
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +20 -80
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts +33 -0
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +114 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts +8 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +33 -101
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts +45 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +123 -0
- package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts +51 -0
- package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts.map +1 -0
- package/src/shade/renderer/particles/sort/graph_particle_sort.js +120 -0
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts +6 -0
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +16 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +4 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +261 -140
- package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/chunk_particle_vm.js +217 -255
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts +43 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts.map +1 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.js +55 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts +62 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts.map +1 -0
- package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.js +86 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.js +32 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts +9 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.js +19 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/README.md +65 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.js +83 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.js +42 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts +31 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.js +80 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts +26 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.js +109 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts +38 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.js +129 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts +21 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.js +35 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts +19 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.js +28 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.js +22 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.js +59 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.js +74 -0
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts +34 -1
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +41 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -2
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +49 -10
- package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
- package/src/view/minimap/dom/MinimapCameraView.js +4 -9
- package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts +0 -15
- package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts +0 -45
- package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts +0 -24
- package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts.map +0 -1
- package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts +0 -19
- package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts.map +0 -1
- package/src/engine/ecs/transform/__probe.d.ts +0 -4
- package/src/engine/ecs/transform/__probe.d.ts.map +0 -1
- package/src/engine/ecs/util/hideEntityGracefully.d.ts +0 -9
- package/src/engine/ecs/util/hideEntityGracefully.d.ts.map +0 -1
- package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts +0 -27
- package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts.map +0 -1
- package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts +0 -14
- package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +0 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts +0 -156
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/Emitter.d.ts +0 -219
- package/src/shade/renderer/particles/runtime/Emitter.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts +0 -77
- package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/ProgramArena.js +0 -155
- package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts +0 -15
- package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts.map +0 -1
- package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts +0 -34
- package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts.map +0 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts +0 -32
- package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts.map +0 -1
|
@@ -1,86 +1,124 @@
|
|
|
1
|
-
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
2
1
|
import { chunk_random } from "../../shader/chunk/random/chunk_random.js";
|
|
2
|
+
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
PARTICLE_PROGRAM_HEADER_WORDS,
|
|
6
|
-
PARTICLE_VM_MAX_INSTRUCTIONS,
|
|
7
|
-
PARTICLE_VM_REGISTER_SLOTS,
|
|
8
|
-
} from "../ParticleConstants.js";
|
|
9
|
-
import {
|
|
4
|
+
PARTICLE_VM_INSTRUCTION_WORDS,
|
|
10
5
|
VM_BUILTIN,
|
|
6
|
+
VM_DST_MASK,
|
|
7
|
+
VM_DST_SHIFT,
|
|
8
|
+
VM_KIND,
|
|
9
|
+
VM_KIND_BITS,
|
|
10
|
+
VM_KIND_MASK,
|
|
11
|
+
VM_KIND_SHIFT,
|
|
11
12
|
VM_OP,
|
|
12
13
|
VM_OP_MASK,
|
|
14
|
+
VM_OPERAND_BASE_MASK,
|
|
15
|
+
VM_OPERAND_SWIZZLE_SHIFT,
|
|
16
|
+
VM_SWIZZLE_IDENTITY,
|
|
13
17
|
VM_WIDTH_MASK,
|
|
14
18
|
VM_WIDTH_SHIFT,
|
|
15
19
|
} from "../isa/ParticleVMISA.js";
|
|
20
|
+
import {
|
|
21
|
+
PARTICLE_PROGRAM_CODE_BASE_WORD,
|
|
22
|
+
PARTICLE_PROGRAM_HEADER_WORDS,
|
|
23
|
+
PARTICLE_VM_MAX_INSTRUCTIONS,
|
|
24
|
+
} from "../ParticleConstants.js";
|
|
25
|
+
import { PARTICLE_VM_CONTEXT_STRUCT } from "./PARTICLE_VM_CONTEXT_STRUCT.js";
|
|
16
26
|
|
|
17
27
|
/**
|
|
18
28
|
* WGSL implementation of the particle VM — the interpreter a single simulation dispatch runs over
|
|
19
29
|
* every particle. It is written to match {@link ../vm/ParticleVMReference.js} exactly; the parity
|
|
20
30
|
* spec cross-checks the two through the emulator.
|
|
21
31
|
*
|
|
22
|
-
* Opcode numbers, register-file size and the instruction budget are interpolated
|
|
23
|
-
* ISA / constants so the WGSL can never drift from the JS side.
|
|
32
|
+
* Opcode numbers, field positions, register-file size and the instruction budget are interpolated
|
|
33
|
+
* straight from the ISA / constants so the WGSL can never drift from the JS side.
|
|
34
|
+
*
|
|
35
|
+
* ## Resolve, compute, write
|
|
36
|
+
*
|
|
37
|
+
* Every instruction runs in three steps, and only the middle one knows the opcode. {@link vm_source}
|
|
38
|
+
* resolves each of the three sources into a four-lane value by the kind word 0 gives it — a register
|
|
39
|
+
* run read through its swizzle, or a literal — with the lanes past the instruction's width zero.
|
|
40
|
+
* The opcode body is then one expression over those values, `d = a + b`, and the lanes the opcode
|
|
41
|
+
* writes go back to the register file afterwards. Because every source is read before anything is
|
|
42
|
+
* written, a source may overlap the destination in any way; there is no aliasing rule to keep.
|
|
43
|
+
*
|
|
44
|
+
* That shape is what the operand swizzles and the literal kind bought: there is no `SWIZZLE` case,
|
|
45
|
+
* no `SCALE` case, no per-opcode operand loop, and the reductions sum four lanes of which the unread
|
|
46
|
+
* ones are zero.
|
|
47
|
+
*
|
|
48
|
+
* ## A lane per statement, never a computed component
|
|
49
|
+
*
|
|
50
|
+
* Nothing here indexes a vector by a variable. {@link vm_source} fills `v.x`, `v.y`, `v.z`, `v.w`
|
|
51
|
+
* one statement each behind a width test; the stores, the pool and attribute loads and the RNG draws
|
|
52
|
+
* do the same; the write-back is four predicated stores. The obvious loop — `for (c < lanes) {
|
|
53
|
+
* v[c] = ... }` — is the same program and three times slower on an RTX 4090 (5.0 ms against 1.7 ms
|
|
54
|
+
* for the simulate pass of a 4876-instruction effect at 20k alive): a vector written through a
|
|
55
|
+
* computed index is addressable memory as far as the compiler is concerned, so `a`, `b`, `c` and `d`
|
|
56
|
+
* all moved to local memory and every lane became a store and a reload. Spelled out, they stay in
|
|
57
|
+
* registers, and an instruction costs what it did under the per-opcode loops (within noise at 50k
|
|
58
|
+
* and 200k alive on the same effect), with the literal kind's savings on top. The register file is
|
|
59
|
+
* the one dynamically indexed array, as it always was.
|
|
60
|
+
*
|
|
61
|
+
* ## Registers are scalars, and they are not declared here
|
|
24
62
|
*
|
|
25
|
-
*
|
|
63
|
+
* A register is one `f32` slot, not a `vec4`, and an instruction's width says how many consecutive
|
|
64
|
+
* slots each of its operands spans. The same count of floats as slots holds far more values than it
|
|
65
|
+
* did as `vec4`s, because a `vec3` costs three of them instead of four: as `vec4`s the file cost 81
|
|
66
|
+
* VGPRs on RDNA2 and held the shader to 10 waves against a cap of 16.
|
|
26
67
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
68
|
+
* Where those slots LIVE is not this chunk's business. The interpreter reads and writes them through
|
|
69
|
+
* `vm_reg_read` and `vm_reg_write`, which a backing chunk supplies — the same external-symbol seam
|
|
70
|
+
* `particle_vm_sample_curve` uses. There are two backings and they are the two interpreters:
|
|
71
|
+
*
|
|
72
|
+
* - {@link ./chunk_particle_vm_registers_fast.js} — a `var<private>` array of
|
|
73
|
+
* {@link ../ParticleConstants.js PARTICLE_VM_FAST_REGISTER_SLOTS}. Dynamically indexed, so it
|
|
74
|
+
* lives in registers rather than scratch, and its size is the shader's register footprint. This
|
|
75
|
+
* is the interpreter everything runs on.
|
|
76
|
+
* - {@link ./chunk_particle_vm_registers_wide.js} — a storage buffer of
|
|
77
|
+
* {@link ../ParticleConstants.js PARTICLE_VM_REGISTER_SLOTS}, which is every slot the ISA can
|
|
78
|
+
* name. Slow, and the fallback for a program the fast file cannot hold.
|
|
79
|
+
*
|
|
80
|
+
* The seam is deliberately narrow: two functions, no opcode knows which backing it has, and the
|
|
81
|
+
* measurements below were taken on the fast one and describe it.
|
|
35
82
|
*
|
|
36
83
|
* ## The builtin context stays a struct
|
|
37
84
|
*
|
|
38
85
|
* `vm_load_builtin`'s `switch` looks like something an `array<f32, 8 * 4>` indexed by builtin id
|
|
39
86
|
* would delete outright — the shape the JS reference's `builtins` already has. It is measured, not
|
|
40
|
-
* assumed, and the array loses: on RDNA2 (gfx1030, amdspv
|
|
41
|
-
*
|
|
42
|
-
* interpreter, one
|
|
43
|
-
*
|
|
44
|
-
* | builtin context | VGPRs | scratch | waves |
|
|
45
|
-
* |-----------------------------|-------|-----------|-------|
|
|
46
|
-
* | struct + switch (this) | 53 | 0 | 16 |
|
|
47
|
-
* | `array<f32, 32>` by id | 46 | 64 dwords | 16 |
|
|
48
|
-
* | `array<vec4<f32>, 8>` | 47 | 64 dwords | 16 |
|
|
49
|
-
* | context atop a 64-slot file | 78 | 0 | 12 |
|
|
87
|
+
* assumed, and the array loses: on RDNA2 (gfx1030, amdspv, simulate's wave-uniform form, a 48-slot
|
|
88
|
+
* file) a SECOND dynamically indexed array costs sixteen VGPRs whatever its size — as much as growing
|
|
89
|
+
* the register file by a third — for 28 more instructions and nothing back. Same interpreter, one
|
|
90
|
+
* builtin load:
|
|
50
91
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
92
|
+
* | builtin context | VGPRs | scratch | instructions |
|
|
93
|
+
* |-----------------------------|-------|---------|--------------|
|
|
94
|
+
* | struct + switch (this) | 80 | 0 | 917 |
|
|
95
|
+
* | `array<f32, 32>` by id | 96 | 0 | 945 |
|
|
96
|
+
* | `array<vec4<f32>, 8>` | 96 | 0 | 945 |
|
|
97
|
+
* | this atop a 64-slot file | 96 | 0 | 925 |
|
|
56
98
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* read-modify-write, and now that the emulator wraps u32 arithmetic at 32 bits it runs through the
|
|
61
|
-
* interpreter loop too and is cross-checked against the reference by the parity spec.
|
|
99
|
+
* Under the per-opcode interpreter this replaced it was worse still: the promotion pass gave up on
|
|
100
|
+
* both arrays rather than picking one and spilled the register file to scratch. So the id stays a
|
|
101
|
+
* `switch` over named fields.
|
|
62
102
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
103
|
+
* Dispatch uses a `switch` over the opcode — a jump table on real hardware and directly
|
|
104
|
+
* emulator-runnable. Register-file writes are the only per-instruction state mutation; the RNG
|
|
105
|
+
* state (`RANDOM`) is a running read-modify-write over the shared `rnd_state`, which the emulator
|
|
106
|
+
* wraps at 32 bits and the parity spec holds to the reference draw for draw.
|
|
66
107
|
*
|
|
67
108
|
* ## The RNG has no distributions
|
|
68
109
|
*
|
|
69
|
-
* `RANDOM` is one uniform draw per lane, and that is the whole opcode.
|
|
70
|
-
*
|
|
71
|
-
* can write over this draw for itself: with their constants hoisted, a unit sphere is ten
|
|
72
|
-
* instructions and a unit disk seven, bit-identical to what the switch computed, because they are
|
|
73
|
-
* the same expression. A sampler is a useful thing to have and there is no principled place to stop
|
|
74
|
-
* adding them, which is the argument for the VM having none: they belong in a library over the
|
|
75
|
-
* instruction set, not inside it — see ../graph/particle_graph_distributions.js.
|
|
110
|
+
* `RANDOM` is one uniform draw per lane, and that is the whole opcode. A shaped distribution is
|
|
111
|
+
* arithmetic a program writes over the draw — see ../graph/particle_graph_distributions.js.
|
|
76
112
|
*
|
|
77
113
|
* ## Contract
|
|
78
114
|
*
|
|
79
|
-
* -
|
|
80
|
-
*
|
|
81
|
-
*
|
|
115
|
+
* - The enclosing shader must include exactly one register backing chunk — see above. Nothing in
|
|
116
|
+
* here declares `vm_reg_read` / `vm_reg_write`.
|
|
117
|
+
* - Kill flag and the builtin context are module-scope `var<private>`, as is the shared `rnd_state`
|
|
118
|
+
* the RNG runs on. Call `particle_vm_reset()` at the start of each particle, seed `rnd_state`, and
|
|
119
|
+
* populate `vm_ctx` before invoking {@link particle_vm_execute}.
|
|
82
120
|
* - `particle_vm_execute(program, code_offset, instruction_count, constant_offset, pool,
|
|
83
|
-
* record_base)` runs one section. `program` is the packed
|
|
121
|
+
* record_base)` runs one section. `program` is the packed program buffer — header, constant pool,
|
|
84
122
|
* code, see `ParticleConstants.PARTICLE_PROGRAM_HEADER_WORDS` — so code and data are one binding.
|
|
85
123
|
* Attributes are read/written as f32 bit patterns inside `pool` at `record_base +
|
|
86
124
|
* attribute_offset`.
|
|
@@ -94,36 +132,21 @@ import {
|
|
|
94
132
|
* f32`. The enclosing shader must define it (production: animation-curve backed; tests: a stub).
|
|
95
133
|
*/
|
|
96
134
|
|
|
97
|
-
const R = PARTICLE_VM_REGISTER_SLOTS;
|
|
98
|
-
|
|
99
135
|
const source = /* language=wgsl */ `
|
|
100
|
-
const PARTICLE_VM_REGISTER_SLOTS : u32 = ${R}u;
|
|
101
136
|
const PARTICLE_VM_MAX_INSTRUCTIONS : u32 = ${PARTICLE_VM_MAX_INSTRUCTIONS}u;
|
|
137
|
+
const PARTICLE_VM_INSTRUCTION_WORDS : u32 = ${PARTICLE_VM_INSTRUCTION_WORDS}u;
|
|
102
138
|
const PARTICLE_PROGRAM_HEADER_WORDS : u32 = ${PARTICLE_PROGRAM_HEADER_WORDS}u;
|
|
103
139
|
const PARTICLE_PROGRAM_CODE_BASE_WORD : u32 = ${PARTICLE_PROGRAM_CODE_BASE_WORD}u;
|
|
104
140
|
|
|
105
|
-
// Per-invocation builtin inputs the host assembles before running a program.
|
|
106
|
-
struct ParticleVMContext {
|
|
107
|
-
delta_time : f32,
|
|
108
|
-
emitter_age : f32,
|
|
109
|
-
time : f32,
|
|
110
|
-
spawn_fraction : f32,
|
|
111
|
-
particle_index : f32,
|
|
112
|
-
emitter_position : vec3<f32>,
|
|
113
|
-
emitter_direction : vec3<f32>,
|
|
114
|
-
emitter_up : vec3<f32>,
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// One f32 per slot. A value of width w occupies w consecutive slots, and an operand names the first.
|
|
118
|
-
var<private> vm_reg : array<f32, ${R}>;
|
|
119
141
|
var<private> vm_killed : bool;
|
|
120
|
-
var<private> vm_ctx :
|
|
142
|
+
var<private> vm_ctx : ${PARTICLE_VM_CONTEXT_STRUCT.wgsl_ref};
|
|
121
143
|
|
|
122
|
-
//
|
|
144
|
+
// Ready the interpreter for one particle: clear the kill flag, and nothing else. Neither backing
|
|
145
|
+
// resets its register file — the private one is zero at the start of every invocation by language
|
|
146
|
+
// rule, the storage one is undefined until written — so there is nothing to call. The flag is reset
|
|
147
|
+
// because a wide invocation walks many particles in a grid-stride loop, and the second must not
|
|
148
|
+
// inherit the first's verdict.
|
|
123
149
|
fn particle_vm_reset() {
|
|
124
|
-
for (var i = 0u; i < PARTICLE_VM_REGISTER_SLOTS; i = i + 1u) {
|
|
125
|
-
vm_reg[i] = 0.0;
|
|
126
|
-
}
|
|
127
150
|
vm_killed = false;
|
|
128
151
|
}
|
|
129
152
|
|
|
@@ -143,38 +166,29 @@ fn vm_load_builtin(id : u32) -> vec4<f32> {
|
|
|
143
166
|
}
|
|
144
167
|
}
|
|
145
168
|
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
vm_reg[dst + c] = 0.0;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// One record word per component, and the width is the component count — a store cannot write slots
|
|
168
|
-
// the value does not have.
|
|
169
|
-
fn vm_store_attr(pool : ptr<storage, array<u32>, read_write>, base : u32, off : u32, comp : u32, src : u32) {
|
|
170
|
-
for (var c = 0u; c < comp; c = c + 1u) {
|
|
171
|
-
(*pool)[base + off + c] = bitcast<u32>(vm_reg[src + c]);
|
|
169
|
+
// One source, resolved by the kind word 0 gives it: a register run read through its swizzle, or a
|
|
170
|
+
// literal in every lane. Lanes past \`lanes\` are zero, so a reduction may sum all four. The only
|
|
171
|
+
// place the kinds and swizzles are read; every opcode below sees a value.
|
|
172
|
+
fn vm_source(kind : u32, word : u32, lanes : u32) -> vec4<f32> {
|
|
173
|
+
// One lane per statement, each behind its own width test: a component written through a
|
|
174
|
+
// computed index would put the vector in local memory, and that is the whole cost of the VM.
|
|
175
|
+
var v = vec4<f32>(0.0);
|
|
176
|
+
if (kind == ${VM_KIND.REG}u) {
|
|
177
|
+
let base = word & ${VM_OPERAND_BASE_MASK}u;
|
|
178
|
+
let swizzle = ((word >> ${VM_OPERAND_SWIZZLE_SHIFT}u) & 0xffu) ^ ${VM_SWIZZLE_IDENTITY}u;
|
|
179
|
+
v.x = vm_reg_read(base + (swizzle & 3u));
|
|
180
|
+
if (lanes > 1u) { v.y = vm_reg_read(base + ((swizzle >> 2u) & 3u)); }
|
|
181
|
+
if (lanes > 2u) { v.z = vm_reg_read(base + ((swizzle >> 4u) & 3u)); }
|
|
182
|
+
if (lanes > 3u) { v.w = vm_reg_read(base + ((swizzle >> 6u) & 3u)); }
|
|
183
|
+
} else if (kind == ${VM_KIND.IMM}u) {
|
|
184
|
+
v = select(vec4<f32>(0.0), vec4<f32>(bitcast<f32>(word)), vec4<bool>(true, lanes > 1u, lanes > 2u, lanes > 3u));
|
|
172
185
|
}
|
|
186
|
+
return v;
|
|
173
187
|
}
|
|
174
188
|
|
|
175
189
|
// Execute one program section against a particle record living in pool at record_base.
|
|
176
190
|
//
|
|
177
|
-
// \`program\` is the packed
|
|
191
|
+
// \`program\` is the packed program buffer: a header, the constant pool, then the code. The header's
|
|
178
192
|
// first word says where the code starts; \`code_offset\` is a word offset into the code section and
|
|
179
193
|
// \`constant_offset\` a WORD index into the pool — both as the emitter record carries them.
|
|
180
194
|
fn particle_vm_execute(
|
|
@@ -187,184 +201,132 @@ fn particle_vm_execute(
|
|
|
187
201
|
) {
|
|
188
202
|
let count = min(instruction_count, PARTICLE_VM_MAX_INSTRUCTIONS);
|
|
189
203
|
let code_base = (*program)[PARTICLE_PROGRAM_CODE_BASE_WORD] + code_offset;
|
|
204
|
+
let pool_base = PARTICLE_PROGRAM_HEADER_WORDS + constant_offset;
|
|
190
205
|
|
|
191
206
|
for (var pc = 0u; pc < count; pc = pc + 1u) {
|
|
192
|
-
let ib = code_base + pc *
|
|
207
|
+
let ib = code_base + pc * PARTICLE_VM_INSTRUCTION_WORDS;
|
|
193
208
|
let word0 = (*program)[ib];
|
|
209
|
+
let s0 = (*program)[ib + 1u];
|
|
210
|
+
let s1 = (*program)[ib + 2u];
|
|
211
|
+
let s2 = (*program)[ib + 3u];
|
|
212
|
+
|
|
194
213
|
let op = word0 & ${VM_OP_MASK}u;
|
|
195
|
-
// Lane count this instruction spans. The opcodes whose count is fixed
|
|
214
|
+
// Lane count this instruction spans. The opcodes whose count is fixed have it encoded so.
|
|
196
215
|
let w = (word0 >> ${VM_WIDTH_SHIFT}u) & ${VM_WIDTH_MASK}u;
|
|
197
|
-
let dst = (
|
|
198
|
-
|
|
199
|
-
let
|
|
200
|
-
let
|
|
216
|
+
let dst = (word0 >> ${VM_DST_SHIFT}u) & ${VM_DST_MASK}u;
|
|
217
|
+
|
|
218
|
+
let a = vm_source((word0 >> ${VM_KIND_SHIFT}u) & ${VM_KIND_MASK}u, s0, w);
|
|
219
|
+
let b = vm_source((word0 >> ${VM_KIND_SHIFT + VM_KIND_BITS}u) & ${VM_KIND_MASK}u, s1, w);
|
|
220
|
+
let c = vm_source((word0 >> ${VM_KIND_SHIFT + 2 * VM_KIND_BITS}u) & ${VM_KIND_MASK}u, s2, w);
|
|
221
|
+
|
|
222
|
+
var d = vec4<f32>(0.0);
|
|
223
|
+
// How many lanes of d reach the register file: the width, one for a reduction, none for an
|
|
224
|
+
// opcode whose effect is elsewhere.
|
|
225
|
+
var lanes = w;
|
|
201
226
|
|
|
202
227
|
switch op {
|
|
203
228
|
case ${VM_OP.HALT}u: { return; }
|
|
204
|
-
case ${VM_OP.NOP}u: {}
|
|
205
|
-
case ${VM_OP.MOV}u: {
|
|
206
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = vm_reg[s0 + c]; }
|
|
207
|
-
}
|
|
229
|
+
case ${VM_OP.NOP}u: { lanes = 0u; }
|
|
230
|
+
case ${VM_OP.MOV}u: { d = a; }
|
|
208
231
|
case ${VM_OP.LOAD_CONST}u: {
|
|
209
|
-
let
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
232
|
+
let k = pool_base + s0;
|
|
233
|
+
d.x = bitcast<f32>((*program)[k]);
|
|
234
|
+
if (w > 1u) { d.y = bitcast<f32>((*program)[k + 1u]); }
|
|
235
|
+
if (w > 2u) { d.z = bitcast<f32>((*program)[k + 2u]); }
|
|
236
|
+
if (w > 3u) { d.w = bitcast<f32>((*program)[k + 3u]); }
|
|
237
|
+
}
|
|
238
|
+
case ${VM_OP.LOAD_ATTR}u: {
|
|
239
|
+
// Lanes past the attribute's component count read zero, which is how a narrow
|
|
240
|
+
// attribute reaches a wider operation for free.
|
|
241
|
+
let k = record_base + s0;
|
|
242
|
+
let n = min(w, s1);
|
|
243
|
+
d.x = bitcast<f32>((*pool)[k]);
|
|
244
|
+
if (n > 1u) { d.y = bitcast<f32>((*pool)[k + 1u]); }
|
|
245
|
+
if (n > 2u) { d.z = bitcast<f32>((*pool)[k + 2u]); }
|
|
246
|
+
if (n > 3u) { d.w = bitcast<f32>((*pool)[k + 3u]); }
|
|
247
|
+
}
|
|
248
|
+
case ${VM_OP.STORE_ATTR}u: {
|
|
249
|
+
// One record word per component; the width is the component count.
|
|
250
|
+
let k = record_base + s1;
|
|
251
|
+
(*pool)[k] = bitcast<u32>(a.x);
|
|
252
|
+
if (s2 > 1u) { (*pool)[k + 1u] = bitcast<u32>(a.y); }
|
|
253
|
+
if (s2 > 2u) { (*pool)[k + 2u] = bitcast<u32>(a.z); }
|
|
254
|
+
if (s2 > 3u) { (*pool)[k + 3u] = bitcast<u32>(a.w); }
|
|
255
|
+
lanes = 0u;
|
|
256
|
+
}
|
|
257
|
+
case ${VM_OP.LOAD_BUILTIN}u: { d = vm_load_builtin(s0); }
|
|
258
|
+
case ${VM_OP.KILL}u: {
|
|
259
|
+
if (a.x > 0.0) { vm_killed = true; }
|
|
260
|
+
lanes = 0u;
|
|
219
261
|
}
|
|
220
|
-
case ${VM_OP.KILL}u: { if (vm_reg[dst] > 0.0) { vm_killed = true; } }
|
|
221
262
|
|
|
222
|
-
case ${VM_OP.ADD}u: {
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
case ${VM_OP.
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
case ${VM_OP.
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
case ${VM_OP.DIV}u: {
|
|
232
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = vm_reg[s0 + c] / vm_reg[s1 + c]; }
|
|
233
|
-
}
|
|
234
|
-
case ${VM_OP.MAD}u: {
|
|
235
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = vm_reg[s0 + c] * vm_reg[s1 + c] + vm_reg[s2 + c]; }
|
|
236
|
-
}
|
|
237
|
-
case ${VM_OP.MIN}u: {
|
|
238
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = min(vm_reg[s0 + c], vm_reg[s1 + c]); }
|
|
239
|
-
}
|
|
240
|
-
case ${VM_OP.MAX}u: {
|
|
241
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = max(vm_reg[s0 + c], vm_reg[s1 + c]); }
|
|
242
|
-
}
|
|
243
|
-
case ${VM_OP.MIX}u: {
|
|
244
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = mix(vm_reg[s0 + c], vm_reg[s1 + c], vm_reg[s2 + c]); }
|
|
245
|
-
}
|
|
246
|
-
case ${VM_OP.CLAMP}u: {
|
|
247
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = clamp(vm_reg[s0 + c], vm_reg[s1 + c], vm_reg[s2 + c]); }
|
|
248
|
-
}
|
|
249
|
-
case ${VM_OP.SCALE}u: {
|
|
250
|
-
let k = vm_reg[s1];
|
|
251
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = vm_reg[s0 + c] * k; }
|
|
252
|
-
}
|
|
263
|
+
case ${VM_OP.ADD}u: { d = a + b; }
|
|
264
|
+
case ${VM_OP.SUB}u: { d = a - b; }
|
|
265
|
+
case ${VM_OP.MUL}u: { d = a * b; }
|
|
266
|
+
case ${VM_OP.DIV}u: { d = a / b; }
|
|
267
|
+
case ${VM_OP.MAD}u: { d = a * b + c; }
|
|
268
|
+
case ${VM_OP.MIN}u: { d = min(a, b); }
|
|
269
|
+
case ${VM_OP.MAX}u: { d = max(a, b); }
|
|
270
|
+
case ${VM_OP.MIX}u: { d = mix(a, b, c); }
|
|
271
|
+
case ${VM_OP.CLAMP}u: { d = clamp(a, b, c); }
|
|
253
272
|
|
|
254
|
-
case ${VM_OP.NEG}u: {
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
case ${VM_OP.
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
case ${VM_OP.
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
case ${VM_OP.
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
case ${VM_OP.
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
case ${VM_OP.
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
case ${VM_OP.COS}u: {
|
|
273
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = cos(vm_reg[s0 + c]); }
|
|
274
|
-
}
|
|
275
|
-
case ${VM_OP.EXP}u: {
|
|
276
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = exp(vm_reg[s0 + c]); }
|
|
277
|
-
}
|
|
278
|
-
case ${VM_OP.LOG}u: {
|
|
279
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = log(vm_reg[s0 + c]); }
|
|
280
|
-
}
|
|
281
|
-
case ${VM_OP.POW}u: {
|
|
282
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = pow(vm_reg[s0 + c], vm_reg[s1 + c]); }
|
|
283
|
-
}
|
|
284
|
-
case ${VM_OP.STEP}u: {
|
|
285
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = step(vm_reg[s0 + c], vm_reg[s1 + c]); }
|
|
286
|
-
}
|
|
287
|
-
case ${VM_OP.SMOOTHSTEP}u: {
|
|
288
|
-
for (var c = 0u; c < w; c = c + 1u) {
|
|
289
|
-
vm_reg[dst + c] = smoothstep(vm_reg[s0 + c], vm_reg[s1 + c], vm_reg[s2 + c]);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
273
|
+
case ${VM_OP.NEG}u: { d = -a; }
|
|
274
|
+
case ${VM_OP.ABS}u: { d = abs(a); }
|
|
275
|
+
case ${VM_OP.FLOOR}u: { d = floor(a); }
|
|
276
|
+
case ${VM_OP.FRACT}u: { d = fract(a); }
|
|
277
|
+
case ${VM_OP.SQRT}u: { d = sqrt(a); }
|
|
278
|
+
case ${VM_OP.SIN}u: { d = sin(a); }
|
|
279
|
+
case ${VM_OP.COS}u: { d = cos(a); }
|
|
280
|
+
case ${VM_OP.EXP}u: { d = exp(a); }
|
|
281
|
+
case ${VM_OP.LOG}u: { d = log(a); }
|
|
282
|
+
case ${VM_OP.POW}u: { d = pow(a, b); }
|
|
283
|
+
case ${VM_OP.STEP}u: { d = step(a, b); }
|
|
284
|
+
case ${VM_OP.SMOOTHSTEP}u: { d = smoothstep(a, b, c); }
|
|
285
|
+
case ${VM_OP.RSQRT}u: { d = inverseSqrt(a); }
|
|
286
|
+
case ${VM_OP.TAN}u: { d = tan(a); }
|
|
287
|
+
case ${VM_OP.ASIN}u: { d = asin(a); }
|
|
288
|
+
case ${VM_OP.ACOS}u: { d = acos(a); }
|
|
289
|
+
case ${VM_OP.ATAN2}u: { d = atan2(a, b); }
|
|
292
290
|
|
|
293
|
-
// The reductions write ONE
|
|
294
|
-
|
|
295
|
-
case ${VM_OP.
|
|
296
|
-
case ${VM_OP.
|
|
297
|
-
// Both operands are read out before either is written: the destination is allowed to
|
|
298
|
-
// be one of them.
|
|
299
|
-
let ax = vm_reg[s0]; let ay = vm_reg[s0 + 1u]; let az = vm_reg[s0 + 2u];
|
|
300
|
-
let bx = vm_reg[s1]; let by = vm_reg[s1 + 1u]; let bz = vm_reg[s1 + 2u];
|
|
301
|
-
vm_reg[dst] = ay * bz - az * by;
|
|
302
|
-
vm_reg[dst + 1u] = az * bx - ax * bz;
|
|
303
|
-
vm_reg[dst + 2u] = ax * by - ay * bx;
|
|
304
|
-
// A fourth slot, if asked for, is the zero the opcode used to append.
|
|
305
|
-
for (var c = 3u; c < w; c = c + 1u) { vm_reg[dst + c] = 0.0; }
|
|
306
|
-
}
|
|
307
|
-
case ${VM_OP.LENGTH}u: { vm_reg[dst] = sqrt(vm_dot_slots(s0, s0, w)); }
|
|
291
|
+
// The reductions write ONE lane; the lanes past the width are zero and add nothing.
|
|
292
|
+
case ${VM_OP.DOT}u: { d.x = dot(a, b); lanes = 1u; }
|
|
293
|
+
case ${VM_OP.CROSS}u: { d = vec4<f32>(cross(a.xyz, b.xyz), 0.0); }
|
|
294
|
+
case ${VM_OP.LENGTH}u: { d.x = sqrt(dot(a, a)); lanes = 1u; }
|
|
308
295
|
case ${VM_OP.NORMALIZE}u: {
|
|
309
|
-
let len = sqrt(
|
|
310
|
-
|
|
311
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = vm_reg[s0 + c] * inv; }
|
|
296
|
+
let len = sqrt(dot(a, a));
|
|
297
|
+
d = a * select(0.0, 1.0 / len, len > 0.0);
|
|
312
298
|
}
|
|
313
299
|
case ${VM_OP.DISTANCE}u: {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
sum = sum + e * e;
|
|
318
|
-
}
|
|
319
|
-
vm_reg[dst] = sqrt(sum);
|
|
320
|
-
}
|
|
321
|
-
case ${VM_OP.SWIZZLE}u: {
|
|
322
|
-
// Every selected slot is read before any is written, so an in-place swizzle — which
|
|
323
|
-
// is what a broadcast is — reads the value it meant to.
|
|
324
|
-
let l0 = vm_reg[s0 + (s1 & 3u)];
|
|
325
|
-
let l1 = vm_reg[s0 + ((s1 >> 2u) & 3u)];
|
|
326
|
-
let l2 = vm_reg[s0 + ((s1 >> 4u) & 3u)];
|
|
327
|
-
let l3 = vm_reg[s0 + ((s1 >> 6u) & 3u)];
|
|
328
|
-
if (w > 0u) { vm_reg[dst] = l0; }
|
|
329
|
-
if (w > 1u) { vm_reg[dst + 1u] = l1; }
|
|
330
|
-
if (w > 2u) { vm_reg[dst + 2u] = l2; }
|
|
331
|
-
if (w > 3u) { vm_reg[dst + 3u] = l3; }
|
|
300
|
+
let e = a - b;
|
|
301
|
+
d.x = sqrt(dot(e, e));
|
|
302
|
+
lanes = 1u;
|
|
332
303
|
}
|
|
333
304
|
|
|
334
|
-
case ${VM_OP.CMP_LT}u: {
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
case ${VM_OP.
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
case ${VM_OP.CMP_GT}u: {
|
|
341
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = select(0.0, 1.0, vm_reg[s0 + c] > vm_reg[s1 + c]); }
|
|
342
|
-
}
|
|
343
|
-
case ${VM_OP.CMP_GE}u: {
|
|
344
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = select(0.0, 1.0, vm_reg[s0 + c] >= vm_reg[s1 + c]); }
|
|
345
|
-
}
|
|
346
|
-
case ${VM_OP.CMP_EQ}u: {
|
|
347
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = select(0.0, 1.0, vm_reg[s0 + c] == vm_reg[s1 + c]); }
|
|
348
|
-
}
|
|
349
|
-
case ${VM_OP.SELECT}u: {
|
|
350
|
-
for (var c = 0u; c < w; c = c + 1u) {
|
|
351
|
-
vm_reg[dst + c] = select(vm_reg[s0 + c], vm_reg[s1 + c], vm_reg[s2 + c] > 0.5);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
305
|
+
case ${VM_OP.CMP_LT}u: { d = select(vec4<f32>(0.0), vec4<f32>(1.0), a < b); }
|
|
306
|
+
case ${VM_OP.CMP_LE}u: { d = select(vec4<f32>(0.0), vec4<f32>(1.0), a <= b); }
|
|
307
|
+
case ${VM_OP.CMP_GT}u: { d = select(vec4<f32>(0.0), vec4<f32>(1.0), a > b); }
|
|
308
|
+
case ${VM_OP.CMP_GE}u: { d = select(vec4<f32>(0.0), vec4<f32>(1.0), a >= b); }
|
|
309
|
+
case ${VM_OP.CMP_EQ}u: { d = select(vec4<f32>(0.0), vec4<f32>(1.0), a == b); }
|
|
310
|
+
case ${VM_OP.SELECT}u: { d = select(a, b, c > vec4<f32>(0.5)); }
|
|
354
311
|
|
|
355
312
|
// \`random()\` off the shared \`rnd_state\`, which has to match
|
|
356
313
|
// u32_to_unit_f32(pcg_next()) in ParticleVMReference.js bit-for-bit; the parity spec
|
|
357
|
-
// holds them to it. One draw per lane, so the draw count is the width.
|
|
314
|
+
// holds them to it. One draw per lane, in lane order, so the draw count is the width.
|
|
358
315
|
case ${VM_OP.RANDOM}u: {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
for (var c = 0u; c < w; c = c + 1u) { vm_reg[dst + c] = v; }
|
|
316
|
+
d.x = random();
|
|
317
|
+
if (w > 1u) { d.y = random(); }
|
|
318
|
+
if (w > 2u) { d.z = random(); }
|
|
319
|
+
if (w > 3u) { d.w = random(); }
|
|
364
320
|
}
|
|
321
|
+
case ${VM_OP.CURVE}u: { d = vec4<f32>(particle_vm_sample_curve(s0, b.x)); }
|
|
365
322
|
|
|
366
|
-
default: {}
|
|
323
|
+
default: { lanes = 0u; }
|
|
367
324
|
}
|
|
325
|
+
|
|
326
|
+
if (lanes > 0u) { vm_reg_write(dst, d.x); }
|
|
327
|
+
if (lanes > 1u) { vm_reg_write(dst + 1u, d.y); }
|
|
328
|
+
if (lanes > 2u) { vm_reg_write(dst + 2u, d.z); }
|
|
329
|
+
if (lanes > 3u) { vm_reg_write(dst + 3u, d.w); }
|
|
368
330
|
}
|
|
369
331
|
}
|
|
370
332
|
`;
|
|
@@ -373,4 +335,4 @@ fn particle_vm_execute(
|
|
|
373
335
|
* The particle VM interpreter.
|
|
374
336
|
* @type {CodeChunk}
|
|
375
337
|
*/
|
|
376
|
-
export const chunk_particle_vm = CodeChunk.from(source, [chunk_random]);
|
|
338
|
+
export const chunk_particle_vm = CodeChunk.from(source, [chunk_random, PARTICLE_VM_CONTEXT_STRUCT.declaration_chunk]);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fast register backing for {@link ./chunk_particle_vm.js}: the VM's register file as a
|
|
3
|
+
* `var<private>` array of {@link ../ParticleConstants.js PARTICLE_VM_FAST_REGISTER_SLOTS} floats.
|
|
4
|
+
*
|
|
5
|
+
* This is the interpreter the system runs on. The array is dynamically indexed — an operand's base
|
|
6
|
+
* comes out of the instruction word — which is what keeps it in registers rather than scratch, and
|
|
7
|
+
* therefore what makes the file's size the shader's register footprint outright. Every program pays
|
|
8
|
+
* that footprint, not only the ones with a wide working set, so the slot count is a whole-system
|
|
9
|
+
* cost and not a per-effect one. See {@link ../ParticleConstants.js} for what it was measured at.
|
|
10
|
+
*
|
|
11
|
+
* The file is zero when a program starts, and the language is what says so: WGSL zero-initialises a
|
|
12
|
+
* `var<private>` declared without an initializer, once per invocation, and a fast pass runs exactly
|
|
13
|
+
* one program per invocation ({@link ../shaders/shader_particle_simulate.js},
|
|
14
|
+
* {@link ../shaders/shader_particle_emit.js}). Nothing in the compiler's output reads a slot it has
|
|
15
|
+
* not written — the graph allocator assigns a register at the instruction that defines the value — so
|
|
16
|
+
* that zero is not what makes correct programs work. It is what makes an INCORRECT program
|
|
17
|
+
* deterministic, and that matters because it is the behaviour {@link ./ParticleVMReference.js}
|
|
18
|
+
* defines and the parity spec holds the two to. The wide backing cannot offer the same guarantee and
|
|
19
|
+
* does not try; see {@link ./chunk_particle_vm_registers_wide.js}.
|
|
20
|
+
*
|
|
21
|
+
* Nothing here clears the file. A `vm_reg_clear` used to zero it in a loop on top of the
|
|
22
|
+
* initialisation above, which could only ever be a second pass over the same slots; it outlived its
|
|
23
|
+
* reason when {@link ../../../wgsl/emulator/ComputeShaderEmulator.js} learned to reset private state
|
|
24
|
+
* per dispatch, and an empty one outlived its reason with it. Removed 2026-09-06.
|
|
25
|
+
*
|
|
26
|
+
* Measured before removing, compiled to RDNA2 (gfx1030): the two zeroing passes folded into one, so
|
|
27
|
+
* the loop cost 2 instructions of 917 at unchanged VGPRs — what a compiler that sees through it
|
|
28
|
+
* charges. One pass is about 22 instructions there (893 with no zeroing, 915 with the mandatory
|
|
29
|
+
* one), which is what a driver that does not see through it charges again on every particle.
|
|
30
|
+
*
|
|
31
|
+
* A fast pass that ran more than one program per invocation — the grid-stride shape the wide passes
|
|
32
|
+
* use — would not inherit the guarantee, since the second program would start on the first's
|
|
33
|
+
* registers. That pass would zero the file itself, in the loop it needs and where its cost is
|
|
34
|
+
* visible, rather than every pass carrying a call for it.
|
|
35
|
+
*
|
|
36
|
+
* The enclosing shader includes this chunk or the wide one, never both — they define the same two
|
|
37
|
+
* symbols.
|
|
38
|
+
*
|
|
39
|
+
* @type {CodeChunk}
|
|
40
|
+
*/
|
|
41
|
+
export const chunk_particle_vm_registers_fast: CodeChunk;
|
|
42
|
+
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
43
|
+
//# sourceMappingURL=chunk_particle_vm_registers_fast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk_particle_vm_registers_fast.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,+CAFU,SAAS,CAahB;0BAtDuB,oCAAoC"}
|