Add CanvasKit web engine spike + W0 findings (recipes-web)
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user