Sfoglia il codice sorgente

Add glfwInitVulkanLoader

This removes the GLFW_VULKAN_STATIC CMake option and the
_GLFW_VULKAN_STATIC configuration macro and replaces them with the
glfwInitVulkanLoader function, allowing a single library binary to
provide both behaviors.

This is based on the design from PR #1374 by @pmuetschard.

Closes #1374
Closes #1890
Camilla Löwy 3 anni fa
parent
commit
76a5f781db
12 ha cambiato i file con 127 aggiunte e 71 eliminazioni
  1. 0 1
      CMakeLists.txt
  2. 1 0
      CONTRIBUTORS.md
  3. 1 0
      README.md
  4. 0 8
      docs/compile.dox
  5. 1 0
      docs/intro.dox
  6. 12 0
      docs/news.dox
  7. 23 16
      docs/vulkan.dox
  8. 48 0
      include/GLFW/glfw3.h
  9. 0 5
      src/CMakeLists.txt
  10. 6 0
      src/init.c
  11. 4 10
      src/internal.h
  12. 31 31
      src/vulkan.c

+ 0 - 1
CMakeLists.txt

@@ -27,7 +27,6 @@ option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ${GLFW_STANDALONE})
 option(GLFW_BUILD_TESTS "Build the GLFW test programs" ${GLFW_STANDALONE})
 option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
 option(GLFW_INSTALL "Generate installation target" ON)
-option(GLFW_VULKAN_STATIC "Assume the Vulkan loader is linked with the application" OFF)
 
 include(GNUInstallDirs)
 include(CMakeDependentOption)

+ 1 - 0
CONTRIBUTORS.md

@@ -128,6 +128,7 @@ video tutorials.
  - Jon Morton
  - Pierre Moulon
  - Martins Mozeiko
+ - Pascal Muetschard
  - Julian Møller
  - ndogxj
  - n3rdopolis

+ 1 - 0
README.md

