Browse Source

Null: Add Vulkan 'window' surface creation

This adds support for Vulkan 'window' surface creation on the Null
platform via the VK_EXT_headless_surface extension, where available.

Tested with MoltenVK.
Camilla Löwy 1 year ago
parent
commit
860c8ef38f
5 changed files with 46 additions and 3 deletions
  1. 1 0
      README.md
  2. 2 0
      src/internal.h
  3. 11 0
      src/null_platform.h
  4. 30 3
      src/null_window.c
  5. 2 0
      src/vulkan.c

+ 1 - 0
README.md

@@ -124,6 +124,7 @@ information on what to include when reporting a bug.
  - Added `GLFW_UNLIMITED_MOUSE_BUTTONS` input mode that allows mouse buttons beyond
  - Added `GLFW_UNLIMITED_MOUSE_BUTTONS` input mode that allows mouse buttons beyond
    the limit of the mouse button tokens to be reported (#2423)
    the limit of the mouse button tokens to be reported (#2423)
  - [Wayland] Bugfix: The fractional scaling related objects were not destroyed
  - [Wayland] Bugfix: The fractional scaling related objects were not destroyed
+ - [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
 
 
 
 
 ## Contact
 ## Contact

+ 2 - 0
src/internal.h

@@ -277,6 +277,7 @@ typedef enum VkStructureType
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
     VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
     VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
     VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
     VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
+    VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000,
     VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
     VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
 } VkStructureType;
 } VkStructureType;
 
 
@@ -861,6 +862,7 @@ struct _GLFWlibrary
         GLFWbool        KHR_xlib_surface;
         GLFWbool        KHR_xlib_surface;
         GLFWbool        KHR_xcb_surface;
         GLFWbool        KHR_xcb_surface;
         GLFWbool        KHR_wayland_surface;
         GLFWbool        KHR_wayland_surface;
+        GLFWbool        EXT_headless_surface;
     } vk;
     } vk;
 
 
     struct {
     struct {

+ 11 - 0
src/null_platform.h

@@ -156,6 +156,17 @@
 #define GLFW_NULL_SC_MENU           120
 #define GLFW_NULL_SC_MENU           120
 #define GLFW_NULL_SC_LAST           GLFW_NULL_SC_MENU
 #define GLFW_NULL_SC_LAST           GLFW_NULL_SC_MENU
 
 
+typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT;
+
+typedef struct VkHeadlessSurfaceCreateInfoEXT
+{
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkHeadlessSurfaceCreateFlagsEXT flags;
+} VkHeadlessSurfaceCreateInfoEXT;
+
+typedef VkResult (APIENTRY *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance,const VkHeadlessSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*);
+
 // Null-specific per-window data
 // Null-specific per-window data
 //
 //
 typedef struct _GLFWwindowNull
 typedef struct _GLFWwindowNull

+ 30 - 3
src/null_window.c

@@ -28,6 +28,7 @@
 #include "internal.h"
 #include "internal.h"
 
 
 #include <stdlib.h>
 #include <stdlib.h>
+#include <string.h>
 
 
 static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
 static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
 {
 {
@@ -699,13 +700,18 @@ int _glfwGetKeyScancodeNull(int key)
 
 
 void _glfwGetRequiredInstanceExtensionsNull(char** extensions)
 void _glfwGetRequiredInstanceExtensionsNull(char** extensions)
 {
 {
+    if (!_glfw.vk.KHR_surface || !_glfw.vk.EXT_headless_surface)
+        return;
+
+    extensions[0] = "VK_KHR_surface";
+    extensions[1] = "VK_EXT_headless_surface";
 }
 }
 
 
 GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance,
 GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance,
                                                        VkPhysicalDevice device,
                                                        VkPhysicalDevice device,
                                                        uint32_t queuefamily)
                                                        uint32_t queuefamily)
 {
 {
-    return GLFW_FALSE;
+    return GLFW_TRUE;
 }
 }
 
 
 VkResult _glfwCreateWindowSurfaceNull(VkInstance instance,
 VkResult _glfwCreateWindowSurfaceNull(VkInstance instance,
@@ -713,7 +719,28 @@ VkResult _glfwCreateWindowSurfaceNull(VkInstance instance,
                                       const VkAllocationCallbacks* allocator,
                                       const VkAllocationCallbacks* allocator,
                                       VkSurfaceKHR* surface)
                                       VkSurfaceKHR* surface)
 {
 {
-    // This seems like the most appropriate error to return here
-    return VK_ERROR_EXTENSION_NOT_PRESENT;
+    PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT =
+        (PFN_vkCreateHeadlessSurfaceEXT)
+        vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT");
+    if (!vkCreateHeadlessSurfaceEXT)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Null: Vulkan instance missing VK_EXT_headless_surface extension");
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+
+    VkHeadlessSurfaceCreateInfoEXT sci;
+    memset(&sci, 0, sizeof(sci));
+    sci.sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT;
+
+    const VkResult err = vkCreateHeadlessSurfaceEXT(instance, &sci, allocator, surface);
+    if (err)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Null: Failed to create Vulkan surface: %s",
+                        _glfwGetVulkanResultString(err));
+    }
+
+    return err;
 }
 }
 
 

+ 2 - 0
src/vulkan.c

@@ -142,6 +142,8 @@ GLFWbool _glfwInitVulkan(int mode)
             _glfw.vk.KHR_xcb_surface = GLFW_TRUE;
             _glfw.vk.KHR_xcb_surface = GLFW_TRUE;
         else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
         else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
             _glfw.vk.KHR_wayland_surface = GLFW_TRUE;
             _glfw.vk.KHR_wayland_surface = GLFW_TRUE;
+        else if (strcmp(ep[i].extensionName, "VK_EXT_headless_surface") == 0)
+            _glfw.vk.EXT_headless_surface = GLFW_TRUE;
     }
     }
 
 
     _glfw_free(ep);
     _glfw_free(ep);