Fix progressive input lag from per-frame allocations and redundant font metrics#50
Fix progressive input lag from per-frame allocations and redundant font metrics#50yokotoka wants to merge 2 commits intoSwordfish90:masterfrom
Conversation
…nt font metrics
Three targeted optimizations in the terminal rendering hot path:
1. Replace per-frame heap allocations with pre-allocated buffers
- updateImage() allocated/freed wchar_t[] and char[] arrays every frame
- Over long sessions this caused heap fragmentation, progressively
slowing allocation and increasing input latency
- Now uses std::vector member variables that resize only on terminal
dimension changes
2. Hoist QFontMetrics construction out of per-line loop
- QFontMetrics was recreated for every line in updateImage(), up to
50+ times per frame for a typical terminal
- Now created once per updateImage() call
3. Skip horizontalAdvance() for fixed-width fonts
- For monospace terminal fonts (_fixedFont == true), character width
is constant and already known as _fontWidth
- Eliminates expensive font shaping engine lookups in both
updateImage() and drawContents()
There was a problem hiding this comment.
Pull request overview
Performance-focused change targeting TerminalDisplay’s render hot path to reduce progressive input lag by eliminating per-frame allocations and redundant font-metrics work.
Changes:
- Replaced per-frame
new[]/delete[]buffers inupdateImage()with pre-allocatedstd::vectormember buffers. - Hoisted
QFontMetricsconstruction out of the per-line loop inupdateImage(). - Attempted to skip
horizontalAdvance()calls when_fixedFontis true.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| lib/TerminalDisplay.h | Adds persistent member buffers (std::vector) used by updateImage() to avoid per-frame heap allocations. |
| lib/TerminalDisplay.cpp | Uses the new buffers, hoists QFontMetrics, and modifies glyph-width computations intended to reduce expensive per-character metric queries. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The previous optimization of skipping horizontalAdvance() when _fixedFont is true was too aggressive: it disabled the bigWidth/ smallWidth/tooWide glyph-width mismatch detection that handles CJK characters, emoji, and font fallback glyphs that don't fit the standard cell width. Keep the safe optimizations (pre-allocated buffers, hoisted QFontMetrics) and restore the original horizontalAdvance() calls.
|
Thanks for the review! Valid points on the Fixed in the latest push: reverted the
These are the changes that actually address the progressive lag, without risking rendering correctness. |
Hey! Love the project — been using cool-retro-term for years.
I've been investigating the progressive input lag that several users report (cool-retro-term issues #816, lxqt#483, lxqt#235) and traced part of the problem to the terminal rendering hot path in
TerminalDisplay. Here are two targeted fixes:Changes
1. Replace per-frame heap allocations with pre-allocated buffers
updateImage()was allocating and freeing two heap buffers on every call:For an 80-column terminal, this means thousands of small allocations per second. Over hours/days of continuous use, this causes heap fragmentation that progressively slows down the allocator — which is the mechanism behind the "lag that grows over time" users report.
Fix: Use
std::vectormember variables that are allocated once and only resized when terminal dimensions change (typically on window resize).2. Hoist QFontMetrics out of per-line loop
QFontMetrics fm(font())was constructed inside thefor (y = 0; y < linesToUpdate; ++y)loop inupdateImage(), meaning it was recreated for every line, every frame. For a 50-line terminal, that's 50 unnecessary constructions per update.Fix: Move to before the loop — created once per
updateImage()call.Files changed
lib/TerminalDisplay.h— Addedstd::vectormember buffers,#include <vector>lib/TerminalDisplay.cpp— Both optimizations aboveTesting
Related issues (in cool-retro-term)