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
|
// Sequence: 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 (default Source/Sink)
F32X4,
F16X8,
DEPTH24,
COMPUTE_F32,
};
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();
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);
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_;
};
#endif // SEQUENCE_H
|