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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/buffer/out/TextAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,6 @@ void TextAttribute::SetColor(const COLORREF rgbColor, const bool fIsForeground)
}
}

bool TextAttribute::_IsReverseVideo() const noexcept
{
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO);
}

bool TextAttribute::IsLeadingByte() const noexcept
{
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_LEADING_BYTE);
Expand Down
31 changes: 30 additions & 1 deletion src/buffer/out/TextAttribute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,41 @@ class TextAttribute final
return _foreground.IsRgb() || _background.IsRgb();
}

// This returns whether this attribute, if printed directly next to another attribute, for the space
// character, would look identical to the other one.
constexpr bool HasIdenticalVisualRepresentationForBlankSpace(const TextAttribute& other, const bool inverted = false) const noexcept
{
// sneaky-sneaky: I'm using xor here
// inverted is whether there's a global invert; Reverse is a local one.
// global ^ local == true : the background attribute is actually the visible foreground, so we care about the foregrounds being identical
// global ^ local == false: the foreground attribute is the visible foreground, so we care about the backgrounds being identical
const auto checkForeground = (inverted != _IsReverseVideo());
return !IsAnyGridLineEnabled() && // grid lines have a visual representation
// crossed out, doubly and singly underlined have a visual representation
WI_AreAllFlagsClear(_extendedAttrs, ExtendedAttributes::CrossedOut | ExtendedAttributes::DoublyUnderlined | ExtendedAttributes::Underlined) &&
// all other attributes do not have a visual representation
(_wAttrLegacy & META_ATTRS) == (other._wAttrLegacy & META_ATTRS) &&
((checkForeground && _foreground == other._foreground) ||
(!checkForeground && _background == other._background)) &&
_extendedAttrs == other._extendedAttrs;
}

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

}

private:
COLORREF _GetRgbForeground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultColor) const noexcept;
COLORREF _GetRgbBackground(std::basic_string_view<COLORREF> colorTable,
COLORREF defaultColor) const noexcept;
bool _IsReverseVideo() const noexcept;

constexpr bool _IsReverseVideo() const noexcept
{
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO);
}

void _SetBoldness(const bool isBold) noexcept;

WORD _wAttrLegacy;
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class Microsoft::Terminal::Core::Terminal final :
CursorType GetCursorStyle() const noexcept override;
COLORREF GetCursorColor() const noexcept override;
bool IsCursorDoubleWidth() const noexcept override;
bool IsScreenReversed() const noexcept override;
const std::vector<Microsoft::Console::Render::RenderOverlay> GetOverlays() const noexcept override;
const bool IsGridLineDrawingAllowed() noexcept override;
#pragma endregion
Expand Down
10 changes: 10 additions & 0 deletions src/cascadia/TerminalCore/terminalrenderdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,13 @@ void Terminal::UnlockConsole() noexcept
{
_readWriteLock.unlock_shared();
}

// Method Description:
// - Returns whether the screen is inverted;
// This state is not currently known to Terminal.
// Return Value:
// - false.
bool Terminal::IsScreenReversed() const noexcept
{
return false;
}
12 changes: 12 additions & 0 deletions src/host/renderData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,16 @@ void RenderData::ColorSelection(const COORD coordSelectionStart, const COORD coo
{
Selection::Instance().ColorSelection(coordSelectionStart, coordSelectionEnd, attr);
}

// Method Description:
// - Returns true if the screen is globally inverted
// Arguments:
// - <none>
// Return Value:
// - true if the screen is globally inverted
bool RenderData::IsScreenReversed() const noexcept
{
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
return gci.IsScreenReversed();
}
#pragma endregion
2 changes: 2 additions & 0 deletions src/host/renderData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class RenderData final :
COLORREF GetCursorColor() const noexcept override;
bool IsCursorDoubleWidth() const noexcept override;

bool IsScreenReversed() const noexcept override;

const std::vector<Microsoft::Console::Render::RenderOverlay> GetOverlays() const noexcept override;

const bool IsGridLineDrawingAllowed() noexcept override;
Expand Down
18 changes: 16 additions & 2 deletions src/renderer/base/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,11 +615,19 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
}
}

static bool _IsAllSpaces(const std::wstring_view v)
{
// first non-space char is not found (is npos)
return v.find_first_not_of(L" ") == decltype(v)::npos;
}

void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
TextBufferCellIterator it,
const COORD target,
const bool lineWrapped)
{
auto globalInvert{ _pData->IsScreenReversed() };

// If we have valid data, let's figure out how to draw it.
if (it)
{
Expand Down Expand Up @@ -666,8 +674,14 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
{
if (color != it->TextAttr())
{
color = it->TextAttr();
break;
auto newAttr{ it->TextAttr() };
// foreground doesn't matter for runs of spaces (!)
// if we trick it . . . we call Paint far fewer times for cmatrix
if (!_IsAllSpaces(it->Chars()) || !newAttr.HasIdenticalVisualRepresentationForBlankSpace(color, globalInvert))
{
color = newAttr;
break; // vend this run
DHowett-MSFT marked this conversation as resolved.
Show resolved Hide resolved
}
}

// Walk through the text data and turn it into rendering clusters.
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/inc/IRenderData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ namespace Microsoft::Console::Render
virtual COLORREF GetCursorColor() const noexcept = 0;
virtual bool IsCursorDoubleWidth() const noexcept = 0;

virtual bool IsScreenReversed() const noexcept = 0;

virtual const std::vector<RenderOverlay> GetOverlays() const noexcept = 0;

virtual const bool IsGridLineDrawingAllowed() noexcept = 0;
Expand Down