diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 72987ead7..643d9a31f 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -1669,6 +1669,13 @@ namespace bgfx { m_renderCtx->flip(m_render->m_hmd); m_flipped = true; + + if (m_renderCtx->isDeviceRemoved() ) + { + // Something horribly went wrong, fallback to noop renderer. + m_renderCtx = m_renderNoop; + g_caps.rendererType = m_renderCtx->getRendererType(); + } } if (apiSemWait(_msecs) ) @@ -1834,7 +1841,7 @@ namespace bgfx static RendererCreator s_rendererCreator[] = { - { noop::rendererCreate, noop::rendererDestroy, BGFX_RENDERER_NOOP_NAME, !!BGFX_CONFIG_RENDERER_NOOP }, // Noop + { noop::rendererCreate, noop::rendererDestroy, BGFX_RENDERER_NOOP_NAME, true }, // Noop { d3d9::rendererCreate, d3d9::rendererDestroy, BGFX_RENDERER_DIRECT3D9_NAME, !!BGFX_CONFIG_RENDERER_DIRECT3D9 }, // Direct3D9 { d3d11::rendererCreate, d3d11::rendererDestroy, BGFX_RENDERER_DIRECT3D11_NAME, !!BGFX_CONFIG_RENDERER_DIRECT3D11 }, // Direct3D11 { d3d12::rendererCreate, d3d12::rendererDestroy, BGFX_RENDERER_DIRECT3D12_NAME, !!BGFX_CONFIG_RENDERER_DIRECT3D12 }, // Direct3D12 @@ -1850,8 +1857,6 @@ namespace bgfx }; BX_STATIC_ASSERT(BX_COUNTOF(s_rendererCreator) == RendererType::Count); - static RendererDestroyFn s_rendererDestroyFn; - struct Condition { enum Enum @@ -1974,7 +1979,6 @@ namespace bgfx renderCtx = s_rendererCreator[renderer].createFn(); if (NULL != renderCtx) { - s_rendererDestroyFn = s_rendererCreator[renderer].destroyFn; break; } @@ -1984,9 +1988,12 @@ namespace bgfx return renderCtx; } - void rendererDestroy() + void rendererDestroy(RendererContextI* _renderCtx) { - s_rendererDestroyFn(); + if (NULL != _renderCtx) + { + s_rendererCreator[_renderCtx->getRendererType()].destroyFn(); + } } void Context::rendererExecCommands(CommandBuffer& _cmdbuf) @@ -2020,8 +2027,9 @@ namespace bgfx RendererType::Enum type; _cmdbuf.read(type); - m_renderCtx = rendererCreate(type); - m_rendererInitialized = NULL != m_renderCtx; + m_renderMain = rendererCreate(type); + + m_rendererInitialized = NULL != m_renderMain; if (!m_rendererInitialized) { @@ -2031,6 +2039,12 @@ namespace bgfx ); return; } + + m_renderCtx = m_renderMain; + m_renderNoop = RendererType::Noop != type + ? rendererCreate(RendererType::Noop) + : NULL + ; } break; } @@ -2053,8 +2067,15 @@ namespace bgfx case CommandBuffer::RendererShutdownEnd: { BX_CHECK(!m_rendererInitialized && !m_exit, "This shouldn't happen! Bad synchronization?"); - rendererDestroy(); + m_renderCtx = NULL; + + rendererDestroy(m_renderMain); + m_renderMain = NULL; + + rendererDestroy(m_renderNoop); + m_renderNoop = NULL; + m_exit = true; } // fall through diff --git a/src/bgfx_p.h b/src/bgfx_p.h index b8306aa62..b49b4eaed 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -2178,6 +2178,7 @@ namespace bgfx virtual ~RendererContextI() = 0; virtual RendererType::Enum getRendererType() const = 0; virtual const char* getRendererName() const = 0; + virtual bool isDeviceRemoved() = 0; virtual void flip(HMD& _hmd) = 0; virtual void createIndexBuffer(IndexBufferHandle _handle, Memory* _mem, uint16_t _flags) = 0; virtual void destroyIndexBuffer(IndexBufferHandle _handle) = 0; @@ -2244,6 +2245,8 @@ namespace bgfx , m_frames(0) , m_debug(BGFX_DEBUG_NONE) , m_renderCtx(NULL) + , m_renderMain(NULL) + , m_renderNoop(NULL) , m_rendererInitialized(false) , m_exit(false) , m_flipAfterRender(false) @@ -4308,6 +4311,8 @@ namespace bgfx ClearQuad m_clearQuad; RendererContextI* m_renderCtx; + RendererContextI* m_renderMain; + RendererContextI* m_renderNoop; bool m_rendererInitialized; bool m_exit; diff --git a/src/config.h b/src/config.h index 6ee682243..9f5ca582e 100644 --- a/src/config.h +++ b/src/config.h @@ -19,8 +19,7 @@ && !defined(BGFX_CONFIG_RENDERER_OPENGL) \ && !defined(BGFX_CONFIG_RENDERER_OPENGLES) \ && !defined(BGFX_CONFIG_RENDERER_VULKAN) \ - && !defined(BGFX_CONFIG_RENDERER_GNM) \ - && !defined(BGFX_CONFIG_RENDERER_NOOP) + && !defined(BGFX_CONFIG_RENDERER_GNM) # ifndef BGFX_CONFIG_RENDERER_DIRECT3D9 # define BGFX_CONFIG_RENDERER_DIRECT3D9 (0 \ @@ -86,18 +85,6 @@ ? 1 : 0) # endif // BGFX_CONFIG_RENDERER_GNM -# ifndef BGFX_CONFIG_RENDERER_NOOP -# define BGFX_CONFIG_RENDERER_NOOP (!(0 \ - || BGFX_CONFIG_RENDERER_DIRECT3D9 \ - || BGFX_CONFIG_RENDERER_DIRECT3D11 \ - || BGFX_CONFIG_RENDERER_DIRECT3D12 \ - || BGFX_CONFIG_RENDERER_METAL \ - || BGFX_CONFIG_RENDERER_OPENGL \ - || BGFX_CONFIG_RENDERER_OPENGLES \ - || BGFX_CONFIG_RENDERER_VULKAN \ - || BGFX_CONFIG_RENDERER_GNM \ - ? 1 : 0) ) -# endif // BGFX_CONFIG_RENDERER_NOOP #else # ifndef BGFX_CONFIG_RENDERER_DIRECT3D9 # define BGFX_CONFIG_RENDERER_DIRECT3D9 0 @@ -130,10 +117,6 @@ # ifndef BGFX_CONFIG_RENDERER_GNM # define BGFX_CONFIG_RENDERER_GNM 0 # endif // BGFX_CONFIG_RENDERER_GNM - -# ifndef BGFX_CONFIG_RENDERER_NOOP -# define BGFX_CONFIG_RENDERER_NOOP 0 -# endif // BGFX_CONFIG_RENDERER_NOOP #endif // !defined... #if BGFX_CONFIG_RENDERER_OPENGL && BGFX_CONFIG_RENDERER_OPENGL < 21 diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 7b1e23dc7..30223ee86 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -455,6 +455,35 @@ namespace bgfx { namespace d3d11 ; } + static const char* getLostReason(HRESULT _hr) + { + switch (_hr) + { + // The GPU device instance has been suspended. Use GetDeviceRemovedReason to determine the appropriate action. + case DXGI_ERROR_DEVICE_REMOVED: return "DXGI_ERROR_DEVICE_REMOVED"; + + // The GPU will not respond to more commands, most likely because of an invalid command passed by the calling application. + case DXGI_ERROR_DEVICE_HUNG: return "DXGI_ERROR_DEVICE_HUNG"; + + // The GPU will not respond to more commands, most likely because some other application submitted invalid commands. + // The calling application should re-create the device and continue. + case DXGI_ERROR_DEVICE_RESET: return "DXGI_ERROR_DEVICE_RESET"; + + // An internal issue prevented the driver from carrying out the specified operation. The driver's state is probably + // suspect, and the application should not continue. + case DXGI_ERROR_DRIVER_INTERNAL_ERROR: return "DXGI_ERROR_DRIVER_INTERNAL_ERROR"; + + // A resource is not available at the time of the call, but may become available later. + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: return "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE"; + + case S_OK: return "S_OK"; + + default: break; + } + + return "Unknown HRESULT?"; + } + template static BX_NO_INLINE void setDebugObjectName(Ty* _interface, const char* _format, ...) { @@ -654,7 +683,7 @@ namespace bgfx { namespace d3d11 , m_adapter(NULL) , m_factory(NULL) , m_swapChain(NULL) - , m_lost(0) + , m_lost(false) , m_numWindows(0) , m_device(NULL) , m_deviceCtx(NULL) @@ -2263,9 +2292,15 @@ BX_PRAGMA_DIAGNOSTIC_POP(); capturePostReset(); } + bool isDeviceRemoved() BX_OVERRIDE + { + return m_lost; + } + void flip(HMD& _hmd) BX_OVERRIDE { - if (NULL != m_swapChain) + if (NULL != m_swapChain + && !m_lost) { HRESULT hr = S_OK; uint32_t syncInterval = BX_ENABLED(!BX_PLATFORM_WINDOWS) @@ -2298,15 +2333,14 @@ BX_PRAGMA_DIAGNOSTIC_POP(); } } - if (isLost(hr) ) - { - ++m_lost; - BGFX_FATAL(10 > m_lost, bgfx::Fatal::DeviceLost, "Device is lost. FAILED 0x%08x", hr); - } - else - { - m_lost = 0; - } + m_lost = d3d11::isLost(hr); + BGFX_FATAL(!m_lost + , bgfx::Fatal::DeviceLost + , "Device is lost. FAILED 0x%08x %s (%s)" + , hr + , getLostReason(hr) + , DXGI_ERROR_DEVICE_REMOVED == hr ? getLostReason(m_device->GetDeviceRemovedReason() ) : "no info" + ); } } @@ -3551,7 +3585,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); #endif // BX_PLATFORM_WINDOWS bool m_needPresent; - uint16_t m_lost; + bool m_lost; uint16_t m_numWindows; FrameBufferHandle m_windows[BGFX_CONFIG_MAX_FRAME_BUFFERS]; @@ -5273,7 +5307,8 @@ BX_PRAGMA_DIAGNOSTIC_POP(); void RendererContextD3D11::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) { - if (updateResolution(_render->m_resolution) ) + if (m_lost + || updateResolution(_render->m_resolution) ) { return; } diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index bea9c232e..93b62a8f2 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -1260,7 +1260,7 @@ namespace bgfx { namespace d3d12 return BGFX_RENDERER_DIRECT3D12_NAME; } - static bool isLost(HRESULT _hr) + static bool isDeviceRemoved(HRESULT _hr) { return DXGI_ERROR_DEVICE_REMOVED == _hr || DXGI_ERROR_DEVICE_HUNG == _hr @@ -1270,6 +1270,11 @@ namespace bgfx { namespace d3d12 ; } + bool isDeviceRemoved() BX_OVERRIDE + { + return false; + } + void flip(HMD& /*_hmd*/) BX_OVERRIDE { if (NULL != m_swapChain) @@ -1294,7 +1299,7 @@ namespace bgfx { namespace d3d12 m_presentElapsed = now - start; if (FAILED(hr) - && isLost(hr) ) + && isDeviceRemoved(hr) ) { ++m_lost; BGFX_FATAL(10 > m_lost, bgfx::Fatal::DeviceLost, "Device is lost. FAILED 0x%08x", hr); @@ -5337,7 +5342,7 @@ data.NumQualityLevels = 0; buffer.setState(m_commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); scratchBuffer.allocUav(srvHandle[stage], buffer); } - else + else { buffer.setState(m_commandList, D3D12_RESOURCE_STATE_GENERIC_READ); scratchBuffer.allocSrv(srvHandle[stage], buffer); diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index 9dc4cdd52..0fb09fa01 100644 --- a/src/renderer_d3d9.cpp +++ b/src/renderer_d3d9.cpp @@ -1458,6 +1458,11 @@ namespace bgfx { namespace d3d9 m_flushQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); } + bool isDeviceRemoved() BX_OVERRIDE + { + return false; + } + void flip(HMD& /*_hmd*/) BX_OVERRIDE { if (NULL != m_swapChain) @@ -1488,7 +1493,7 @@ namespace bgfx { namespace d3d9 } #if BX_PLATFORM_WINDOWS - if (isLost(hr) ) + if (d3d9::isLost(hr) ) { do { diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index cc2075b93..da123ffd0 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2289,6 +2289,11 @@ namespace bgfx { namespace gl return BGFX_RENDERER_OPENGL_NAME; } + bool isDeviceRemoved() BX_OVERRIDE + { + return false; + } + void flip(HMD& _hmd) { if (m_flip) diff --git a/src/renderer_mtl.mm b/src/renderer_mtl.mm index 2d749de45..b822dd973 100644 --- a/src/renderer_mtl.mm +++ b/src/renderer_mtl.mm @@ -1069,6 +1069,11 @@ namespace bgfx { namespace mtl } } + bool isDeviceRemoved() BX_OVERRIDE + { + return false; + } + void flip(HMD& /*_hmd*/) BX_OVERRIDE { if (NULL == m_commandBuffer) diff --git a/src/renderer_noop.cpp b/src/renderer_noop.cpp index 24fbfb485..5a1e2285e 100644 --- a/src/renderer_noop.cpp +++ b/src/renderer_noop.cpp @@ -5,8 +5,6 @@ #include "bgfx_p.h" -#if BGFX_CONFIG_RENDERER_NOOP - namespace bgfx { namespace noop { struct RendererContextNOOP : public RendererContextI @@ -52,6 +50,11 @@ namespace bgfx { namespace noop return BGFX_RENDERER_NOOP_NAME; } + bool isDeviceRemoved() BX_OVERRIDE + { + return false; + } + void flip(HMD& /*_hmd*/) BX_OVERRIDE { } @@ -224,19 +227,3 @@ namespace bgfx { namespace noop s_renderNOOP = NULL; } } /* namespace noop */ } // namespace bgfx - -#else - -namespace bgfx { namespace noop -{ - RendererContextI* rendererCreate() - { - return NULL; - } - - void rendererDestroy() - { - } -} /* namespace noop */ } // namespace bgfx - -#endif // BGFX_CONFIG_RENDERER_NOOP diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index f9d633f1b..28e2146c5 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -1919,6 +1919,11 @@ VK_IMPORT_DEVICE return BGFX_RENDERER_VULKAN_NAME; } + bool isDeviceRemoved() BX_OVERRIDE + { + return false; + } + void flip(HMD& /*_hmd*/) BX_OVERRIDE { if (VK_NULL_HANDLE != m_swapchain)