SDL: Improved error information when renderer creation fails

From 3316dde0c2fc49b3f48759477bf4ae2a3a5b2a4e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 8 Oct 2025 19:36:19 -0700
Subject: [PATCH] Improved error information when renderer creation fails

On Android, if you create a window with SDL_WINDOW_OPENGL, you can't create a Vulkan surface. The error message has been improved to reflect this, and the error is propagated back up to the application.

Also added warn level logging if the renderer couldn't be created.
---
 src/render/SDL_render.c               | 11 ++++++++++-
 src/render/vulkan/SDL_render_vulkan.c |  1 -
 src/video/android/SDL_androidvulkan.c |  7 ++++++-
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index aeb3424b13cac..b08e0c95c453e 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -1096,6 +1096,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
             goto error;
         }
     } else {
+        char *driver_error = NULL;
         bool rc = false;
         if (!driver_name) {
             driver_name = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
@@ -1110,10 +1111,13 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
                 for (int i = 0; render_drivers[i]; i++) {
                     const SDL_RenderDriver *driver = render_drivers[i];
                     if ((driver_attempt_len == SDL_strlen(driver->name)) && (SDL_strncasecmp(driver->name, driver_attempt, driver_attempt_len) == 0)) {
+                        SDL_free(driver_error);
                         rc = driver->CreateRenderer(renderer, window, props);
                         if (rc) {
                             break;
                         }
+                        driver_error = SDL_strdup(SDL_GetError());
+                        SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "Couldn't create renderer %s: %s\n", driver->name, driver_error);
                         SDL_DestroyRendererWithoutFreeing(renderer);
                         SDL_zerop(renderer); // make sure we don't leave function pointers from a previous CreateRenderer() in this struct.
                     }
@@ -1137,7 +1141,12 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
             SDL_DebugLogBackend("render", renderer->name);
         } else {
             if (driver_name) {
-                SDL_SetError("%s not available", driver_name);
+                if (driver_error) {
+                    SDL_SetError("%s", driver_error);
+                    SDL_free(driver_error);
+                } else {
+                    SDL_SetError("%s not available", driver_name);
+                }
             } else {
                 SDL_SetError("Couldn't find matching render driver");
             }
diff --git a/src/render/vulkan/SDL_render_vulkan.c b/src/render/vulkan/SDL_render_vulkan.c
index a06598ea0caf4..18a32f6907066 100644
--- a/src/render/vulkan/SDL_render_vulkan.c
+++ b/src/render/vulkan/SDL_render_vulkan.c
@@ -1812,7 +1812,6 @@ static VkResult VULKAN_CreateDeviceResources(SDL_Renderer *renderer, SDL_Propert
     } else {
         if (!SDL_Vulkan_CreateSurface(renderer->window, rendererData->instance, NULL, &rendererData->surface)) {
             VULKAN_DestroyAll(renderer);
-            SET_ERROR_MESSAGE("Vulkan_CreateSurface() failed");
             return VK_ERROR_UNKNOWN;
         }
     }
diff --git a/src/video/android/SDL_androidvulkan.c b/src/video/android/SDL_androidvulkan.c
index 2ab925f74a732..52ba1621b5c25 100644
--- a/src/video/android/SDL_androidvulkan.c
+++ b/src/video/android/SDL_androidvulkan.c
@@ -145,6 +145,7 @@ bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
         return SDL_SetError(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
                             " extension is not enabled in the Vulkan instance.");
     }
+
     SDL_zero(createInfo);
     createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
     createInfo.pNext = NULL;
@@ -152,7 +153,11 @@ bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
     createInfo.window = windowData->native_window;
     result = vkCreateAndroidSurfaceKHR(instance, &createInfo, allocator, surface);
     if (result != VK_SUCCESS) {
-        return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
+        if (result == VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) {
+            return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s, was the window created with SDL_WINDOW_VULKAN?", SDL_Vulkan_GetResultString(result));
+        } else {
+            return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
+        }
     }
     return true;
 }