From 1b89a26a750cc32725564a0c5186a437f372fd93 Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 8 Feb 2026 22:17:31 +0100 Subject: feat: Fix CircleMaskEffect and RotatingCubeEffect auxiliary texture masking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves critical shader composition and format mismatch issues, enabling the circle mask + rotating cube demonstration at 2.0s-4.0s in the timeline. **Key Fixes:** 1. **Shader Function Name** (masked_cube.wgsl): - Fixed call to `ray_box_intersection()` (was incorrectly `ray_box()`) - Updated return value handling to use `RayBounds` struct (`.hit`, `.t_entry`, `.t_exit`) - Removed unused `sky_tex` binding to match pipeline layout expectations (5 bindings → 4) 2. **Shader Lifetime Issue** (rotating_cube_effect.h/cc): - Added `std::string composed_shader_` member to persist shader source - Prevents use-after-free when WebGPU asynchronously parses shader code 3. **Format Mismatch** (circle_mask_effect.cc): - Changed compute pipeline format from hardcoded `RGBA8Unorm` to `ctx_.format` (Bgra8UnormSrgb) - Matches auxiliary texture format created by `MainSequence::register_auxiliary_texture()` - Added depth stencil state to render pipeline to match scene pass requirements: * Format: Depth24Plus * depthWriteEnabled: False (no depth writes needed) * depthCompare: Always (always pass depth test) 4. **WebGPU Descriptor Initialization** (circle_mask_effect.cc): - Added `depthSlice = WGPU_DEPTH_SLICE_UNDEFINED` for non-Windows builds - Ensures proper initialization of render pass color attachments 5. **Test Coverage** (test_demo_effects.cc): - Updated EXPECTED_SCENE_COUNT: 6 → 8 (added CircleMaskEffect, RotatingCubeEffect) - Marked both effects as requiring 3D pipeline setup (skipped in basic tests) **Technical Details:** - **Auxiliary Texture Flow**: CircleMaskEffect generates mask (1.0 inside, 0.0 outside) → RotatingCubeEffect samples mask to render only inside circle → GaussianBlurEffect post-processes - **Pipeline Format Matching**: All pipelines targeting same render pass must use matching formats: * Color: Bgra8UnormSrgb (system framebuffer format) * Depth: Depth24Plus (scene pass depth buffer) - **ShaderComposer Integration**: Relies on `InitShaderComposer()` (called in `gpu.cc:372`) registering snippets: `common_uniforms`, `math/sdf_utils`, `ray_box`, etc. **Effect Behavior:** - Runs from 2.0s to 4.0s in demo timeline - CircleMaskEffect (priority 0): Draws green outside circle, transparent inside - RotatingCubeEffect (priority 1): Renders bump-mapped cube inside circle - GaussianBlurEffect (priority 2): Post-process blur on entire composition **Test Results:** - All 33 tests pass (100%) - No WebGPU validation errors - Demo runs cleanly with `--seek 2.0` Co-Authored-By: Claude Sonnet 4.5 --- src/tests/test_demo_effects.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/tests/test_demo_effects.cc') diff --git a/src/tests/test_demo_effects.cc b/src/tests/test_demo_effects.cc index cf77c13..25ada59 100644 --- a/src/tests/test_demo_effects.cc +++ b/src/tests/test_demo_effects.cc @@ -17,8 +17,9 @@ static constexpr int EXPECTED_POST_PROCESS_COUNT = // ChromaAberrationEffect, SolarizeEffect, FadeEffect, // ThemeModulationEffect, VignetteEffect static constexpr int EXPECTED_SCENE_COUNT = - 6; // HeptagonEffect, ParticlesEffect, ParticleSprayEffect, - // MovingEllipseEffect, FlashCubeEffect, Hybrid3DEffect + 8; // HeptagonEffect, ParticlesEffect, ParticleSprayEffect, + // MovingEllipseEffect, FlashCubeEffect, Hybrid3DEffect, + // CircleMaskEffect, RotatingCubeEffect #include "effect_test_helpers.h" #include "gpu/demo_effects.h" @@ -154,6 +155,8 @@ static void test_scene_effects() { std::make_shared(fixture.ctx())}, {"FlashCubeEffect", std::make_shared(fixture.ctx())}, {"Hybrid3DEffect", std::make_shared(fixture.ctx())}, + {"CircleMaskEffect", std::make_shared(fixture.ctx())}, + {"RotatingCubeEffect", std::make_shared(fixture.ctx())}, }; int passed = 0; @@ -163,9 +166,11 @@ static void test_scene_effects() { assert(!effect->is_post_process() && "Scene effect should return false for is_post_process()"); - // FlashCubeEffect and Hybrid3DEffect require full 3D pipeline (Renderer3D) + // FlashCubeEffect, Hybrid3DEffect, RotatingCubeEffect, and CircleMaskEffect require full 3D pipeline (Renderer3D) or auxiliary textures const bool requires_3d = (strcmp(name, "FlashCubeEffect") == 0 || - strcmp(name, "Hybrid3DEffect") == 0); + strcmp(name, "Hybrid3DEffect") == 0 || + strcmp(name, "RotatingCubeEffect") == 0 || + strcmp(name, "CircleMaskEffect") == 0); const int result = test_effect_smoke(name, effect, &main_seq, requires_3d); if (result == 1) { -- cgit v1.2.3