From 3fe7df49182d7e2f29bd0a68e3372e499b895cb6 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett (MSFT)" Date: Tue, 14 Apr 2020 13:11:47 -0700 Subject: [PATCH] Add support for renderer backoff, don't FAIL_FAST on 3x failures, add UI (#5353) Renderer: Add support for backoff and auto-disable on failed retry This commit introduces a backoff (150ms * number of tries) to the renderer's retry logic (introduced in #2830). It also changes the FAIL_FAST to a less globally-harmful render thread disable, so that we stop blowing up any application hosting a terminal when the graphics driver goes away. In addition, it adds a callback that a Renderer consumer can use to determine when the renderer _has_ failed, and a public method to kick it back into life. Fixes #5340. This PR also wires up TermControl so that it shows some UI when the renderer tastes clay. ![image](https://user-images.githubusercontent.com/14316954/79266118-f073f680-7e4b-11ea-8b96-5588a13aff3b.png) ![image](https://user-images.githubusercontent.com/14316954/79266125-f36ee700-7e4b-11ea-9314-4280e9149461.png) * [x] Closes #5340 * [x] cla * [ ] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. I tested this by dropping the number of retries to 1 and forcing a TDR while doing `wsl cmatrix -u0`. It picked up exactly where it left off. As a bonus, you can actually still type into the terminal when it's graphically suspended (and `exit` still works.). The block is _entirely graphical_. --- .../Resources/Resources.language-en.resw | 8 ++++- src/cascadia/TerminalControl/TermControl.cpp | 32 +++++++++++++++++ src/cascadia/TerminalControl/TermControl.h | 2 ++ src/cascadia/TerminalControl/TermControl.xaml | 17 +++++++++ src/renderer/base/renderer.cpp | 36 ++++++++++++++++++- src/renderer/base/renderer.hpp | 5 +++ src/renderer/base/thread.cpp | 6 ++++ src/renderer/base/thread.hpp | 1 + src/renderer/inc/IRenderThread.hpp | 1 + 9 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalControl/Resources/Resources.language-en.resw b/src/cascadia/TerminalControl/Resources/Resources.language-en.resw index 555318f3e8e..8b51e3c3245 100644 --- a/src/cascadia/TerminalControl/Resources/Resources.language-en.resw +++ b/src/cascadia/TerminalControl/Resources/Resources.language-en.resw @@ -164,4 +164,10 @@ Close Search Box - \ No newline at end of file + + This terminal has encountered an issue with the graphics driver and it could not recover in time. It has been suspended. + + + Resume + + diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 0d955716ca0..6f40a442891 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -522,6 +522,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation _renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(_terminal.get(), nullptr, 0, std::move(renderThread)); ::Microsoft::Console::Render::IRenderTarget& renderTarget = *_renderer; + _renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() { + if (auto strongThis{ weakThis.get() }) + { + strongThis->_RendererEnteredErrorState(); + } + }); + THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get())); // Set up the DX Engine @@ -2362,6 +2369,31 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation e.DragUIOverride().IsGlyphVisible(false); } + // Method Description: + // - Produces the error dialog that notifies the user that rendering cannot proceed. + winrt::fire_and_forget TermControl::_RendererEnteredErrorState() + { + auto strongThis{ get_strong() }; + co_await Dispatcher(); // pop up onto the UI thread + + if (auto loadedUiElement{ FindName(L"RendererFailedNotice") }) + { + if (auto uiElement{ loadedUiElement.try_as<::winrt::Windows::UI::Xaml::UIElement>() }) + { + uiElement.Visibility(Visibility::Visible); + } + } + } + + // Method Description: + // - Responds to the Click event on the button that will re-enable the renderer. + void TermControl::_RenderRetryButton_Click(IInspectable const& /*sender*/, IInspectable const& /*args*/) + { + // It's already loaded if we get here, so just hide it. + RendererFailedNotice().Visibility(Visibility::Collapsed); + _renderer->ResetErrorStateAndResume(); + } + // -------------------------------- WinRT Events --------------------------------- // Winrt events need a method for adding a callback to the event and removing the callback. // These macros will define them both for you. diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 57606506bee..a76772bed1a 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -78,6 +78,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void ResetFontSize(); winrt::fire_and_forget SwapChainChanged(); + winrt::fire_and_forget _RendererEnteredErrorState(); + void _RenderRetryButton_Click(IInspectable const& button, IInspectable const& args); void CreateSearchBoxControl(); diff --git a/src/cascadia/TerminalControl/TermControl.xaml b/src/cascadia/TerminalControl/TermControl.xaml index a6a24e628b2..32609b73926 100644 --- a/src/cascadia/TerminalControl/TermControl.xaml +++ b/src/cascadia/TerminalControl/TermControl.xaml @@ -77,6 +77,23 @@ CurrentCursorPosition="_CurrentCursorPositionHandler" CurrentFontInfo="_FontInfoHandler" /> + + + + +