diff --git a/src/renderer/base/renderer.cpp b/src/renderer/base/renderer.cpp index 2dffc9a1550..e434c5d0725 100644 --- a/src/renderer/base/renderer.cpp +++ b/src/renderer/base/renderer.cpp @@ -10,6 +10,8 @@ using namespace Microsoft::Console::Render; using namespace Microsoft::Console::Types; +static constexpr auto maxRetriesForRenderEngine = 3; + // Routine Description: // - Creates a new renderer controller for a console. // Arguments: @@ -62,7 +64,21 @@ Renderer::~Renderer() for (IRenderEngine* const pEngine : _rgpEngines) { - LOG_IF_FAILED(_PaintFrameForEngine(pEngine)); + auto tries = maxRetriesForRenderEngine; + while (tries > 0) + { + const auto hr = _PaintFrameForEngine(pEngine); + if (E_PENDING == hr) + { + if (--tries == 0) + { + FAIL_FAST_HR_MSG(E_UNEXPECTED, "A rendering engine required too many retries."); + } + continue; + } + LOG_IF_FAILED(hr); + break; + } } return S_OK; diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index e8cb5589de6..3d52a4b68d1 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -866,15 +866,31 @@ void DxEngine::_InvalidOr(RECT rc) noexcept // Arguments: // - // Return Value: -// - S_OK or relevant DirectX error +// - S_OK on success, E_PENDING to indicate a retry or a relevant DirectX error [[nodiscard]] HRESULT DxEngine::Present() noexcept { if (_presentReady) { try { - FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present(1, 0)); - /*FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present1(1, 0, &_presentParams));*/ + HRESULT hr = S_OK; + + hr = _dxgiSwapChain->Present(1, 0); + /*hr = _dxgiSwapChain->Present1(1, 0, &_presentParams);*/ + + if (FAILED(hr)) + { + // These two error codes are indicated for destroy-and-recreate + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) + { + // We don't need to end painting here, as the renderer has done it for us. + _ReleaseDeviceResources(); + FAIL_FAST_IF_FAILED(InvalidateAll()); + return E_PENDING; // Indicate a retry to the renderer. + } + + FAIL_FAST_HR(hr); + } RETURN_IF_FAILED(_CopyFrontToBack()); _presentReady = false;