summaryrefslogtreecommitdiff
path: root/src/gpu/sequence.h
blob: ee0260d22cc7ca805ace688c3fba315509ab1498 (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
132
// Sequence: DAG-based effect routing with ping-pong optimization

#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 (default Source/Sink)
  F32X4,
  F16X8,
  DEPTH24,
  COMPUTE_F32,
  // G-buffer types for CNN v3
  GBUF_ALBEDO,  // rgba16float: RENDER_ATTACHMENT | TEXTURE_BINDING |
                // STORAGE_BINDING | COPY_SRC
  GBUF_DEPTH32, // depth32float: RENDER_ATTACHMENT | TEXTURE_BINDING | COPY_SRC
  GBUF_R8, // rgba8unorm (4ch for compat): STORAGE_BINDING | TEXTURE_BINDING |
           // RENDER_ATTACHMENT
  GBUF_RGBA32UINT, // rgba32uint: STORAGE_BINDING | TEXTURE_BINDING
};

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 noise; // Random value [0..1]
};
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();

  void declare_node(const std::string& name, NodeType type, int width,
                    int height);

  void declare_aliased_node(const std::string& name,
                            const std::string& alias_of);

  WGPUTextureView get_view(const std::string& name);
  std::vector<WGPUTextureView>
  get_output_views(const std::vector<std::string>& names);

  WGPUTexture get_texture(const std::string& name);

  void resize(int width, int height);

  bool has_node(const std::string& name) const;

  void set_external_view(const std::string& name, WGPUTextureView view);

  int default_width() const {
    return default_width_;
  }
  int default_height() const {
    return default_height_;
  }

 private:
  WGPUDevice device_;
  int default_width_;
  int default_height_;
  std::map<std::string, Node> nodes_;
  std::map<std::string, std::string> aliases_;

  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;
};

class Sequence {
 public:
  Sequence(const GpuContext& ctx, int width, int height);
  virtual ~Sequence() = default;

  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);

  void init_effect_nodes();

  void set_sink_view(WGPUTextureView view) {
    nodes_.set_external_view("sink", view);
  }

  void set_source_view(WGPUTextureView view) {
    nodes_.set_external_view("source", view);
  }

  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_;
};