Dedicated "paint" interface for VtRenderer #14438

Open
opened 2026-01-31 04:10:23 +00:00 by claunia · 0 comments
Owner

Originally created by @skyline75489 on GitHub (Jul 9, 2021).

Description

As shown in #10563, ConPTY suffers from significant performance drop with too much scrolling request. A typical repro is:

time bash -c 'yes | head -n1000000'

This is a typical trace of OpenConsole.exe under the above workload:

image

Discussion

The main issue that caused this, I think, is that VtRenderer suffers from using the same interface as other graphic renderer. To break it down:

  1. Carriage return & linefeed can trigger graphic renderer to circling the buffer & force repaint. But for VtRenderer, it dosen't really need to do too much, other than print the newly added line. It doesn't really need to flush the buffer (EndPaint as shown above), because the actual text added to the buffer is only a single line (120 chars in a typical display).
  2. The _PaintBufferOutputHelper method insider renderer is obviously graphic-oriented. After all these years of development, I don't think it suits the need for VtRenderer anymore. An example is #10567, in which I try to reduce the cost of reassemble the line buffer. The reason why we need to reassemble the clusters, is because they are produced by splitting up the original buffer in _PaintBufferOutputHelper, which is heavily required by graphic renderers. If we have a dedicated interface, unnecessary operations like these can be eliminated.
  3. In VtEngine & XtermEngine, the actual number of methods that're both overridden and practically useful is rather small, comparing to the large amount of base methods in IRenderEngine. This indicates that the fundamental goal of VtEngine isn't really the same as the graphic renderers.

Proposed solution

I'm proposing a three-phase refactoring process for VtEngine to move away from IRenderEngine:

  1. Separate the methods in VtEngine that are heavily burdened by the current design, such as _PaintBufferOutputHelper. We add them as base methods to IRenderEngine. VtEngine is still a child class of IRenderEngine, but we add dedicated IO methods in it and test the performance gain.
  2. Separate the rest the methods in VtEngine same way as above.
  3. When we finished the first two steps, we should have a clear path towards adding a dedicated interface just for VtEngine, probably name it IVtEngine. Then we can create IVtEngine from IRenderEngine, and let IRenderEngine be what's left in it.

CC @DHowett @miniksa @zadjii-msft @lhecker @j4james for discussion.

(How can I just At everyone who's collaborator of this project. That would be helpful.)

Originally created by @skyline75489 on GitHub (Jul 9, 2021). ### Description As shown in #10563, ConPTY suffers from significant performance drop with too much scrolling request. A typical repro is: ```bash time bash -c 'yes | head -n1000000' ``` This is a typical trace of `OpenConsole.exe` under the above workload: ![image](https://user-images.githubusercontent.com/4710575/125062000-809cfc00-e0e0-11eb-9d0d-c9ec9e95884b.png) ### Discussion The main issue that caused this, I think, is that VtRenderer suffers from using the same interface as other graphic renderer. To break it down: 1. Carriage return & linefeed can trigger graphic renderer to circling the buffer & force repaint. But for VtRenderer, it dosen't really need to do too much, other than print the newly added line. It doesn't really need to flush the buffer (`EndPaint` as shown above), because the actual text added to the buffer is only a single line (120 chars in a typical display). 2. The `_PaintBufferOutputHelper` method insider `renderer` is obviously graphic-oriented. After all these years of development, I don't think it suits the need for VtRenderer anymore. An example is #10567, in which I try to reduce the cost of reassemble the line buffer. The reason why we need to reassemble the clusters, is because they are produced by splitting up the original buffer in `_PaintBufferOutputHelper`, which is heavily required by graphic renderers. If we have a dedicated interface, unnecessary operations like these can be eliminated. 3. In `VtEngine` & `XtermEngine`, the actual number of methods that're both overridden and practically useful is rather small, comparing to the large amount of base methods in `IRenderEngine`. This indicates that the fundamental goal of `VtEngine` isn't really the same as the graphic renderers. ### Proposed solution I'm proposing a three-phase refactoring process for VtEngine to move away from `IRenderEngine`: 1. Separate the methods in `VtEngine` that are heavily burdened by the current design, such as `_PaintBufferOutputHelper`. We add them as base methods to `IRenderEngine`. `VtEngine` is still a child class of `IRenderEngine`, but we add dedicated IO methods in it and test the performance gain. 1. Separate the rest the methods in `VtEngine` same way as above. 1. When we finished the first two steps, we should have a clear path towards adding a dedicated interface just for `VtEngine`, probably name it `IVtEngine`. Then we can create `IVtEngine` from `IRenderEngine`, and let `IRenderEngine` be what's left in it. CC @DHowett @miniksa @zadjii-msft @lhecker @j4james for discussion. (How can I just At everyone who's collaborator of this project. That would be helpful.)
claunia added the Issue-FeatureNeeds-TriageArea-VTProduct-Conpty labels 2026-01-31 04:10:24 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#14438