Monorepo for Aesthetic.Computer aesthetic.computer
at main 267 lines 8.7 kB view raw view rendered
1# WebGPU Renderer Plan for aesthetic.computer 2 3## Current State Analysis 4 5### What's Already Built ✅ 6 7**1. `/system/public/aesthetic.computer/lib/webgpu.mjs`** (381 lines) 8A foundational WebGPU renderer with: 9- WebGPU initialization with adapter/device setup 10- Canvas context configuration with alpha blending 11- **Clear pipeline** - full-screen clear with configurable color 12- **Line pipeline** - basic 1px line rendering in pixel coordinates 13- Proper uniform buffers (color, resolution) with WGSL shaders 14- Graceful fallback when WebGPU unavailable 15 16**2. BIOS Integration (`bios.mjs`)** 17- WebGPU module imported at line 41 18- `initWebGPU(canvas)` async initializer (line 1611-1617) 19- Message handler for `webgpu-command` (lines 10353-10355) 20 21**3. Disk API (`disk.mjs`)** 22- `$commonApi.webgpu` object with: 23 - `enabled` flag to disable CPU renderer 24 - `clear(r, g, b, a)` function 25 - `line(x1, y1, x2, y2, r, g, b, a)` function 26 - `render()` function 27- Auto-routing in `ink()` and `wipe()` when `webgpu.enabled = true` 28 29### Existing CPU Renderer Capabilities (graph.mjs) 30 31The current `graph.mjs` has sophisticated features that WebGPU needs to match/accelerate: 32 33**Pixel Manipulation:** 34- `plot(x, y)` - single pixel 35- `point(x, y)` - with pan translation 36- `pixel(x, y)` - read pixel color 37- `copy()` / `paste()` - buffer blitting with alpha, scaling, rotation 38- `copyRow()` / `copyRegion()` - optimized sub-region operations 39 40**Primitives:** 41- `line()` - Bresenham with thickness support 42- `lineh()` - horizontal line (fast path) 43- `lineAngle()` - angle-based line 44- `circle()` - filled/outline with thickness 45- `rect()` / `box()` - rectangles 46- `poly()` / `pline()` - polylines with thickness 47 48**Sprite/Texture:** 49- `paste(from, destX, destY, scale, blit)` - full sprite system 50 - Supports ImageBitmap, canvas buffers, pixel arrays 51 - Integer scaling (1-8x) with fast nearest-neighbor path 52 - Rotation via transform object `{ scale, angle, anchor, crop }` 53 - Alpha blending 54- `bitmapPixelCache` - WeakMap cache for ImageBitmap pixel extraction 55 56**Text System (type.mjs + graph.mjs):** 57- `printLine()` - renders text using `draw()` function 58- `draw()` - interprets glyph command lists: 59 - BDF fonts (unifont, MatrixChunky8) → pixel arrays 60 - Vector fonts → `line` and `point` commands 61 - Supports rotation, scaling, thickness 62- Typeface glyphs are just drawing commands (`{name: "line", args: [x1,y1,x2,y2]}`) 63- **Key insight:** Text can be accelerated by accelerating the underlying primitives! 64 65**Effects:** 66- `spin()` - radial blur/rotation with SIMD-like batching 67- `noise16()` variants - procedural noise 68- Mask system (`activeMask`) for clipping 69 70### What's Missing / Needs Work 🚧 71 72**1. Core Primitives for WebGPU** 73- [ ] Rectangle fill (`rect`) - enables text backgrounds 74- [ ] Circle/ellipse (`circle`, `oval`) 75- [ ] Filled polygon 76- [ ] Thick lines (line width > 1px) 77- [ ] Point rendering (single pixel) 78 79**2. Sprite/Texture Support** (HIGH PRIORITY) 80Since `paste()` is heavily used: 81- [ ] Texture upload from ImageBitmap/Uint8ClampedArray 82- [ ] Textured quad rendering 83- [ ] Nearest-neighbor sampling for pixel art aesthetic 84- [ ] Alpha blending modes 85 86**3. Text Rendering Strategy** 87Two approaches: 881. **Primitive-based:** Accelerate `point()` and `line()`, text rendering follows automatically 892. **Glyph atlas:** Pre-render glyphs to texture atlas, sample as textured quads 90 91**4. Compute Shader Rasterization** (from tutorial) 92The current implementation uses traditional render pipelines. For maximum flexibility and performance, a compute shader approach would enable: 93- Atomic depth testing 94- Custom blending modes (averaging, XOR, etc.) 95- Order-independent transparency 96- Performance wins for many small triangles 97 98**5. Command Batching** 99Current implementation executes commands immediately. Should batch for performance: 100- Accumulate commands during frame 101- Submit single command buffer at end of frame 102- Reuse buffers between frames 103 104--- 105 106## Tutorial Reference Summary 107 108The [WebGPU Compute Rasterizer tutorial](https://github.com/OmarShehata/webgpu-compute-rasterizer) demonstrates: 109 110### Architecture 111``` 112[Compute Pass] → outputColorBuffer (storage buffer) 113114[Fullscreen Pass] → reads buffer → draws to screen 115``` 116 117### Key Techniques 1181. **Storage Buffers** for pixel data (`WIDTH * HEIGHT * 3` for RGB) 1192. **Barycentric Coordinates** for triangle fill 1203. **Atomic Operations** (`atomicMin`) for depth testing without race conditions 1214. **Workgroup Dispatch** - one compute thread per triangle 122 123### Code Patterns Worth Adopting 124 125**Triangle Fill (WGSL):** 126```wgsl 127fn barycentric(v1: vec3<f32>, v2: vec3<f32>, v3: vec3<f32>, p: vec2<f32>) -> vec3<f32> { 128 let u = cross( 129 vec3<f32>(v3.x - v1.x, v2.x - v1.x, v1.x - p.x), 130 vec3<f32>(v3.y - v1.y, v2.y - v1.y, v1.y - p.y) 131 ); 132 if (abs(u.z) < 1.0) { return vec3<f32>(-1.0, 1.0, 1.0); } 133 return vec3<f32>(1.0 - (u.x+u.y)/u.z, u.y/u.z, u.x/u.z); 134} 135 136fn draw_triangle(v1: vec3<f32>, v2: vec3<f32>, v3: vec3<f32>) { 137 let min_max = get_min_max(v1, v2, v3); 138 for (var x = startX; x <= endX; x++) { 139 for (var y = startY; y <= endY; y++) { 140 let bc = barycentric(v1, v2, v3, vec2<f32>(f32(x), f32(y))); 141 if (bc.x >= 0.0 && bc.y >= 0.0 && bc.z >= 0.0) { 142 color_pixel(x, y, color); 143 } 144 } 145 } 146} 147``` 148 149**Atomic Depth Testing:** 150```wgsl 151struct ColorBuffer { 152 values: array<atomic<u32>>, 153}; 154 155fn color_pixel(x: u32, y: u32, r: u32, g: u32, b: u32) { 156 let pixelID = u32(x + y * u32(uniforms.screenWidth)) * 3u; 157 atomicMin(&outputColorBuffer.values[pixelID + 0u], r); 158 // ... etc 159} 160``` 161 162--- 163 164## Implementation Phases 165 166### Phase 1: Solidify Current Renderer ✨ 167**Goal:** Make `webgpu.mjs` useful for basic pieces 168 169- [ ] Add `rect(x, y, w, h, color)` with fill 170- [ ] Add `circle(x, y, radius, color)` with fill 171- [ ] Add thick line support (line width uniform) 172- [ ] Test with a demo piece that uses `webgpu.enabled = true` 173 174### Phase 2: Compute Rasterizer Foundation 🔧 175**Goal:** Set up compute-based rendering pipeline 176 177- [ ] Create dual-buffer system (color storage + screen texture) 178- [ ] Implement fullscreen quad pass to display storage buffer 179- [ ] Port clear pass to compute shader 180- [ ] Add basic triangle fill using barycentric coordinates 181 182### Phase 3: Full 2D Primitive Set 📐 183**Goal:** Replace all CPU drawing with GPU 184 185- [ ] Filled rectangles via compute 186- [ ] Filled circles via distance function 187- [ ] Lines with thickness (quad-based) 188- [ ] Polygons via triangle fan 189- [ ] Depth buffer for proper layering 190 191### Phase 4: Advanced Features 🚀 192**Goal:** Enable effects not possible with CPU renderer 193 194- [ ] Custom blend modes (multiply, screen, overlay) 195- [ ] Per-pixel effects (blur, glow, distortion) 196- [ ] Text rendering with SDF fonts 197- [ ] Instanced rendering for particles 198- [ ] Real-time filters on pixel buffer 199 200--- 201 202## Questions to Answer 203 2041. **Canvas Sizing:** How does `webgpu.mjs` handle resolution changes? Should it match the low-res aesthetic or render at native resolution? 205 2062. **CPU/GPU Hybrid:** When `webgpu.enabled = true`, should ALL rendering go through GPU, or should we support hybrid mode? 207 2083. **Compatibility:** WebGPU is still experimental. What's the fallback strategy? 209 - WebGL2 via existing `2d.mjs`? 210 - CPU rendering via canvas? 211 2124. **Memory Budget:** How large can the storage buffer be for high-res displays? 213 214--- 215 216## Test Piece Idea 217 218Create `system/public/aesthetic.computer/disks/webgpu-test.mjs`: 219 220```javascript 221// webgpu-test.mjs - WebGPU Renderer Demo 222export const desc = "WebGPU renderer test"; 223 224export function boot({ webgpu }) { 225 webgpu.enabled = true; 226} 227 228export function paint({ webgpu, screen }) { 229 webgpu.clear(20, 20, 40, 255); 230 231 // Draw some lines 232 for (let i = 0; i < 10; i++) { 233 webgpu.line( 234 10 + i * 10, 10, 235 screen.width - 10, 10 + i * 20, 236 255, 100 + i * 15, 50, 255 237 ); 238 } 239} 240 241export function act({ event: e }) { 242 // Handle input 243} 244``` 245 246--- 247 248## Related Files 249 250- `/workspaces/aesthetic-computer/gpu/RESEARCH.md` - Original research doc 251- `/workspaces/aesthetic-computer/system/public/aesthetic.computer/lib/2d.mjs` - Disabled WebGL2 renderer 252- `/workspaces/aesthetic-computer/system/public/aesthetic.computer/lib/3d.mjs` - ThreeJS renderer (for reference) 253- `/workspaces/aesthetic-computer/TODO.txt` line 627 - WebGPU rasterizer TODO 254- `/workspaces/aesthetic-computer/TODO.txt` line 1491 - WebGL2/WebGPU Backend TODO 255 256--- 257 258## Next Steps 259 2601. **Create test piece** to validate current `clear` and `line` commands work 2612. **Add `rect` primitive** as first compute-based fill 2623. **Set up command batching** architecture 2634. **Profile performance** vs CPU renderer 264 265--- 266 267*Last updated: November 26, 2025*