diff options
Diffstat (limited to 'src')
25 files changed, 139 insertions, 51 deletions
diff --git a/src/effects/flash_effect.cc b/src/effects/flash_effect.cc index ac46562..c8638f0 100644 --- a/src/effects/flash_effect.cc +++ b/src/effects/flash_effect.cc @@ -7,9 +7,11 @@ #include "util/fatal_error.h" Flash::Flash(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), - sampler_(nullptr), dummy_texture_(nullptr), dummy_texture_view_(nullptr) { + const std::vector<std::string>& outputs, float start_time, + float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time), pipeline_(nullptr), + bind_group_(nullptr), sampler_(nullptr), dummy_texture_(nullptr), + dummy_texture_view_(nullptr) { HEADLESS_RETURN_IF_NULL(ctx_.device); uniforms_buffer_.init(ctx_.device); diff --git a/src/effects/flash_effect.h b/src/effects/flash_effect.h index 08b7709..1117e0a 100644 --- a/src/effects/flash_effect.h +++ b/src/effects/flash_effect.h @@ -8,7 +8,8 @@ class Flash : public Effect { public: Flash(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); ~Flash() override; void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, diff --git a/src/effects/gaussian_blur_effect.cc b/src/effects/gaussian_blur_effect.cc index b2713ae..02cd77e 100644 --- a/src/effects/gaussian_blur_effect.cc +++ b/src/effects/gaussian_blur_effect.cc @@ -7,8 +7,9 @@ GaussianBlur::GaussianBlur(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), + const std::vector<std::string>& outputs, float start_time, + float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time), pipeline_(nullptr), bind_group_(nullptr), sampler_(nullptr) { // Headless mode: skip GPU resource creation (compiled out in STRIP_ALL) HEADLESS_RETURN_IF_NULL(ctx_.device); diff --git a/src/effects/gaussian_blur_effect.h b/src/effects/gaussian_blur_effect.h index 4cb55a3..cc9ff56 100644 --- a/src/effects/gaussian_blur_effect.h +++ b/src/effects/gaussian_blur_effect.h @@ -17,7 +17,8 @@ static_assert(sizeof(GaussianBlurParams) == 16, class GaussianBlur : public Effect { public: GaussianBlur(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) override; diff --git a/src/effects/heptagon_effect.cc b/src/effects/heptagon_effect.cc index fd83229..13d7aad 100644 --- a/src/effects/heptagon_effect.cc +++ b/src/effects/heptagon_effect.cc @@ -8,8 +8,9 @@ Heptagon::Heptagon(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), + const std::vector<std::string>& outputs, float start_time, + float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time), pipeline_(nullptr), bind_group_(nullptr), sampler_(nullptr) { // Headless mode: skip GPU resource creation (compiled out in STRIP_ALL) HEADLESS_RETURN_IF_NULL(ctx_.device); diff --git a/src/effects/heptagon_effect.h b/src/effects/heptagon_effect.h index f4e4f9e..ef05d79 100644 --- a/src/effects/heptagon_effect.h +++ b/src/effects/heptagon_effect.h @@ -8,7 +8,8 @@ class Heptagon : public Effect { public: Heptagon(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); ~Heptagon(); void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, diff --git a/src/effects/hybrid3_d_effect.cc b/src/effects/hybrid3_d_effect.cc index 027e2a7..1dd1c05 100644 --- a/src/effects/hybrid3_d_effect.cc +++ b/src/effects/hybrid3_d_effect.cc @@ -9,8 +9,9 @@ Hybrid3D::Hybrid3D(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth"), + const std::vector<std::string>& outputs, float start_time, + float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time), depth_node_(outputs[0] + "_depth"), dummy_texture_(nullptr), dummy_texture_view_(nullptr) { // Headless mode: skip GPU resource creation (compiled out in STRIP_ALL) HEADLESS_RETURN_IF_NULL(ctx_.device); diff --git a/src/effects/hybrid3_d_effect.h b/src/effects/hybrid3_d_effect.h index 10bee58..e0aa6da 100644 --- a/src/effects/hybrid3_d_effect.h +++ b/src/effects/hybrid3_d_effect.h @@ -12,7 +12,8 @@ class Hybrid3D : public Effect { public: Hybrid3D(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); ~Hybrid3D() override; void declare_nodes(NodeRegistry& registry) override; diff --git a/src/effects/particles_effect.cc b/src/effects/particles_effect.cc index 35e9919..22e41e9 100644 --- a/src/effects/particles_effect.cc +++ b/src/effects/particles_effect.cc @@ -9,8 +9,9 @@ Particles::Particles(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs) { + const std::vector<std::string>& outputs, float start_time, + float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time) { // Headless mode: skip GPU resource creation (compiled out in STRIP_ALL) HEADLESS_RETURN_IF_NULL(ctx_.device); diff --git a/src/effects/particles_effect.h b/src/effects/particles_effect.h index 5799690..38c60d7 100644 --- a/src/effects/particles_effect.h +++ b/src/effects/particles_effect.h @@ -21,7 +21,8 @@ struct Particle { class Particles : public Effect { public: Particles(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) override; diff --git a/src/effects/passthrough_effect.cc b/src/effects/passthrough_effect.cc index be53846..392102d 100644 --- a/src/effects/passthrough_effect.cc +++ b/src/effects/passthrough_effect.cc @@ -7,9 +7,10 @@ Passthrough::Passthrough(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), - sampler_(nullptr) { + const std::vector<std::string>& outputs, + float start_time, float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time), pipeline_(nullptr), + bind_group_(nullptr), sampler_(nullptr) { // Headless mode: skip GPU resource creation (compiled out in STRIP_ALL) HEADLESS_RETURN_IF_NULL(ctx_.device); diff --git a/src/effects/passthrough_effect.h b/src/effects/passthrough_effect.h index 00bf423..f684b9b 100644 --- a/src/effects/passthrough_effect.h +++ b/src/effects/passthrough_effect.h @@ -8,7 +8,8 @@ class Passthrough : public Effect { public: Passthrough(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) override; diff --git a/src/effects/peak_meter_effect.cc b/src/effects/peak_meter_effect.cc index a2cf6fc..63be2c0 100644 --- a/src/effects/peak_meter_effect.cc +++ b/src/effects/peak_meter_effect.cc @@ -7,8 +7,9 @@ PeakMeter::PeakMeter(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr) { + const std::vector<std::string>& outputs, float start_time, + float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time), pipeline_(nullptr), bind_group_(nullptr) { HEADLESS_RETURN_IF_NULL(ctx_.device); uniforms_buffer_.init(ctx_.device); diff --git a/src/effects/peak_meter_effect.h b/src/effects/peak_meter_effect.h index b563289..e397a71 100644 --- a/src/effects/peak_meter_effect.h +++ b/src/effects/peak_meter_effect.h @@ -8,7 +8,8 @@ class PeakMeter : public Effect { public: PeakMeter(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); ~PeakMeter() override; void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, diff --git a/src/effects/placeholder_effect.cc b/src/effects/placeholder_effect.cc index 1428779..6ba665a 100644 --- a/src/effects/placeholder_effect.cc +++ b/src/effects/placeholder_effect.cc @@ -9,9 +9,10 @@ Placeholder::Placeholder(const GpuContext& ctx, const std::vector<std::string>& inputs, const std::vector<std::string>& outputs, + float start_time, float end_time, const char* placeholder_name) - : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), - sampler_(nullptr), name_(placeholder_name) { + : Effect(ctx, inputs, outputs, start_time, end_time), pipeline_(nullptr), + bind_group_(nullptr), sampler_(nullptr), name_(placeholder_name) { // Log once on construction fprintf(stderr, "TODO: %s not yet implemented, using passthrough\n", name_); diff --git a/src/effects/placeholder_effect.h b/src/effects/placeholder_effect.h index 7d8d734..24cf3f4 100644 --- a/src/effects/placeholder_effect.h +++ b/src/effects/placeholder_effect.h @@ -9,8 +9,8 @@ class Placeholder : public Effect { public: Placeholder(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs, - const char* placeholder_name = "UnknownEffect"); + const std::vector<std::string>& outputs, float start_time, + float end_time, const char* placeholder_name = "UnknownEffect"); void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) override; diff --git a/src/effects/rotating_cube_effect.cc b/src/effects/rotating_cube_effect.cc index 42a0ba7..0f1781d 100644 --- a/src/effects/rotating_cube_effect.cc +++ b/src/effects/rotating_cube_effect.cc @@ -9,8 +9,9 @@ RotatingCube::RotatingCube(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth") { + const std::vector<std::string>& outputs, float start_time, + float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time), depth_node_(outputs[0] + "_depth") { // Headless mode: skip GPU resource creation (compiled out in STRIP_ALL) HEADLESS_RETURN_IF_NULL(ctx_.device); diff --git a/src/effects/rotating_cube_effect.h b/src/effects/rotating_cube_effect.h index 0c713d2..e773025 100644 --- a/src/effects/rotating_cube_effect.h +++ b/src/effects/rotating_cube_effect.h @@ -11,7 +11,8 @@ class RotatingCube : public Effect { public: RotatingCube(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); ~RotatingCube() override; void declare_nodes(NodeRegistry& registry) override; diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc index b729321..117ede2 100644 --- a/src/gpu/effect.cc +++ b/src/gpu/effect.cc @@ -1,11 +1,64 @@ // 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) - : ctx_(ctx), input_nodes_(inputs), output_nodes_(outputs) { + 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); +} + +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; + } + +#if defined(DEMO_CROSS_COMPILE_WIN32) + WGPUImageCopyTexture src_copy = { + .texture = src, .mipLevel = 0, .origin = {0, 0, 0}}; + WGPUImageCopyTexture dst_copy = { + .texture = dst, .mipLevel = 0, .origin = {0, 0, 0}}; +#else + WGPUTexelCopyTextureInfo src_copy = { + .texture = src, .mipLevel = 0, .origin = {0, 0, 0}}; + WGPUTexelCopyTextureInfo dst_copy = { + .texture = dst, .mipLevel = 0, .origin = {0, 0, 0}}; +#endif + + WGPUExtent3D extent = {static_cast<unsigned int>(width_), + static_cast<unsigned int>(height_), 1}; + + wgpuCommandEncoderCopyTextureToTexture(encoder, &src_copy, &dst_copy, + &extent); } diff --git a/src/gpu/effect.h b/src/gpu/effect.h index d40e750..0d7e35e 100644 --- a/src/gpu/effect.h +++ b/src/gpu/effect.h @@ -14,7 +14,8 @@ class NodeRegistry; class Effect { public: Effect(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs); + const std::vector<std::string>& outputs, float start_time, + float end_time); virtual ~Effect() = default; // Optional: Declare temporary nodes (e.g., multi-pass intermediate buffers) @@ -22,7 +23,12 @@ class Effect { (void)registry; } - // Render effect (multi-input/multi-output) + // Dispatch render with automatic passthrough outside [start, end] + void dispatch_render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes); + + // Render effect (multi-input/multi-output) - override in derived classes virtual void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) = 0; @@ -46,5 +52,12 @@ class Effect { std::vector<std::string> output_nodes_; int width_ = 1280; int height_ = 720; + + private: + float start_time_; + float end_time_; + + // Auto-passthrough helper for 1:1 input/output effects + void blit_input_to_output(WGPUCommandEncoder encoder, NodeRegistry& nodes); }; #endif // EFFECT_H diff --git a/src/gpu/sequence.cc b/src/gpu/sequence.cc index 5348992..d2f99bc 100644 --- a/src/gpu/sequence.cc +++ b/src/gpu/sequence.cc @@ -240,7 +240,7 @@ void Sequence::postprocess(WGPUCommandEncoder encoder) { void Sequence::render_effects(WGPUCommandEncoder encoder) { // Execute DAG in topological order (pre-sorted by compiler) for (const auto& dag_node : effect_dag_) { - dag_node.effect->render(encoder, params_, nodes_); + dag_node.effect->dispatch_render(encoder, params_, nodes_); } } diff --git a/src/tests/gpu/test_demo_effects.cc b/src/tests/gpu/test_demo_effects.cc index 7f9d3da..f193c76 100644 --- a/src/tests/gpu/test_demo_effects.cc +++ b/src/tests/gpu/test_demo_effects.cc @@ -39,31 +39,31 @@ static void test_effects() { std::vector<std::pair<const char*, std::shared_ptr<Effect>>> effects = { {"Passthrough", std::make_shared<Passthrough>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"GaussianBlur", std::make_shared<GaussianBlur>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"Placeholder", std::make_shared<Placeholder>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"Heptagon", std::make_shared<Heptagon>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"Particles", std::make_shared<Particles>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"RotatingCube", std::make_shared<RotatingCube>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"Hybrid3D", std::make_shared<Hybrid3D>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"Flash", std::make_shared<Flash>(fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, {"PeakMeter", std::make_shared<PeakMeter>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"})}, + std::vector<std::string>{"sink"}, 0.0f, 1000.0f)}, }; int passed = 0; diff --git a/src/tests/gpu/test_effect_base.cc b/src/tests/gpu/test_effect_base.cc index f46a4ef..29d3348 100644 --- a/src/tests/gpu/test_effect_base.cc +++ b/src/tests/gpu/test_effect_base.cc @@ -83,7 +83,7 @@ static void test_effect_construction() { // Create Passthrough (simple effect) auto effect = std::make_shared<Passthrough>( fixture.ctx(), std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"}); + std::vector<std::string>{"sink"}, 0.0f, 1000.0f); assert(effect != nullptr && "Effect should be constructed"); @@ -106,7 +106,8 @@ static void test_effect_in_sequence() { TestSequence(const GpuContext& ctx, int w, int h) : Sequence(ctx, w, h) { auto effect = std::make_shared<Passthrough>(ctx, std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"}); + std::vector<std::string>{"sink"}, 0.0f, + 1000.0f); effect_dag_.push_back({effect, {"source"}, {"sink"}, 0}); init_effect_nodes(); @@ -138,7 +139,8 @@ static void test_sequence_render() { TestSequence(const GpuContext& ctx, int w, int h) : Sequence(ctx, w, h) { auto effect = std::make_shared<Passthrough>(ctx, std::vector<std::string>{"source"}, - std::vector<std::string>{"sink"}); + std::vector<std::string>{"sink"}, 0.0f, + 1000.0f); effect_dag_.push_back({effect, {"source"}, {"sink"}, 0}); init_effect_nodes(); diff --git a/src/tests/gpu/test_sequence.cc b/src/tests/gpu/test_sequence.cc index fa6bd5e..8e27efb 100644 --- a/src/tests/gpu/test_sequence.cc +++ b/src/tests/gpu/test_sequence.cc @@ -11,8 +11,10 @@ class TestEffect : public Effect { public: TestEffect(const GpuContext& ctx, const std::vector<std::string>& inputs, - const std::vector<std::string>& outputs) - : Effect(ctx, inputs, outputs), render_called_(false) { + const std::vector<std::string>& outputs, float start_time = 0.0f, + float end_time = 1000.0f) + : Effect(ctx, inputs, outputs, start_time, end_time), + render_called_(false) { } void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, diff --git a/src/tests/gpu/test_sequence_e2e.cc b/src/tests/gpu/test_sequence_e2e.cc index ed8920a..5d59e0d 100644 --- a/src/tests/gpu/test_sequence_e2e.cc +++ b/src/tests/gpu/test_sequence_e2e.cc @@ -23,13 +23,13 @@ class SimpleTestSequence : public Sequence { // Effect DAG construction (2 effects: source->temp->sink) effect_dag_.push_back({.effect = std::make_shared<Passthrough>( ctx, std::vector<std::string>{"source"}, - std::vector<std::string>{"temp"}), + std::vector<std::string>{"temp"}, 0.0f, 1000.0f), .input_nodes = {"source"}, .output_nodes = {"temp"}, .execution_order = 0}); effect_dag_.push_back({.effect = std::make_shared<Passthrough>( ctx, std::vector<std::string>{"temp"}, - std::vector<std::string>{"sink"}), + std::vector<std::string>{"sink"}, 0.0f, 1000.0f), .input_nodes = {"temp"}, .output_nodes = {"sink"}, .execution_order = 1}); |
