diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-12 15:10:17 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-12 15:10:17 +0100 |
| commit | 8b30cadfc19647487986d14dba9ddba7908dd1d0 (patch) | |
| tree | f865b42945f72bfc480e2c2a6849127bf56d1a59 /src/gpu/effects/cnn_v2_effect.cc | |
| parent | 1effb125973ac0948de3015be1d53ae72463858b (diff) | |
test_demo: Add beat-synchronized CNN post-processing with version selection
- Add --cnn-version <1|2> flag to select between CNN v1 and v2
- Implement beat_phase modulation for dynamic blend in both CNN effects
- Fix CNN v2 per-layer uniform buffer sharing (each layer needs own buffer)
- Fix CNN v2 y-axis orientation to match render pass convention
- Add Scene1Effect as base visual layer to test_demo timeline
- Reorganize CNN v2 shaders into cnn_v2/ subdirectory
- Update asset paths and documentation for new shader organization
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/gpu/effects/cnn_v2_effect.cc')
| -rw-r--r-- | src/gpu/effects/cnn_v2_effect.cc | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/src/gpu/effects/cnn_v2_effect.cc b/src/gpu/effects/cnn_v2_effect.cc index 9cb6d57..9c727ba 100644 --- a/src/gpu/effects/cnn_v2_effect.cc +++ b/src/gpu/effects/cnn_v2_effect.cc @@ -20,9 +20,24 @@ CNNv2Effect::CNNv2Effect(const GpuContext& ctx) static_features_view_(nullptr), layer_pipeline_(nullptr), weights_buffer_(nullptr), - layer_params_buffer_(nullptr), input_mip_tex_(nullptr), current_input_view_(nullptr), + blend_amount_(1.0f), + initialized_(false) { + std::memset(input_mip_view_, 0, sizeof(input_mip_view_)); +} + +CNNv2Effect::CNNv2Effect(const GpuContext& ctx, const CNNv2EffectParams& params) + : PostProcessEffect(ctx), + static_pipeline_(nullptr), + static_bind_group_(nullptr), + static_features_tex_(nullptr), + static_features_view_(nullptr), + layer_pipeline_(nullptr), + weights_buffer_(nullptr), + input_mip_tex_(nullptr), + current_input_view_(nullptr), + blend_amount_(params.blend_amount), initialized_(false) { std::memset(input_mip_view_, 0, sizeof(input_mip_view_)); } @@ -93,13 +108,16 @@ void CNNv2Effect::load_weights() { // Upload weights data wgpuQueueWriteBuffer(ctx_.queue, weights_buffer_, 0, weights_data, weights_size); - // Create uniform buffer for layer params - WGPUBufferDescriptor params_desc = {}; - params_desc.size = sizeof(LayerParams); - params_desc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst; - params_desc.mappedAtCreation = false; + // Create uniform buffers for layer params (one per layer) + for (uint32_t i = 0; i < num_layers; ++i) { + WGPUBufferDescriptor params_desc = {}; + params_desc.size = sizeof(LayerParams); + params_desc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst; + params_desc.mappedAtCreation = false; - layer_params_buffer_ = wgpuDeviceCreateBuffer(ctx_.device, ¶ms_desc); + WGPUBuffer buf = wgpuDeviceCreateBuffer(ctx_.device, ¶ms_desc); + layer_params_buffers_.push_back(buf); + } } void CNNv2Effect::create_textures() { @@ -284,8 +302,8 @@ void CNNv2Effect::create_pipelines() { if (!layer_module) return; // Create bind group layout for layer compute - // 0=static_features, 1=layer_input, 2=output, 3=weights, 4=params - WGPUBindGroupLayoutEntry layer_bgl_entries[5] = {}; + // 0=static_features, 1=layer_input, 2=output, 3=weights, 4=params, 5=original_input + WGPUBindGroupLayoutEntry layer_bgl_entries[6] = {}; // Binding 0: Static features (texture) layer_bgl_entries[0].binding = 0; @@ -317,8 +335,14 @@ void CNNv2Effect::create_pipelines() { layer_bgl_entries[4].buffer.type = WGPUBufferBindingType_Uniform; layer_bgl_entries[4].buffer.minBindingSize = sizeof(LayerParams); + // Binding 5: Original input (for blending) + layer_bgl_entries[5].binding = 5; + layer_bgl_entries[5].visibility = WGPUShaderStage_Compute; + layer_bgl_entries[5].texture.sampleType = WGPUTextureSampleType_Float; + layer_bgl_entries[5].texture.viewDimension = WGPUTextureViewDimension_2D; + WGPUBindGroupLayoutDescriptor layer_bgl_desc = {}; - layer_bgl_desc.entryCount = 5; + layer_bgl_desc.entryCount = 6; layer_bgl_desc.entries = layer_bgl_entries; WGPUBindGroupLayout layer_bgl = wgpuDeviceCreateBindGroupLayout(ctx_.device, &layer_bgl_desc); @@ -399,7 +423,7 @@ void CNNv2Effect::update_bind_group(WGPUTextureView input_view) { // Create bind group for each layer for (size_t i = 0; i < layer_info_.size(); ++i) { - WGPUBindGroupEntry layer_entries[5] = {}; + WGPUBindGroupEntry layer_entries[6] = {}; // Binding 0: Static features (constant) layer_entries[0].binding = 0; @@ -419,14 +443,18 @@ void CNNv2Effect::update_bind_group(WGPUTextureView input_view) { layer_entries[3].buffer = weights_buffer_; layer_entries[3].size = wgpuBufferGetSize(weights_buffer_); - // Binding 4: Layer params (will be updated per dispatch) + // Binding 4: Layer params (use dedicated buffer for this layer) layer_entries[4].binding = 4; - layer_entries[4].buffer = layer_params_buffer_; + layer_entries[4].buffer = layer_params_buffers_[i]; layer_entries[4].size = sizeof(LayerParams); + // Binding 5: Original input (for blending) + layer_entries[5].binding = 5; + layer_entries[5].textureView = input_view; + WGPUBindGroupDescriptor layer_bg_desc = {}; layer_bg_desc.layout = layer_bgl; - layer_bg_desc.entryCount = 5; + layer_bg_desc.entryCount = 6; layer_bg_desc.entries = layer_entries; WGPUBindGroup layer_bg = wgpuDeviceCreateBindGroup(ctx_.device, &layer_bg_desc); @@ -438,9 +466,13 @@ void CNNv2Effect::update_bind_group(WGPUTextureView input_view) { void CNNv2Effect::compute(WGPUCommandEncoder encoder, const CommonPostProcessUniforms& uniforms) { - (void)uniforms; if (!initialized_ || !static_pipeline_ || !static_bind_group_) return; + float effective_blend = blend_amount_; + if (beat_modulated_) { + effective_blend = blend_amount_ * uniforms.beat_phase * beat_scale_; + } + // Pass 1: Compute static features WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr); @@ -458,20 +490,20 @@ void CNNv2Effect::compute(WGPUCommandEncoder encoder, // Execute CNN layer passes if (!layer_pipeline_ || layer_bind_groups_.empty()) return; + // Update layer params (each layer has own buffer) for (size_t i = 0; i < layer_info_.size(); ++i) { const LayerInfo& info = layer_info_[i]; - // Update layer params uniform buffer LayerParams params; params.kernel_size = info.kernel_size; params.in_channels = info.in_channels; params.out_channels = info.out_channels; params.weight_offset = info.weight_offset; params.is_output_layer = (i == layer_info_.size() - 1) ? 1 : 0; + params.blend_amount = effective_blend; - wgpuQueueWriteBuffer(ctx_.queue, layer_params_buffer_, 0, ¶ms, sizeof(params)); + wgpuQueueWriteBuffer(ctx_.queue, layer_params_buffers_[i], 0, ¶ms, sizeof(params)); - // Execute layer compute pass WGPUComputePassEncoder layer_pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr); wgpuComputePassEncoderSetPipeline(layer_pass, layer_pipeline_); @@ -499,7 +531,8 @@ void CNNv2Effect::cleanup() { if (layer_pipeline_) wgpuComputePipelineRelease(layer_pipeline_); if (weights_buffer_) wgpuBufferRelease(weights_buffer_); - if (layer_params_buffer_) wgpuBufferRelease(layer_params_buffer_); + for (auto buf : layer_params_buffers_) wgpuBufferRelease(buf); + layer_params_buffers_.clear(); for (int i = 0; i < 3; ++i) { if (input_mip_view_[i]) wgpuTextureViewRelease(input_mip_view_[i]); |
