summaryrefslogtreecommitdiff
path: root/src/gpu/effect.h
blob: 488e92e3dc6d4b0b4c6a447d78f3ac832f083ac2 (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
#pragma once
#include "gpu/gpu.h"
#include <algorithm>
#include <memory>
#include <vector>

#if defined(DEMO_CROSS_COMPILE_WIN32)
#include <webgpu/webgpu.h>
#else
#include <webgpu.h>
#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */

class MainSequence;
class PostProcessEffect;

class Effect {
 public:
  Effect(WGPUDevice device, WGPUQueue queue)
      : device_(device), queue_(queue) {}
  virtual ~Effect() = default;
  virtual void init(MainSequence* demo) {
    (void)demo;
  }
  virtual void start() {
  }
  virtual void compute(WGPUCommandEncoder encoder, float time, float beat,
                       float intensity, float aspect_ratio) {
    (void)encoder;
    (void)time;
    (void)beat;
    (void)intensity;
    (void)aspect_ratio;
  }
  virtual void render(WGPURenderPassEncoder pass, float time, float beat,
                      float intensity, float aspect_ratio) = 0;
  virtual void end() {
  }
  bool is_initialized = false;
  virtual bool is_post_process() const {
    return false;
  }

 protected:
  WGPUDevice device_;
  WGPUQueue queue_;
  GpuBuffer uniforms_;
};

class PostProcessEffect : public Effect {
 public:
  PostProcessEffect(WGPUDevice device, WGPUQueue queue)
      : Effect(device, queue) {}
  bool is_post_process() const override {
    return true;
  }
  void compute(WGPUCommandEncoder, float, float, float, float) override {
  }
  void render(WGPURenderPassEncoder pass, float time, float beat,
              float intensity, float aspect_ratio) override;
  virtual void update_bind_group(WGPUTextureView input_view) = 0;

 protected:
  WGPURenderPipeline pipeline_ = nullptr;
  WGPUBindGroup bind_group_ = nullptr;
};

struct SequenceItem {
  std::shared_ptr<Effect> effect;
  float start_time; // Relative to Sequence start
  float end_time;   // Relative to Sequence start
  int priority;     // Render order within sequence (higher = later/top)
  bool active;
};

class Sequence {
 public:
  int priority = 0; // Render order of this sequence (higher = later/top)
  void init(MainSequence* demo);
  void add_effect(std::shared_ptr<Effect> effect, float start_time,
                  float end_time, int priority = 0);
  void update_active_list(float seq_time);
  void collect_active_effects(std::vector<SequenceItem*>& scene_effects,
                              std::vector<SequenceItem*>& post_effects);
  void reset();

 private:
  std::vector<SequenceItem> items_;
  bool is_sorted_ = false;
  void sort_items();
};

class MainSequence {
 public:
  MainSequence();
  ~MainSequence();
  WGPUDevice device;
  WGPUQueue queue;
  WGPUTextureFormat format;

  void init(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format,
            int width, int height);
  void add_sequence(std::shared_ptr<Sequence> seq, float start_time,
                    int priority = 0);
  void render_frame(float global_time, float beat, float peak,
                    float aspect_ratio, WGPUSurface surface);
  void shutdown();

#if !defined(STRIP_ALL)
  void simulate_until(float target_time, float step_rate);
#endif /* !defined(STRIP_ALL) */

 private:
  struct ActiveSequence {
    std::shared_ptr<Sequence> seq;
    float start_time;
    int priority;
  };
  std::vector<ActiveSequence> sequences_;

  WGPUTexture framebuffer_a_ = nullptr;
  WGPUTextureView framebuffer_view_a_ = nullptr;
  WGPUTexture framebuffer_b_ = nullptr;
  WGPUTextureView framebuffer_view_b_ = nullptr;

 public: // Made public for testing
  void init_test(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format);

 private: // Restore private access for other members
  std::unique_ptr<PostProcessEffect> passthrough_effect_;

  void create_framebuffers(int width, int height);
};