# Shader Code Reuse Investigation ## Current State ### Duplication Analysis - **36 duplicate shader files** between main and test workspaces - Common files include: math utilities, render helpers, compute shaders, uniforms - Files are byte-identical duplicates (verified) ### Current System Architecture 1. **ShaderComposer**: Runtime shader composition via `#include` directives 2. **Asset System**: Shaders loaded from workspace `assets.txt` 3. **Registration**: `InitShaderComposer()` registers snippets with paths like: - `common_uniforms` - `math/sdf_shapes`, `math/noise`, `math/common_utils` - `render/shadows`, `render/scene_query_bvh`, `render/lighting_utils` ### Duplicate Common Shaders ``` Common across both workspaces: - common_uniforms.wgsl - math/{common_utils, noise, sdf_shapes, sdf_utils}.wgsl - render/{lighting_utils, scene_query_bvh, scene_query_linear, shadows}.wgsl - compute/{gen_blend, gen_grid, gen_mask, gen_noise, gen_perlin}.wgsl - Various effect shaders (passthrough, lighting, ray_box, etc.) ``` --- ## Proposed Approaches ### Option 1: Shared Common Directory (Original Design) **Structure:** ``` /common/ /shaders/ /math/ # Shared math utilities /render/ # Shared rendering helpers /compute/ # Shared compute shaders common_uniforms.wgsl /workspaces/ /main/ /shaders/ # Workspace-specific only /music/ /weights/ /obj/ ``` **Pros:** - Single source of truth for common code - No duplication - Clear separation: common vs workspace-specific - Matches original design doc intent **Cons:** - Breaks workspace isolation (workspaces depend on external directory) - Harder to version control per-workspace - Need to update asset packer to handle cross-workspace references - Complicates workspace portability --- ### Option 2: Symbolic Links **Structure:** ``` /workspaces/ /main/ /shaders/ /common@ -> ../../common/shaders/ # Symlink custom_effect.wgsl ``` **Pros:** - Maintains single source - Works with existing asset system - Simple filesystem solution **Cons:** - Windows symlink issues (requires admin or dev mode) - Git symlink handling varies - Still breaks workspace isolation - Can confuse developers --- ### Option 3: Build-Time Copy/Sync **Structure:** Workspaces keep duplicates, but sync from canonical source at build time. ``` /common/shaders/ # Canonical source /workspaces/*/shaders/ # Build-synced copies ``` **Implementation:** - CMake script copies common/ → workspaces/ before asset packing - Or: Pre-commit hook validates consistency **Pros:** - Workspaces remain self-contained - No runtime dependencies - Works across all platforms - Git shows actual files **Cons:** - Easy to forget sync - Merge conflicts if edited in workspace - Need tooling to maintain consistency --- ### Option 4: Asset System Extension **Enhance asset packer to support cross-workspace includes:** `workspaces/main/assets.txt`: ``` SHADER_COMMON_UTILS, NONE, @common/shaders/math/common_utils.wgsl SHADER_CUSTOM, NONE, shaders/custom_effect.wgsl ``` **Pros:** - Clean at asset definition level - ShaderComposer unchanged - Explicit common vs local **Cons:** - Asset packer modification needed - New syntax to learn - Breaks workspace portability --- ### Option 5: Status Quo + Documentation **Keep duplicates, document as intentional.** Add `common/shaders/` as reference templates that workspaces copy. **Pros:** - Workspaces fully independent - Can diverge per-workspace if needed - No build system changes - Simple mental model **Cons:** - Ongoing duplication - Manual sync required - Disk space (minimal impact) - Bug fixes need multi-workspace updates --- ## Recommendation Matrix | Criteria | Opt 1 | Opt 2 | Opt 3 | Opt 4 | Opt 5 | |----------|-------|-------|-------|-------|-------| | No duplication | ✓ | ✓ | ✗ | ✓ | ✗ | | Workspace isolation | ✗ | ✗ | ✓ | ✗ | ✓ | | Cross-platform | ✓ | ✗ | ✓ | ✓ | ✓ | | Low complexity | ✗ | ✓ | ✗ | ✗ | ✓ | | Easy maintenance | ✓ | ✓ | ✗ | ✓ | ✗ | --- ## Current Implementation Details ### How Shaders Are Currently Included **In WGSL files:** ```wgsl #include "common_uniforms" #include "math/sdf_shapes" #include "render/shadows" ``` **In C++ (shaders.cc):** ```cpp void InitShaderComposer() { auto& sc = ShaderComposer::Get(); sc.RegisterSnippet("common_uniforms", ...); sc.RegisterSnippet("math/sdf_shapes", ...); sc.RegisterSnippet("render/shadows", ...); } ``` **Asset Registration (assets.txt):** ``` SHADER_MATH_SDF_SHAPES, NONE, shaders/math/sdf_shapes.wgsl SHADER_RENDER_SHADOWS, NONE, shaders/render/shadows.wgsl ``` ### ShaderComposer Flow 1. Assets loaded from workspace `assets.txt` 2. Snippets registered in `InitShaderComposer()` 3. Effects call `Compose()` with dependencies 4. `#include` directives recursively resolved 5. Final shader string assembled --- ## Next Steps 1. **Decide on approach** based on project priorities: - Simplicity → Option 5 - True reuse → Option 1 or 4 - Compatibility → Option 3 2. **If Option 1 chosen:** - Create `/common/shaders/` with canonical sources - Update `workspace.cfg` to reference common - Update asset packer to resolve `../common/` paths - Update docs 3. **If Option 3 chosen:** - Create sync script in `scripts/` - Add to build process - Document workflow 4. **If Option 5 chosen:** - Create `/common/shaders/` as templates - Add `doc/SHADER_COMMON.md` explaining pattern - Accept duplication as intentional