From 76a5f781dbff5366271c021ee763da2a44fdcef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 21 Oct 2021 20:45:44 +0200 Subject: [PATCH] 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 --- CMakeLists.txt | 1 - CONTRIBUTORS.md | 1 + README.md | 1 + docs/compile.dox | 8 ------ docs/intro.dox | 1 + docs/news.dox | 12 +++++++++ docs/vulkan.dox | 33 +++++++++++++---------- include/GLFW/glfw3.h | 48 ++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 5 ---- src/init.c | 6 +++++ src/internal.h | 14 +++------- src/vulkan.c | 62 ++++++++++++++++++++++---------------------- 12 files changed, 124 insertions(+), 68 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5042ab9c..f5e538bf 100644 --- a/CMakeLists.txt +++ b/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) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 7e79b955..84320b17 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -128,6 +128,7 @@ video tutorials. - Jon Morton - Pierre Moulon - Martins Mozeiko + - Pascal Muetschard - Julian Møller - ndogxj - n3rdopolis diff --git a/README.md b/README.md index e6da3acd..6cfb59a5 100644 --- a/README.md +++ b/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) diff --git a/docs/compile.dox b/docs/compile.dox index 63479516..05da99cf 100644 --- a/docs/compile.dox +++ b/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 diff --git a/docs/intro.dox b/docs/intro.dox index c50a3722..5cbd7eb0 100644 --- a/docs/intro.dox +++ b/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 diff --git a/docs/news.dox b/docs/news.dox index 28affab0..6c55e65f 100644 --- a/docs/news.dox +++ b/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 diff --git a/docs/vulkan.dox b/docs/vulkan.dox index 734c630b..31891036 100644 --- a/docs/vulkan.dox +++ b/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 +@section vulkan_loader Finding 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. +GLFW itself does not ever need to be linked against the Vulkan loader. -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. +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 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 +@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 diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 17cb66c2..751615eb 100644 --- a/include/GLFW/glfw3.h +++ b/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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ab57255..a0be580e 100644 --- a/src/CMakeLists.txt +++ b/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() diff --git a/src/init.c b/src/init.c index 65f5de31..c4c5e030 100644 --- a/src/init.c +++ b/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) diff --git a/src/internal.h b/src/internal.h index 1a38ba7e..c853ad9b 100644 --- a/src/internal.h +++ b/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; diff --git a/src/vulkan.c b/src/vulkan.c index b5ca25c0..2a64ecb4 100644 --- a/src/vulkan.c +++ b/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; }