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
|
// Effect implementation
#include "gpu/effect.h"
#include "gpu/gpu.h"
#include "gpu/sequence.h"
#include "util/fatal_error.h"
Effect::Effect(const GpuContext& ctx, const std::vector<std::string>& inputs,
const std::vector<std::string>& outputs, float start_time,
float end_time)
: ctx_(ctx), input_nodes_(inputs), output_nodes_(outputs),
start_time_(start_time), end_time_(end_time) {
FATAL_CHECK(!inputs.empty(), "Effect must have at least one input\n");
FATAL_CHECK(!outputs.empty(), "Effect must have at least one output\n");
FATAL_CHECK(start_time <= end_time, "Invalid time range: %f > %f\n",
start_time, end_time);
HEADLESS_RETURN_IF_NULL(ctx_.device);
}
void Effect::dispatch_render(WGPUCommandEncoder encoder,
const UniformsSequenceParams& params,
NodeRegistry& nodes) {
// Check if effect is active at current time
const bool active =
(params.time >= start_time_ && params.time < end_time_);
// Auto-passthrough for 1:1 input/output effects outside active range
if (!active && input_nodes_.size() == 1 && output_nodes_.size() == 1) {
blit_input_to_output(encoder, nodes);
} else if (active) {
render(encoder, params, nodes);
}
// Multi-output effects: output undefined when inactive (validated at compile time)
}
void Effect::blit_input_to_output(WGPUCommandEncoder encoder,
NodeRegistry& nodes) {
HEADLESS_RETURN_IF_NULL(encoder);
WGPUTexture src = nodes.get_texture(input_nodes_[0]);
WGPUTexture dst = nodes.get_texture(output_nodes_[0]);
// Skip passthrough if textures are external (source/sink) or invalid
if (!src || !dst) {
return;
}
GpuTextureCopyInfo src_copy = {
.texture = src, .mipLevel = 0, .origin = {0, 0, 0}};
GpuTextureCopyInfo dst_copy = {
.texture = dst, .mipLevel = 0, .origin = {0, 0, 0}};
WGPUExtent3D extent = {(unsigned int)(width_),
(unsigned int)(height_), 1};
wgpuCommandEncoderCopyTextureToTexture(encoder, &src_copy, &dst_copy,
&extent);
}
void Effect::init_uniforms_buffer() {
uniforms_buffer_.init(ctx_.device);
}
void Effect::create_linear_sampler() {
sampler_ = gpu_create_linear_sampler(ctx_.device);
}
void Effect::create_nearest_sampler() {
sampler_ = gpu_create_nearest_sampler(ctx_.device);
}
void Effect::create_dummy_scene_texture() {
TextureWithView dummy = gpu_create_dummy_scene_texture(ctx_.device);
dummy_texture_ = dummy.texture;
dummy_texture_view_ = dummy.view;
}
|