diff --git a/doc/cascadia/SettingsSchema.md b/doc/cascadia/SettingsSchema.md index 5d38e8e15669..0ee88a6d5c55 100644 --- a/doc/cascadia/SettingsSchema.md +++ b/doc/cascadia/SettingsSchema.md @@ -22,6 +22,8 @@ Properties listed below affect the entire window, regardless of the profile sett | `wordDelimiters` | Optional | String |  /\()"'-:,.;<>~!@#$%^&*|+=[]{}~?│
_(`│` is `U+2502 BOX DRAWINGS LIGHT VERTICAL`)_ | Determines the delimiters used in a double click selection. | | `confirmCloseAllTabs` | Optional | Boolean | `true` | When set to `true` closing a window with multiple tabs open WILL require confirmation. When set to `false` closing a window with multiple tabs open WILL NOT require confirmation. | | `disabledProfileSources` | Optional | Array[String] | `[]` | Disables all the dynamic profile generators in this list, preventing them from adding their profiles to the list of profiles on startup. This array can contain any combination of `Windows.Terminal.Wsl`, `Windows.Terminal.Azure`, or `Windows.Terminal.PowershellCore`. For more information, see [UsingJsonSettings.md](https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingJsonSettings.md#dynamic-profiles) | +| `experimental.rendering.forceFullRepaint` | Optional | Boolean | `false` | When set to true, we will redraw the entire screen each frame. When set to false, we will render only the updates to the screen between frames. | +| `experimental.rendering.software` | Optional | Boolean | `false` | When set to true, we will use the software renderer (a.k.a. WARP) instead of the hardware one. | ## Profiles Properties listed below are specific to each unique profile. diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 882347f95e18..8ebcb9746e42 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -300,6 +300,14 @@ }, "type": "array" }, + "experimental.rendering.forceFullRepaint": { + "description": "When set to true, we will redraw the entire screen each frame. When set to false, we will render only the updates to the screen between frames.", + "type": "boolean" + }, + "experimental.rendering.software": { + "description": "When set to true, we will use the software renderer (a.k.a. WARP) instead of the hardware one.", + "type": "boolean" + }, "initialCols": { "default": 120, "description": "The number of columns displayed in the window upon first load.", @@ -332,7 +340,7 @@ "description": "The number of rows to scroll at a time with the mouse wheel. This will override the system setting if the value is not zero or \"system\".", "maximum": 999, "minimum": 0, - "type": ["integer", "string"] + "type": [ "integer", "string" ] }, "keybindings": { "description": "Properties are specific to each custom key binding.", @@ -383,7 +391,7 @@ "confirmCloseAllTabs": { "default": true, "description": "When set to \"true\" closing a window with multiple tabs open will require confirmation. When set to \"false\", the confirmation dialog will not appear.", - "type":"boolean" + "type": "boolean" } }, "required": [ diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalApp/GlobalAppSettings.cpp index 62c814779f10..5e7ab9552469 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalApp/GlobalAppSettings.cpp @@ -42,6 +42,9 @@ static constexpr std::wstring_view LightThemeValue{ L"light" }; static constexpr std::wstring_view DarkThemeValue{ L"dark" }; static constexpr std::wstring_view SystemThemeValue{ L"system" }; +static constexpr std::string_view ForceFullRepaintRenderingKey{ "experimental.rendering.forceFullRepaint" }; +static constexpr std::string_view SoftwareRenderingKey{ "experimental.rendering.software" }; + static constexpr std::string_view DebugFeaturesKey{ "debugFeatures" }; #ifdef _DEBUG @@ -70,6 +73,8 @@ GlobalAppSettings::GlobalAppSettings() : _copyOnSelect{ false }, _copyFormatting{ false }, _launchMode{ LaunchMode::DefaultMode }, + _forceFullRepaintRendering{ false }, + _softwareRendering{ false }, _debugFeatures{ debugFeaturesDefault } { } @@ -187,6 +192,16 @@ void GlobalAppSettings::SetConfirmCloseAllTabs(const bool confirmCloseAllTabs) n _confirmCloseAllTabs = confirmCloseAllTabs; } +bool GlobalAppSettings::GetForceFullRepaintRendering() noexcept +{ + return _forceFullRepaintRendering; +} + +bool GlobalAppSettings::GetSoftwareRendering() noexcept +{ + return _softwareRendering; +} + bool GlobalAppSettings::DebugFeaturesEnabled() const noexcept { return _debugFeatures; @@ -230,6 +245,8 @@ void GlobalAppSettings::ApplyToSettings(TerminalSettings& settings) const noexce settings.WordDelimiters(_wordDelimiters); settings.CopyOnSelect(_copyOnSelect); + settings.ForceFullRepaintRendering(_forceFullRepaintRendering); + settings.SoftwareRendering(_softwareRendering); } // Method Description: @@ -259,6 +276,8 @@ Json::Value GlobalAppSettings::ToJson() const jsonObject[JsonKey(KeybindingsKey)] = _keybindings->ToJson(); jsonObject[JsonKey(ConfirmCloseAllKey)] = _confirmCloseAllTabs; jsonObject[JsonKey(SnapToGridOnResizeKey)] = _SnapToGridOnResize; + jsonObject[JsonKey(ForceFullRepaintRenderingKey)] = _forceFullRepaintRendering; + jsonObject[JsonKey(SoftwareRenderingKey)] = _softwareRendering; jsonObject[JsonKey(DebugFeaturesKey)] = _debugFeatures; return jsonObject; @@ -350,6 +369,10 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) JsonUtils::GetBool(json, SnapToGridOnResizeKey, _SnapToGridOnResize); + JsonUtils::GetBool(json, ForceFullRepaintRenderingKey, _forceFullRepaintRendering); + + JsonUtils::GetBool(json, SoftwareRenderingKey, _softwareRendering); + // GetBool will only override the current value if the key exists JsonUtils::GetBool(json, DebugFeaturesKey, _debugFeatures); } diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.h b/src/cascadia/TerminalApp/GlobalAppSettings.h index 44435c3d5775..d390403e93ea 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.h +++ b/src/cascadia/TerminalApp/GlobalAppSettings.h @@ -77,6 +77,9 @@ class TerminalApp::GlobalAppSettings final winrt::TerminalApp::LaunchMode GetLaunchMode() const noexcept; void SetLaunchMode(const winrt::TerminalApp::LaunchMode launchMode); + bool GetForceFullRepaintRendering() noexcept; + bool GetSoftwareRendering() noexcept; + bool DebugFeaturesEnabled() const noexcept; Json::Value ToJson() const; @@ -118,6 +121,9 @@ class TerminalApp::GlobalAppSettings final winrt::TerminalApp::LaunchMode _launchMode; + bool _softwareRendering; + bool _forceFullRepaintRendering; + bool _debugFeatures; static winrt::Windows::UI::Xaml::ElementTheme _ParseTheme(const std::wstring& themeString) noexcept; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 94878332c513..7b3aa1dce2df 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -586,9 +586,11 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation _terminal->CreateFromSettings(_settings, renderTarget); - // TODO:GH#3927 - Make it possible to hot-reload this setting. Right + // TODO:GH#3927 - Make it possible to hot-reload these settings. Right // here, the setting will only be used when the Terminal is initialized. dxEngine->SetRetroTerminalEffects(_settings.RetroTerminalEffect()); + dxEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering()); + dxEngine->SetSoftwareRendering(_settings.SoftwareRendering()); // TODO:GH#3927 - hot-reload this one too // Update DxEngine's AntialiasingMode diff --git a/src/cascadia/TerminalSettings/IControlSettings.idl b/src/cascadia/TerminalSettings/IControlSettings.idl index 4f40c32691b8..ce750d01e833 100644 --- a/src/cascadia/TerminalSettings/IControlSettings.idl +++ b/src/cascadia/TerminalSettings/IControlSettings.idl @@ -52,6 +52,8 @@ namespace Microsoft.Terminal.Settings UInt32 SelectionBackground; Boolean RetroTerminalEffect; + Boolean ForceFullRepaintRendering; + Boolean SoftwareRendering; TextAntialiasingMode AntialiasingMode; }; diff --git a/src/cascadia/TerminalSettings/TerminalSettings.cpp b/src/cascadia/TerminalSettings/TerminalSettings.cpp index 46fe1b45d369..45174a5c85bb 100644 --- a/src/cascadia/TerminalSettings/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettings/TerminalSettings.cpp @@ -41,8 +41,9 @@ namespace winrt::Microsoft::Terminal::Settings::implementation _backgroundImageVerticalAlignment{ winrt::Windows::UI::Xaml::VerticalAlignment::Center }, _keyBindings{ nullptr }, _scrollbarState{ ScrollbarState::Visible }, - _antialiasingMode{ TextAntialiasingMode::Grayscale } - + _antialiasingMode{ TextAntialiasingMode::Grayscale }, + _forceFullRepaintRendering{ false }, + _softwareRendering{ false } { } @@ -387,6 +388,26 @@ namespace winrt::Microsoft::Terminal::Settings::implementation _retroTerminalEffect = value; } + bool TerminalSettings::ForceFullRepaintRendering() noexcept + { + return _forceFullRepaintRendering; + } + + void TerminalSettings::ForceFullRepaintRendering(bool value) noexcept + { + _forceFullRepaintRendering = value; + } + + bool TerminalSettings::SoftwareRendering() noexcept + { + return _softwareRendering; + } + + void TerminalSettings::SoftwareRendering(bool value) noexcept + { + _softwareRendering = value; + } + Settings::TextAntialiasingMode TerminalSettings::AntialiasingMode() const noexcept { return _antialiasingMode; diff --git a/src/cascadia/TerminalSettings/terminalsettings.h b/src/cascadia/TerminalSettings/terminalsettings.h index e78fa00901ef..6fa5c16dc9f4 100644 --- a/src/cascadia/TerminalSettings/terminalsettings.h +++ b/src/cascadia/TerminalSettings/terminalsettings.h @@ -104,6 +104,12 @@ namespace winrt::Microsoft::Terminal::Settings::implementation bool RetroTerminalEffect() noexcept; void RetroTerminalEffect(bool value) noexcept; + bool ForceFullRepaintRendering() noexcept; + void ForceFullRepaintRendering(bool value) noexcept; + + bool SoftwareRendering() noexcept; + void SoftwareRendering(bool value) noexcept; + TextAntialiasingMode AntialiasingMode() const noexcept; void AntialiasingMode(winrt::Microsoft::Terminal::Settings::TextAntialiasingMode const& value) noexcept; @@ -143,6 +149,8 @@ namespace winrt::Microsoft::Terminal::Settings::implementation Settings::ScrollbarState _scrollbarState; bool _retroTerminalEffect; + bool _forceFullRepaintRendering; + bool _softwareRendering; Settings::TextAntialiasingMode _antialiasingMode; }; diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index 1f2cbcdc7cfd..167853fa9dbe 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -84,6 +84,8 @@ DxEngine::DxEngine() : _boxDrawingEffect{}, _haveDeviceResources{ false }, _retroTerminalEffects{ false }, + _forceFullRepaintRendering{ false }, + _softwareRendering{ false }, _antialiasingMode{ D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE }, _defaultTextBackgroundOpacity{ 1.0f }, _hwndTarget{ static_cast(INVALID_HANDLE_VALUE) }, @@ -387,16 +389,23 @@ try // Trying hardware first for maximum performance, then trying WARP (software) renderer second // in case we're running inside a downlevel VM where hardware passthrough isn't enabled like // for Windows 7 in a VM. - const auto hardwareResult = D3D11CreateDevice(nullptr, - D3D_DRIVER_TYPE_HARDWARE, - nullptr, - DeviceFlags, - FeatureLevels.data(), - gsl::narrow_cast(FeatureLevels.size()), - D3D11_SDK_VERSION, - &_d3dDevice, - nullptr, - &_d3dDeviceContext); + HRESULT hardwareResult = E_NOT_SET; + + // If we're not forcing software rendering, try hardware first. + // Otherwise, let the error state fall down and create with the software renderer directly. + if (!_softwareRendering) + { + hardwareResult = D3D11CreateDevice(nullptr, + D3D_DRIVER_TYPE_HARDWARE, + nullptr, + DeviceFlags, + FeatureLevels.data(), + gsl::narrow_cast(FeatureLevels.size()), + D3D11_SDK_VERSION, + &_d3dDevice, + nullptr, + &_d3dDeviceContext); + } if (FAILED(hardwareResult)) { @@ -676,6 +685,16 @@ void DxEngine::SetRetroTerminalEffects(bool enable) noexcept _retroTerminalEffects = enable; } +void DxEngine::SetForceFullRepaintRendering(bool enable) noexcept +{ + _forceFullRepaintRendering = enable; +} + +void DxEngine::SetSoftwareRendering(bool enable) noexcept +{ + _softwareRendering = enable; +} + Microsoft::WRL::ComPtr DxEngine::GetSwapChain() { if (_dxgiSwapChain.Get() == nullptr) @@ -897,11 +916,14 @@ try { RETURN_HR_IF(E_NOT_VALID_STATE, _isPainting); // invalid to start a paint while painting. + // If someone explicitly requested differential rendering off, then we need to invalidate everything + // so the entire frame is repainted. + // // If retro terminal effects are on, we must invalidate everything for them to draw correctly. // Yes, this will further impact the performance of retro terminal effects. // But we're talking about running the entire display pipeline through a shader for // cosmetic effect, so performance isn't likely the top concern with this feature. - if (_retroTerminalEffects) + if (_forceFullRepaintRendering || _retroTerminalEffects) { _invalidMap.set_all(); } diff --git a/src/renderer/dx/DxRenderer.hpp b/src/renderer/dx/DxRenderer.hpp index 22f73c3e2b2b..95d2d1b02f4a 100644 --- a/src/renderer/dx/DxRenderer.hpp +++ b/src/renderer/dx/DxRenderer.hpp @@ -55,6 +55,10 @@ namespace Microsoft::Console::Render void SetRetroTerminalEffects(bool enable) noexcept; + void SetForceFullRepaintRendering(bool enable) noexcept; + + void SetSoftwareRendering(bool enable) noexcept; + ::Microsoft::WRL::ComPtr GetSwapChain(); // IRenderEngine Members @@ -190,6 +194,10 @@ namespace Microsoft::Console::Render ::Microsoft::WRL::ComPtr _samplerState; ::Microsoft::WRL::ComPtr _framebufferCapture; + // Preferences and overrides + bool _softwareRendering; + bool _forceFullRepaintRendering; + D2D1_TEXT_ANTIALIAS_MODE _antialiasingMode; float _defaultTextBackgroundOpacity;