From 427172edcfb16b10a6609391beb491c661868da5 Mon Sep 17 00:00:00 2001 From: myT Date: Tue, 7 Jul 2020 09:07:53 +0200 Subject: [PATCH] fixed D3D11 device resets being sometimes treated as fatal errors after getting DXGI_ERROR_DEVICE_REMOVED or D3DDDIERR_DEVICEREMOVED, GetDeviceRemovedReason can return DXGI_ERROR_DEVICE_RESET this particular case should trigger a video restart instead of a fatal error --- changelog.txt | 2 ++ code/renderer/tr_backend_d3d11.cpp | 35 ++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 35d673f..4f4ebfb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -9,6 +9,8 @@ add: r_alphaToCoverageMipBoost <0.0 to 0.5> (default: 0.125) boosts the alpha va chg: with r_backend GL3, alpha to coverage now requires GLSL 4.00 at a minimum +fix: with r_backend D3D11, some device reset scenarios caused fatal errors instead of video restarts + fix: CVar slots that have been freed (e.g. through unset/cvar_trim/cvar_reset) can now be re-used fix: with alpha to coverage enabled, high r_picmip values should longer cause diff --git a/code/renderer/tr_backend_d3d11.cpp b/code/renderer/tr_backend_d3d11.cpp index 11969a3..7a53c53 100644 --- a/code/renderer/tr_backend_d3d11.cpp +++ b/code/renderer/tr_backend_d3d11.cpp @@ -542,16 +542,17 @@ static qbool D3D11_CreateInputLayout(const D3D11_INPUT_ELEMENT_DESC* pInputEleme return CheckAndName(hr, "CreateInputLayout", *ppInputLayout, name); } -static const char* GetDeviceRemovedReason() +static const char* GetDeviceRemovedReasonString(HRESULT reason) { - switch(d3ds.device->GetDeviceRemovedReason()) + switch(reason) { case DXGI_ERROR_DEVICE_HUNG: return "device hung"; case DXGI_ERROR_DEVICE_REMOVED: return "device removed"; case DXGI_ERROR_DEVICE_RESET: return "device reset"; case DXGI_ERROR_DRIVER_INTERNAL_ERROR: return "internal driver error"; case DXGI_ERROR_INVALID_CALL: return "invalid call"; - default: return "unknown"; + case S_OK: return "no error"; + default: return va("unknown error code 0x%08X", (unsigned int)reason); } } @@ -2090,11 +2091,37 @@ static void GAL_EndFrame() const UINT presentFlags = d3ds.flipAndTear && r_swapInterval->integer == 0 ? DXGI_PRESENT_ALLOW_TEARING : 0; const HRESULT hr = d3ds.swapChain->Present(abs(r_swapInterval->integer), presentFlags); + + enum PresentError + { + PE_NONE, + PE_DEVICE_REMOVED, + PE_DEVICE_RESET + }; + PresentError presentError = PE_NONE; + HRESULT deviceRemovedReason = S_OK; if(hr == DXGI_ERROR_DEVICE_REMOVED || hr == D3DDDIERR_DEVICEREMOVED) { - ri.Error(ERR_FATAL, "Direct3D device was removed! Reason: %s", GetDeviceRemovedReason()); + deviceRemovedReason = d3ds.device->GetDeviceRemovedReason(); + if(deviceRemovedReason == DXGI_ERROR_DEVICE_RESET) + { + presentError = PE_DEVICE_RESET; + } + else + { + presentError = PE_DEVICE_REMOVED; + } } else if(hr == DXGI_ERROR_DEVICE_RESET) + { + presentError = PE_DEVICE_RESET; + } + + if(presentError == PE_DEVICE_REMOVED) + { + ri.Error(ERR_FATAL, "Direct3D device was removed! Reason: %s", GetDeviceRemovedReasonString(deviceRemovedReason)); + } + else if(presentError == PE_DEVICE_RESET) { ri.Printf(PRINT_ERROR, "Direct3D device was reset! Restarting the video system..."); Cmd_ExecuteString("vid_restart;");