Commit Graph

5 Commits

Author SHA1 Message Date
Brennan Benson 7c0b84f2b6
fix(terminal): invalidate cached glyphs when WebGL atlas changes (#8899)
* feat(terminal): add flag-gated render-desync sentinel for WebGL panes

Detects the buffer-clean/render-stale glyph garble class in the field: per
visible WebGL pane, compare the cells the xterm buffer says hold glyphs
against the ink actually present on the canvas, sampled in the same task as
a forced synchronous redraw so a divergence proves the render model/atlas is
wrong rather than a missed present. A trip requires the same screen cells to
stay divergent across three samples (real desync is pinned; scroll lag moves),
then records a webgl-render-desync breadcrumb, stashes evidence (canvas PNG +
buffer text) for bug reports, and runs the same shared-atlas recovery a tab
reveal performs, so a stuck-garbled pane self-heals within seconds.

Off by default; arm on any build via
localStorage.setItem('orca:render-desync-sentinel', '1') and reload.

* fix(terminal): invalidate glyph cache on atlas replacement

Reproduce the WebGL atlas identity mismatch with two live terminals and force cached geometry to rebuild whenever a different shared atlas is attached. Persist flag-gated render-desync evidence and retain the investigation tooling used to validate the field signature.

* fix(terminal): harden render desync diagnostics

* docs(reliability): clarify Linux WebGL evidence gap
2026-07-17 16:16:17 -07:00
Brennan Benson 59a7fffcd6
fix(terminal): keep WebGL glyph atlas pages within the shader sampler budget (#8672)
* fix(terminal): keep WebGL glyph atlas pages within the shader sampler budget

The fragment shader has sampler slots for maxAtlasPages (16 on most Macs)
and leaves outColor uninitialized for any higher page index, so glyphs
rasterized onto pages past the budget render as garbled pixels. Long
sessions grow past the budget via the merge fallback, and the previous
wipe fix re-activated those unbindable pages, so every atlas wipe
re-allocated glyphs onto them (post-wipe allocation prefers the last,
highest-index active page) and garbled whole panes mid-stream.

Fix, matching the direction xterm.js maintainers are pursuing upstream
(xtermjs/xterm.js#6043): a shared _evictAllPages resets the atlas to one
fresh page, called from clearTexture and from the two allocation paths
that could otherwise push a page past the budget (merge fallback and
oversized-glyph page creation), so the page count can never exceed the
renderer's texture capacity. Defensive backstops: a one-time warn plus
bind-loop clamp, and an else branch in the generated shader so an
unexpected overflow renders blank instead of undefined pixels.

* test(terminal): cover WebGL atlas sampler budget

* fix(terminal): align WebGL atlas invalidation source
2026-07-14 14:48:21 -07:00
Jinjing 969c0ef147
fix: strip trailing whitespace from xterm webgl patch (#8330)
Blank context lines in the @xterm/addon-webgl patch had trailing spaces,
which made git diff --check fail. Strip only that whitespace and refresh
the pnpm patchedDependencies hash so the lockfile stays consistent.
2026-07-11 17:43:02 -07:00
Brennan Benson 7a5632584a
Fix WebGL glyph atlas wipe no-op, retry-consume, and page-overflow in addon patch (#8150)
TextureAtlas.clearTexture() guarded on pages[0].currentRow being at the
origin — but merged pages are never written through currentRow, so once a
page merge lands a merged page at index 0, every atlas wipe for the rest
of the session silently no-ops: no content clear, no glyph-cache clear,
no clear-model generation bump. Recoveries degrade to placebo, the glyph
cache grows unboundedly, and the session drifts into a merge-heavy state
where stale vertex data paints the tiny-glyph garble seen after
unfocus-then-paste into Claude Code.

Fixes in @xterm/addon-webgl patch (lib bundles + readable src):
- clearTexture(): guard on any-page-has-glyphs; restore _activePages
  after wiping (merges permanently shrink the active set)
- AtlasPage.clear(): reset _glyphs/_usedPixels so wiped pages stop
  distorting merge-candidate selection
- renderRows merge-retry loop: check the retry budget before
  beginFrame() so tripping the limit cannot consume the clear-model
  notification and strand a stale model
- GlyphRenderer.render(): clamp texture binds to the sampler budget so
  pages overflowing maxAtlasPages cannot TypeError and kill rendering

Verified: two-terminal shared-atlas harness (storm scenario proves the
no-op and its fix; 6-seed adversarial fuzzer clean), 405 unit tests in
pane-manager/atlas-recovery suites, terminal-rendering golden e2e.
2026-07-10 14:44:38 -07:00
Jinjing d4084ba982
fix(terminal): force model clear when webgl texture atlas is reset (#6868)
Patch @xterm/addon-webgl so clearTexture() and page merge/delete operations
request a model clear and bump a generation counter. Without this, the renderer
keeps drawing glyphs against a stale atlas after the texture is reset, leaving
garbled or blank cells until the next full repaint.

Co-authored-by: Orca <help@stably.ai>
2026-06-30 01:06:45 -07:00