- Render thread: the player extracts each frame on the main thread into a self-contained
FrameExtract(FrameBuilder), and a render thread uploads, encodes, submits and presents it (FrameRenderer). Two extracts circulate, so frame N+1 simulates while frame N renders, with no per-frame allocation. - Extraction: FxHash maps and per-material cached linear colors cut extraction from 1.43 ms to 0.39 ms for 10,000 renderers (about 40 ns each), with 0 allocations per frame.
- Measured (
dotnet/samples/scenes/stress.json: 10,000 scripted spinning cubes, RTX 4070 SUPER, release, no vsync): frame interval 0.77 ms (simulate 0.33 ms + extract 0.39 ms on the main thread; render thread 0.43 ms overlapped), down from 1.88 ms. - Allocations: 0 per frame in simulation and extraction; about 62 per frame remain inside wgpu (command encoding, render pass recording, buffer writes, submission), and about 40 more for acquiring and presenting the surface.
- Tools:
--statsreports frame interval, simulation, render and wait times;--headless --renderrenders offscreen every frame and splits allocations between extraction and rendering. - Deferred: a render graph waits until there is more than one pass (shadows, post-processing); with a single forward pass it would only add indirection.
- Next: FBX import, sprite batching across textures (atlases), texture sharing across imported files, and reducing wgpu's per-frame allocations (staging belt, reused encoders where wgpu allows).
Phase 2 · Slice 4 ·