mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
fix(renderer): WebGL longtask auto-fallback to canvas renderer (#83)
The xterm WebGL renderer can stall the main thread for hundreds of ms under GPU pressure (driver hiccup, integrated-GPU memory pressure, hardware-accelerated browser layers contending for the GPU). Symptom: the page becomes intermittently unresponsive and Chrome eventually shows the "Page Unresponsive" dialog. Today the only mitigation is ?nowebgl, which the user has to remember and re-apply on every load. This patch installs a PerformanceObserver after WebGL init that watches for sustained main-thread stalls and falls back to the DOM renderer automatically: - Threshold: 3 long tasks of >=200ms each within a 30-second window. - 5-second grace period after init skips the noisy initial-load stalls so a slow first paint does not trip the guard. - On trigger: dispose the WebGL addon, write a sticky disable to localStorage with a reason and timestamp, and refresh the terminal so the canvas renderer takes over without a page reload. - Subsequent loads honor the sticky disable for 7 days, then auto- expire so users retry after a driver/Chrome update. - Force re-enable any time with ?webgl=force (also clears the sticky entry). - Existing ?nowebgl behaviour is unchanged. - The same disable path is reused by the existing onContextLoss callback so a hard context loss also persists across reloads. Files: - src/web/public/app.js: _initWebGL onContextLoss now persists + schedules the watchdog; new _installWebGLLongTaskGuard and _disableWebGLSticky helpers. - src/web/public/terminal-ui.js: WebGL init checks the sticky entry with 7-day expiry, honors ?webgl=force, threads sticky into skipWebGL alongside the existing mobile + ?nowebgl gates. PerformanceObserver longtask is widely supported (Chromium, Edge); the try/catch around .observe() makes Firefox/Safari (which lack the longtask entry type) silently no-op and just keep WebGL. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
edd494ec5f
commit
e87b03b6c2
@@ -174,10 +174,36 @@ Object.assign(CodemanApp.prototype, {
|
||||
// but the 48KB/frame flush cap in flushPendingWrites() now prevents
|
||||
// oversized terminal.write() calls that triggered the stalls.
|
||||
// Disable with ?nowebgl URL param if GPU issues return.
|
||||
// Auto-fallback: _initWebGL installs a long-task watchdog that disables
|
||||
// WebGL sticky in localStorage after repeated GPU stalls (see app.js).
|
||||
// Force re-enable after sticky disable with ?webgl=force.
|
||||
// Lazy-loaded: script downloaded only on desktop (saves 244KB on mobile).
|
||||
this._webglAddon = null;
|
||||
const skipWebGL = MobileDetection.getDeviceType() !== 'desktop';
|
||||
if (!skipWebGL && !new URLSearchParams(location.search).has('nowebgl')) {
|
||||
const _params = new URLSearchParams(location.search);
|
||||
if (_params.get('webgl') === 'force') {
|
||||
try { localStorage.removeItem('codeman-webgl-disabled'); } catch {}
|
||||
}
|
||||
const _stickyDisabled = (() => {
|
||||
try {
|
||||
const raw = localStorage.getItem('codeman-webgl-disabled');
|
||||
if (!raw) return false;
|
||||
const { at } = JSON.parse(raw);
|
||||
// Auto-expire after 7 days so we retry (driver may have been fixed)
|
||||
if (Date.now() - at > 7 * 24 * 60 * 60 * 1000) {
|
||||
localStorage.removeItem('codeman-webgl-disabled');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch { return false; }
|
||||
})();
|
||||
const skipWebGL =
|
||||
MobileDetection.getDeviceType() !== 'desktop' ||
|
||||
_params.has('nowebgl') ||
|
||||
_stickyDisabled;
|
||||
if (_stickyDisabled) {
|
||||
console.log('[CRASH-DIAG] WebGL sticky-disabled from prior stalls — DOM renderer in use. Re-enable: ?webgl=force');
|
||||
}
|
||||
if (!skipWebGL) {
|
||||
if (typeof WebglAddon !== 'undefined') {
|
||||
this._initWebGL();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user