diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index bc5becb5f2299..aeff5264a6697 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -228,6 +228,7 @@ typedef enum SDL_EventType /* Render events */ SDL_EVENT_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */ SDL_EVENT_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */ + SDL_EVENT_RENDER_DEVICE_LOST, /**< The device has been lost and can't be recovered. */ /* Reserved events for private platforms */ SDL_EVENT_PRIVATE0 = 0x4000, diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index f75bf02e3c7f5..f678dfb893ae5 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -982,39 +982,6 @@ static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer *renderer) SAFE_RELEASE(data->mainRenderTargetView); } -static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer); - -static HRESULT D3D11_HandleDeviceLost(SDL_Renderer *renderer) -{ - HRESULT result = S_OK; - - D3D11_ReleaseAll(renderer); - - result = D3D11_CreateDeviceResources(renderer); - if (FAILED(result)) { - // D3D11_CreateDeviceResources will set the SDL error - D3D11_ReleaseAll(renderer); - return result; - } - - result = D3D11_UpdateForWindowSizeChange(renderer); - if (FAILED(result)) { - // D3D11_UpdateForWindowSizeChange will set the SDL error - D3D11_ReleaseAll(renderer); - return result; - } - - // Let the application know that the device has been reset - { - SDL_Event event; - event.type = SDL_EVENT_RENDER_DEVICE_RESET; - event.common.timestamp = 0; - SDL_PushEvent(&event); - } - - return S_OK; -} - // Initialize all resources that change when the window's size changes. static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) { @@ -1045,15 +1012,7 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) w, h, DXGI_FORMAT_UNKNOWN, 0); - if (result == DXGI_ERROR_DEVICE_REMOVED) { - // If the device was removed for any reason, a new device and swap chain will need to be created. - D3D11_HandleDeviceLost(renderer); - - /* Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method - * and correctly set up the new device. - */ - goto done; - } else if (FAILED(result)) { + if (FAILED(result)) { WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result); goto done; } @@ -1110,6 +1069,28 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) return result; } +static bool D3D11_HandleDeviceLost(SDL_Renderer *renderer) +{ + bool recovered = false; + + D3D11_ReleaseAll(renderer); + + if (SUCCEEDED(D3D11_CreateDeviceResources(renderer)) && + SUCCEEDED(D3D11_CreateWindowSizeDependentResources(renderer))) { + recovered = true; + } else { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError()); + } + + // Let the application know that the device has been reset or lost + SDL_Event event; + event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST; + event.common.timestamp = 0; + SDL_PushEvent(&event); + + return recovered; +} + // This method is called when the window's size changes. static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer) { @@ -2644,7 +2625,7 @@ static bool D3D11_RenderPresent(SDL_Renderer *renderer) * must recreate all device resources. */ if (result == DXGI_ERROR_DEVICE_REMOVED) { - if (SUCCEEDED(D3D11_HandleDeviceLost(renderer))) { + if (D3D11_HandleDeviceLost(renderer)) { SDL_SetError("Present failed, device lost"); } else { // Recovering from device lost failed, error is already set diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c index ec3cfe9dbbbfa..c5bb46c736351 100644 --- a/src/render/direct3d12/SDL_render_d3d12.c +++ b/src/render/direct3d12/SDL_render_d3d12.c @@ -1326,38 +1326,6 @@ static HRESULT D3D12_CreateSwapChain(SDL_Renderer *renderer, int w, int h) } #endif -static HRESULT D3D12_UpdateForWindowSizeChange(SDL_Renderer *renderer); - -HRESULT -D3D12_HandleDeviceLost(SDL_Renderer *renderer) -{ - HRESULT result = S_OK; - - D3D12_ReleaseAll(renderer); - - result = D3D12_CreateDeviceResources(renderer); - if (FAILED(result)) { - // D3D12_CreateDeviceResources will set the SDL error - return result; - } - - result = D3D12_UpdateForWindowSizeChange(renderer); - if (FAILED(result)) { - // D3D12_UpdateForWindowSizeChange will set the SDL error - return result; - } - - // Let the application know that the device has been reset - { - SDL_Event event; - event.type = SDL_EVENT_RENDER_DEVICE_RESET; - event.common.timestamp = 0; - SDL_PushEvent(&event); - } - - return S_OK; -} - // Initialize all resources that change when the window's size changes. static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer) { @@ -1396,15 +1364,7 @@ static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer) w, h, DXGI_FORMAT_UNKNOWN, data->swapFlags); - if (result == DXGI_ERROR_DEVICE_REMOVED) { - // If the device was removed for any reason, a new device and swap chain will need to be created. - D3D12_HandleDeviceLost(renderer); - - /* Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method - * and correctly set up the new device. - */ - goto done; - } else if (FAILED(result)) { + if (FAILED(result)) { WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result); goto done; } @@ -1484,6 +1444,28 @@ static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer) return result; } +static bool D3D12_HandleDeviceLost(SDL_Renderer *renderer) +{ + bool recovered = false; + + D3D12_ReleaseAll(renderer); + + if (SUCCEEDED(D3D12_CreateDeviceResources(renderer)) && + SUCCEEDED(D3D12_CreateWindowSizeDependentResources(renderer))) { + recovered = true; + } else { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError()); + } + + // Let the application know that the device has been reset or lost + SDL_Event event; + event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST; + event.common.timestamp = 0; + SDL_PushEvent(&event); + + return recovered; +} + // This method is called when the window's size changes. static HRESULT D3D12_UpdateForWindowSizeChange(SDL_Renderer *renderer) { @@ -3137,7 +3119,7 @@ static bool D3D12_RenderPresent(SDL_Renderer *renderer) * must recreate all device resources. */ if (result == DXGI_ERROR_DEVICE_REMOVED) { - if (SUCCEEDED(D3D12_HandleDeviceLost(renderer))) { + if (D3D12_HandleDeviceLost(renderer)) { SDL_SetError("Present failed, device lost"); } else { // Recovering from device lost failed, error is already set diff --git a/src/render/vulkan/SDL_render_vulkan.c b/src/render/vulkan/SDL_render_vulkan.c index a5db6113b4567..a829c3a8cf7b6 100644 --- a/src/render/vulkan/SDL_render_vulkan.c +++ b/src/render/vulkan/SDL_render_vulkan.c @@ -490,6 +490,7 @@ static void VULKAN_DestroyAll(SDL_Renderer *renderer) if (rendererData->surfaceFormats != NULL) { SDL_free(rendererData->surfaceFormats); rendererData->surfaceFormats = NULL; + rendererData->surfaceFormatsAllocatedCount = 0; } if (rendererData->swapchainImages != NULL) { SDL_free(rendererData->swapchainImages); @@ -2481,28 +2482,24 @@ static VkResult VULKAN_CreateWindowSizeDependentResources(SDL_Renderer *renderer static bool VULKAN_HandleDeviceLost(SDL_Renderer *renderer) { VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; - - VULKAN_WaitForGPU(rendererData); + bool recovered = false; VULKAN_DestroyAll(renderer); - if (VULKAN_CreateDeviceResources(renderer, rendererData->create_props) != VK_SUCCESS) { - return false; - } - - if (VULKAN_CreateWindowSizeDependentResources(renderer) != VK_SUCCESS) { - return false; + if (VULKAN_CreateDeviceResources(renderer, rendererData->create_props) == VK_SUCCESS && + VULKAN_CreateWindowSizeDependentResources(renderer) == VK_SUCCESS) { + recovered = true; + } else { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError()); } - // Let the application know that the device has been reset - { - SDL_Event event; - event.type = SDL_EVENT_RENDER_DEVICE_RESET; - event.common.timestamp = 0; - SDL_PushEvent(&event); - } + // Let the application know that the device has been reset or lost + SDL_Event event; + event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST; + event.common.timestamp = 0; + SDL_PushEvent(&event); - return true; + return recovered; } // This method is called when the window's size changes. @@ -4111,7 +4108,15 @@ static bool VULKAN_RenderPresent(SDL_Renderer *renderer) // Wait for previous time this command buffer was submitted, will be N frames ago result = vkWaitForFences(rendererData->device, 1, &rendererData->fences[rendererData->currentCommandBufferIndex], VK_TRUE, UINT64_MAX); if (result != VK_SUCCESS) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "vkWaitForFences(): %s\n", SDL_Vulkan_GetResultString(result)); + if (result == VK_ERROR_DEVICE_LOST) { + if (VULKAN_HandleDeviceLost(renderer)) { + SDL_SetError("Present failed, device lost"); + } else { + // Recovering from device lost failed, error is already set + } + } else { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "vkWaitForFences(): %s\n", SDL_Vulkan_GetResultString(result)); + } return false; }