Browse Source

Added SDL_EVENT_RENDER_DEVICE_LOST

This is sent when the device is lost and can't be recovered.

Also fixed the vulkan renderer so it returns errors appropriately and will log and break if debug mode is enabled.
Sam Lantinga 9 months ago
parent
commit
3d47877bb4

+ 1 - 0
include/SDL3/SDL_events.h

@@ -228,6 +228,7 @@ typedef enum SDL_EventType
     /* Render events */
     /* Render events */
     SDL_EVENT_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
     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_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 */
     /* Reserved events for private platforms */
     SDL_EVENT_PRIVATE0 = 0x4000,
     SDL_EVENT_PRIVATE0 = 0x4000,

+ 30 - 45
src/render/direct3d11/SDL_render_d3d11.c

@@ -307,10 +307,9 @@ static void D3D11_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
 static void D3D11_ReleaseAll(SDL_Renderer *renderer)
 static void D3D11_ReleaseAll(SDL_Renderer *renderer)
 {
 {
     D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal;
     D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal;
-    SDL_Texture *texture = NULL;
 
 
     // Release all textures
     // Release all textures
-    for (texture = renderer->textures; texture; texture = texture->next) {
+    for (SDL_Texture *texture = renderer->textures; texture; texture = texture->next) {
         D3D11_DestroyTexture(renderer, texture);
         D3D11_DestroyTexture(renderer, texture);
     }
     }
 
 
@@ -982,39 +981,6 @@ static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer *renderer)
     SAFE_RELEASE(data->mainRenderTargetView);
     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.
 // Initialize all resources that change when the window's size changes.
 static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
 static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
 {
 {
@@ -1045,15 +1011,7 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
                                               w, h,
                                               w, h,
                                               DXGI_FORMAT_UNKNOWN,
                                               DXGI_FORMAT_UNKNOWN,
                                               0);
                                               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);
             WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result);
             goto done;
             goto done;
         }
         }
@@ -1110,6 +1068,29 @@ done:
     return result;
     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());
