WebGPU pixel look: GPU colours the world, CPU only rare cells (t88 phase 2a)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 19:49:36 -04:00
co-authored by Claude Opus 5.5
parent b2c9ad9533
commit fc05146887
29 changed files with 949 additions and 386 deletions
+14 -4
View File
@@ -54,14 +54,14 @@ def report(result, baseline=None):
m = result['machine']
print(f"GPU: {m['renderer']}\nCores: {m['cores']} | isolated: {m['crossOriginIsolated']} | navigator.gpu: {m['webgpu']}")
print(f"Viewport {result['options']['viewport']} | world {result['options']['world']} | seed 424242 | ms (CPU wall time)")
print('\nScene Look Zoom Light Grains World Light Prep Colour Upload Blit Overlays Scale')
print('\nScene Look Zoom Light Grains World Frame Light Prep Colour Upload Blit Overlays Scale')
for scene, data in result['scenes'].items():
for key, view in data['views'].items():
look, zoom = key.split('/')
for light, r in view['lighting'].items():
p = r['marks_ms']
print(f"{scene:8} {look:6} {zoom:>4} {light:>5} {view['grains']:6d} "
f"{r['drawWorld_ms']:7.2f} {p['light']:6.2f} {p['prepare']:5.2f} {p['color']:6.2f} "
f"{r['drawWorld_ms']:7.2f} {r.get('frame_ms', 0):6.2f} {p['light']:6.2f} {p['prepare']:5.2f} {p['color']:6.2f} "
f"{p['upload']:6.2f} {p['blit']:6.2f} {r['overlay_ms']:8.3f} {r['scale']:5.2f}")
print('\nSimulation: average ms/tick (periodic work amortized over 240 ticks)')
names = list(next(iter(result['scenes'].values()))['sim']['steps'])
@@ -125,8 +125,10 @@ def main():
options = dict(viewport=list(args.viewport), world=list(args.world), zooms=zooms,
looks=looks, scenes=scenes, seconds=args.seconds)
baseline = json.loads(args.compare.read_text()) if args.compare else None
if baseline and (baseline.get('schema') != 1 or baseline['options'] != options):
ap.error('baseline schema/options differ; use the same matrix, dimensions and seconds')
if baseline and (baseline.get('schema') != 1
or any(baseline['options'].get(k) != v for k, v in options.items() if k not in ('looks', 'scenes', 'zooms'))
or any(not set(options[k]).issubset(baseline['options'][k]) for k in ('looks', 'scenes', 'zooms'))):
ap.error('baseline schema/options differ; use a subset of the baseline matrix with the same dimensions and seconds')
ensure_playwright()
started = time.monotonic()
subprocess.run([sys.executable, str(ROOT / 'build.py')], cwd=ROOT, check=True, stdout=sys.stderr)
@@ -154,6 +156,9 @@ def main():
const id = raf(t => { pending.delete(id); f(t); }); pending.add(id); return id;
};''')
pg.goto(url)
pg.evaluate('CAPS_CHECK')
if not pg.evaluate('GPU.ok'):
raise RuntimeError('WebGPU unavailable: ' + pg.evaluate('GPU.error'))
pg.add_script_tag(content=(ROOT / 'tools/perf-scenes.js').read_text())
pg.add_script_tag(content=(ROOT / 'tools/perf-measure.js').read_text())
result['machine'] = pg.evaluate('''() => {
@@ -162,6 +167,7 @@ def main():
return { renderer: dbg ? gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) : gl.getParameter(gl.RENDERER),
vendor: dbg ? gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL) : gl.getParameter(gl.VENDOR),
cores: navigator.hardwareConcurrency, crossOriginIsolated, webgpu: !!navigator.gpu,
adapter: CAPS.adapterInfo, timestamp_query: !!GPU.queries,
user_agent: navigator.userAgent, dpr: devicePixelRatio };
}''')
if not result['machine']['crossOriginIsolated']:
@@ -185,6 +191,8 @@ def main():
view['lighting'][light] = pg.evaluate('([l,o]) => perfRender(l,o)', [light, overlays])
if view['lighting']['full']['actual_look'] != look or view['lighting']['off']['actual_look'] != look:
raise RuntimeError('Look fell back while measuring')
if look == 'pixel' and any(r['renderer'] != 'webgpu' for r in view['lighting'].values()):
raise RuntimeError('WebGPU fell back while measuring: ' + pg.evaluate('GPU.error'))
data['views'][f'{look}/{zoom:g}'] = view
for look in looks:
for zoom in [2, 6]:
@@ -193,6 +201,8 @@ def main():
r = pg.evaluate('seconds => perfRun(seconds)', args.seconds)
if r['actual_look'] != look:
raise RuntimeError('Look fell back during real run')
if look == 'pixel' and r['renderer'] != 'webgpu':
raise RuntimeError('WebGPU fell back during real run: ' + pg.evaluate('GPU.error'))
for key in ['interval', 'work', 'sim']:
r[key + '_ms'] = quantiles([s[key] for s in r['samples']])
data['runs'][f'{look}/{zoom}'] = r