Skip to content

Commit 5d4e6ce

Browse files
committed
Add some retry support to Renderer::PaintFrame (#2830)
If _PaintFrameForEngine returns E_PENDING, we'll give it another two tries to get itself straight. If it continues to fail, we'll take down the application. We observed that the DX renderer was failing to present the swap chain and failfast'ing when it did so; however, there are some errors from which DXGI guidance suggests we try to recover. We'll now return E_PENDING (and destroy our device resources) when we hit those errors. Fixes #2265. (cherry picked from commit 277acc3)
1 parent 929c9af commit 5d4e6ce

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

src/renderer/base/renderer.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
using namespace Microsoft::Console::Render;
1111
using namespace Microsoft::Console::Types;
1212

13+
static constexpr auto maxRetriesForRenderEngine = 3;
14+
1315
// Routine Description:
1416
// - Creates a new renderer controller for a console.
1517
// Arguments:
@@ -62,7 +64,21 @@ Renderer::~Renderer()
6264

6365
for (IRenderEngine* const pEngine : _rgpEngines)
6466
{
65-
LOG_IF_FAILED(_PaintFrameForEngine(pEngine));
67+
auto tries = maxRetriesForRenderEngine;
68+
while (tries > 0)
69+
{
70+
const auto hr = _PaintFrameForEngine(pEngine);
71+
if (E_PENDING == hr)
72+
{
73+
if (--tries == 0)
74+
{
75+
FAIL_FAST_HR_MSG(E_UNEXPECTED, "A rendering engine required too many retries.");
76+
}
77+
continue;
78+
}
79+
LOG_IF_FAILED(hr);
80+
break;
81+
}
6682
}
6783

6884
return S_OK;

src/renderer/dx/DxRenderer.cpp

+19-3
Original file line numberDiff line numberDiff line change
@@ -866,15 +866,31 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
866866
// Arguments:
867867
// - <none>
868868
// Return Value:
869-
// - S_OK or relevant DirectX error
869+
// - S_OK on success, E_PENDING to indicate a retry or a relevant DirectX error
870870
[[nodiscard]] HRESULT DxEngine::Present() noexcept
871871
{
872872
if (_presentReady)
873873
{
874874
try
875875
{
876-
FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present(1, 0));
877-
/*FAIL_FAST_IF_FAILED(_dxgiSwapChain->Present1(1, 0, &_presentParams));*/
876+
HRESULT hr = S_OK;
877+
878+
hr = _dxgiSwapChain->Present(1, 0);
879+
/*hr = _dxgiSwapChain->Present1(1, 0, &_presentParams);*/
880+
881+
if (FAILED(hr))
882+
{
883+
// These two error codes are indicated for destroy-and-recreate
884+
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
885+
{
886+
// We don't need to end painting here, as the renderer has done it for us.
887+
_ReleaseDeviceResources();
888+
FAIL_FAST_IF_FAILED(InvalidateAll());
889+
return E_PENDING; // Indicate a retry to the renderer.
890+
}
891+
892+
FAIL_FAST_HR(hr);
893+
}
878894

879895
RETURN_IF_FAILED(_CopyFrontToBack());
880896
_presentReady = false;

0 commit comments

Comments
 (0)