WebGPU renderer complete: dirty uploads, default limits, legacy removed, WebGPU required, warm-up (t88 phase 2d)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 23:17:17 -04:00
co-authored by Claude Opus 5.5
parent 452b6aed32
commit 20963c776e
83 changed files with 776 additions and 1240 deletions
+32 -12
View File
@@ -67,30 +67,42 @@ diff -r /tmp/before /tmp/after
gamepad and world sizes. Screenshots go to
`shots/play/`. Pixel look by default; `python3 test/play.py shots/play smooth` uses the smooth
look.
- `test/t_smooth.py` checks that the WebGPU smooth look compiles and draws, compares legacy at half resolution, and falls back
to pixels cleanly, and that the thermal lens works.
- Run them one at a time. Two headless browsers at once can starve each other, and
`t_smooth.py`'s half-resolution check then fails. `run_all.py` runs them one after the other.
- `test/t_smooth.py` checks WebGPU smooth shapes, seams, joins, fog and the thermal lens.
- `test/t_gpu_golden.py` compares 28 cropped legacy reference PNGs (384x288, under
`test/fixtures/golden/`) against WebGPU: renderer, joins, sky and four light scenes,
both looks at zoom 12 and 2. ImageMagick decodes RGB; the per-channel tolerance is 8,
mean RGB error must stay below 0.5/255 and fewer than 0.3% of pixels may exceed 8
(smooth AO/edge rounding). These are frozen pre-removal legacy images, not generated
from the new renderer. Inspect the matching `shots/golden-*.png` after visible changes.
- `test/t_gpu.py` checks default limits (four storage textures per stage), dirty-upload
readback after 240 busy ticks with scrolling and both looks, exact dirty/full image equality
with a frozen clock, world replacement, transparent overlays, drill contours, shader compilation timing, successful device recreation and failed recovery with
an autosave and Reload. `gpuCheckUploads()` reads actual resident GPU texture bytes and
compares them to the full CPU arrays, including Float32 temperatures, machine and block data.
- `test/t_render_dirty.js` checks invalidation of sleeping chunks, heat edges, swaps, fog and trees.
- The old CPU light checks now run as `test/t_gpu_light.py` / `test/light-cases.js`, reading the
actual WGSL float light grid. Transmission tolerance is 0.001 because the GPU work textures
store float16 (the removed CPU implementation used float32). Behavioural expectations remain.
- Browser suites run one at a time; concurrent GPU work distorts timing and can starve tests.
- Rebuild first (`python3 build.py`); `run_all.py --browser` rebuilds for you. All browser tools
use `tools/browser.py` and `tools/server.py`: a free-port background HTTP server serves the
built page with COOP/COEP headers and shuts down after the browser. No `file://` loads.
- Choose Chromium graphics with `--gpu real|soft` or `DEEPGRAIN_GPU=real|soft` (the command line
wins). This works for the suite runner, individual browser tests, screenshots and profiler.
Real mode uses ANGLE Vulkan on the host GPU; soft uses SwiftShader and sets
`window.__allowSoftwareGL` before load. The explicit software-fallback test still uses soft
mode with that override off. Firefox uses its own default graphics backend.
Real mode uses ANGLE Vulkan on the host GPU; soft uses SwiftShader.
Unsupported software adapters show the same startup notice. Firefox uses its own default graphics backend.
The default is **real**, including the profiler and `caps.py`. No colour tolerances were
changed. The play test holds the slow-save fixture open during its screenshot, waits for
tool/selection UI updates, disables camera lead after testing it, and gives the gamepad drill
a known reachable target; these checks do not depend on GPU speed or earlier digging.
- `python3 tools/caps.py` prints isolation, actual WebGPU adapter info and the GL renderer for
Chromium and installed Firefox. Real mode requires a hardware Chromium adapter.
- `test/t_caps.py` checks missing, null and rejected WebGPU adapters, both title notices, warning
mode and the future `REQUIRE_GPU_AND_THREADS` startup gate. Its forced notice screenshot is
`shots/t88-p1-notice.png`.
- `test/t_caps.py` checks absent, null, rejected and insufficient-limit adapters, notices and
the mandatory WebGPU startup gate. Threads remain optional until Phase 3. Firefox smoke
checks that a browser without WebGPU shows the notice and cannot start a world.
- Install Firefox with `.venv/bin/python -m playwright install firefox`.
`python3 test/firefox_smoke.py` checks isolation and the WebGPU notice, starts a pixel world,
runs three seconds and checks page errors. `run_all.py --browser` includes it and prints a
`python3 test/firefox_smoke.py` checks isolation and the WebGPU notice, starts a pixel world
only when WebGPU is available, and otherwise verifies the startup block. `run_all.py --browser` includes it and prints a
skip note if Firefox is absent; an installed browser that fails to launch is a failure.
- Linux WebGPU currently needs Firefox Nightly; the notice points to `about:config` →
`dom.webgpu.enabled`. Sources: [Mozilla's experimental features](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Experimental_features#webgpu_api)
@@ -245,3 +257,11 @@ The screenshot tool invalidates the shared parallax horizon after scene setup ch
so renderer startup timing cannot change the hills in a comparison. Mip pass references:
[Chrome's porting guide](https://developer.chrome.com/docs/web-platform/webgpu/from-webgl-to-webgpu#mipmap_generation)
and [WebGPU Fundamentals](https://webgpufundamentals.org/webgpu/lessons/webgpu-importing-textures.html#generating-mips-on-the-gpu).
The required pipeline limits are checked in `gpuLimitsOK` before requesting the device: four
storage textures, sixteen sampled textures and eight storage buffers per stage, plus 8192 for
2D textures; no non-default limit is requested. References: [WebGPU limits](https://www.w3.org/TR/2026/CRD-webgpu-20260109/#limits)
and [Chromium Dawn defaults](https://dawn.googlesource.com/dawn.git/+/refs/heads/chromium/7945/src/dawn/native/Limits.cpp).
All game pipelines use async creation during capability checking. World loading submits both
looks before `GAME.running` becomes true. Shader and loading timings are printed by `t_gpu.py`;
look/zoom switches must not call synchronous pipeline creation.