Waiting
-
-
GPU Diagnostics
-- Quick CEF-compatible checks for WebGL, WebGL2, Canvas 2D, GPU renderer strings, - and browser runtime details. Use this page to verify graphics support after GPU - flag or runtime changes. -
+ +
+
+
+
+
+ GPU Diagnostics
+ / + not run +
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
+
-
+
+
-
-
+
+
-
-
+
+
+
-
+ Overall
+ WAITING
-
-
+
+
+
+
+
-
+ WebGL 1
+ WAITING
+
+
+
+
+
+ Waiting
- WebGL
- - -
+
-
+ WebGL 2
+ WAITING
+
+
+
+
+
+ Waiting
- WebGL2
- - -
+
-
+ Canvas 2D
+ WAITING
+
+
+
+
+
+ Waiting
- Canvas 2D
- - -
+
-
+ WebGPU
+ WAITING
+
+
+
+
+ Detailed Information
-Waiting for diagnostics...-
+
-
+ /* webgl 2 */
+ log('[WebGL2] Initialising context…', 'dim');
+ try {
+ const t1 = performance.now();
+ report.webgl2 = drawWebGL('webgl2-canvas', 2);
+ const elapsed = ((performance.now() - t1) / 1).toFixed(1);
+ if (report.webgl2.ok) {
+ log(`[WebGL2] OK — ${report.webgl2.renderer.unmaskedRenderer || report.webgl2.renderer.renderer} (${elapsed} ms)`, 'ok');
+ setBadge('badge-webgl2', 'ok', 'OK');
+ kvFill('kv-webgl2', [
+ ['Status', 'Available', 'ok'],
+ ['Renderer', report.webgl2.renderer.unmaskedRenderer || report.webgl2.renderer.renderer],
+ ['Vendor', report.webgl2.renderer.unmaskedVendor || report.webgl2.renderer.vendor],
+ ['Version', report.webgl2.renderer.version],
+ ['GLSL', report.webgl2.renderer.glslVersion],
+ ['Extensions', `${report.webgl2.extensions.length} supported`],
+ ['Init time', `${elapsed} ms`],
+ ]);
+ } else {
+ log(`[WebGL2] UNAVAIL — ${report.webgl2.error}`, 'warn');
+ setBadge('badge-webgl2', 'warn', 'N/A');
+ kvFill('kv-webgl2', [['Status', 'Unavailable', 'warn'], ['Reason', report.webgl2.error]]);
+ }
+ } catch (e) {
+ report.webgl2 = { ok: false, error: e.message };
+ log(`[WebGL2] ERROR — ${e.message}`, 'err');
+ setBadge('badge-webgl2', 'err', 'ERROR');
+ kvFill('kv-webgl2', [['Status', 'Error', 'err'], ['Error', e.message]]);
+ }
+
+ /* canvas 2d */
+ log('[Canvas2D] Running draw stress test (900 ops)…', 'dim');
+ try {
+ const t1 = performance.now();
+ report.canvas2d = testCanvas2D();
+ const elapsed = ((performance.now() - t1) / 1).toFixed(1);
+ if (report.canvas2d.ok) {
+ log(`[Canvas2D] OK — ${report.canvas2d.drawTimeMs} ms draw time`, 'ok');
+ setBadge('badge-canvas2d', 'ok', 'OK');
+ kvFill('kv-canvas2d', [
+ ['Status', 'Working', 'ok'],
+ ['Draw time', `${report.canvas2d.drawTimeMs} ms`],
+ ['Ops', `${report.canvas2d.ops} arcs`],
+ ['Compositing', report.canvas2d.compositing],
+ ['Smoothing', String(report.canvas2d.smoothingEnabled)],
+ ]);
+ } else {
+ log(`[Canvas2D] FAIL — ${report.canvas2d.error}`, 'err');
+ setBadge('badge-canvas2d', 'err', 'FAIL');
+ kvFill('kv-canvas2d', [['Status', 'Unavailable', 'err'], ['Error', report.canvas2d.error]]);
+ }
+ } catch (e) {
+ report.canvas2d = { ok: false, error: e.message };
+ log(`[Canvas2D] ERROR — ${e.message}`, 'err');
+ setBadge('badge-canvas2d', 'err', 'ERROR');
+ kvFill('kv-canvas2d', [['Status', 'Error', 'err'], ['Error', e.message]]);
+ }
+
+ /* webgpu */
+ log('[WebGPU] Probing adapter…', 'dim');
+ report.webgpu = await probeWebGPU();
+ if (report.webgpu.ok) {
+ log(`[WebGPU] Adapter found — ${report.webgpu.vendor} / ${report.webgpu.architecture}`, 'ok');
+ setBadge('badge-webgpu', 'ok', 'OK');
+ kvFill('kv-webgpu', [
+ ['Status', 'Available', 'ok'],
+ ['Vendor', report.webgpu.vendor],
+ ['Architecture', report.webgpu.architecture],
+ ['Device', report.webgpu.device],
+ ['Description', report.webgpu.description],
+ ]);
+ } else {
+ log(`[WebGPU] UNAVAIL — ${report.webgpu.reason}`, 'warn');
+ setBadge('badge-webgpu', 'warn', 'N/A');
+ kvFill('kv-webgpu', [['Status', 'Unavailable', 'warn'], ['Reason', report.webgpu.reason]]);
+ }
+
+ /* capability table — prefer WebGL2, fall back to WebGL1 */
+ const glForCaps = report.webgl2.ok ? report.webgl2 : report.webgl.ok ? report.webgl : null;
+ const extensions = glForCaps ? glForCaps.extensions : [];
+ if (glForCaps) {
+ const capRows = [...glForCaps.caps];
+
+ // Shader precision section
+ capRows.push({ section: 'Shader Precision' });
+ glForCaps.precisions.forEach(([k, v]) => capRows.push({ name: k, val: v }));
+
+ // Context attributes
+ capRows.push({ section: 'Context Attributes' });
+ glForCaps.contextAttrs.forEach(([k, v]) => capRows.push({ name: k, val: v }));
+
+ renderCapTable(capRows, extensions);
+ }
+
+ /* overall */
+ const healthy = report.webgl.ok && report.canvas2d.ok;
+ const gl2ok = report.webgl2.ok;
+ const overallLevel = healthy ? 'ok' : 'err';
+ const overallText = healthy ? 'PASS' : 'DEGRADED';
+ setBadge('badge-overall', overallLevel, overallText);
+
+ kvFill('kv-overall', [
+ ['Status', healthy ? 'All critical tests passed' : 'One or more critical tests failed', healthy ? 'ok' : 'err'],
+ ['WebGL 1', report.webgl.ok ? 'OK' : 'FAIL', report.webgl.ok ? 'ok' : 'err'],
+ ['WebGL 2', gl2ok ? 'OK' : 'N/A', gl2ok ? 'ok' : 'warn'],
+ ['Canvas 2D', report.canvas2d.ok ? 'OK' : 'FAIL', report.canvas2d.ok ? 'ok' : 'err'],
+ ['WebGPU', report.webgpu.ok ? 'OK' : 'N/A', report.webgpu.ok ? 'ok' : 'warn'],
+ ]);
+
+ const totalMs = (performance.now() - t0.v).toFixed(1);
+ log(`Run complete in ${totalMs} ms`, healthy ? 'ok' : 'warn');
+
+ reportData = report;
+ }
+
+ /* ── copy report ── */
+ $('btn-copy').addEventListener('click', () => {
+ if (!reportData) return;
+ navigator.clipboard.writeText(JSON.stringify(reportData, null, 2)).then(() => {
+ const btn = $('btn-copy');
+ btn.textContent = 'Copied!';
+ btn.classList.add('flash');
+ setTimeout(() => { btn.textContent = 'Copy Report'; btn.classList.remove('flash'); }, 1200);
+ });
+ });
+
+ $('btn-run').addEventListener('click', runDiagnostics);
+ window.addEventListener('DOMContentLoaded', runDiagnostics);
+
+ System
+
+
+
+
+