summaryrefslogtreecommitdiff
path: root/src/effects/circle_mask_effect.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-16 11:54:46 +0100
committerskal <pascal.massimino@gmail.com>2026-02-16 11:54:46 +0100
commitaf5d0e4c3a6cb773a4fb51ac32f4c33a7f8d8224 (patch)
treea76464ca40a43d6042ed5431547008cfbe746c34 /src/effects/circle_mask_effect.cc
parent8eeadaf0d5653c21b948103e4d328f634b739a17 (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.cc221
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);
-}