SDL: vulkan: Make SDL_Vulkan_GetInstanceExtensions more robust.

From e7be7d844a06bd160f6147e9ecb6aa6bed94769f Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 9 Jul 2026 17:20:44 -0400
Subject: [PATCH] vulkan: Make SDL_Vulkan_GetInstanceExtensions more robust.

Now it handles NULL `count` params at the higher level, and doesn't explode if
a backend doesn't implement it.
---
 src/video/SDL_video.c                     | 11 +++++
 src/video/android/SDL_androidvulkan.c     |  4 +-
 src/video/cocoa/SDL_cocoavulkan.m         |  4 +-
 src/video/kmsdrm/SDL_kmsdrmvulkan.c       |  4 +-
 src/video/offscreen/SDL_offscreenvulkan.c | 50 +++++++++--------------
 src/video/uikit/SDL_uikitvulkan.m         |  4 +-
 src/video/vivante/SDL_vivantevulkan.c     |  4 +-
 src/video/wayland/SDL_waylandvulkan.c     |  5 +--
 src/video/windows/SDL_windowsvulkan.c     |  4 +-
 src/video/x11/SDL_x11vulkan.c             |  8 +---
 10 files changed, 40 insertions(+), 58 deletions(-)

diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 3ae6ea215c454..4ea43ae23d299 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -6315,6 +6315,17 @@ void SDL_Vulkan_UnloadLibrary(void)
 
 char const * const *SDL_Vulkan_GetInstanceExtensions(Uint32 *count)
 {
+    Uint32 tmpcount = 0;
+    if (!count) {
+        count = &tmpcount;
+    }
+
+    if (!_this->Vulkan_GetInstanceExtensions) {
+        *count = 0;
+        SDL_Unsupported();
+        return NULL;
+    }
+
     return _this->Vulkan_GetInstanceExtensions(_this, count);
 }
 
diff --git a/src/video/android/SDL_androidvulkan.c b/src/video/android/SDL_androidvulkan.c
index 7436c2df5ac80..117f2dbd09a42 100644
--- a/src/video/android/SDL_androidvulkan.c
+++ b/src/video/android/SDL_androidvulkan.c
@@ -115,9 +115,7 @@ char const * const *Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
     static const char *const extensionsForAndroid[] = {
         VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
     };
-    if (count) {
-        *count = SDL_arraysize(extensionsForAndroid);
-    }
+    *count = SDL_arraysize(extensionsForAndroid);
     return extensionsForAndroid;
 }
 
diff --git a/src/video/cocoa/SDL_cocoavulkan.m b/src/video/cocoa/SDL_cocoavulkan.m
index 991d10dbfa15b..74c64733abf41 100644
--- a/src/video/cocoa/SDL_cocoavulkan.m
+++ b/src/video/cocoa/SDL_cocoavulkan.m
@@ -168,9 +168,7 @@ void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
     static const char *const extensionsForCocoa[] = {
         VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_EXTENSION_NAME
     };
-    if(count) {
-        *count = SDL_arraysize(extensionsForCocoa);
-    }
+    *count = SDL_arraysize(extensionsForCocoa);
     return extensionsForCocoa;
 }
 
diff --git a/src/video/kmsdrm/SDL_kmsdrmvulkan.c b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
index 8fdde581a027b..9d1f8cb003040 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvulkan.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
@@ -152,9 +152,7 @@ char const * const *KMSDRM_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
     static const char *const extensionsForKMSDRM[] = {
         VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_DISPLAY_EXTENSION_NAME
     };
-    if (count) {
-        *count = SDL_arraysize(extensionsForKMSDRM);
-    }
+    *count = SDL_arraysize(extensionsForKMSDRM);
     return extensionsForKMSDRM;
 }
 
diff --git a/src/video/offscreen/SDL_offscreenvulkan.c b/src/video/offscreen/SDL_offscreenvulkan.c
index 79c6f6d12540c..0a5f5c0bc2426 100644
--- a/src/video/offscreen/SDL_offscreenvulkan.c
+++ b/src/video/offscreen/SDL_offscreenvulkan.c
@@ -179,45 +179,35 @@ void OFFSCREEN_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
 char const *const *OFFSCREEN_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
                                                           Uint32 *count)
 {
+    static const char *const returnExtensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME };
+
+    *count = SDL_arraysize(returnExtensions);
+
 #if (HEADLESS_SURFACE_EXTENSION_REQUIRED_TO_LOAD == 0)
     VkExtensionProperties *enumerateExtensions = NULL;
     Uint32 enumerateExtensionCount = 0;
     bool hasHeadlessSurfaceExtension = false;
     Uint32 i;
-#endif
 
