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

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

class MainSequence;
class PostProcessEffect;

class Effect {
public:
  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;
  }
};

class PostProcessEffect : public Effect {
public:
  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();

#ifndef STRIP_ALL
  void simulate_until(float target_time, float step_rate);
#endif

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