diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index bbff93f15..fb48eab36 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -1841,6 +1841,12 @@ namespace bgfx { namespace d3d11 m_textures[ii].destroy(); } + for (uint32_t ii = 0; ii < BX_COUNTOF(m_uniforms); ++ii) + { + bx::free(g_allocator, m_uniforms[ii]); + m_uniforms[ii] = NULL; + } + DX_RELEASE(m_annotation, 1); dumpInfoQueue(); DX_RELEASE_W(m_infoQueue, 0); @@ -2477,6 +2483,26 @@ namespace bgfx { namespace d3d11 return m_lost; } + bool handleDeviceLost(HRESULT _hr) + { + const bool lost = isLost(_hr); + + if (lost + && !m_lost) + { + m_lost = true; + BGFX_FATAL(false + , bgfx::Fatal::DeviceLost + , "Device is lost. FAILED HRESULT(%x) %s (%s)" + , _hr + , getLostReason(_hr) + , DXGI_ERROR_DEVICE_REMOVED == _hr ? getLostReason(m_device->GetDeviceRemovedReason() ) : "no info" + ); + } + + return lost; + } + void flip() override { if (!m_lost) @@ -2514,15 +2540,7 @@ namespace bgfx { namespace d3d11 } } - m_lost = isLost(hr); - BGFX_FATAL( - !m_lost - , bgfx::Fatal::DeviceLost - , "Device is lost. FAILED HRESULT(%x) %s (%s)" - , hr - , getLostReason(hr) - , DXGI_ERROR_DEVICE_REMOVED == hr ? getLostReason(m_device->GetDeviceRemovedReason() ) : "no info" - ); + handleDeviceLost(hr); } } @@ -5983,24 +6001,6 @@ namespace bgfx { namespace d3d11 } } - static bool deviceLost(const HRESULT _hr) - { - if (isLost(_hr) ) - { - s_renderD3D11->m_lost = true; - BGFX_FATAL(false - , bgfx::Fatal::DeviceLost - , "Device is lost. FAILED HRESULT(%x) %s (%s)" - , _hr - , getLostReason(_hr) - , DXGI_ERROR_DEVICE_REMOVED == _hr ? getLostReason(s_renderD3D11->m_device->GetDeviceRemovedReason() ) : "no info" - ); - return true; - } - - return false; - } - bool TimerQueryD3D11::update() { if (0 != m_control.getNumUsed() ) @@ -6020,7 +6020,10 @@ namespace bgfx { namespace d3d11 { m_control.consume(1); - if (deviceLost(hr) ) + Result& result = m_result[query.m_resultIdx]; + --result.m_pending; + + if (s_renderD3D11->handleDeviceLost(hr) ) { return false; } @@ -6032,25 +6035,26 @@ namespace bgfx { namespace d3d11 }; D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint; - HRESULT hrDisjoint = deviceCtx->GetData(query.m_disjoint, &disjoint, sizeof(disjoint), 0); - if (deviceLost(hrDisjoint) ) + hr = deviceCtx->GetData(query.m_disjoint, &disjoint, sizeof(disjoint), 0); + + if (s_renderD3D11->handleDeviceLost(hr) ) { return false; } - DX_CHECK(hrDisjoint); + + BX_ASSERT(SUCCEEDED(hr), "GetData(m_disjoint) FAILED 0x%08x.", (uint32_t)hr); uint64_t timeBegin; - HRESULT hrBegin = deviceCtx->GetData(query.m_begin, &timeBegin, sizeof(timeBegin), 0); - if (deviceLost(hrBegin) ) + hr = deviceCtx->GetData(query.m_begin, &timeBegin, sizeof(timeBegin), 0); + + if (s_renderD3D11->handleDeviceLost(hr) ) { return false; } - DX_CHECK(hrBegin); - Result& result = m_result[query.m_resultIdx]; - --result.m_pending; - result.m_frameNum = query.m_frameNum; + BX_ASSERT(SUCCEEDED(hr), "GetData(m_begin) FAILED 0x%08x.", (uint32_t)hr); + result.m_frameNum = query.m_frameNum; result.m_frequency = disjoint.Frequency; result.m_begin = timeBegin; result.m_end = timeEnd; diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index 334fac978..9829f2b95 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -2131,6 +2131,12 @@ namespace bgfx { namespace d3d12 m_textures[ii].destroy(); } + for (uint32_t ii = 0; ii < BX_COUNTOF(m_uniforms); ++ii) + { + bx::free(g_allocator, m_uniforms[ii]); + m_uniforms[ii] = NULL; + } + #if BX_PLATFORM_WINDOWS dumpInfoQueue(); DX_RELEASE_W(m_infoQueue, 0); @@ -2186,6 +2192,26 @@ namespace bgfx { namespace d3d12 return m_lost; } + bool handleDeviceLost(HRESULT _hr) + { + const bool lost = isLost(_hr); + + if (lost + && !m_lost) + { + m_lost = true; + BGFX_FATAL(false + , 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" + ); + } + + return lost; + } + void flip() override { if (!m_lost) @@ -2223,14 +2249,7 @@ namespace bgfx { namespace d3d12 const int64_t now = bx::getHPCounter(); m_presentElapsed = now - start; - m_lost = 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" - ); + handleDeviceLost(hr); } } @@ -5165,7 +5184,12 @@ namespace bgfx { namespace d3d12 , currentIdx*sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) ); - DX_CHECK(commandList.m_commandList->Close() ); + HRESULT hr = commandList.m_commandList->Close(); + + if (!s_renderD3D12->handleDeviceLost(hr) ) + { + BX_ASSERT(SUCCEEDED(hr), "Close() FAILED 0x%08x.", (uint32_t)hr); + } ID3D12CommandList* commandLists[] = { commandList.m_commandList }; m_commandQueue->ExecuteCommandLists(BX_COUNTOF(commandLists), commandLists); @@ -5176,8 +5200,22 @@ namespace bgfx { namespace d3d12 commandList.m_event = CreateEventExA(NULL, NULL, 0, EVENT_ALL_ACCESS); #endif // BX_PLATFORM_LINUX const uint64_t fence = m_currentFence++; - m_commandQueue->Signal(m_fence, fence); - m_fence->SetEventOnCompletion(fence, commandList.m_event); + + hr = m_commandQueue->Signal(m_fence, fence); + + if (SUCCEEDED(hr) ) + { + hr = m_fence->SetEventOnCompletion(fence, commandList.m_event); + } + + if (FAILED(hr) ) + { + s_renderD3D12->handleDeviceLost(hr); + +#if !BX_PLATFORM_LINUX + SetEvent(commandList.m_event); +#endif // !BX_PLATFORM_LINUX + } m_control.commit(1); @@ -5229,10 +5267,18 @@ namespace bgfx { namespace d3d12 { CloseHandle(commandList.m_event); commandList.m_event = NULL; - m_completedFence = m_fence->GetCompletedValue(); - BX_WARN(UINT64_MAX != m_completedFence, "D3D12: Device lost."); - m_commandQueue->Wait(m_fence, m_completedFence); + const uint64_t completedFence = m_fence->GetCompletedValue(); + + if (UINT64_MAX == completedFence) + { + s_renderD3D12->handleDeviceLost(DXGI_ERROR_DEVICE_REMOVED); + } + else + { + m_completedFence = completedFence; + m_commandQueue->Wait(m_fence, m_completedFence); + } ResourceArray& ra = m_release[m_control.m_read]; for (ResourceArray::iterator it = ra.begin(), itEnd = ra.end(); it != itEnd; ++it) diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index 5412273f5..e65d68ceb 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -2508,6 +2508,12 @@ VK_IMPORT_DEVICE m_textures[ii].destroy(); } + for (uint32_t ii = 0; ii < BX_COUNTOF(m_uniforms); ++ii) + { + bx::free(g_allocator, m_uniforms[ii]); + m_uniforms[ii] = NULL; + } + m_backBuffer.destroy(); m_cmd.shutdown(); @@ -2560,11 +2566,35 @@ VK_IMPORT_DEVICE bool isDeviceRemoved() override { - return false; + return m_lost; + } + + bool handleDeviceLost(VkResult _result) + { + const bool lost = VK_ERROR_DEVICE_LOST == _result; + + if (lost + && !m_lost) + { + m_lost = true; + BGFX_FATAL(false + , bgfx::Fatal::DeviceLost + , "Device is lost. VK error 0x%x: %s" + , _result + , getName(_result) + ); + } + + return lost; } void flip() override { + if (m_lost) + { + return; + } + int64_t start = bx::getHPCounter(); for (uint16_t ii = 0; ii < m_numWindows; ++ii) @@ -5013,6 +5043,7 @@ VK_IMPORT_DEVICE bool m_borderColorSupport; bool m_timerQuerySupport; bool m_swapchainMaintenance1Supported = false; + bool m_lost = false; FrameBufferVK m_backBuffer; @@ -8785,6 +8816,7 @@ VK_DESTROY return false; default: + s_renderVK->handleDeviceLost(result); BX_ASSERT(VK_SUCCESS == result, "vkAcquireNextImageKHR(...); VK error 0x%x: %s", result, getName(result) ); return false; } @@ -8793,13 +8825,20 @@ VK_DESTROY { BGFX_PROFILER_SCOPE("vkWaitForFences", kColorWait); - VK_CHECK(vkWaitForFences( + result = vkWaitForFences( device , 1 , &m_backBufferFence[m_backBufferColorIdx] , VK_TRUE , UINT64_MAX - ) ); + ); + + if (s_renderVK->handleDeviceLost(result) ) + { + return false; + } + + BX_ASSERT(VK_SUCCESS == result, "vkWaitForFences(...); VK error 0x%x: %s", result, getName(result) ); } transitionImage(_commandBuffer); @@ -8873,6 +8912,7 @@ VK_DESTROY break; default: + s_renderVK->handleDeviceLost(result); BX_ASSERT(VK_SUCCESS == result, "vkQueuePresentKHR(...); VK error 0x%x: %s", result, getName(result) ); break; } @@ -9312,6 +9352,7 @@ VK_DESTROY if (VK_SUCCESS != result) { + s_renderVK->handleDeviceLost(result); BX_TRACE("Allocate command buffer error: vkWaitForFences failed %d: %s.", result, getName(result) ); return result; } @@ -9422,14 +9463,24 @@ VK_DESTROY { BGFX_PROFILER_SCOPE("vkQueueSubmit", kColorDraw); - VK_CHECK(vkQueueSubmit(m_queue, 1, &si, m_completedFence) ); + VkResult result = vkQueueSubmit(m_queue, 1, &si, m_completedFence); + + if (!s_renderVK->handleDeviceLost(result) ) + { + BX_ASSERT(VK_SUCCESS == result, "vkQueueSubmit(...); VK error 0x%x: %s", result, getName(result) ); + } } if (_wait) { BGFX_PROFILER_SCOPE("vkWaitForFences", kColorWait); - VK_CHECK(vkWaitForFences(device, 1, &m_completedFence, VK_TRUE, UINT64_MAX) ); + VkResult result = vkWaitForFences(device, 1, &m_completedFence, VK_TRUE, UINT64_MAX); + + if (!s_renderVK->handleDeviceLost(result) ) + { + BX_ASSERT(VK_SUCCESS == result, "vkWaitForFences(...); VK error 0x%x: %s", result, getName(result) ); + } } m_activeCommandBuffer = VK_NULL_HANDLE; @@ -9741,7 +9792,8 @@ VK_DESTROY void RendererContextVK::submit(Frame* _render, const ClearQuad& /*_clearQuad*/, const MipGen& /*_mipGen*/, TextVideoMemBlitter& _textVideoMemBlitter) { - if (updateResolution(_render->m_resolution) ) + if (m_lost + || updateResolution(_render->m_resolution) ) { return; } diff --git a/src/renderer_webgpu.cpp b/src/renderer_webgpu.cpp index 3986667fb..b58e00d45 100644 --- a/src/renderer_webgpu.cpp +++ b/src/renderer_webgpu.cpp @@ -780,21 +780,6 @@ WGPU_IMPORT } } - static void deviceLostCb( - const WGPUDevice* _device - , WGPUDeviceLostReason _reason - , WGPUStringView _message - , void* _userdata1 - , void* _userdata2 - ) - { - BX_UNUSED(_device, _reason, _message, _userdata1, _userdata2); - - BX_TRACE("Reason: %d", _reason); - - trace(_message); - } - static uint32_t s_uncapturedError = 0; static bool wgpuErrorCheck() @@ -912,6 +897,52 @@ WGPU_IMPORT renderCtx->m_device = _device; } + static void deviceLostCb( + const WGPUDevice* _device + , WGPUDeviceLostReason _reason + , WGPUStringView _message + , void* _userdata1 + , void* _userdata2 + ) + { + BX_UNUSED(_device, _userdata2); + + BX_TRACE("Reason: %d", _reason); + + trace(_message); + + switch (_reason) + { + case WGPUDeviceLostReason_Destroyed: + case WGPUDeviceLostReason_CallbackCancelled: + case WGPUDeviceLostReason_FailedCreation: + return; + + default: + break; + } + + RendererContextWGPU* renderCtx = (RendererContextWGPU*)_userdata1; + renderCtx->handleDeviceLost(_message); + } + + void handleDeviceLost(const WGPUStringView& _message) + { + if (0 != bx::atomicCompareAndSwap(&m_lost, 0, 1) ) + { + return; + } + + const bx::StringView msg = toStringView(_message); + + BGFX_FATAL(false + , bgfx::Fatal::DeviceLost + , "Device is lost. %.*s" + , msg.getLength() + , msg.getPtr() + ); + } + WGPUWaitStatus waitForFuture(WGPUFutureWaitInfo& _fwi) { wgpuInstanceProcessEvents(m_instance); @@ -1268,10 +1299,7 @@ WGPU_IMPORT .deviceLostCallbackInfo = { .nextInChain = NULL, - .mode = BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) - ? WGPUCallbackMode_AllowSpontaneous - : WGPUCallbackMode_WaitAnyOnly - , + .mode = WGPUCallbackMode_AllowSpontaneous, .callback = deviceLostCb, .userdata1 = this, .userdata2 = NULL, @@ -1563,6 +1591,12 @@ WGPU_IMPORT m_textures[ii].destroy(); } + for (uint32_t ii = 0; ii < BX_COUNTOF(m_uniforms); ++ii) + { + bx::free(g_allocator, m_uniforms[ii]); + m_uniforms[ii] = NULL; + } + m_backBuffer.destroy(); m_gpuTimer.shutdown(); @@ -1593,11 +1627,16 @@ WGPU_IMPORT bool isDeviceRemoved() override { - return false; + return 0 != m_lost; } void flip() override { + if (0 != m_lost) + { + return; + } + int64_t start = bx::getHPCounter(); for (uint16_t ii = 0; ii < m_numWindows; ++ii) @@ -3463,6 +3502,8 @@ WGPU_IMPORT uint8_t m_fsScratch[64<<10]; uint8_t m_vsScratch[64<<10]; + + uint32_t m_lost = 0; }; static RendererContextWGPU* s_renderWGPU; @@ -5887,6 +5928,11 @@ m_resolution.formatColor = TextureFormat::BGRA8; void RendererContextWGPU::submit(Frame* _render, const ClearQuad& _clearQuad, const MipGen& _mipGen, TextVideoMemBlitter& _textVideoMemBlitter) { + if (0 != m_lost) + { + return; + } + m_mipGen = &_mipGen; m_occlusionQuery.readResultsAsync(_render); m_gpuTimer.readResultsAsync();