+        D3D11_ReleaseAll(renderer);
+    }
+
+    // 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.
 // This method is called when the window's size changes.
 static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer)
 static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer)
 {
 {
@@ -1164,6 +1145,10 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
     D3D11_TEXTURE2D_DESC textureDesc;
     D3D11_TEXTURE2D_DESC textureDesc;
     D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
     D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
 
 
+    if (!rendererData->d3dDevice) {
+        return SDL_SetError("Device lost and couldn't be recovered");
+    }
+
     if (textureFormat == DXGI_FORMAT_UNKNOWN) {
     if (textureFormat == DXGI_FORMAT_UNKNOWN) {
         return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified",
         return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified",
                             __FUNCTION__, texture->format);
                             __FUNCTION__, texture->format);
@@ -2644,7 +2629,7 @@ static bool D3D11_RenderPresent(SDL_Renderer *renderer)
          * must recreate all device resources.
          * must recreate all device resources.
          */
          */
         if (result == DXGI_ERROR_DEVICE_REMOVED) {
         if (result == DXGI_ERROR_DEVICE_REMOVED) {
-            if (SUCCEEDED(D3D11_HandleDeviceLost(renderer))) {
+            if (D3D11_HandleDeviceLost(renderer)) {
                 SDL_SetError("Present failed, device lost");
                 SDL_SetError("Present failed, device lost");
             } else {
             } else {
                 // Recovering from device lost failed, error is already set
                 // Recovering from device lost failed, error is already set

+ 30 - 46
src/render/direct3d12/SDL_render_d3d12.c

@@ -374,14 +374,13 @@ static void D3D12_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
 static void D3D12_ReleaseAll(SDL_Renderer *renderer)
 static void D3D12_ReleaseAll(SDL_Renderer *renderer)
 {
 {
     D3D12_RenderData *data = (D3D12_RenderData *)renderer->internal;
     D3D12_RenderData *data = (D3D12_RenderData *)renderer->internal;
-    SDL_Texture *texture = NULL;
 
 
     SDL_PropertiesID props = SDL_GetRendererProperties(renderer);
     SDL_PropertiesID props = SDL_GetRendererProperties(renderer);
     SDL_SetPointerProperty(props, SDL_PROP_RENDERER_D3D12_DEVICE_POINTER, NULL);
     SDL_SetPointerProperty(props, SDL_PROP_RENDERER_D3D12_DEVICE_POINTER, NULL);
     SDL_SetPointerProperty(props, SDL_PROP_RENDERER_D3D12_COMMAND_QUEUE_POINTER, NULL);
     SDL_SetPointerProperty(props, SDL_PROP_RENDERER_D3D12_COMMAND_QUEUE_POINTER, NULL);
 
 
     // Release all textures
     // Release all textures
-    for (texture = renderer->textures; texture; texture = texture->next) {
+    for (SDL_Texture *texture = renderer->textures; texture; texture = texture->next) {
         D3D12_DestroyTexture(renderer, texture);
         D3D12_DestroyTexture(renderer, texture);
     }
     }
 
 
@@ -1326,40 +1325,6 @@ done:
 }
 }
 #endif
 #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
-        D3D12_ReleaseAll(renderer);
-        return result;
-    }
-
-    result = D3D12_UpdateForWindowSizeChange(renderer);
-    if (FAILED(result)) {
-        // D3D12_UpdateForWindowSizeChange will set the SDL error
-        D3D12_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.
 // Initialize all resources that change when the window's size changes.
 static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
 static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
 {
 {
@@ -1398,15 +1363,7 @@ static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
                           w, h,
                           w, h,
                           DXGI_FORMAT_UNKNOWN,
                           DXGI_FORMAT_UNKNOWN,
                           data->swapFlags);
                           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);
             WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result);
             goto done;
             goto done;
         }
         }
@@ -1486,6 +1443,29 @@ done:
     return result;
     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());
+        D3D12_ReleaseAll(renderer);
+    }
+
+    // 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.
 // This method is called when the window's size changes.
 static HRESULT D3D12_UpdateForWindowSizeChange(SDL_Renderer *renderer)
 static HRESULT D3D12_UpdateForWindowSizeChange(SDL_Renderer *renderer)
 {
 {
@@ -1568,6 +1548,10 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
     D3D12_HEAP_PROPERTIES heapProps;
     D3D12_HEAP_PROPERTIES heapProps;
     D3D12_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
     D3D12_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
 
 
+    if (!rendererData->d3dDevice) {
+        return SDL_SetError("Device lost and couldn't be recovered");
+    }
+
     if (textureFormat == DXGI_FORMAT_UNKNOWN) {
     if (textureFormat == DXGI_FORMAT_UNKNOWN) {
         return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", __FUNCTION__, texture->format);
         return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", __FUNCTION__, texture->format);
     }
     }
@@ -3147,7 +3131,7 @@ static bool D3D12_RenderPresent(SDL_Renderer *renderer)
          * must recreate all device resources.
          * must recreate all device resources.
          */
          */
         if (result == DXGI_ERROR_DEVICE_REMOVED) {
         if (result == DXGI_ERROR_DEVICE_REMOVED) {
-            if (SUCCEEDED(D3D12_HandleDeviceLost(renderer))) {
+            if (D3D12_HandleDeviceLost(renderer)) {
                 SDL_SetError("Present failed, device lost");
                 SDL_SetError("Present failed, device lost");
             } else {
             } else {
                 // Recovering from device lost failed, error is already set
                 // Recovering from device lost failed, error is already set

File diff suppressed because it is too large
+ 197 - 118
src/render/vulkan/SDL_render_vulkan.c


+ 5 - 2
src/test/SDL_test_common.c

@@ -1880,11 +1880,14 @@ void SDLTest_PrintEvent(const SDL_Event *event)
                 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure);
                 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure);
         break;
         break;
 
 
+    case SDL_EVENT_RENDER_TARGETS_RESET:
+        SDL_Log("SDL EVENT: render targets reset");
+        break;
     case SDL_EVENT_RENDER_DEVICE_RESET:
     case SDL_EVENT_RENDER_DEVICE_RESET:
         SDL_Log("SDL EVENT: render device reset");
         SDL_Log("SDL EVENT: render device reset");
         break;
         break;
-    case SDL_EVENT_RENDER_TARGETS_RESET:
-        SDL_Log("SDL EVENT: render targets reset");
+    case SDL_EVENT_RENDER_DEVICE_LOST:
+        SDL_Log("SDL EVENT: render device lost");
         break;
         break;
 
 
     case SDL_EVENT_TERMINATING:
     case SDL_EVENT_TERMINATING:

Some files were not shown because too many files changed in this diff