Skip to content

Commit

Permalink
Add some retry support to Renderer::PaintFrame (microsoft#2830)
Browse files Browse the repository at this point in the history
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 microsoft#2265.
  • Loading branch information
DHowett authored Sep 23, 2019
1 parent 8afc5b2 commit 277acc3
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
18 changes: 17 additions & 1 deletion src/renderer/base/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down
22 changes: 19 additions & 3 deletions src/renderer/dx/DxRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -866,15 +866,31 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
// Arguments:
// - <none>
// 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;
Expand Down

0 comments on commit 277acc3

Please sign in to comment.