Browse Source

Add SDL_Vulkan_GetPresentationSupport

Ethan Lee 9 months ago
parent
commit
1993ef664e

+ 20 - 0
include/SDL3/SDL_vulkan.h

@@ -51,6 +51,7 @@ extern "C" {
 #endif
 
 VK_DEFINE_HANDLE(VkInstance)
+VK_DEFINE_HANDLE(VkPhysicalDevice)
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
 struct VkAllocationCallbacks;
 
@@ -211,6 +212,25 @@ extern SDL_DECLSPEC void SDLCALL SDL_Vulkan_DestroySurface(VkInstance instance,
                                                        VkSurfaceKHR surface,
                                                        const struct VkAllocationCallbacks *allocator);
 
+/**
+ * Query support for presentation via a given physical device and queue family.
+ *
+ * The `instance` must have been created with extensions returned by
+ * SDL_Vulkan_GetInstanceExtensions() enabled.
+ *
+ * \param instance the Vulkan instance handle.
+ * \param physicalDevice a valid Vulkan physical device handle.
+ * \param queueFamilyIndex a valid queue family index for the given physical device.
+ * \returns SDL_TRUE if supported, SDL_FALSE if unsupported or an error occurred.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_Vulkan_GetInstanceExtensions
+ */
+extern SDL_DECLSPEC SDL_bool SDLCALL SDL_Vulkan_GetPresentationSupport(VkInstance instance,
+                                                                       VkPhysicalDevice physicalDevice,
+                                                                       Uint32 queueFamilyIndex);
+
 /* @} *//* Vulkan support functions */
 
 /* Ends C function definitions when using C++ */

+ 1 - 0
src/dynapi/SDL_dynapi.sym

@@ -1045,6 +1045,7 @@ SDL3_0.0.0 {
     SDL_wcsnstr;
     SDL_wcsstr;
     SDL_wcstol;
+    SDL_Vulkan_GetPresentationSupport;
     # extra symbols go here (don't modify this line)
   local: *;
 };

+ 1 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -1070,3 +1070,4 @@
 #define SDL_wcsnstr SDL_wcsnstr_REAL
 #define SDL_wcsstr SDL_wcsstr_REAL
 #define SDL_wcstol SDL_wcstol_REAL
+#define SDL_Vulkan_GetPresentationSupport SDL_Vulkan_GetPresentationSupport_REAL

+ 1 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -1076,3 +1076,4 @@ SDL_DYNAPI_PROC(size_t,SDL_wcsnlen,(const wchar_t *a, size_t b),(a,b),return)
 SDL_DYNAPI_PROC(wchar_t*,SDL_wcsnstr,(const wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
 SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),return)
 SDL_DYNAPI_PROC(long,SDL_wcstol,(const wchar_t *a, wchar_t **b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(SDL_bool,SDL_Vulkan_GetPresentationSupport,(VkInstance a, VkPhysicalDevice b, Uint32 c),(a,b,c),return)

+ 1 - 0
src/video/SDL_sysvideo.h

@@ -304,6 +304,7 @@ struct SDL_VideoDevice
     char const* const* (*Vulkan_GetInstanceExtensions)(SDL_VideoDevice *_this, Uint32 *count);
     int (*Vulkan_CreateSurface)(SDL_VideoDevice *_this, SDL_Window *window, VkInstance instance, const struct VkAllocationCallbacks *allocator, VkSurfaceKHR *surface);
     void (*Vulkan_DestroySurface)(SDL_VideoDevice *_this, VkInstance instance, VkSurfaceKHR surface, const struct VkAllocationCallbacks *allocator);
+    SDL_bool (*Vulkan_GetPresentationSupport)(SDL_VideoDevice *_this, VkInstance instance, VkPhysicalDevice physicalDevice, Uint32 queueFamilyIndex);
 
     /* * * */
     /*

+ 18 - 0
src/video/SDL_video.c

@@ -5526,6 +5526,24 @@ void SDL_Vulkan_DestroySurface(VkInstance instance,
     }
 }
 
+SDL_bool SDL_Vulkan_GetPresentationSupport(VkInstance instance,
+                                           VkPhysicalDevice physicalDevice,
+                                           Uint32 queueFamilyIndex)
+{
+    if (_this && instance && physicalDevice) {
+        if (_this->Vulkan_GetPresentationSupport) {
+            return _this->Vulkan_GetPresentationSupport(_this, instance, physicalDevice, queueFamilyIndex);
+        }
+
+        /* If the backend does not have this function then it does not have a
+         * WSI function to query it; in other words it's not necessary to check
+         * as it is always supported.
+         */
+        return SDL_TRUE;
+    }
+    return SDL_FALSE;
+}
+
 SDL_MetalView SDL_Metal_CreateView(SDL_Window *window)
 {
     CHECK_WINDOW_MAGIC(window, NULL);

+ 1 - 0
src/video/wayland/SDL_waylandvideo.c

@@ -519,6 +519,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
     device->Vulkan_GetInstanceExtensions = Wayland_Vulkan_GetInstanceExtensions;
     device->Vulkan_CreateSurface = Wayland_Vulkan_CreateSurface;
     device->Vulkan_DestroySurface = Wayland_Vulkan_DestroySurface;
+    device->Vulkan_GetPresentationSupport = Wayland_Vulkan_GetPresentationSupport;
 #endif
 
     device->free = Wayland_DeleteDevice;

+ 28 - 0
src/video/wayland/SDL_waylandvulkan.c

@@ -175,4 +175,32 @@ void Wayland_Vulkan_DestroySurface(SDL_VideoDevice *_this,
     }
 }
 
+SDL_bool Wayland_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
+                                               VkInstance instance,
+                                               VkPhysicalDevice physicalDevice,
+                                               Uint32 queueFamilyIndex)
+{
+    PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
+        (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
+    PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR =
+        (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)vkGetInstanceProcAddr(
+            instance,
+            "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
+
+    if (!_this->vulkan_config.loader_handle) {
+        SDL_SetError("Vulkan is not loaded");
+        return SDL_FALSE;
+    }
+
+    if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR) {
+        SDL_SetError(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
+                     " extension is not enabled in the Vulkan instance.");
+        return SDL_FALSE;
+    }
+
+    return vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice,
+                                                            queueFamilyIndex,
+                                                            _this->driverdata->display);
+}
+
 #endif

