Просмотр исходного кода

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 лет назад
Родитель
Сommit
76a5f781db
12 измененных файлов с 127 добавлено и 71 удалено
  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_TESTS "Build the GLFW test programs" ${GLFW_STANDALONE})
 option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
 option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
 option(GLFW_INSTALL "Generate installation target" 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(GNUInstallDirs)
 include(CMakeDependentOption)
 include(CMakeDependentOption)

+ 1 - 0
CONTRIBUTORS.md

@@ -128,6 +128,7 @@ video tutorials.
  - Jon Morton
  - Jon Morton
  - Pierre Moulon
  - Pierre Moulon
  - Martins Mozeiko
  - Martins Mozeiko
+ - Pascal Muetschard
  - Julian Møller
  - Julian Møller
  - ndogxj
  - ndogxj
  - n3rdopolis
  - 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 `glfwInitAllocator` for setting a custom memory allocator (#544,#1628,#1947)
  - Added `GLFWallocator` struct and `GLFWallocatefun`, `GLFWreallocatefun` and
  - Added `GLFWallocator` struct and `GLFWallocatefun`, `GLFWreallocatefun` and
    `GLFWdeallocatefun` types (#544,#1628,#1947)
    `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`,
  - Added `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR`,
    `GLFW_RESIZE_ALL_CURSOR` and `GLFW_NOT_ALLOWED_CURSOR` cursor shapes (#427)
    `GLFW_RESIZE_ALL_CURSOR` and `GLFW_NOT_ALLOWED_CURSOR` cursor shapes (#427)
  - Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#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
 with the library.  This is enabled by default if
 [Doxygen](https://www.doxygen.nl/) is found by CMake during configuration.
 [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
 @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
 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.
 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
 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
 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
 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 glfwSetErrorCallback
  - @ref glfwInitHint
  - @ref glfwInitHint
  - @ref glfwInitAllocator
  - @ref glfwInitAllocator
+ - @ref glfwInitVulkanLoader
  - @ref glfwInit
  - @ref glfwInit
  - @ref glfwTerminate
  - @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
 @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
 @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
 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 glfwInitAllocator
  - @ref glfwGetPlatform
  - @ref glfwGetPlatform
  - @ref glfwPlatformSupported
  - @ref glfwPlatformSupported
+ - @ref glfwInitVulkanLoader
 
 
 
 
 @subsubsection types_34 New types in version 3.4
 @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
  - @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).
 [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
 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.
 GLFW functions will not be declared, as depend on Vulkan types.
 
 
+ - @ref glfwInitVulkanLoader
  - @ref glfwGetInstanceProcAddress
  - @ref glfwGetInstanceProcAddress
  - @ref glfwGetPhysicalDevicePresentationSupport
  - @ref glfwGetPhysicalDevicePresentationSupport
  - @ref glfwCreateWindowSurface
  - @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);
 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.
 /*! @brief Retrieves the version of the GLFW library.
  *
  *
  *  This function retrieves the major, minor and revision numbers of the GLFW
  *  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)
                                 LANGUAGE C)
 endif()
 endif()
 
 
-if (GLFW_VULKAN_STATIC)
-    target_compile_definitions(glfw PRIVATE _GLFW_VULKAN_STATIC)
-    list(APPEND glfw_PKG_DEPS "vulkan")
-endif()
-
 if (GLFW_BUILD_WIN32)
 if (GLFW_BUILD_WIN32)
     list(APPEND glfw_PKG_LIBS "-lgdi32")
     list(APPEND glfw_PKG_LIBS "-lgdi32")
 endif()
 endif()

+ 6 - 0
src/init.c

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

+ 4 - 10
src/internal.h

@@ -323,14 +323,9 @@ typedef struct VkExtensionProperties
 
 
 typedef void (APIENTRY * PFN_vkVoidFunction)(void);
 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"
 #include "platform.h"
 
 
@@ -382,6 +377,7 @@ struct _GLFWinitconfig
     GLFWbool      hatButtons;
     GLFWbool      hatButtons;
     int           angleType;
     int           angleType;
     int           platformID;
     int           platformID;
+    PFN_vkGetInstanceProcAddr vulkanLoader;
     struct {
     struct {
         GLFWbool  menubar;
         GLFWbool  menubar;
         GLFWbool  chdir;
         GLFWbool  chdir;
@@ -853,9 +849,7 @@ struct _GLFWlibrary
         GLFWbool        available;
         GLFWbool        available;
         void*           handle;
         void*           handle;
         char*           extensions[2];
         char*           extensions[2];
-#if !defined(_GLFW_VULKAN_STATIC)
         PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
         PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
-#endif
         GLFWbool        KHR_surface;
         GLFWbool        KHR_surface;
         GLFWbool        KHR_win32_surface;
         GLFWbool        KHR_win32_surface;
         GLFWbool        MVK_macos_surface;
         GLFWbool        MVK_macos_surface;

+ 31 - 31
src/vulkan.c

@@ -51,35 +51,39 @@ GLFWbool _glfwInitVulkan(int mode)
     if (_glfw.vk.available)
     if (_glfw.vk.available)
         return GLFW_TRUE;
         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)
 #if defined(_GLFW_VULKAN_LIBRARY)
-    _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
+        _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
 #elif defined(_GLFW_WIN32)
 #elif defined(_GLFW_WIN32)
-    _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
+        _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
 #elif defined(_GLFW_COCOA)
 #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
 #else
-    _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");
+        _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");
 #endif
 #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)
     vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
@@ -92,7 +96,6 @@ GLFWbool _glfwInitVulkan(int mode)
         _glfwTerminateVulkan();
         _glfwTerminateVulkan();
         return GLFW_FALSE;
         return GLFW_FALSE;
     }
     }
-#endif // _GLFW_VULKAN_STATIC
 
 
     err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
     err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
     if (err)
     if (err)
@@ -152,10 +155,8 @@ GLFWbool _glfwInitVulkan(int mode)
 
 
 void _glfwTerminateVulkan(void)
 void _glfwTerminateVulkan(void)
 {
 {
-#if !defined(_GLFW_VULKAN_STATIC)
     if (_glfw.vk.handle)
     if (_glfw.vk.handle)
         _glfwPlatformFreeModule(_glfw.vk.handle);
         _glfwPlatformFreeModule(_glfw.vk.handle);
-#endif
 }
 }
 
 
 const char* _glfwGetVulkanResultString(VkResult result)
 const char* _glfwGetVulkanResultString(VkResult result)
@@ -253,17 +254,16 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
         return NULL;
         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);
     proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
-#if defined(_GLFW_VULKAN_STATIC)
     if (!proc)
     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;
     return proc;
 }
 }