summaryrefslogtreecommitdiff
path: root/src/gpu/effect.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-10 12:48:43 +0100
committerskal <pascal.massimino@gmail.com>2026-02-10 12:48:43 +0100
commit6944733a6a2f05c18e7e0b73f847a4c9144801fd (patch)
tree10713cd41a0e038a016a2e6b357471690f232834 /src/gpu/effect.cc
parentcc9cbeb75353181193e3afb880dc890aa8bf8985 (diff)
feat: Add multi-layer CNN support with framebuffer capture and blend control
Implements automatic layer chaining and generic framebuffer capture API for multi-layer neural network effects with proper original input preservation. Key changes: - Effect::needs_framebuffer_capture() - generic API for pre-render capture - MainSequence: auto-capture to "captured_frame" auxiliary texture - CNNEffect: multi-layer support via layer_index/total_layers params - seq_compiler: expands "layers=N" to N chained effect instances - Shader: @binding(4) original_input available to all layers - Training: generates layer switches and original input binding - Blend: mix(original, result, blend_amount) uses layer 0 input Timeline syntax: CNNEffect layers=3 blend=0.7 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/gpu/effect.cc')
-rw-r--r--src/gpu/effect.cc37
1 files changed, 35 insertions, 2 deletions
diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc
index 6a4762c..0662f26 100644
--- a/src/gpu/effect.cc
+++ b/src/gpu/effect.cc
@@ -65,7 +65,7 @@ void Sequence::update_active_list(float seq_time) {
#if !defined(STRIP_ALL)
Effect* effect_ptr = item.effect.get();
const char* effect_name = typeid(*effect_ptr).name();
- printf(" [EFFECT START] %s (priority=%d, time=%.2f-%.2f)\n", effect_name,
+ printf(" [EFFECT START] <%s> (priority=%d, time=%.2f-%.2f)\n", effect_name,
item.priority, item.start_time, item.end_time);
#endif
item.effect->start();
@@ -74,7 +74,7 @@ void Sequence::update_active_list(float seq_time) {
#if !defined(STRIP_ALL)
Effect* effect_ptr = item.effect.get();
const char* effect_name = typeid(*effect_ptr).name();
- printf(" [EFFECT END] %s (priority=%d)\n", effect_name, item.priority);
+ printf(" [EFFECT END] <%s> (priority=%d)\n", effect_name, item.priority);
#endif
item.effect->end();
item.active = false;
@@ -339,6 +339,39 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
PostProcessEffect* pp =
(PostProcessEffect*)(post_effects[i]->effect.get());
+
+ // Capture framebuffer if effect needs it
+ if (pp->needs_framebuffer_capture()) {
+ WGPUTextureView captured_view = get_auxiliary_view("captured_frame");
+ if (captured_view) {
+ // Get source texture from current_input view
+ // Note: This is a simplified blit using a render pass
+ WGPURenderPassColorAttachment capture_attachment = {};
+ capture_attachment.view = captured_view;
+ capture_attachment.resolveTarget = nullptr;
+ capture_attachment.loadOp = WGPULoadOp_Load;
+ capture_attachment.storeOp = WGPUStoreOp_Store;
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
+ capture_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
+#endif
+ WGPURenderPassDescriptor capture_desc = {
+ .colorAttachmentCount = 1, .colorAttachments = &capture_attachment};
+ WGPURenderPassEncoder capture_pass =
+ wgpuCommandEncoderBeginRenderPass(encoder, &capture_desc);
+ wgpuRenderPassEncoderSetViewport(capture_pass, 0.0f, 0.0f,
+ (float)width_, (float)height_, 0.0f,
+ 1.0f);
+
+ // Use passthrough effect to copy current_input to captured_frame
+ PostProcessEffect* passthrough =
+ (PostProcessEffect*)passthrough_effect_.get();
+ passthrough->update_bind_group(current_input);
+ passthrough->render(capture_pass, 0, 0, 0, aspect_ratio);
+
+ wgpuRenderPassEncoderEnd(capture_pass);
+ }
+ }
+
pp->update_bind_group(current_input);
WGPURenderPassColorAttachment pp_attachment = {};