+ 4 - 0
src/video/wayland/SDL_waylandvulkan.h

@@ -46,6 +46,10 @@ void Wayland_Vulkan_DestroySurface(SDL_VideoDevice *_this,
                                    VkInstance instance,
                                    VkSurfaceKHR surface,
                                    const struct VkAllocationCallbacks *allocator);
+SDL_bool Wayland_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
+                                               VkInstance instance,
+                                               VkPhysicalDevice physicalDevice,
+                                               Uint32 queueFamilyIndex);
 
 #endif
 

+ 1 - 0
src/video/windows/SDL_windowsvideo.c

@@ -263,6 +263,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
     device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions;
     device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface;
     device->Vulkan_DestroySurface = WIN_Vulkan_DestroySurface;
+    device->Vulkan_GetPresentationSupport = WIN_Vulkan_GetPresentationSupport;
 #endif
 
 #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)

+ 27 - 0
src/video/windows/SDL_windowsvulkan.c

@@ -166,4 +166,31 @@ void WIN_Vulkan_DestroySurface(SDL_VideoDevice *_this,
     }
 }
 
+SDL_bool WIN_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
+                                           VkInstance instance,
+                                           VkPhysicalDevice physicalDevice,
+                                           Uint32 queueFamilyIndex)
+{
+    PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
+        (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
+    PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR =
+        (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)vkGetInstanceProcAddr(
+            instance,
+            "vkGetPhysicalDeviceWin32PresentationSupportKHR");
+
+    if (!_this->vulkan_config.loader_handle) {
+        SDL_SetError("Vulkan is not loaded");
+        return SDL_FALSE;
+    }
+
+    if (!vkGetPhysicalDeviceWin32PresentationSupportKHR) {
+        SDL_SetError(VK_KHR_WIN32_SURFACE_EXTENSION_NAME
+                     " extension is not enabled in the Vulkan instance.");
+        return SDL_FALSE;
+    }
+
+    return vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice,
+                                                          queueFamilyIndex);
+}
+
 #endif

