summaryrefslogtreecommitdiff
path: root/src/gpu/sequence.h
blob: a33dedbae48143ecf5da633f123669498d814ffa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 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 <map>
#include <memory>
#include <string>
#include <vector>

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<WGPUTextureView> 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<WGPUTextureView>
  get_output_views(const std::vector<std::string>& 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<std::string, Node> nodes_;
  std::map<std::string, std::string> aliases_; // name -> backing node name

  void create_texture(Node& node);
};

struct EffectDAGNode {
  std::shared_ptr<Effect> effect;
  std::vector<std::string> input_nodes;
  std::vector<std::string> 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<EffectDAGNode>& get_effect_dag() const {
    return effect_dag_;
  }

 protected:
  const GpuContext& ctx_;
  int width_;
  int height_;
  NodeRegistry nodes_;
  std::vector<EffectDAGNode> effect_dag_;
  UniformsSequenceParams params_;
  UniformBuffer<UniformsSequenceParams> uniforms_buffer_;
};
#endif // SEQUENCE_H