# Auxiliary Texture Masking System ## Purpose Share textures between effects within a single frame for **screen-space partitioning** (split-screen, portals, picture-in-picture). ## Concept - Effect1: Generate mask (1 = region A, 0 = region B) - Effect1: Render scene A where mask = 1 - Effect2: Reuse mask, render scene B where mask = 0 - Both render to same framebuffer ## Design Choice: Mask Texture vs Stencil Buffer **Chosen: Mask Texture** Pros: - Flexible (soft edges, gradients) - Debuggable (visualize as texture) - Reusable (multiple effects read same mask) - Simple pipeline setup Cons: - Memory cost (~4 MB for 1280x720 RGBA8) - Fragment shader discard (slightly slower than stencil) **Not Chosen: Stencil Buffer** Pros: Hardware-accelerated, fast early-rejection Cons: 8-bit limitation, complex pipeline, hard to debug ## API Reference ```cpp class MainSequence { public: // Register once in effect init void register_auxiliary_texture(const char* name, int width, int height); // Get view every frame WGPUTextureView get_auxiliary_view(const char* name); }; ``` ## Usage Pattern ```cpp // Effect1 (mask generator) void init(MainSequence* demo) { demo->register_auxiliary_texture("portal_mask", width, height); } void compute(WGPUCommandEncoder encoder, ...) { WGPUTextureView mask = demo_->get_auxiliary_view("portal_mask"); // Generate mask to texture } void render(WGPURenderPassEncoder pass, ...) { WGPUTextureView mask = demo_->get_auxiliary_view("portal_mask"); // Sample mask, discard where mask < 0.5, render scene A } // Effect2 (mask consumer) void render(WGPURenderPassEncoder pass, ...) { WGPUTextureView mask = demo_->get_auxiliary_view("portal_mask"); // Sample mask, discard where mask > 0.5, render scene B } ``` ## Shader Example **Mask Generation:** ```wgsl @fragment fn fs_main(@builtin(position) p: vec4) -> @location(0) vec4 { let uv = p.xy / uniforms.resolution; let dist = length(uv - vec2(0.5)); let mask = f32(dist < 0.3); // Circular portal return vec4(mask); } ``` **Masked Rendering:** ```wgsl @group(0) @binding(3) var mask_texture: texture_2d; @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { let uv = in.position.xy / uniforms.resolution; let mask = textureSample(mask_texture, mask_sampler, uv).r; if (mask < 0.5) { discard; } // Effect1: discard outside // if (mask > 0.5) { discard; } // Effect2: discard inside return compute_scene_color(in); } ``` ## Memory Impact Per texture: **width × height × 4 bytes** - 1280×720: ~3.7 MB - 1920×1080: ~8.3 MB Typical usage: 2-3 masks = 10-25 MB (acceptable overhead) ## Use Cases 1. Split-screen (vertical/horizontal) 2. Portals (arbitrary shape windows) 3. Picture-in-picture 4. Masked transitions (wipe effects) 5. Shadow maps (pre-generated in compute) 6. Reflection probes ## Size Impact - Code: ~100 lines (~500 bytes) - Runtime memory: 4-8 MB per mask ## Future Extensions - Multi-channel masks (RGBA = 4 regions) - Mipmap support - R8 compression (1 byte/pixel) - Enum-based lookup (replace string keys)