Files
RecipesCam/web/spike/gpu.html
T

115 lines
4.1 KiB
HTML

<!doctype html>
<html>
<head><meta charset="utf-8"><title>W0 GPU bench</title></head>
<body>
<pre id="out">running…</pre>
<script src="/bin/full/canvaskit.js"></script>
<script>
(async () => {
const CanvasKitInit = window.CanvasKitInit;
const log = (s) => { document.getElementById('out').textContent += '\n' + s; };
const results = {};
try {
const CK = await CanvasKitInit({ locateFile: (f) => '/bin/full/' + f });
const img = await fetch('/samples/p2.jpg').then((r) => r.arrayBuffer()).then((b) => new Uint8Array(b));
let t0 = performance.now();
const src = CK.MakeImageFromEncoded(img);
log(`decode 12MP: ${(performance.now() - t0).toFixed(0)}ms ${src.width()}x${src.height()}`);
const W = src.width();
const H = src.height();
const sizes = [
{ name: '1024', w: 1024, h: Math.round((1024 * H) / W) },
{ name: '2048', w: 2048, h: Math.round((2048 * H) / W) },
{ name: 'full', w: W, h: H },
];
const tone = CK.RuntimeEffect.Make(
'uniform shader src; uniform float a; vec4 main(vec2 p){ vec4 c = src.eval(p); return vec4(c.rgb*(1.0+a), c.a);}'
);
const sharpen = CK.RuntimeEffect.Make(
'uniform shader img; uniform float2 texel; uniform float amount; vec4 main(vec2 p){ vec4 c=img.eval(p); vec4 n=img.eval(p+float2(0.0,-texel.y)); vec4 s=img.eval(p+float2(0.0,texel.y)); vec4 w=img.eval(p+float2(-texel.x,0.0)); vec4 e=img.eval(p+float2(texel.x,0.0)); return vec4(clamp(c.rgb*(1.0+4.0*amount)-amount*(n.rgb+s.rgb+w.rgb+e.rgb),0.0,1.0), c.a);}'
);
log('runtime effects: tone=' + !!tone + ' sharpen=' + !!sharpen);
for (const s of sizes) {
log(`\n[webgl canvas ${s.w}x${s.h}]`);
const canvas = new OffscreenCanvas(s.w, s.h);
const gl0 = canvas.getContext('webgl2');
const dbg = gl0 && gl0.getExtension('WEBGL_debug_renderer_info');
if (dbg) log(' GL: ' + gl0.getParameter(dbg.UNMASKED_RENDERER_WEBGL));
t0 = performance.now();
const surface = CK.MakeWebGLCanvasSurface(canvas);
log(` MakeWebGLCanvasSurface: ${(performance.now() - t0).toFixed(0)}ms ok=${!!surface}`);
if (!surface) continue;
const cv = surface.getCanvas();
results[s.name] = {};
const shader = src.makeShaderOptions(CK.TileMode.Clamp, CK.TileMode.Clamp, CK.FilterMode.Linear, CK.MipmapMode.None);
const toneShader = tone.makeShaderWithChildren([0.2], [shader]);
const draw = () => {
const p = new CK.Paint();
p.setShader(toneShader);
cv.drawRect(CK.XYWHRect(0, 0, s.w, s.h), p);
surface.flush();
p.delete();
};
draw(); // warm-up: shader compile + texture upload
const measure = (label, fn) => {
fn();
const t = performance.now();
fn();
const ms = performance.now() - t;
log(` ${label.padEnd(26)} ${ms.toFixed(0)}ms`);
results[s.name][label] = ms;
};
measure('tone skSL pass', draw);
measure('clarity skSL 5-tap', () => {
const snap = surface.makeImageSnapshot();
const child = snap.makeShaderOptions(CK.TileMode.Clamp, CK.TileMode.Clamp, CK.FilterMode.Linear, CK.MipmapMode.None);
const sh = sharpen.makeShaderWithChildren([0.3, 1, 1], [child]);
const p = new CK.Paint();
p.setShader(sh);
cv.drawRect(CK.XYWHRect(0, 0, s.w, s.h), p);
surface.flush();
p.delete(); sh.delete(); child.delete(); snap.delete();
});
measure('blur sigma=40', () => {
const snap = surface.makeImageSnapshot();
const p = new CK.Paint();
p.setImageFilter(CK.ImageFilter.MakeBlur(40, 40, CK.TileMode.Clamp, null));
cv.clear(CK.Color(0, 0, 0, 0));
cv.drawImage(snap, 0, 0, p);
surface.flush();
p.delete(); snap.delete();
});
let enc = -1;
measure('jpeg q95 encode', () => {
const snap = surface.makeImageSnapshot();
const b = snap.encodeToBytes(CK.ImageFormat.JPEG, 95);
enc = b ? b.length : -1;
snap.delete();
});
log(' encoded bytes: ' + enc);
surface.delete();
}
window.__results = results;
log('\nDONE');
document.title = 'done';
} catch (e) {
log('ERROR ' + (e && e.stack ? e.stack : e));
document.title = 'error';
}
})();
</script>
</body>
</html>