@@ -131,6 +131,7 @@ information on what to include when reporting a bug.
  - Added `glfwInitAllocator` for setting a custom memory allocator (#544,#1628,#1947)
  - Added `GLFWallocator` struct and `GLFWallocatefun`, `GLFWreallocatefun` and
    `GLFWdeallocatefun` types (#544,#1628,#1947)
+ - Added `glfwInitVulkanLoader` for using a non-default Vulkan loader (#1374,#1890)
  - Added `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR`,
    `GLFW_RESIZE_ALL_CURSOR` and `GLFW_NOT_ALLOWED_CURSOR` cursor shapes (#427)
  - Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#427)

+ 0 - 8
docs/compile.dox

@@ -273,10 +273,6 @@ __GLFW_BUILD_DOCS__ determines whether the GLFW documentation is built along
 with the library.  This is enabled by default if
 [Doxygen](https://www.doxygen.nl/) is found by CMake during configuration.
 
-@anchor GLFW_VULKAN_STATIC
-__GLFW_VULKAN_STATIC__ determines whether to use the Vulkan loader linked
-directly with the application.  This is disabled by default.
-
 
 @subsection compile_options_win32 Win32 specific CMake options
 
@@ -383,10 +379,6 @@ attempts to detect the appropriate platform at initialization.
 If you are building GLFW as a shared library / dynamic library / DLL then you
 must also define @b _GLFW_BUILD_DLL.  Otherwise, you must not define it.
 
-If you are linking the Vulkan loader directly with your application then you
-must also define @b _GLFW_VULKAN_STATIC.  Otherwise, GLFW will attempt to use the
-external version.
-
 If you are using a custom name for the Vulkan, EGL, GLX, OSMesa, OpenGL, GLESv1
 or GLESv2 library, you can override the default names by defining those you need
 of @b _GLFW_VULKAN_LIBRARY, @b _GLFW_EGL_LIBRARY, @b _GLFW_GLX_LIBRARY, @b

+ 1 - 0
docs/intro.dox

@@ -35,6 +35,7 @@ successfully initialized, and only from the main thread.
  - @ref glfwSetErrorCallback
  - @ref glfwInitHint
  - @ref glfwInitAllocator
+ - @ref glfwInitVulkanLoader
  - @ref glfwInit
  - @ref glfwTerminate
 

+ 12 - 0
docs/news.dox

@@ -142,6 +142,17 @@ GLFW_TRANSPARENT_FRAMEBUFFER on Windows 7 if DWM transparency is off
 
 @subsection removals_34 Removals in 3.4
 
+@subsubsection vulkan_static_34 GLFW_VULKAN_STATIC CMake option has been removed
+
+This option was used to compile GLFW directly linked with the Vulkan loader, instead of
+using dynamic loading to get hold of `vkGetInstanceProcAddr` at initialization.  This is
+now done by calling the @ref glfwInitVulkanLoader function before initialization.
+
+If you need backward compatibility, this macro can still be defined for GLFW 3.4 and will
+have no effect.  The call to @ref glfwInitVulkanLoader can be conditionally enabled in
+your code by checking the @ref GLFW_VERSION_MAJOR and @ref GLFW_VERSION_MINOR macros.
+
+
 @subsubsection osmesa_option_34 GLFW_USE_OSMESA CMake option has been removed
 
 This option was used to compile GLFW for the Null platform.  The Null platform is now
@@ -168,6 +179,7 @@ then GLFW will fail to initialize.
  - @ref glfwInitAllocator
  - @ref glfwGetPlatform
  - @ref glfwPlatformSupported
+ - @ref glfwInitVulkanLoader
 
 
 @subsubsection types_34 New types in version 3.4

+ 23 - 16
docs/vulkan.dox

@@ -29,22 +29,28 @@ are also guides for the other areas of the GLFW API.
  - @ref input_guide
 
 
-@section vulkan_loader Linking against the Vulkan loader
-
-By default, GLFW will look for the Vulkan loader on demand at runtime via its
-standard name (`vulkan-1.dll` on Windows, `libvulkan.so.1` on Linux and other
-Unix-like systems and `libvulkan.1.dylib` on macOS).  This means that GLFW does
-not need to be linked against the loader.  However, it also means that if you
-are using the static library form of the Vulkan loader GLFW will either fail to
-find it or (worse) use the wrong one.
-
-The @ref GLFW_VULKAN_STATIC CMake option makes GLFW call the Vulkan loader
-directly instead of dynamically loading it at runtime.  Not linking against the
-Vulkan loader will then be a compile-time error.
-
-@macos Because the Vulkan loader and ICD are not installed globally on macOS,
-you need to set up the application bundle according to the LunarG SDK
-documentation.  This is explained in more detail in the
+@section vulkan_loader Finding the Vulkan loader
+
+GLFW itself does not ever need to be linked against the Vulkan loader.
+
+By default, GLFW will load the Vulkan loader dynamically at runtime via its standard name:
+`vulkan-1.dll` on Windows, `libvulkan.so.1` on Linux and other Unix-like systems and
+`libvulkan.1.dylib` on macOS.
+
+@macos GLFW will also look up and search the executable subdirectory of your application
+bundle.
+
+If your code is using a Vulkan loader with a different name or in a non-standard location
+you will need to direct GLFW to it.  Pass your version of `vkGetInstanceProcAddr` to @ref
+glfwInitVulkanLoader before initializing GLFW and it will use that function for all Vulkan
+entry point retrieval.  This prevents GLFW from dynamically loading the Vulkan loader.
+
+@code
+glfwInitVulkanLoader(vkGetInstanceProcAddr);
+@endcode
+
+@macos To make your application be redistributable you will need to set up the application
+bundle according to the LunarG SDK documentation.  This is explained in more detail in the
 [SDK documentation for macOS](https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html).
 
 
@@ -69,6 +75,7 @@ your own custom Vulkan header then do this before the GLFW header.
 Unless a Vulkan header is included, either by the GLFW header or above it, the following
 GLFW functions will not be declared, as depend on Vulkan types.
 
+ - @ref glfwInitVulkanLoader
  - @ref glfwGetInstanceProcAddress
  - @ref glfwGetPhysicalDevicePresentationSupport
  - @ref glfwCreateWindowSurface

+ 48 - 0
include/GLFW/glfw3.h

@@ -2224,6 +2224,54 @@ GLFWAPI void glfwInitHint(int hint, int value);
  */
 GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator);
 
+#if defined(VK_VERSION_1_0)
+
+/*! @brief Sets the desired Vulkan `vkGetInstanceProcAddr` function.
+ *
+ *  This function sets the `vkGetInstanceProcAddr` function that GLFW will use for all
+ *  Vulkan related entry point queries.
+ *
+ *  This feature is mostly useful on macOS, if your copy of the Vulkan loader is in
+ *  a location where GLFW cannot find it through dynamic loading, or if you are still
+ *  using the static library version of the loader.
+ *
+ *  If set to `NULL`, GLFW will try to load the Vulkan loader dynamically by its standard
+ *  name and get this function from there.  This is the default behavior.
+ *
+ *  The standard name of the loader is `vulkan-1.dll` on Windows, `libvulkan.so.1` on
+ *  Linux and other Unix-like systems and `libvulkan.1.dylib` on macOS.  If your code is
+ *  also loading it via these names then you probably don't need to use this function.
+ *
+ *  The function address you set is never reset by GLFW, but it only takes effect during
+ *  initialization.  Once GLFW has been initialized, any updates will be ignored until the
+ *  library is terminated and initialized again.
+ *
+ *  @param[in] loader The address of the function to use, or `NULL`.
+ *
+ *  @par Loader function signature
+ *  @code
+ *  PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance instance, const char* name)
+ *  @endcode
+ *  For more information about this function, see the
+ *  [Vulkan Registry](https://www.khronos.org/registry/vulkan/).
+ *
+ *  @errors None.
+ *
+ *  @remark This function may be called before @ref glfwInit.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref vulkan_loader
+ *  @sa @ref glfwInit
+ *
+ *  @since Added in version 3.4.
+ *
+ *  @ingroup init
+ */
+GLFWAPI void glfwInitVulkanLoader(PFN_vkGetInstanceProcAddr loader);
+
+#endif /*VK_VERSION_1_0*/
+
 /*! @brief Retrieves the version of the GLFW library.
  *
  *  This function retrieves the major, minor and revision numbers of the GLFW

+ 0 - 5
src/CMakeLists.txt

@@ -155,11 +155,6 @@ if (CMAKE_VERSION VERSION_LESS "3.16" AND APPLE)
                                 LANGUAGE C)
 endif()
 
-if (GLFW_VULKAN_STATIC)
-    target_compile_definitions(glfw PRIVATE _GLFW_VULKAN_STATIC)
-    list(APPEND glfw_PKG_DEPS "vulkan")
-endif()
-
 if (GLFW_BUILD_WIN32)
     list(APPEND glfw_PKG_LIBS "-lgdi32")
 endif()

+ 6 - 0
src/init.c

@@ -55,6 +55,7 @@ static _GLFWinitconfig _glfwInitHints =
     GLFW_TRUE,      // hat buttons
     GLFW_ANGLE_PLATFORM_TYPE_NONE, // ANGLE backend
     GLFW_ANY_PLATFORM, // preferred platform
+    NULL,           // vkGetInstanceProcAddr function
     {
         GLFW_TRUE,  // macOS menu bar
         GLFW_TRUE   // macOS bundle chdir
@@ -404,6 +405,11 @@ GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator)
         memset(&_glfwInitAllocator, 0, sizeof(GLFWallocator));
 }
 
+GLFWAPI void glfwInitVulkanLoader(PFN_vkGetInstanceProcAddr loader)
+{
+    _glfwInitHints.vulkanLoader = loader;
+}
+
 GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)
 {
     if (major != NULL)

+ 4 - 10
src/internal.h

@@ -323,14 +323,9 @@ typedef struct VkExtensionProperties
 
 typedef void (APIENTRY * PFN_vkVoidFunction)(void);
 
-#if defined(_GLFW_VULKAN_STATIC)
-  PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*);
-  VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*);
-#else
-  typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
-  typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
-  #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
-#endif
+typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
+typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
+#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
 
 #include "platform.h"
 
@@ -382,6 +377,7 @@ struct _GLFWinitconfig
     GLFWbool      hatButtons;
     int           angleType;
     int           platformID;
+    PFN_vkGetInstanceProcAddr vulkanLoader;
     struct {
         GLFWbool  menubar;
         GLFWbool  chdir;
@@ -853,9 +849,7 @@ struct _GLFWlibrary
         GLFWbool        available;
         void*           handle;
         char*           extensions[2];
-#if !defined(_GLFW_VULKAN_STATIC)
         PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
-#endif
         GLFWbool        KHR_surface;
         GLFWbool        KHR_win32_surface;
         GLFWbool        MVK_macos_surface;

+ 31 - 31
src/vulkan.c

@@ -51,35 +51,39 @@ GLFWbool _glfwInitVulkan(int mode)
     if (_glfw.vk.available)
         return GLFW_TRUE;
 
-#if !defined(_GLFW_VULKAN_STATIC)
+    if (_glfw.hints.init.vulkanLoader)
+        _glfw.vk.GetInstanceProcAddr = _glfw.hints.init.vulkanLoader;
+    else
+    {
 #if defined(_GLFW_VULKAN_LIBRARY)
-    _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
+        _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
 #elif defined(_GLFW_WIN32)
-    _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
+        _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
 #elif defined(_GLFW_COCOA)
-    _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
-    if (!_glfw.vk.handle)
-        _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
+        _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
+        if (!_glfw.vk.handle)
+            _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
 #else
-    _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");
+        _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");
 #endif
-    if (!_glfw.vk.handle)
-    {
-        if (mode == _GLFW_REQUIRE_LOADER)
-            _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
+        if (!_glfw.vk.handle)
+        {
+            if (mode == _GLFW_REQUIRE_LOADER)
+                _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
 
-        return GLFW_FALSE;
-    }
+            return GLFW_FALSE;
+        }
 
-    _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
-        _glfwPlatformGetModuleSymbol(_glfw.vk.handle, "vkGetInstanceProcAddr");
-    if (!_glfw.vk.GetInstanceProcAddr)
-    {
-        _glfwInputError(GLFW_API_UNAVAILABLE,
-                        "Vulkan: Loader does not export vkGetInstanceProcAddr");
+        _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
+            _glfwPlatformGetModuleSymbol(_glfw.vk.handle, "vkGetInstanceProcAddr");
+        if (!_glfw.vk.GetInstanceProcAddr)
+        {
+            _glfwInputError(GLFW_API_UNAVAILABLE,
+                            "Vulkan: Loader does not export vkGetInstanceProcAddr");
 
-        _glfwTerminateVulkan();
-        return GLFW_FALSE;
+            _glfwTerminateVulkan();
+            return GLFW_FALSE;
+        }
     }
 
     vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
@@ -92,7 +96,6 @@ GLFWbool _glfwInitVulkan(int mode)
         _glfwTerminateVulkan();
         return GLFW_FALSE;
     }
-#endif // _GLFW_VULKAN_STATIC
 
     err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
     if (err)
@@ -152,10 +155,8 @@ GLFWbool _glfwInitVulkan(int mode)
 
 void _glfwTerminateVulkan(void)
 {
-#if !defined(_GLFW_VULKAN_STATIC)
     if (_glfw.vk.handle)
         _glfwPlatformFreeModule(_glfw.vk.handle);
-#endif
 }
 
 const char* _glfwGetVulkanResultString(VkResult result)
@@ -253,17 +254,16 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
         return NULL;
 
+    // NOTE: Vulkan 1.0 and 1.1 vkGetInstanceProcAddr cannot return itself
+    if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
+        return (GLFWvkproc) vkGetInstanceProcAddr;
+
     proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
-#if defined(_GLFW_VULKAN_STATIC)
     if (!proc)
     {
-        if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
-            return (GLFWvkproc) vkGetInstanceProcAddr;
+        if (_glfw.vk.handle)
+            proc = (GLFWvkproc) _glfwPlatformGetModuleSymbol(_glfw.vk.handle, procname);
     }
-#else
-    if (!proc)
-        proc = (GLFWvkproc) _glfwPlatformGetModuleSymbol(_glfw.vk.handle, procname);
-#endif
 
     return proc;
 }