// Drives spike/gpu.html in headless Chromium: is a WebGL-backed CanvasKit // surface fast enough to replace the CPU raster path (which measured 3.2s for a // single 12MP tone pass in Node)? Run: // node spike/gpu-bench.mjs import http from 'node:http'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { chromium } from 'playwright-core'; const here = path.dirname(fileURLToPath(import.meta.url)); const webRoot = path.resolve(here, '..'); const SAMPLES = process.env.W0_SAMPLES ?? '/tmp/w0'; const CK_BIN = path.join(webRoot, 'node_modules/canvaskit-wasm/bin'); const routes = [ { prefix: '/bin/', dir: CK_BIN }, { prefix: '/samples/', dir: SAMPLES }, { prefix: '/', dir: path.join(webRoot, 'spike') }, ]; const MIME = { '.js': 'text/javascript', '.wasm': 'application/wasm', '.html': 'text/html', '.jpg': 'image/jpeg', '.png': 'image/png' }; const server = http.createServer((req, res) => { const url = decodeURIComponent(req.url.split('?')[0]); const route = routes.find((r) => url.startsWith(r.prefix)); if (!route) { res.writeHead(404).end(); return; } const rel = url.slice(route.prefix.length) || 'gpu.html'; const file = path.join(route.dir, rel); fs.readFile(file, (err, data) => { if (err) { res.writeHead(404).end(String(err)); return; } res.writeHead(200, { 'content-type': MIME[path.extname(file)] ?? 'application/octet-stream' }); res.end(data); }); }); await new Promise((r) => server.listen(0, '127.0.0.1', r)); const port = server.address().port; console.log(`serving on ${port}`); const browser = await chromium.launch({ // The cached playwright build is chromium-1228 while playwright-core wants // 1243; point straight at the cached binary instead of downloading one. executablePath: process.env.CHROME_PATH ?? '/home/locpham/.cache/ms-playwright/chromium-1228/chrome-linux64/chrome', args: ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader', '--no-sandbox'], }); const page = await browser.newPage(); page.on('console', (m) => console.log('[browser]', m.text())); page.on('pageerror', (e) => console.log('[pageerror]', e.message)); await page.goto(`http://127.0.0.1:${port}/gpu.html`, { waitUntil: 'load' }); await page.waitForFunction(() => document.title === 'done' || document.title === 'error', null, { timeout: 180000 }); console.log(await page.textContent('#out').catch(() => '(no output element)')); const results = await page.evaluate(() => window.__results ?? null); console.log('\njson:', JSON.stringify(results)); await browser.close(); server.close();