+ 4 - 0
src/video/windows/SDL_windowsvulkan.h

@@ -46,6 +46,10 @@ void WIN_Vulkan_DestroySurface(SDL_VideoDevice *_this,
                                VkInstance instance,
                                VkSurfaceKHR surface,
                                const struct VkAllocationCallbacks *allocator);
+SDL_bool WIN_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
+                                           VkInstance instance,
+                                           VkPhysicalDevice physicalDevice,
+                                           Uint32 queueFamilyIndex);
 
 #endif
 

+ 1 - 0
src/video/x11/SDL_x11video.c

@@ -280,6 +280,7 @@ static SDL_VideoDevice *X11_CreateDevice(void)
     device->Vulkan_GetInstanceExtensions = X11_Vulkan_GetInstanceExtensions;
     device->Vulkan_CreateSurface = X11_Vulkan_CreateSurface;
     device->Vulkan_DestroySurface = X11_Vulkan_DestroySurface;
+    device->Vulkan_GetPresentationSupport = X11_Vulkan_GetPresentationSupport;
 #endif
 
 #ifdef SDL_USE_LIBDBUS

+ 55 - 0
src/video/x11/SDL_x11vulkan.c

@@ -232,4 +232,59 @@ void X11_Vulkan_DestroySurface(SDL_VideoDevice *_this,
     }
 }
 
+SDL_bool X11_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
+                                           VkInstance instance,
+                                           VkPhysicalDevice physicalDevice,
+                                           Uint32 queueFamilyIndex)
+{
+    SDL_VideoData *videoData = _this->driverdata;
+    PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
+    const char *forced_visual_id;
+    VisualID visualid;
+
+    if (!_this->vulkan_config.loader_handle) {
+        return SDL_SetError("Vulkan is not loaded");
+    }
+    vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
+
+    forced_visual_id = SDL_GetHint(SDL_HINT_VIDEO_X11_WINDOW_VISUALID);
+    if (forced_visual_id) {
+        visualid = SDL_strtol(forced_visual_id, NULL, 0);
+    } else {
+        visualid = X11_XVisualIDFromVisual(DefaultVisual(videoData->display, DefaultScreen(videoData->display)));
+    }
+
+    if (videoData->vulkan_xlib_xcb_library) {
+        PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR =
+            (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)vkGetInstanceProcAddr(
+                instance,
+                "vkGetPhysicalDeviceXcbPresentationSupportKHR");
+
+        if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) {
+            SDL_SetError(VK_KHR_XCB_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
+            return SDL_FALSE;
+        }
+
+        return vkGetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice,
+                                                            queueFamilyIndex,
+                                                            videoData->vulkan_XGetXCBConnection(videoData->display),
+                                                            visualid);
+    } else {
+        PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR =
+            (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)vkGetInstanceProcAddr(
+                instance,
+                "vkGetPhysicalDeviceXlibPresentationSupportKHR");
+
+        if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) {
+            SDL_SetError(VK_KHR_XLIB_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
+            return SDL_FALSE;
+        }
+
+        return vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice,
+                                                             queueFamilyIndex,
+                                                             videoData->display,
+                                                             visualid);
+    }
+}
+
 #endif

+ 4 - 0
src/video/x11/SDL_x11vulkan.h

@@ -43,6 +43,10 @@ void X11_Vulkan_DestroySurface(SDL_VideoDevice *_this,
                                VkInstance instance,
                                VkSurfaceKHR surface,
                                const struct VkAllocationCallbacks *allocator);
+SDL_bool X11_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
+                                           VkInstance instance,
+                                           VkPhysicalDevice physicalDevice,
+                                           Uint32 queueFamilyIndex);
 
 #endif