From 491a3c1ccbd0f46be655e97d2e3697135df6e3a2 Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 23 Mar 2026 07:54:18 +0100 Subject: feat(gbuffer): wire_dag() + find_downstream_output() for temporal feedback - Add Effect::wire_dag() virtual (called from init_effect_nodes after full DAG built) - Add Effect::find_downstream_output() protected helper (first downstream consumer output) - GBufferEffect::wire_dag() auto-sets cnn_output_node_ via find_downstream_output, guarding against sink (external view, null texture) - GBufferEffect::post_render() null-checks src texture before CopyTextureToTexture - Tests: find_downstream_output cases + wire_dag integration in test_effect_base - Doc: SEQUENCE.md updated with wire_dag pattern, helper contract, and sink guard Co-Authored-By: Claude Sonnet 4.6 --- src/gpu/effect.cc | 14 ++++++++++++++ src/gpu/effect.h | 14 ++++++++++++++ src/gpu/sequence.cc | 3 +++ 3 files changed, 31 insertions(+) (limited to 'src/gpu') diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc index 4230021..1257090 100644 --- a/src/gpu/effect.cc +++ b/src/gpu/effect.cc @@ -58,6 +58,20 @@ void Effect::blit_input_to_output(WGPUCommandEncoder encoder, &extent); } +std::string Effect::find_downstream_output( + const std::vector& dag) const { + for (const auto& node : dag) { + for (const auto& in : node.input_nodes) { + for (const auto& out : output_nodes_) { + if (in == out && !node.output_nodes.empty()) { + return node.output_nodes[0]; + } + } + } + } + return ""; +} + void Effect::create_linear_sampler() { sampler_.set(gpu_create_linear_sampler(ctx_.device)); } diff --git a/src/gpu/effect.h b/src/gpu/effect.h index 566faba..6c50d84 100644 --- a/src/gpu/effect.h +++ b/src/gpu/effect.h @@ -41,6 +41,13 @@ class Effect { (void)nodes; } + // Called once after the full DAG is built (init_effect_nodes). + // Override to auto-wire inter-effect dependencies (e.g. temporal feedback). + // Default is a no-op. + virtual void wire_dag(const std::vector& dag) { + (void)dag; + } + virtual void resize(int width, int height) { width_ = width; height_ = height; @@ -67,6 +74,13 @@ class Effect { Texture dummy_texture_; TextureView dummy_texture_view_; + // DAG query helpers (callable from wire_dag overrides) + // + // Returns output_nodes[0] of the first effect in |dag| whose input_nodes + // intersect this effect's output_nodes_ (i.e. the first direct downstream + // consumer). Returns "" if no such effect exists or it has no outputs. + std::string find_downstream_output(const std::vector& dag) const; + // Helper: Create linear sampler (call in subclass constructor if needed) void create_linear_sampler(); diff --git a/src/gpu/sequence.cc b/src/gpu/sequence.cc index 78647b2..6bff34e 100644 --- a/src/gpu/sequence.cc +++ b/src/gpu/sequence.cc @@ -291,4 +291,7 @@ void Sequence::init_effect_nodes() { for (auto& dag_node : effect_dag_) { dag_node.effect->declare_nodes(nodes_); } + for (auto& dag_node : effect_dag_) { + dag_node.effect->wire_dag(effect_dag_); + } } -- cgit v1.2.3