summaryrefslogtreecommitdiff
path: root/src/gpu/sequence_v2.h
blob: 9cd93c68212beb8ae74f384a80d93ab79c9042dc (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
// Sequence v2: Explicit node system with DAG effect routing
// Replaces implicit framebuffer ping-pong with compile-time optimized nodes

#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 EffectV2;

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;

 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<EffectV2> effect;
  std::vector<std::string> input_nodes;
  std::vector<std::string> output_nodes;
  int execution_order; // Topologically sorted
};

class SequenceV2 {
 public:
  SequenceV2(const GpuContext& ctx, int width, int height);
  virtual ~SequenceV2() = 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);

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