Draw the background separately from the foreground during render passes #8585

Closed
opened 2026-01-31 01:33:09 +00:00 by claunia · 9 comments
Owner

Originally created by @DHowett on GitHub (May 26, 2020).

preliminary work: https://github.com/microsoft/terminal/tree/dev/duhowett/background-atlas

I've been thinking a bit about the DX renderer drawing a "background atlas" before it draws any text.

If we separate background drawing into a totally separate phase, we get the following benefits:

  • We do not need to break runs of text until their foreground presentation changes (performance)
  • We will not break ligatures when the background changes (correctness) (fixes #800)
  • We can draw stuff behind the text (visuals, correctness) (touches mini-spec #6151)

It would look, roughly, like this:

step 1 (empty renderer)

image

step 2 (drawing background atlas)

image

step 3 (drawing foreground)

image

may need a mini-spec

Originally created by @DHowett on GitHub (May 26, 2020). preliminary work: https://github.com/microsoft/terminal/tree/dev/duhowett/background-atlas I've been thinking a bit about the DX renderer drawing a "background atlas" _before it draws any text_. If we separate background drawing into a totally separate phase, we get the following benefits: * We do not need to break runs of text until their _foreground presentation_ changes (performance) * We will not break ligatures when the background changes (correctness) (fixes #800) * We can draw stuff behind the text (visuals, correctness) (touches mini-spec #6151) It would look, roughly, like this: ### step 1 (empty renderer) ![image](https://user-images.githubusercontent.com/189190/82858125-d0facf80-9ec7-11ea-9ad5-c89028d5a3c7.png) ### step 2 (drawing background atlas) ![image](https://user-images.githubusercontent.com/189190/82858147-db1cce00-9ec7-11ea-91fc-07f18ee4fa2c.png) ### step 3 (drawing foreground) ![image](https://user-images.githubusercontent.com/189190/82858106-c6d8d100-9ec7-11ea-8eb8-260b10bbf7e6.png) _may need a mini-spec_
claunia added the Area-RenderingIssue-TaskNeeds-Tag-FixProduct-Terminal labels 2026-01-31 01:33:10 +00:00
Author
Owner

@DHowett commented on GitHub (May 26, 2020):

Hey, it works!

image

@DHowett commented on GitHub (May 26, 2020): Hey, it works! ![image](https://user-images.githubusercontent.com/189190/82864397-5044cf00-9ed9-11ea-9f4b-40c3f2e36268.png)
Author
Owner

@DHowett commented on GitHub (May 26, 2020):

Right now, I'm inefficiently iterating over the entire dirty region twice -- once row by row x attr by attr with an AttrRowIterator, and once row by row x cell by cell with a TextBufferCellIterator.

They're the same expense, roughly, because AttrRowIterator doesn't have any affordances for getting the run length and skipping it. If it did, we could dispense with some of the complexity.

IDEALLY, I would have one function that turned out a vector of clusters and a vector of backgrounds. This would save the cost of iterating twice.

@DHowett commented on GitHub (May 26, 2020): Right now, I'm inefficiently iterating over the entire dirty region twice -- once row by row x attr by attr with an AttrRowIterator, and once row by row x cell by cell with a TextBufferCellIterator. They're the same expense, roughly, because AttrRowIterator doesn't have any affordances for getting the run length and skipping it. If it did, we could dispense with some of the complexity. _IDEALLY_, I would have one function that turned out a vector of clusters and a vector of backgrounds. This would save the cost of iterating twice.
Author
Owner

@zadjii-msft commented on GitHub (May 26, 2020):

Okay, so this might be working better than my hack to manually break the run with the cursor on it. I need to add at least O(Rows+Cols) checks to painting the frame in my prototype, to check if we're on the cursor row, and the perf so far is horrifyingly bad.

If this truly doesn't double the work done for a single frame, then this seems like it might be a better solution to combine with the pre/post rendering of the cursor.

@zadjii-msft commented on GitHub (May 26, 2020): Okay, so this might be working better than my hack to manually break the run with the cursor on it. I need to add at least O(Rows+Cols) checks to painting the frame in my prototype, to check if we're on the cursor row, and the perf so far is horrifyingly bad. If this truly doesn't _double_ the work done for a single frame, then this seems like it might be a better solution to combine with the pre/post rendering of the cursor.
Author
Owner

@egmontkob commented on GitHub (May 26, 2020):

VTE does 2-pass rendering like this.

IMO the biggest advantage is that letters can slightly overflow to neighboring cells, e.g. diacritics above or below don't get cropped, bold letters don't get their right edge cut off.

@egmontkob commented on GitHub (May 26, 2020): VTE does 2-pass rendering like this. IMO the biggest advantage is that letters can slightly overflow to neighboring cells, e.g. diacritics above or below don't get cropped, bold letters don't get their right edge cut off.
Author
Owner

@DHowett commented on GitHub (May 27, 2020):

Alright, I've got this down to a single function that takes each dirty region and produces...

  • A list of damaged backgrounds to repaint
  • A list of colored cluster lists to repaint

I don't like the number of vectors here, but... we're saving money by invalidating narrowly whenever possible.

Dirty Region [1..n]
- Origin (SCREEN CHAR COORDS)
- At line wrap point
- Region intersected right half of DBCS char (left trim)
- Background Run [1..n]
  - Attribute
  - Rect Covered (SCREEN CHAR COORDS)
- Colored Foreground Run [1..n]
  - Attribute
  - Columns
  - Cluster [1..n]

Right now, because of some minor issues (#2661), backgrounds are attributes and actual final colors. It's not pleasant!

To fix:

  • reverse is occasionally (!) broken
  • render engines need flags to say "plz no background splitting" (vt engine needs to update drawing brushes per text run, foreground and background)
  • need to re-enable space optimization (if the cell is non-printing (and has no underline, etc.), no point in forwarding it to the cluster renderer!)
@DHowett commented on GitHub (May 27, 2020): Alright, I've got this down to a single function that takes each dirty region and produces... * A list of damaged backgrounds to repaint * A list of colored cluster lists to repaint I don't like the number of vectors here, but... we're saving money by invalidating narrowly whenever possible. ``` Dirty Region [1..n] - Origin (SCREEN CHAR COORDS) - At line wrap point - Region intersected right half of DBCS char (left trim) - Background Run [1..n] - Attribute - Rect Covered (SCREEN CHAR COORDS) - Colored Foreground Run [1..n] - Attribute - Columns - Cluster [1..n] ``` Right now, because of some minor issues (#2661), backgrounds are attributes _and_ actual final colors. It's not pleasant! To fix: * [ ] reverse is occasionally (!) broken * [x] render engines need flags to say "plz no background splitting" (vt engine needs to update drawing brushes per text run, foreground _and_ background) * [ ] need to re-enable space optimization (if the cell is non-printing (and has no underline, etc.), no point in forwarding it to the cluster renderer!)
Author
Owner

@DHowett commented on GitHub (May 27, 2020):

branch

@DHowett commented on GitHub (May 27, 2020): [branch](https://github.com/microsoft/terminal/tree/dev/duhowett/background-atlas)
Author
Owner

@DHowett commented on GitHub (Jun 3, 2020):

Michael's got some ideas that will be less invasive than this.

@DHowett commented on GitHub (Jun 3, 2020): Michael's got some ideas that will be less invasive than this.
Author
Owner

@DHowett commented on GitHub (Jul 1, 2020):

preliminary work: https://github.com/microsoft/terminal/tree/dev/duhowett/background-atlas

@DHowett commented on GitHub (Jul 1, 2020): preliminary work: https://github.com/microsoft/terminal/tree/dev/duhowett/background-atlas
Author
Owner

@DHowett commented on GitHub (Jun 29, 2022):

Atlas supersedes this.

@DHowett commented on GitHub (Jun 29, 2022): Atlas supersedes this.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#8585