Skip to content

fix: keep WebGL contexts across panel hides to stop renderer-swap ghosting#313

Merged
parsakhaz merged 1 commit into
mainfrom
webgl-context-keepalive
Jul 7, 2026
Merged

fix: keep WebGL contexts across panel hides to stop renderer-swap ghosting#313
parsakhaz merged 1 commit into
mainfrom
webgl-context-keepalive

Conversation

@parsakhaz

Copy link
Copy Markdown
Member

Summary

On v2.4.11+ (post-#310), switching tabs/panes can leave ghosted/overdrawn terminal rows — two frames of text interleaved in the same rows — persisting through live output until the manual Refresh button's full reset+replay. Reported on v2.4.13 in production use.

Root cause

Every panel hide disposed the WebGL addon and every show recreated it, swapping renderers (WebGL→DOM→WebGL) on each tab switch. A stale frame or texture-atlas state from one renderer can survive the swap; the light activation repaint (which replaced the old full reset+replay in #310) redraws the live renderer but cannot touch the stale layer, so the ghost persists. Same failure family as blank-canvas-on-refocus (#306) and the missed-repaint-after-blur fix in #310.

Change

  • Attach WebGL lazily on a panel's first show, then keep the context while the panel is mounted — hides no longer detach it, so routine tab switches involve no renderer swap at all
  • Detach only after the sustained app-blur timeout (10s) and on unmount (unchanged)
  • On the remaining reattach path (post-blur), clear the texture atlas before the deferred full repaint
  • Lifecycle JSDoc updated to document the policy and why

Context budget: contexts are bounded by the active session's mounted terminals (typically ≤5–8, under the browser's ~16 ceiling); idle contexts cost no GPU time; onContextLoss already falls back to the DOM renderer gracefully.

Pre-Merge Testing

  • Rapidly switch tabs/panes with a streaming Claude/Codex TUI — no ghosted/overdrawn rows, no manual Refresh needed
  • Blur app 15+ seconds, refocus — clean repaint (atlas-clear + deferred refresh path)
  • Long session with multiple terminals in split view — no WebGL context-loss fallbacks in logs
  • Battery saver mode activation still does its single full re-sync

Build Verification

  • pnpm typecheck passes
  • pnpm lint passes (0 errors)

…sting

Disposing WebGL on every panel hide and reattaching on show swaps
renderers (WebGL->DOM->WebGL) on every tab switch. A stale frame or
texture atlas from one renderer can survive into the next, producing
ghosted/overdrawn rows that persist through live output until a manual
full refresh — the same family as the blank-canvas-on-refocus bug
(#306) and the missed repaint after blur.

- Attach WebGL lazily on first show, keep the context while the panel
  is mounted (bounded by the active session's terminals, ~16-context
  ceiling is not approached; onContextLoss falls back to DOM renderer)
- Detach only after the sustained app-blur timeout and on unmount
- On reattach, clear the texture atlas before the deferred full repaint
- Update the TerminalPanel lifecycle doc to match
@parsakhaz parsakhaz merged commit c00196e into main Jul 7, 2026
16 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7654d9fff9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
// Lazy first attach: never-shown background panels stay on the DOM
// renderer; once attached, the context survives hides (see policy above).
if (!panelVisible && !webglAddonRef.current) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cap retained WebGL contexts for hidden terminals

When a user opens and visits many terminal tabs in one session, this guard only skips never-shown hidden panels; every previously shown hidden terminal keeps its WebGL context because the hide path no longer detaches it. PanelGroupView keeps terminal tabs mounted behind display:none, and the UI/IPC paths allow creating arbitrary terminal panels, so sessions with enough visited terminals can exceed Chromium's WebGL context budget and force context loss or renderer fallback in active terminals. Please add an eviction/cap for hidden WebGL contexts rather than retaining all of them indefinitely.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant