Smooth look on WebGPU: WGSL port fed by GPU inputs and CPU overrides (t88 phase 2c)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -66,7 +66,7 @@ async function perfRender(lighting, overlays) {
|
||||
return { frame_ms, drawWorld_ms: draw, computeLight_ms: light, marks_ms: marks,
|
||||
overlays: Object.fromEntries(Object.entries(data).map(([key, d]) => [key, { ms_per_frame: d.ms / n, calls: d.calls }])),
|
||||
overlay_ms: Object.values(data).reduce((sum, d) => sum + d.ms / n, 0),
|
||||
scale: SM.scale, actual_look: SET.look, renderer: R.gpuOn ? 'webgpu' : 'legacy', override_cells: GPU.overrideCount || 0, gpu_ms };
|
||||
scale: R.gpuOn ? 1 : SM.scale, actual_look: SET.look, renderer: R.gpuOn ? 'webgpu' : 'legacy', override_cells: GPU.overrideCount || 0, gpu_ms };
|
||||
} finally { PERF_MARKS = false; }
|
||||
}
|
||||
function perfRun(seconds) {
|
||||
@@ -84,7 +84,7 @@ function perfRun(seconds) {
|
||||
requestAnimationFrame(frame);
|
||||
setTimeout(() => {
|
||||
window.__perfHalt(); PERF_FRAME = null; GAME.paused = true;
|
||||
resolve({ samples, end: perfState(), scale: SM.scale, actual_look: SET.look, renderer: R.gpuOn ? 'webgpu' : 'legacy', override_cells: GPU.overrideCount || 0, gpu_ms: R.gpuOn ? GPU.gpuMs : null });
|
||||
resolve({ samples, end: perfState(), scale: R.gpuOn ? 1 : SM.scale, actual_look: SET.look, renderer: R.gpuOn ? 'webgpu' : 'legacy', override_cells: GPU.overrideCount || 0, gpu_ms: R.gpuOn ? GPU.gpuMs : null });
|
||||
}, seconds * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,6 +61,6 @@ function perfView(look, zoom) {
|
||||
SET.look = look; SET.zoom = zoom; SET.lighting = 'full';
|
||||
resizeRender(); snapCamera();
|
||||
for (let k = 0; k < 5; k++) { R.frame++; drawWorld(); }
|
||||
if (look === 'smooth' && (!SM.ok || !R.smoothOn)) throw Error('Smooth look unavailable: ' + SM.why);
|
||||
return { grains: R.bw * R.bh, buffer: [R.bw, R.bh], scale: SM.scale };
|
||||
if (look === 'smooth' && (!R.smoothOn || (!R.gpuOn && !SM.ok))) throw Error('Smooth look unavailable: ' + SM.why);
|
||||
return { grains: R.bw * R.bh, buffer: [R.bw, R.bh], scale: R.gpuOn ? 1 : SM.scale };
|
||||
}
|
||||
|
||||
+2
-2
@@ -191,7 +191,7 @@ 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()):
|
||||
if 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:
|
||||
@@ -201,7 +201,7 @@ 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':
|
||||
if 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']])
|
||||
|
||||
@@ -11,13 +11,15 @@ for (let y = cy - 52; y < cy + 52; y++) for (let x = cx - 90; x < cx + 90; x++)
|
||||
for (let x = cx - 90; x < cx + 90; x++) { surfY[x] = cy + 16; dirtY[x] = cy + 30; graniteY[x] = cy + 38; basaltY[x] = cy + 46; }
|
||||
const fill = (x0,y0,w,h,m,T=20) => { for(let y=y0;y<y0+h;y++)for(let x=x0;x<x0+w;x++)setCell(y*W+x,m,T,F_NAT); };
|
||||
fill(cx-62,cy+6,22,16,WATER); fill(cx-34,cy+11,16,11,MAGMA,1450);
|
||||
fill(cx-33,cy+3,8,8,FIRE,900); fill(cx-12,cy+17,15,6,SAND);
|
||||
fill(cx-33,cy+3,8,8,FIRE,900); fill(cx-32,cy-4,7,6,SMOKE); fill(cx-12,cy+17,15,6,SAND);
|
||||
fill(cx-10,cy+24,12,5,STONE,1100);
|
||||
for(let y=cy-20;y<cy+16;y++)for(let x=cx-58;x<cx-54;x++)bgm[y*W+x]=WOOD;
|
||||
for(let y=cy-28;y<cy-12;y++)for(let x=cx-68;x<cx-44;x++)if((x-cx+56)**2+(y-cy+20)**2<130)bgm[y*W+x]=LEAVES;
|
||||
for(let x=cx-40;x<cx-34;x++)digp[(cy+24)*W+x]=160;
|
||||
const place=(code,v,dx,dy)=>{const e=placeBlock(code,v,(cx+dx)>>2,(cy+dy)>>2,true);if(e)throw Error(e);};
|
||||
for(let dx=-36;dx<-12;dx+=4)place(BP_BELT,1,dx,-12);
|
||||
place(BP_FILTER,128,-12,-12); filterCfg.set(((cy-12)>>2)*BW+((cx-12)>>2),{m:[SAND],inv:1});
|
||||
place(BP_SLOPE_BL,RSTONE,44,-12);
|
||||
place(BP_SCREW,1,-4,-12); place(BP_SCREW,4,0,-12);
|
||||
place(BP_BELT_UP,1,16,-12);place(BP_BELT_UP,1,20,-16);
|
||||
place(BP_PIPE,0,32,-12);place(BP_PIPE,0,36,-12);
|
||||
|
||||
+5
-3
@@ -92,6 +92,8 @@ def main():
|
||||
for code in [pathlib.Path(a.setup).read_text() if a.setup else None, a.js]:
|
||||
if code:
|
||||
pg.evaluate(f'() => {{ {code}\n}}')
|
||||
# Setup scenes can change surfY after the renderer cached the world's horizon.
|
||||
pg.evaluate('SM.surf = -1')
|
||||
if a.ticks:
|
||||
pg.evaluate(f'for (let k = 0; k < {a.ticks}; k++) simTick();')
|
||||
pg.evaluate(f"""GAME.paused = true; $('hud').hidden = {'false' if a.hud else 'true'}; GAME.hidePreviews = {'false' if a.previews else 'true'};
|
||||
@@ -103,7 +105,7 @@ def main():
|
||||
pg.evaluate("() => { window.__frozenNow = 5000; window.requestAnimationFrame = () => 0; }")
|
||||
pg.wait_for_timeout(100)
|
||||
pg.evaluate("() => { R.frame = 999; if (typeof SM !== 'undefined') SM.t0 = 0; frame(lastRender + 1000); }")
|
||||
if a.look == 'pixel' and a.renderer == 'webgpu' and not pg.evaluate('R.gpuOn'):
|
||||
if a.renderer == 'webgpu' and not pg.evaluate('R.gpuOn'):
|
||||
raise RuntimeError('WebGPU fell back: ' + pg.evaluate('GPU.error'))
|
||||
kw = {}
|
||||
if a.clip:
|
||||
@@ -111,9 +113,9 @@ def main():
|
||||
kw['clip'] = {'x': x, 'y': y, 'width': w, 'height': h}
|
||||
pathlib.Path(a.out).parent.mkdir(parents=True, exist_ok=True)
|
||||
pg.screenshot(path=a.out, **kw)
|
||||
note = pg.evaluate("SET.look === 'smooth' ? (SM.ok ? 'smooth look' : 'smooth look FAILED: ' + SM.why) : 'pixel look'")
|
||||
note = pg.evaluate("SET.look === 'smooth' ? (R.smoothOn ? 'smooth look' : 'smooth look FAILED: ' + SM.why) : 'pixel look'")
|
||||
b.close()
|
||||
print(f"saved {a.out} ({note}, {a.renderer if a.look == 'pixel' else 'legacy'})")
|
||||
print(f"saved {a.out} ({note}, {a.renderer})")
|
||||
for e in errors:
|
||||
print('ERROR', e)
|
||||
sys.exit(1 if errors else 0)
|
||||
|
||||
Reference in New Issue
Block a user