microsoft / microsoft/terminal

Use a single renderer instance per window to reduce memory usage

Open
#15,186 5 comments 0 reactions 0 assignees View on GitHub
Area-AtlasEngine Issue-Feature Product-Terminal
Dominant language
C++
Stars
105k
Forks
9.6k
Avg merge
3d 17h
Merged PRs (30d)
29

Description

**The problem:** On my system, when Windows Terminal is maximized, every single DxRenderer/AtlasEngine instance consumes about 30MB committed virtual memory, 10MB physical memory, as well as 34 threads. Most of this is just due to the creation of the D3D11 device. It also consumes 100MB committed GPU memory, most of which is due to the creation of the swap chain. This cost quickly stacks up when you have a lot of open tabs. It gets more dire if you consider that a certain brand of stylish laptops are being sold right now with a total (across CPU _and_ GPU) amount of memory of 8GB, but a 200+ PPI display.

**The solution:** Instead of creating one renderer per pane, we could create one renderer per window.

# Proposed technical implementation details (optional)

Option 1 (?): https://learn.microsoft.com/en-us/uwp/api/windows.ui.composition.compositiontexture?view=winrt-26100

Option 2:

The swap chain would basically exist "behind" the XAML overlay that draws the pane grid lines. (Although, optimally, the renderer would draw them, so that DWM doesn't need to compose two swap chains.)
To allow us to draw multiple panes in a tab, we'll simply pass the renderer an array of `IRenderData`, one `IRenderData` per pane. The renderer will loop over the array and draw them iteratively into the swap chain at the pane's supposed position. Switching tabs simply switches the array of `IRenderData` that is being drawn. In case of `AtlasEngine` each `IRenderData` is assigned one `IBackend` instance which contains the glyph cache.
Implementing this will only be possible once `IRenderData` is less of a `I` and more of a `Data`, so that we can create multiple of them easily, pass them around, etc. It would also require us to implement buffer snapshotting and move the DirectWrite text segmentation into the `IBackend`. Afterwards, the above change can be implemented within a few days (I've already prepared most of what would be necessary for this).

A remaining open question is the overhead of switching tabs since the above proposal would lead to the destruction of the old `IBackend` array when the `IRenderData` array is being replaced. But I believe that this can be solved fairly easily by simply backing up the last used `IRenderData`/`IBackend` array, so that switching back and forth between 2 tabs is very quick at least (the most common scenario I can imagine). `IBackend` creation isn't _that_ expensive though, so even switching between a third tab wouldn't lag _that_ much.

Contributor guide

Open the contributing guide

Research direction

Start by reviewing DxRenderer, AtlasEngine, IRenderData, and IBackend to understand how renderer and swap-chain instances are created per pane. Measure the current per-pane memory cost, then evaluate the proposed per-window renderer and multi-pane data flow. Done means panes and tab switching render correctly while reducing redundant renderer resources per window.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
computer-graphics, desktop, performance
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.