-    static const char *const returnExtensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME };
-    if (count) {
-#       if (HEADLESS_SURFACE_EXTENSION_REQUIRED_TO_LOAD == 0)
-        {
-            /* In optional mode, only return VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME if it's already supported by the instance
-                There's probably a better way to cache the presence of the extension during OFFSCREEN_Vulkan_LoadLibrary().
-                But both SDL_VideoData and SDL_VideoDevice::vulkan_config seem like I'd need to touch a bunch of code to do properly.
-                And I want a smaller footprint for the first pass*/
-            if ( _this->vulkan_config.vkEnumerateInstanceExtensionProperties ) {
-                enumerateExtensions = SDL_Vulkan_CreateInstanceExtensionsList(
-                    (PFN_vkEnumerateInstanceExtensionProperties)
-                        _this->vulkan_config.vkEnumerateInstanceExtensionProperties,
-                    &enumerateExtensionCount);
-                for (i = 0; i < enumerateExtensionCount; i++) {
-                    if (SDL_strcmp(VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, enumerateExtensions[i].extensionName) == 0) {
-                        hasHeadlessSurfaceExtension = true;
-                    }
-                }
-                SDL_free(enumerateExtensions);
-            }
-            if ( hasHeadlessSurfaceExtension == true ) {
-                *count = SDL_arraysize(returnExtensions);
-            } else {
-                *count = SDL_arraysize(returnExtensions) - 1; // assumes VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME is last
+    /* In optional mode, only return VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME if it's already supported by the instance
+       There's probably a better way to cache the presence of the extension during OFFSCREEN_Vulkan_LoadLibrary().
+       But both SDL_VideoData and SDL_VideoDevice::vulkan_config seem like I'd need to touch a bunch of code to do properly.
+       And I want a smaller footprint for the first pass*/
+    if ( _this->vulkan_config.vkEnumerateInstanceExtensionProperties ) {
+        enumerateExtensions = SDL_Vulkan_CreateInstanceExtensionsList((PFN_vkEnumerateInstanceExtensionProperties) _this->vulkan_config.vkEnumerateInstanceExtensionProperties, &enumerateExtensionCount);
+        for (i = 0; i < enumerateExtensionCount; i++) {
+            if (SDL_strcmp(VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, enumerateExtensions[i].extensionName) == 0) {
+                hasHeadlessSurfaceExtension = true;
             }
         }
-#       else
-        {
-            *count = SDL_arraysize(returnExtensions);
-        }
-#       endif
+        SDL_free(enumerateExtensions);
+    }
+
+    if (!hasHeadlessSurfaceExtension) {
+        (*count)--;  // assumes VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME is last
     }
+#endif
+
     return returnExtensions;
 }
 
diff --git a/src/video/uikit/SDL_uikitvulkan.m b/src/video/uikit/SDL_uikitvulkan.m
index b15621926e5c2..d753654912f41 100644
--- a/src/video/uikit/SDL_uikitvulkan.m
+++ b/src/video/uikit/SDL_uikitvulkan.m
@@ -172,9 +172,7 @@ void UIKit_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
     static const char *const extensionsForUIKit[] = {
         VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_EXTENSION_NAME
     };
-    if(count) {
-        *count = SDL_arraysize(extensionsForUIKit);
-    }
+    *count = SDL_arraysize(extensionsForUIKit);
     return extensionsForUIKit;
 }
 
diff --git a/src/video/vivante/SDL_vivantevulkan.c b/src/video/vivante/SDL_vivantevulkan.c
index dc1ec7dc6bff1..d5749d98d5477 100644
--- a/src/video/vivante/SDL_vivantevulkan.c
+++ b/src/video/vivante/SDL_vivantevulkan.c
@@ -122,9 +122,7 @@ char const * const *VIVANTE_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
     static const char *const extensionsForVivante[] = {
         VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_DISPLAY_EXTENSION_NAME
     };
-    if (count) {
-        *count = SDL_arraysize(extensionsForVivante);
-    }
+    *count = SDL_arraysize(extensionsForVivante);
     return extensionsForVivante;
 }
 
diff --git a/src/video/wayland/SDL_waylandvulkan.c b/src/video/wayland/SDL_waylandvulkan.c
index aa1b48e7dcd07..408fcedd8e968 100644
--- a/src/video/wayland/SDL_waylandvulkan.c
+++ b/src/video/wayland/SDL_waylandvulkan.c
@@ -128,10 +128,7 @@ char const * const *Wayland_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
         VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
     };
 
-    if (count) {
-        *count = SDL_arraysize(extensionsForWayland);
-    }
-
+    *count = SDL_arraysize(extensionsForWayland);
     return extensionsForWayland;
 }
 
diff --git a/src/video/windows/SDL_windowsvulkan.c b/src/video/windows/SDL_windowsvulkan.c
index 59f43a01824cd..be215abf8d5c4 100644
--- a/src/video/windows/SDL_windowsvulkan.c
+++ b/src/video/windows/SDL_windowsvulkan.c
@@ -115,9 +115,7 @@ char const * const *WIN_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uin
     static const char *const extensionsForWin32[] = {
         VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME
     };
-    if (count) {
-        *count = SDL_arraysize(extensionsForWin32);
-    }
+    *count = SDL_arraysize(extensionsForWin32);
     return extensionsForWin32;
 }
 
diff --git a/src/video/x11/SDL_x11vulkan.c b/src/video/x11/SDL_x11vulkan.c
index 11fc05c3bc275..a0f4b5747df7a 100644
--- a/src/video/x11/SDL_x11vulkan.c
+++ b/src/video/x11/SDL_x11vulkan.c
@@ -166,18 +166,14 @@ char const * const *X11_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uin
             VK_KHR_SURFACE_EXTENSION_NAME,
             VK_KHR_XCB_SURFACE_EXTENSION_NAME,
         };
-        if(count) {
-            *count = SDL_arraysize(extensionsForXCB);
-        }
+        *count = SDL_arraysize(extensionsForXCB);
         return extensionsForXCB;
     } else {
         static const char *const extensionsForXlib[] = {
             VK_KHR_SURFACE_EXTENSION_NAME,
             VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
         };
-        if(count) {
-            *count = SDL_arraysize(extensionsForXlib);
-        }
+        *count = SDL_arraysize(extensionsForXlib);
         return extensionsForXlib;
     }
 }