// Sequence: Explicit node system with DAG effect routing // DAG-based effect routing with ping-pong optimization #ifndef SEQUENCE_H #define SEQUENCE_H #pragma once #include "gpu/gpu.h" #include "gpu/uniform_helper.h" #include "util/mini_math.h" #include #include #include #include class Effect; enum class NodeType { U8X4_NORM, // RGBAu8 normalized (0-1) - default Source/Sink F32X4, // RGBA float32 F16X8, // 8-channel float16 DEPTH24, // Depth buffer COMPUTE_F32, // Compute buffer }; struct Node { NodeType type; int width; int height; WGPUTexture texture; WGPUTextureView view; std::vector mip_views; // For multi-target render }; struct UniformsSequenceParams { vec2 resolution; float aspect_ratio; float time; // Per-sequence relative time float beat_time; // Musical beats float beat_phase; // Fractional beat 0.0-1.0 float audio_intensity; float _pad; }; static_assert(sizeof(UniformsSequenceParams) == 32, "UniformsSequenceParams must be 32 bytes for WGSL alignment"); class NodeRegistry { public: NodeRegistry(WGPUDevice device, int default_width, int default_height); ~NodeRegistry(); // Declare new node with explicit type/dimensions void declare_node(const std::string& name, NodeType type, int width, int height); // Declare aliased node (ping-pong optimization) void declare_aliased_node(const std::string& name, const std::string& alias_of); // Retrieve views WGPUTextureView get_view(const std::string& name); std::vector get_output_views(const std::vector& names); // Resize all nodes void resize(int width, int height); // Check if node exists bool has_node(const std::string& name) const; // Register external view (for source/sink managed externally) void set_external_view(const std::string& name, WGPUTextureView view); private: WGPUDevice device_; int default_width_; int default_height_; std::map nodes_; std::map aliases_; // name -> backing node name void create_texture(Node& node); }; struct EffectDAGNode { std::shared_ptr effect; std::vector input_nodes; std::vector output_nodes; int execution_order; // Topologically sorted }; class Sequence { public: Sequence(const GpuContext& ctx, int width, int height); virtual ~Sequence() = default; // Virtual methods (most sequences use defaults) virtual void preprocess(float seq_time, float beat_time, float beat_phase, float audio_intensity); virtual void postprocess(WGPUCommandEncoder encoder); virtual void render_effects(WGPUCommandEncoder encoder); void resize(int width, int height); // Initialize effect nodes (call at end of subclass constructor) void init_effect_nodes(); // Set surface texture view for rendering (sink node) void set_sink_view(WGPUTextureView view) { nodes_.set_external_view("sink", view); } // Set source texture view (input framebuffer) void set_source_view(WGPUTextureView view) { nodes_.set_external_view("source", view); } // Test accessor const std::vector& get_effect_dag() const { return effect_dag_; } protected: const GpuContext& ctx_; int width_; int height_; NodeRegistry nodes_; std::vector effect_dag_; UniformsSequenceParams params_; UniformBuffer uniforms_buffer_; }; #endif // SEQUENCE_H