From 88f2e64bb3d6743a15165d02db7a1a012c49dc79 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Nov 2021 16:51:09 -0600 Subject: [PATCH] Transparency is hard --- src/cascadia/TerminalControl/ControlCore.cpp | 8 +++---- src/cascadia/TerminalControl/ControlCore.h | 2 +- src/renderer/dx/DxRenderer.cpp | 25 ++++++++------------ src/renderer/dx/DxRenderer.hpp | 4 ++-- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 540b9f792..b764a709b 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -277,7 +277,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // GH#5098: Inform the engine of the opacity of the default text background. // GH#11315: Always do this, even if they don't have acrylic on. - _renderEngine->SetDefaultTextBackgroundOpacity(_correctForTransparency()); + _renderEngine->SetDefaultTextBackgroundOpacity(_isBackgroundTransparent()); THROW_IF_FAILED(_renderEngine->Enable()); @@ -456,7 +456,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // Update the renderer as well. It might need to fall back from // cleartype -> grayscale if the BG is transparent / acrylic. - _renderEngine->SetDefaultTextBackgroundOpacity(_correctForTransparency()); + _renderEngine->SetDefaultTextBackgroundOpacity(_isBackgroundTransparent()); auto eventArgs = winrt::make_self(newOpacity); _TransparencyChangedHandlers(*this, *eventArgs); @@ -624,7 +624,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _renderEngine->SetForceFullRepaintRendering(_settings->ForceFullRepaintRendering()); _renderEngine->SetSoftwareRendering(_settings->SoftwareRendering()); // Inform the renderer of our opacity - _renderEngine->SetDefaultTextBackgroundOpacity(_correctForTransparency()); + _renderEngine->SetDefaultTextBackgroundOpacity(_isBackgroundTransparent()); _updateAntiAliasingMode(_renderEngine.get()); @@ -1638,7 +1638,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation return _settings->HasUnfocusedAppearance(); } - bool ControlCore::_correctForTransparency() + bool ControlCore::_isBackgroundTransparent() { return Opacity() < 1.0f || UseAcrylic(); } diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index c18a491e6..2e9c9b6f9 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -274,7 +274,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void _connectionOutputHandler(const hstring& hstr); void _updateHoveredCell(const std::optional terminalPosition); - bool _correctForTransparency(); + bool _isBackgroundTransparent(); inline bool _IsClosing() const noexcept { diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index 547eb604f..26805b2ba 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -88,7 +88,7 @@ DxEngine::DxEngine() : _forceFullRepaintRendering{ false }, _softwareRendering{ false }, _antialiasingMode{ D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE }, - _defaultBackgroundIsTransparent{ 0xff000000 }, + _defaultBackgroundIsTransparent{ true }, _hwndTarget{ static_cast(INVALID_HANDLE_VALUE) }, _sizeTarget{}, _dpi{ USER_DEFAULT_SCREEN_DPI }, @@ -909,15 +909,6 @@ void DxEngine::_ReleaseDeviceResources() noexcept // DANGER: Layers slow us down. Only do this in the specific case where // someone has chosen the slower ClearType antialiasing (versus the faster // grayscale antialiasing) - // - // October 2021: We're no longer forcing the BG of the run to be opaque when - // cleartype is enabled and the background isn't fully opaque. In the case - // of (!useAcrylic && opacity<1.0), we actually can still render cleartype - // text just fine. It's only acrylic that messes us up. So we're making a - // small change. Now, when the user requests acrylic, text that's rendered - // on the default text BG will always use grayscale, rather than cleartype. - // This helps support the scenario where the user has (useAcrylic && - // opacity==1.0) const bool usingCleartype = _antialiasingMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; const bool usingTransparency = _defaultBackgroundIsTransparent; // Another way of naming "bgIsDefault" is "bgHasTransparency" @@ -1942,9 +1933,8 @@ CATCH_RETURN() const auto [colorForeground, colorBackground] = pData->GetAttributeColors(textAttributes); const bool usingCleartype = _antialiasingMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; - const bool usingTransparency = _defaultBackgroundIsTransparent != 0; + const bool usingTransparency = _defaultBackgroundIsTransparent; const bool forceOpaqueBG = usingCleartype && !usingTransparency; - // (usingCleartype && !(_defaultBackgroundIsTransparent == 0)) -> wrong, both acry(50)&vint(50) got solid BGs, as well as acry(100) _foregroundColor = _ColorFFromColorRef(OPACITY_OPAQUE | colorForeground); // October 2021: small changes were made to the way BG color interacts with @@ -2246,14 +2236,19 @@ CATCH_LOG() // rendering onto a transparent surface (like acrylic), then cleartype won't // work correctly, and will actually just additively blend with the // background. This is here to support GH#5098. +// - We'll use this, along with whether cleartype was requested, to manually set +// the alpha channel of the background brush to 1.0. We need to do that to +// make cleartype work without blending. However, we don't want to do that too +// often - if we do that on top of a transparent BG, then the entire swap +// chain will be fully opaque. // Arguments: -// - opacity: the new opacity of our background, on [0.0f, 1.0f] +// - isTransparent: true if our BG is transparent (acrylic, or anything that's not fully opaque) // Return Value: // - -void DxEngine::SetDefaultTextBackgroundOpacity(const bool useAcrylic) noexcept +void DxEngine::SetDefaultTextBackgroundOpacity(const bool isTransparent) noexcept try { - _defaultBackgroundIsTransparent = useAcrylic ? 0xff000000 : 0; + _defaultBackgroundIsTransparent = isTransparent; // Make sure we redraw all the cells, to update whether they're actually // drawn with cleartype or not. diff --git a/src/renderer/dx/DxRenderer.hpp b/src/renderer/dx/DxRenderer.hpp index 8e46f06f9..df5d4967e 100644 --- a/src/renderer/dx/DxRenderer.hpp +++ b/src/renderer/dx/DxRenderer.hpp @@ -128,7 +128,7 @@ namespace Microsoft::Console::Render void SetSelectionBackground(const COLORREF color, const float alpha = 0.5f) noexcept; void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept; - void SetDefaultTextBackgroundOpacity(const bool useAcrylic) noexcept; + void SetDefaultTextBackgroundOpacity(const bool isTransparent) noexcept; void SetIntenseIsBold(const bool opacity) noexcept; void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept; @@ -257,7 +257,7 @@ namespace Microsoft::Console::Render D2D1_TEXT_ANTIALIAS_MODE _antialiasingMode; - uint32_t _defaultBackgroundIsTransparent; + bool _defaultBackgroundIsTransparent; bool _intenseIsBold; // DirectX constant buffers need to be a multiple of 16; align to pad the size.