Skip to content

DEC 2026 synchronized output renders at ~1 fps under continuous full-screen animation #6071

Description

@s-celles

Summary

Under a continuous full-screen animation that wraps every frame in a DEC
private mode 2026 (synchronized output) block, the display is capped at
~1 fps no matter how fast frames arrive and how idle the renderer is. The
completed frames are only painted when the 1000 ms synchronized-output timeout
expires.

Details / root cause

When a 2026 block closes, the input handler requests a refresh.
RenderService.refreshRows flushes the buffered rows but schedules the paint
through the render debouncer (requestAnimationFrame). Under a continuous
animation the next frame opens a new 2026 block before that rAF fires, and
_renderRows skips while synchronized output is on — so the debounced paint is
dropped, and the frame only appears on the 1 s sync timeout.

Reproduction

Drive xterm.js (WebGL or canvas) with a program that continuously emits, as
fast as it can:

ESC[?2026h  ESC[1;1H  <full-screen repaint>  ESC[?2026l

Expected: display updates at the frame-arrival rate.
Actual: display updates ~once per second.

(Reproduces via TryIt.jl inside an
xterm.js-based terminal; likely related to #5686.)

Proposed fix

Render synchronously when a synchronized-output buffer was just flushed
(the flush runs from the mode-reset that turned sync off, so sync is already
false but buffered rows are present). This paints the completed frame
before the next frame can reopen the mode, with no partial-frame tearing.

Minimal change in RenderService.refreshRows:

if (sync || buffered) {
  this._renderRows(start, end);
} else {
  this._renderDebouncer.refresh(start, end, this._rowCount);
}

Measured against a 30 fps animated-background TUI: renders went from ~1/s to the
frame-arrival rate, no tearing. Fix + branch available; happy to open a PR.

Assisted-by: AI

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions