Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize rendering runs of spaces when there is no visual change #4877

Merged
merged 4 commits into from
Mar 13, 2020

Conversation

DHowett-MSFT
Copy link
Contributor

@DHowett-MSFT DHowett-MSFT commented Mar 10, 2020

cmatrix is somewhat of a pathological case for our infrastructure: it
prints out a bunch of green and white characters and then updates them a
million times a second.

It also maintains a column of space between every green character. When
it prints this column, it prints it in "default" or "white". This ends
up making runs of text that look like this:

(def: G=green B=bright white W=white *=matrix char =space)

G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W

As characters trickle in:

G*W G*W G*W G*W G*W G*W G*W B*W
G*W G*W G*W G*W G*W G*W G*W G W
G*W G*W G*W B*W G*W G*W G*W G W
G*W B*W G*W G W G*W G*W G*W G*W
G*W G W G*W G W G*W B*W G*W G*W
B*W G W G*W G W G*W G W B*W G*W
G W G W G*W G W G*W G W G W B*W
G W G W B*W G W G*W G W G W G W

Every one of those color transitions causes us to break up the run of
text and start rendering it again. This impacts GDI, Direct2D and
ConPTY. In the example above, there are 120 runs.

The problem is, printing a space doesn't use the foreground color!

This commit introduces an optimization. When we're about to break a text
cluster because its attributes changed, we make sure that it's not just
filled with spaces and doesn't differ in any visually-meaningful way
(like underline or strikethrough, considering global invert state).

This lets us optimize both the rendering and the PTY output to look
like this:

G*   *   *   *   *   *   *  B*G
G*   *   *   *   *   *   *
G*   *   *  B*G  *   *   *
G*  B*G  *       *   *   *   *
G*       *       *  B*G  *   *
B*G      *       *      B*G  *
G        *       *          B*G
G       B*G      *

Text will be printed at best line-by-line and at worst only when the
visible properties of the screen actually change. In the example
above, there are only 21 runs.

This speeds up cmatrix remarkably.

PR Checklist

@j4james
Copy link
Collaborator

j4james commented Mar 10, 2020

I haven't had a chance to try your patch, but I suspect the reverse video attribute might cause problems with this optimisation. Consider the difference between this sequence...

printf "\e[31m     \e[32m     \e[m"

and this...

printf "\e[7;31m     \e[32m     \e[m"

In both case it's just a run of spaces with a foreground change, but the second sequence would actually require a cluster split wouldn't it?

And if that is the case, I assume the DECSCNM mode would cause similar problems.

@DHowett-MSFT
Copy link
Contributor Author

YES, thank you. That's very helpful.

@DHowett-MSFT
Copy link
Contributor Author

It won't change the mergeability of this PR, but would you [request changes] because of that?
Thanks!

@DHowett-MSFT
Copy link
Contributor Author

So, an attribute knows whether it's been reversed. This is fine for reverse video, but not for global DECSCNM. I'd hate to round trip through the thing that knows the colors just to make this determination...

Copy link
Collaborator

@j4james j4james left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, this needs to take into account the reverse video attribute, and potentially the DECSCNM mode.

@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Mar 10, 2020
@j4james
Copy link
Collaborator

j4james commented Mar 10, 2020

Regarding the DECSCNM mode, remember that that's a global attribute, so you should only need to look it up once at the start of the paint. If you can't access the global settings from the renderer, then I suppose you'd have to pass in a bool somewhere along the line. Otherwise maybe we should be updating that state in the renderer itself every time the mode is changed?

Edit: If you want to go the latter route, it looks like it should be an easy change to add something like a SetScreenReversed call to the renderer here:

terminal/src/host/getset.cpp

Lines 1308 to 1313 in a13ccfd

gci.SetScreenReversed(reverseMode);
if (g.pRender)
{
g.pRender->TriggerRedrawAll();
}

@zadjii-msft zadjii-msft added the Product-Terminal The new Windows Terminal. label Mar 11, 2020
cmatrix is somewhat of a pathological case for our infrastructure: it
prints out a bunch of green and white characters and then updates them a
million times a second.

It also maintains a column of space between every green character. When
it prints this column, it prints it in "default" or "white". This ends
up making runs of text that look like this:

(def: G=green B=bright white W=white *=matrix char  =space)

G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W
G W G W G W G W G W G W G W G W

As characters trickle in:

G*W G*W G*W G*W G*W G*W G*W B*W
G*W G*W G*W G*W G*W G*W G*W G W
G*W G*W G*W B*W G*W G*W G*W G W
G*W B*W G*W G W G*W G*W G*W G*W
G*W G W G*W G W G*W B*W G*W G*W
B*W G W G*W G W G*W G W B*W G*W
G W G W G*W G W G*W G W G W B*W
G W G W B*W G W G*W G W G W G W

Every one of those color transitions causes us to break up the run of
text and start rendering it again. This impacts GDI, Direct2D *and*
ConPTY.

The problem is, printing a space doesn't **use** the foreground color!

This commit introduces an optimization. When we're about to break a text
cluster becuase its attributes changed, we make sure that it's not just
filled with spaces and differs only in the foreground parameter.

This lets us optimize both the rendering _and_ the PTY output to look
like this:

G*   *   *   *   *   *   *  B*
G*   *   *   *   *   *   *
G*   *   *  B*   *   *   *
G*  B*   *       *   *   *   *
G*       *       *  B*   *   *
B*       *       *      B*   *
G        *       *          B*
G       B*       *

Text will be printed at best line-by-line and at worst only when the
visible properties of the screen actually change.

This speeds up cmatrix remarkably.
@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Mar 12, 2020
@DHowett-MSFT
Copy link
Contributor Author

This works for both normal and invert video with both yes and no DECSCNM

Copy link
Collaborator

@j4james j4james left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're going to hate me, but I think there's another case you need to deal with. What happens when one of the underline attributes is set? For example:

printf "\e[4;31m     \e[32m     \e[m"

You've got a run of spaces with only the foreground changing, but that still requires two clusters to handle the change in underline color doesn't it?

@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Mar 12, 2020
zadjii-msft
zadjii-msft previously approved these changes Mar 12, 2020
src/renderer/base/renderer.cpp Show resolved Hide resolved
@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Mar 12, 2020
@zadjii-msft zadjii-msft self-requested a review March 12, 2020 20:14
@zadjii-msft
Copy link
Member

I'm clearing my approval in response to @j4james's comment that happened while I was reviewing

@DHowett-MSFT
Copy link
Contributor Author

hate me

oh heck no 😄 i love it


constexpr bool IsAnyGridLineEnabled() const noexcept
{
return WI_IsAnyFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL | COMMON_LVB_UNDERSCORE);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to future proof this by checking the ExtendedAttributes too (CrossedOut, Underlined, etc)? It's a bit open ended, because there are all sorts of these attributes that we may want to implement one day, so I don't know. I just thought it worth mentioning.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're not wrong, I just keep acting like i've never written code before. 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this thread you guys

@DHowett-MSFT DHowett-MSFT dismissed zadjii-msft’s stale review March 12, 2020 21:14

he said he dismissed it!

@DHowett-MSFT
Copy link
Contributor Author

Okay, this is as comprehensive as I think I can make it -- i've renamed the function to compensate.

@DHowett-MSFT DHowett-MSFT changed the title Optimize rendering runs of spaces when only the foreground changes Optimize rendering runs of spaces when there is no visual change Mar 12, 2020
Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay.

@DHowett-MSFT
Copy link
Contributor Author

My most recent test case:

printf "\e[31m     \e[32m     \e[m\n\e[7;31m     \e[32m     \e[m\n\e[4;31m     \e[32m     \e[m\n\e[21;31m     \e[32m     \e[m\n\e[9;31m     \e[32m     \e[m\n"
  1. FG1, FG2
  2. Inverse video, FG1, FG2
  3. Underline, FG1, FG2
  4. Double underline, FG1, FG2
  5. Strikethrough, FG1, FG2

I then toggled DECSCNM on and off with that in the buffer.

@zadjii-msft
Copy link
Member

I'm not sure how you could write a test for that, which is why I'm okay with this not being tested. We don't really have a RendererTest with a mock engine or anything like that (unfortunately)

@zadjii-msft zadjii-msft added the Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues label Mar 12, 2020
@zadjii-msft zadjii-msft added the Needs-Second It's a PR that needs another sign-off label Mar 12, 2020
@ghost ghost requested review from miniksa, carlos-zamora and leonMSFT March 12, 2020 21:33
@zadjii-msft
Copy link
Member

@msftbot make sure @miniksa signs off on this

@ghost ghost added the AutoMerge Marked for automatic merge by the bot when requirements are met label Mar 12, 2020
@ghost
Copy link

ghost commented Mar 12, 2020

Hello @zadjii-msft!

Because you've given me some instructions on how to help merge this pull request, I'll be modifying my merge approach. Here's how I understand your requirements for merging this pull request:

  • I'll only merge this pull request if it's approved by @miniksa

If this doesn't seem right to you, you can tell me to cancel these instructions and use the auto-merge policy that has been configured for this repository. Try telling me "forget everything I just told you".

@DHowett-MSFT
Copy link
Contributor Author

Ugh, I explicitly code-formatted this.

@DHowett-MSFT
Copy link
Contributor Author

Oh, I see. Unformatted code merged into master. Ugh.

@DHowett-MSFT
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@DHowett-MSFT
Copy link
Contributor Author

image

cannot clear olf dtatus

Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, good enough.

@DHowett-MSFT DHowett-MSFT merged commit f919a46 into master Mar 13, 2020
@DHowett-MSFT DHowett-MSFT deleted the dev/duhowett/cmatrix branch March 13, 2020 00:54
@miniksa miniksa mentioned this pull request Mar 20, 2020
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues AutoMerge Marked for automatic merge by the bot when requirements are met Needs-Second It's a PR that needs another sign-off Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants