diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-16 11:54:46 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-16 11:54:46 +0100 |
| commit | af5d0e4c3a6cb773a4fb51ac32f4c33a7f8d8224 (patch) | |
| tree | a76464ca40a43d6042ed5431547008cfbe746c34 /src/effects/circle_mask_effect.cc | |
| parent | 8eeadaf0d5653c21b948103e4d328f634b739a17 (diff) | |
feat(sequence): complete v2 migration with DAG-based routing
Phase 4 complete: V1 system removed, v2 fully operational.
Architecture Changes:
- Explicit Node system with typed buffers (u8x4_norm, f32x4, depth24)
- DAG effect routing with multi-input/multi-output support
- Python compiler (seq_compiler_v2.py) with topological sort and ping-pong optimization
- Compile-time node aliasing for framebuffer reuse
V1 Removal (~4KB):
- Deleted effect.h/cc base classes (1.4KB)
- Deleted 19 v1 effect pairs: heptagon, particles, passthrough, gaussian_blur,
solarize, scene1, chroma_aberration, vignette, hybrid_3d, flash_cube,
theme_modulation, fade, flash, circle_mask, rotating_cube, sdf_test,
distort, moving_ellipse, particle_spray (2.7KB)
V2 Effects Ported:
- PassthroughEffectV2, PlaceholderEffectV2
- GaussianBlurEffectV2 (multi-pass with temp nodes)
- HeptagonEffectV2 (scene effect with dummy texture)
- ParticlesEffectV2 (compute + render, format fixed)
- RotatingCubeEffectV2 (3D with depth node)
- Hybrid3DEffectV2 (Renderer3D integration, dummy textures for noise/sky)
Compiler Features:
- DAG validation (cycle detection, connectivity checks)
- Topological sort for execution order
- Ping-pong optimization (aliased node detection)
- Surface-based and encoder-based RenderV2Timeline generation
- init_effect_nodes() automatic generation
Fixes Applied:
- WebGPU binding layout validation (standard v2 post-process layout)
- Surface format mismatch (ctx.format for blit, RGBA8Unorm for framebuffers)
- Depth attachment compatibility (removed forced depth from gpu_create_render_pass)
- Renderer3D texture initialization (created dummy 1x1 white textures)
- ParticlesEffectV2 format (changed from ctx.format to RGBA8Unorm)
- Encoder-based RenderV2Timeline (added missing preprocess() call)
Testing:
- 34/36 tests passing (2 v1-dependent tests disabled)
- demo64k runs successfully (no crashes)
- All seek positions work (--seek 12, --seek 15 validated)
Documentation:
- Updated PROJECT_CONTEXT.md (v2 status, reference to SEQUENCE_v2.md)
- Added completion entry to COMPLETED.md
TODO (Future):
- Port CNN effects to v2
- Implement flatten mode (--flatten code generation)
- Port remaining 10+ effects
- Update HTML timeline editor for v2 (deferred)
handoff(Claude): Sequence v2 migration complete, v1 removed, system operational.
Phase 5 (editor) deferred per user preference.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/effects/circle_mask_effect.cc')
| -rw-r--r-- | src/effects/circle_mask_effect.cc | 221 |
1 files changed, 0 insertions, 221 deletions
diff --git a/src/effects/circle_mask_effect.cc b/src/effects/circle_mask_effect.cc deleted file mode 100644 index 7a016d9..0000000 --- a/src/effects/circle_mask_effect.cc +++ /dev/null @@ -1,221 +0,0 @@ -// This file is part of the 64k demo project. -// It implements CircleMaskEffect for auxiliary texture masking demonstration. -// Generates circular mask and renders green background outside circle. - -#include "effects/circle_mask_effect.h" -#include "generated/assets.h" -#include "gpu/bind_group_builder.h" -#include "gpu/shader_composer.h" - -CircleMaskEffect::CircleMaskEffect(const GpuContext& ctx, float radius) - : Effect(ctx), radius_(radius) { -} - -CircleMaskEffect::~CircleMaskEffect() { - if (mask_sampler_) - wgpuSamplerRelease(mask_sampler_); - if (render_bind_group_) - wgpuBindGroupRelease(render_bind_group_); - if (render_pipeline_) - wgpuRenderPipelineRelease(render_pipeline_); - if (compute_bind_group_) - wgpuBindGroupRelease(compute_bind_group_); - if (compute_pipeline_) - wgpuRenderPipelineRelease(compute_pipeline_); -} - -void CircleMaskEffect::init(MainSequence* demo) { - demo_ = demo; - - // Register auxiliary texture (width_/height_ set by resize() before init()) - demo_->register_auxiliary_texture("circle_mask", width_, height_); - - compute_params_.init(ctx_.device); - - // Initialize uniforms BEFORE bind group creation - uniforms_.update(ctx_.queue, get_common_uniforms()); - - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; - sampler_desc.maxAnisotropy = 1; - mask_sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); - - size_t compute_size, render_size; - const char* compute_shader = (const char*)GetAsset( - AssetId::ASSET_CIRCLE_MASK_COMPUTE_SHADER, &compute_size); - const char* render_shader = (const char*)GetAsset( - AssetId::ASSET_CIRCLE_MASK_RENDER_SHADER, &render_size); - - // Compose shaders to resolve #include directives - std::string composed_compute = - ShaderComposer::Get().Compose({}, compute_shader); - - WGPUShaderSourceWGSL compute_wgsl = {}; - compute_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL; - compute_wgsl.code = str_view(composed_compute.c_str()); - - WGPUShaderModuleDescriptor compute_desc = {}; - compute_desc.nextInChain = &compute_wgsl.chain; - WGPUShaderModule compute_module = - wgpuDeviceCreateShaderModule(ctx_.device, &compute_desc); - - const WGPUColorTargetState compute_target = { - .format = ctx_.format, // Match auxiliary texture format - .writeMask = WGPUColorWriteMask_All, - }; - WGPUFragmentState compute_frag = {}; - compute_frag.module = compute_module; - compute_frag.entryPoint = str_view("fs_main"); - compute_frag.targetCount = 1; - compute_frag.targets = &compute_target; - WGPURenderPipelineDescriptor compute_pipeline_desc = {}; - compute_pipeline_desc.label = label_view("CircleMaskEffect_compute"); - compute_pipeline_desc.vertex.module = compute_module; - compute_pipeline_desc.vertex.entryPoint = str_view("vs_main"); - compute_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; - compute_pipeline_desc.primitive.cullMode = WGPUCullMode_None; - compute_pipeline_desc.multisample.count = 1; - compute_pipeline_desc.multisample.mask = 0xFFFFFFFF; - compute_pipeline_desc.fragment = &compute_frag; - compute_pipeline_ = - wgpuDeviceCreateRenderPipeline(ctx_.device, &compute_pipeline_desc); - wgpuShaderModuleRelease(compute_module); - - WGPUBindGroupLayout compute_layout = - wgpuRenderPipelineGetBindGroupLayout(compute_pipeline_, 0); - compute_bind_group_ = - BindGroupBuilder() - .buffer(0, uniforms_.get().buffer, sizeof(CommonPostProcessUniforms)) - .buffer(1, compute_params_.get().buffer, sizeof(CircleMaskParams)) - .build(ctx_.device, compute_layout); - wgpuBindGroupLayoutRelease(compute_layout); - - std::string composed_render = - ShaderComposer::Get().Compose({}, render_shader); - - WGPUShaderSourceWGSL render_wgsl = {}; - render_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL; - render_wgsl.code = str_view(composed_render.c_str()); - - WGPUShaderModuleDescriptor render_desc = {}; - render_desc.nextInChain = &render_wgsl.chain; - WGPUShaderModule render_module = - wgpuDeviceCreateShaderModule(ctx_.device, &render_desc); - - const WGPUColorTargetState render_target = { - .format = ctx_.format, - .writeMask = WGPUColorWriteMask_All, - }; - WGPUFragmentState render_frag = {}; - render_frag.module = render_module; - render_frag.entryPoint = str_view("fs_main"); - render_frag.targetCount = 1; - render_frag.targets = &render_target; - const WGPUDepthStencilState depth_stencil = { - .format = WGPUTextureFormat_Depth24Plus, - .depthWriteEnabled = WGPUOptionalBool_False, // Don't write depth - .depthCompare = WGPUCompareFunction_Always, // Always pass - }; - - WGPURenderPipelineDescriptor render_pipeline_desc = {}; - render_pipeline_desc.label = label_view("CircleMaskEffect_render"); - render_pipeline_desc.vertex.module = render_module; - render_pipeline_desc.vertex.entryPoint = str_view("vs_main"); - render_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; - render_pipeline_desc.primitive.cullMode = WGPUCullMode_None; - render_pipeline_desc.depthStencil = &depth_stencil; - render_pipeline_desc.multisample.count = 1; - render_pipeline_desc.multisample.mask = 0xFFFFFFFF; - render_pipeline_desc.fragment = &render_frag; - render_pipeline_ = - wgpuDeviceCreateRenderPipeline(ctx_.device, &render_pipeline_desc); - wgpuShaderModuleRelease(render_module); - - 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::resize(int width, int height) { - if (width == width_ && height == height_) - return; - - 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"); - WGPUBindGroupLayout render_layout = - wgpuRenderPipelineGetBindGroupLayout(render_pipeline_, 0); - render_bind_group_ = - BindGroupBuilder() - .texture(0, mask_view) - .sampler(1, mask_sampler_) - .buffer(2, uniforms_.get().buffer, sizeof(CommonPostProcessUniforms)) - .build(ctx_.device, render_layout); - wgpuBindGroupLayoutRelease(render_layout); -} - -void CircleMaskEffect::compute(WGPUCommandEncoder encoder, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - - const CircleMaskParams params = { - .radius = radius_, - }; - compute_params_.update(ctx_.queue, params); - - WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask"); - WGPURenderPassColorAttachment color_attachment = {}; - color_attachment.view = mask_view; - color_attachment.loadOp = WGPULoadOp_Clear; - color_attachment.storeOp = WGPUStoreOp_Store; - color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0}; -#if !defined(DEMO_CROSS_COMPILE_WIN32) - color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; -#endif - - WGPURenderPassDescriptor pass_desc = {}; - pass_desc.colorAttachmentCount = 1; - pass_desc.colorAttachments = &color_attachment; - - WGPURenderPassEncoder pass = - wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, compute_pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, compute_bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); - wgpuRenderPassEncoderEnd(pass); - wgpuRenderPassEncoderRelease(pass); -} - -void CircleMaskEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - - wgpuRenderPassEncoderSetPipeline(pass, render_pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, render_bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} |
