[PR #8621] Eliminate more transient allocations: Titles and invalid rectangles and bitmap runs and utf8 conversions #27263

Closed
opened 2026-01-31 09:20:56 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/microsoft/terminal/pull/8621

State: closed
Merged: Yes


References

PR Checklist

Detailed Description of the Pull Request / Additional comments

Window Title Generation

Every time the renderer checks the title, it's doing two bad things that
I've fixed:

  1. It's assembling the prefix to the full title doing a concatenation.
    No one ever gets just the prefix ever after it is set besides the
    concat. So instead of storing prefix and the title, I store the
    assembled prefix + title and the bare title.
  2. A copy must be made because it was returning std::wstring instead
    of std::wstring&. Now it returns the ref.

Dirty Area Return

Every time the renderer checks the dirty area, which is sometimes
multiple times per pass (regular text printing, again for selection,
etc.), a vector is created off the heap to return the rectangles. The
consumers only ever iterate this data. Now we return a span over a
rectangle or rectangles that the engine must store itself.

  1. For some renderers, it's always a constant 1 element. They update
    that 1 element when dirty is queried and return it in the span with a
    span size of 1.
  2. For other renderers with more complex behavior, they're already
    holding a cached vector of rectangles. Now it's effectively giving
    out the ref to those in the span for iteration.

Bitmap Runs

The til::bitmap used a std::optional<std::vector<til::rectangle>>
inside itself to cache its runs and would clear the optional when the
runs became invalidated. Unfortunately doing .reset() to clear the
optional will destroy the underlying vector and have it release its
memory. We know it's about to get reallocated again, so we're just going
to make it a std::pmr::vector and give it a memory pool.

The alternative solution here was to use a bool and
std::vector<til::rectangle> and just flag when the vector was invalid,
but that was honestly more code changes and I love excuses to try out
PMR now.

Also, instead of returning the ref to the vector... I'm just returning a
span now. Everyone just iterates it anyway, may as well not share the
implementation detail.

UTF-8 conversions

When testing with Terminal and looking at the conhost.exe's PTY
renderer, it spends a TON of allocation time on converting all the
UTF-16 stuff inside to UTF-8 before it sends it out the PTY. This was
because ConvertToA was allocating a string inside itself and returning
it just to have it freed after printing and looping back around again...
as a PTY does.

The change here is to use til::u16u8 that accepts a buffer out
parameter so the caller can just hold onto it.

Validation Steps Performed

  • big.txt in conhost.exe (GDI renderer)
  • big.txt in Terminal (DX, PTY renderer)
  • Ensure WDDM and BGFX build under Razzle with this change.
**Original Pull Request:** https://github.com/microsoft/terminal/pull/8621 **State:** closed **Merged:** Yes --- ## References * See also #8617 ## PR Checklist * [x] Supports #3075 * [x] I work here. * [x] Manual test. ## Detailed Description of the Pull Request / Additional comments ### Window Title Generation Every time the renderer checks the title, it's doing two bad things that I've fixed: 1. It's assembling the prefix to the full title doing a concatenation. No one ever gets just the prefix ever after it is set besides the concat. So instead of storing prefix and the title, I store the assembled prefix + title and the bare title. 2. A copy must be made because it was returning `std::wstring` instead of `std::wstring&`. Now it returns the ref. ### Dirty Area Return Every time the renderer checks the dirty area, which is sometimes multiple times per pass (regular text printing, again for selection, etc.), a vector is created off the heap to return the rectangles. The consumers only ever iterate this data. Now we return a span over a rectangle or rectangles that the engine must store itself. 1. For some renderers, it's always a constant 1 element. They update that 1 element when dirty is queried and return it in the span with a span size of 1. 2. For other renderers with more complex behavior, they're already holding a cached vector of rectangles. Now it's effectively giving out the ref to those in the span for iteration. ### Bitmap Runs The `til::bitmap` used a `std::optional<std::vector<til::rectangle>>` inside itself to cache its runs and would clear the optional when the runs became invalidated. Unfortunately doing `.reset()` to clear the optional will destroy the underlying vector and have it release its memory. We know it's about to get reallocated again, so we're just going to make it a `std::pmr::vector` and give it a memory pool. The alternative solution here was to use a `bool` and `std::vector<til::rectangle>` and just flag when the vector was invalid, but that was honestly more code changes and I love excuses to try out PMR now. Also, instead of returning the ref to the vector... I'm just returning a span now. Everyone just iterates it anyway, may as well not share the implementation detail. ### UTF-8 conversions When testing with Terminal and looking at the `conhost.exe`'s PTY renderer, it spends a TON of allocation time on converting all the UTF-16 stuff inside to UTF-8 before it sends it out the PTY. This was because `ConvertToA` was allocating a string inside itself and returning it just to have it freed after printing and looping back around again... as a PTY does. The change here is to use `til::u16u8` that accepts a buffer out parameter so the caller can just hold onto it. ## Validation Steps Performed - [x] `big.txt` in conhost.exe (GDI renderer) - [x] `big.txt` in Terminal (DX, PTY renderer) - [x] Ensure WDDM and BGFX build under Razzle with this change.
claunia added the pull-request label 2026-01-31 09:20:56 +00:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#27263