From 5fb1bcc25fef7388a2d68be6c1f062bcf996fd85 Mon Sep 17 00:00:00 2001 From: skal Date: Wed, 11 Feb 2026 11:42:46 +0100 Subject: fix: Resolve auxiliary texture resolution mismatch bug Auxiliary textures were created during init() using default dimensions (1280x720) before resize() was called with actual window size. This caused compute shaders to receive uniforms with correct resolution but render to wrong-sized textures. Changes: - Add MainSequence::resize_auxiliary_texture() to recreate textures - Override resize() in CircleMaskEffect to resize circle_mask texture - Override resize() in CNNEffect to resize captured_frame texture - Bind groups are recreated with new texture views after resize Tests: All 36 tests passing Co-Authored-By: Claude Sonnet 4.5 --- src/gpu/effect.cc | 49 +++++++++++++++++++++++++++++++++++ src/gpu/effect.h | 1 + src/gpu/effects/circle_mask_effect.cc | 29 +++++++++++++++++++++ src/gpu/effects/circle_mask_effect.h | 1 + src/gpu/effects/cnn_effect.cc | 9 +++++++ src/gpu/effects/cnn_effect.h | 1 + 6 files changed, 90 insertions(+) (limited to 'src/gpu') diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc index 528d7fc..42e623a 100644 --- a/src/gpu/effect.cc +++ b/src/gpu/effect.cc @@ -508,6 +508,55 @@ WGPUTextureView MainSequence::get_auxiliary_view(const char* name) { return it->second.view; } +// Resize existing auxiliary texture +void MainSequence::resize_auxiliary_texture(const char* name, int width, + int height) { + const std::string key(name); + auto it = auxiliary_textures_.find(key); + FATAL_CHECK(it == auxiliary_textures_.end(), + "Auxiliary texture not found for resize: %s\n", name); + + // Release old resources + if (it->second.view) + wgpuTextureViewRelease(it->second.view); + if (it->second.texture) + wgpuTextureRelease(it->second.texture); + + // Create new texture with new dimensions + const WGPUTextureDescriptor desc = { + .usage = + WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding, + .dimension = WGPUTextureDimension_2D, + .size = {(uint32_t)width, (uint32_t)height, 1}, + .format = gpu_ctx.format, + .mipLevelCount = 1, + .sampleCount = 1, + }; + + WGPUTexture texture = wgpuDeviceCreateTexture(gpu_ctx.device, &desc); + FATAL_CHECK(!texture, "Failed to resize auxiliary texture: %s\n", name); + + // Create view + const WGPUTextureViewDescriptor view_desc = { + .format = gpu_ctx.format, + .dimension = WGPUTextureViewDimension_2D, + .mipLevelCount = 1, + .arrayLayerCount = 1, + }; + + WGPUTextureView view = wgpuTextureCreateView(texture, &view_desc); + FATAL_CHECK(!view, "Failed to create resized auxiliary texture view: %s\n", + name); + + // Update registry + it->second = {texture, view, width, height}; + +#if !defined(STRIP_ALL) + printf("[MainSequence] Resized auxiliary texture '%s' to %dx%d\n", name, + width, height); +#endif /* !defined(STRIP_ALL) */ +} + #if !defined(STRIP_ALL) void MainSequence::simulate_until(float target_time, float step_rate, float bpm) { diff --git a/src/gpu/effect.h b/src/gpu/effect.h index 7991700..ed90ac7 100644 --- a/src/gpu/effect.h +++ b/src/gpu/effect.h @@ -137,6 +137,7 @@ class MainSequence { // Auxiliary texture registry for inter-effect texture sharing void register_auxiliary_texture(const char* name, int width, int height); + void resize_auxiliary_texture(const char* name, int width, int height); WGPUTextureView get_auxiliary_view(const char* name); #if !defined(STRIP_ALL) diff --git a/src/gpu/effects/circle_mask_effect.cc b/src/gpu/effects/circle_mask_effect.cc index d2645d6..aa9f324 100644 --- a/src/gpu/effects/circle_mask_effect.cc +++ b/src/gpu/effects/circle_mask_effect.cc @@ -157,6 +157,35 @@ void CircleMaskEffect::init(MainSequence* demo) { render_bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &render_bg_desc); } +void CircleMaskEffect::resize(int width, int height) { + Effect::resize(width, height); + + if (!demo_) + return; + + // Resize auxiliary texture + demo_->resize_auxiliary_texture("circle_mask", width, height); + + // Recreate render bind group with new texture view + if (render_bind_group_) + wgpuBindGroupRelease(render_bind_group_); + + WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask"); + const WGPUBindGroupEntry render_entries[] = { + {.binding = 0, .textureView = mask_view}, + {.binding = 1, .sampler = mask_sampler_}, + {.binding = 2, + .buffer = uniforms_.get().buffer, + .size = sizeof(CommonPostProcessUniforms)}, + }; + const WGPUBindGroupDescriptor render_bg_desc = { + .layout = wgpuRenderPipelineGetBindGroupLayout(render_pipeline_, 0), + .entryCount = 3, + .entries = render_entries, + }; + render_bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &render_bg_desc); +} + void CircleMaskEffect::compute(WGPUCommandEncoder encoder, const CommonPostProcessUniforms& uniforms) { uniforms_.update(ctx_.queue, uniforms); diff --git a/src/gpu/effects/circle_mask_effect.h b/src/gpu/effects/circle_mask_effect.h index e52371d..6ebaca1 100644 --- a/src/gpu/effects/circle_mask_effect.h +++ b/src/gpu/effects/circle_mask_effect.h @@ -15,6 +15,7 @@ class CircleMaskEffect : public Effect { ~CircleMaskEffect() override; void init(MainSequence* demo) override; + void resize(int width, int height) override; void compute(WGPUCommandEncoder encoder, const CommonPostProcessUniforms& uniforms) override; void render(WGPURenderPassEncoder pass, diff --git a/src/gpu/effects/cnn_effect.cc b/src/gpu/effects/cnn_effect.cc index 3f6d3b3..84eb530 100644 --- a/src/gpu/effects/cnn_effect.cc +++ b/src/gpu/effects/cnn_effect.cc @@ -65,6 +65,15 @@ void CNNEffect::init(MainSequence* demo) { params_buffer_.update(ctx_.queue, params); } +void CNNEffect::resize(int width, int height) { + PostProcessEffect::resize(width, height); + + // Only layer 0 owns the captured_frame texture + if (layer_index_ == 0 && demo_) { + demo_->resize_auxiliary_texture("captured_frame", width, height); + } +} + void CNNEffect::render(WGPURenderPassEncoder pass, const CommonPostProcessUniforms& uniforms) { (void)uniforms; diff --git a/src/gpu/effects/cnn_effect.h b/src/gpu/effects/cnn_effect.h index f9a982b..1c9f0f3 100644 --- a/src/gpu/effects/cnn_effect.h +++ b/src/gpu/effects/cnn_effect.h @@ -24,6 +24,7 @@ class CNNEffect : public PostProcessEffect { explicit CNNEffect(const GpuContext& ctx, const CNNEffectParams& params); void init(MainSequence* demo) override; + void resize(int width, int height) override; void render(WGPURenderPassEncoder pass, const CommonPostProcessUniforms& uniforms) override; void update_bind_group(WGPUTextureView input_view) override; -- cgit v1.2.3