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;