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