fix: stop ~0.6 s terminal echo lag on Linux WebKitGTK (#224) - #313
Conversation
WebKitGTK's non-DMABUF path (forced on NVIDIA) presents a WebGL canvas one draw behind, so terminal echo only showed on the next cursor-blink redraw (~600 ms). Creating the xterm WebGL addon with preserveDrawingBuffer on Linux presents each frame immediately.
Investigation report for #224 (supporting PR #313)TL;DR
Environment
Method
Test table
Correction recorded during the investigation: a first round of page-variant runs used Which hop carries the latencyAfter xterm's render call returns. The in-app pipeline takes 5–16 ms per key; the remaining ~600 ms is WebKit presenting the WebGL canvas's previous buffer until the next canvas draw.
Root causewebkit2gtk-4.1 2.52.6, when the DMABUF renderer is disabled, presents a WebGL canvas created with
Notes on the issue thread:
FixOn branch
diff --git a/src/components/terminal/MultiplayerTerminalView.tsx b/src/components/terminal/MultiplayerTerminalView.tsx
--- a/src/components/terminal/MultiplayerTerminalView.tsx
+++ b/src/components/terminal/MultiplayerTerminalView.tsx
@@ -1,7 +1,7 @@
-import { WebglAddon } from "@xterm/addon-webgl";
+import { createWebglAddon } from "@/utils/webglAddon";
@@ -47,7 +47,7 @@
- term.loadAddon(new WebglAddon());
+ term.loadAddon(createWebglAddon());
diff --git a/src/hooks/useTerminal.ts b/src/hooks/useTerminal.ts
--- a/src/hooks/useTerminal.ts
+++ b/src/hooks/useTerminal.ts
@@ -2,7 +2,7 @@
-import { WebglAddon } from "@xterm/addon-webgl";
+import { createWebglAddon } from "@/utils/webglAddon";
@@ -1046,7 +1046,7 @@
- term.loadAddon(new WebglAddon());
+ term.loadAddon(createWebglAddon());
diff --git a/src/utils/webglAddon.ts b/src/utils/webglAddon.ts
new file mode 100644
--- /dev/null
+++ b/src/utils/webglAddon.ts
@@ -0,0 +1,10 @@
+import { WebglAddon } from "@xterm/addon-webgl";
+
+// WebKitGTK presents a WebGL canvas one draw behind unless the buffer is preserved,
+// so terminal echo only appears on the next redraw (cursor blink, ~600 ms). #224
+const PRESERVE_DRAWING_BUFFER =
+ typeof navigator !== "undefined" && /Linux/.test(navigator.userAgent) && !/Android/i.test(navigator.userAgent);
+
+export function createWebglAddon(): WebglAddon {
+ return new WebglAddon(PRESERVE_DRAWING_BUFFER);
+}UpstreamFiled as https://bugs.webkit.org/show_bug.cgi?id=324549 (repro page attached there). Standalone repro pageSave the page below as <!doctype html><title>webgl-auto</title>
<style>body{margin:0;background:#123456}#c,#s{position:absolute;top:20px;width:100px;height:100px}#c{left:20px}#s{left:140px}</style>
<canvas id=c width=100 height=100></canvas><div id=s></div>
<script>
const gl=c.getContext('webgl2',{antialias:false,preserveDrawingBuffer:false});
const cols=['ff0000','00ff00','0000ff','ffff00','00ffff','ff00ff','ffffff','000000'];let i=0;
function step(){const h=cols[i++%8];requestAnimationFrame(()=>{s.style.background='#'+h;
const v=[0,2,4].map(k=>parseInt(h.substr(k,2),16)/255);gl.clearColor(v[0],v[1],v[2],1);gl.clear(gl.COLOR_BUFFER_BIT);});}
step();setInterval(step,1000);
</script>Follow-up findingThe DMABUF renderer's failure on NVIDIA + Wayland is an explicit-sync protocol error ( |
|
Related: #315 keeps the DMABUF renderer on native Wayland + NVIDIA by setting This PR is still needed wherever DMABUF stays off:
The two PRs are independent and can merge in either order. |
Fixes #224.
What
On Linux, the xterm WebGL addon is now created with
preserveDrawingBuffer: true. This goes through a smallcreateWebglAddon()helper used by both terminal views (useTerminal.tsandMultiplayerTerminalView.tsx). Other platforms keep xterm's default.Why
With
WEBKIT_DISABLE_DMABUF_RENDERER=1, WebKitGTK shows a WebGL canvas one draw behind when the canvas hasantialias: false(as xterm's does) andpreserveDrawingBuffer: false. A typed character was only drawn to the screen on xterm's next redraw, which with cursor blink on is the 600 ms blink tick. NVIDIA users always end up on this path, because the DMABUF renderer fails on NVIDIA andlinux_gfx.rsturns it off. Upstream bug: https://bugs.webkit.org/show_bug.cgi?id=324549Keydown → IPC → PTY → xterm render takes 5–16 ms. All of the delay came after xterm had drawn.
Testing
Tested on an RTX 5070 with driver 610.57.04, KDE 6.7.4 and webkit2gtk-4.1 2.52.6. Latency was measured by injecting keys and polling screen pixels.
seq 1 1000000): 1.99 s with the fix vs 2.09 s without, so no slowdown.pnpm run buildpasses; its one chunk-size warning is also present ondev.🤖 Generated with Claude Code