Support official Vulkan SDK for macOS.

This tries to load vulkan.framework or libvulkan.1.dylib before MoltenVK.framework
or libMoltenVK.dylib. In the previous version, layers would not work for applications
run-time loading the default library.
This commit is contained in:
Mark Callow 2018-02-25 23:02:09 -08:00
parent f9f45d0bf5
commit be6ca785e3
2 changed files with 59 additions and 24 deletions

View File

@ -69,30 +69,43 @@ typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */
* \brief Dynamically load a Vulkan loader library. * \brief Dynamically load a Vulkan loader library.
* *
* \param [in] path The platform dependent Vulkan loader library name, or * \param [in] path The platform dependent Vulkan loader library name, or
* \c NULL to open the default Vulkan loader library. * \c NULL.
* *
* \return \c 0 on success, or \c -1 if the library couldn't be loaded. * \return \c 0 on success, or \c -1 if the library couldn't be loaded.
* *
* This should be done after initializing the video driver, but before * If \a path is NULL SDL will use the value of the environment variable
* \c SDL_VULKAN_LIBRARY, if set, otherwise it loads the default Vulkan
* loader library.
*
* This should be called after initializing the video driver, but before
* creating any Vulkan windows. If no Vulkan loader library is loaded, the * creating any Vulkan windows. If no Vulkan loader library is loaded, the
* default library will be loaded upon creation of the first Vulkan window. * default library will be loaded upon creation of the first Vulkan window.
* *
* \note If you specify a non-NULL \a path, you should retrieve all of the * \note It is fairly common for Vulkan applications to link with \a libvulkan
* Vulkan functions used in your program from the dynamic library using * instead of explicitly loading it at run time. This will work with
* SDL provided the application links to a dynamic library and both it
* and SDL use the same search path.
*
* \note If you specify a non-NULL \c path, an application should retrieve all
* of the Vulkan functions it uses from the dynamic library using
* \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee * \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee
* \a path points to the same vulkan loader library that you linked to. * \c path points to the same vulkan loader library the application
* linked to.
* *
* \note On Apple devices, if \a path is NULL, SDL will attempt to find * \note On Apple devices, if \a path is NULL, SDL will attempt to find
* the vkGetInstanceProcAddr address within all the mach-o images of * the vkGetInstanceProcAddr address within all the mach-o images of
* the current process. This is because the currently (v0.17.0) * the current process. This is because it is fairly common for Vulkan
* recommended MoltenVK (Vulkan on Metal) usage is as a static library. * applications to link with libvulkan (and historically MoltenVK was
* If it is not found then SDL will attempt to load \c libMoltenVK.dylib. * provided as a static library). If it is not found then, on macOS, SDL
* Applications using the dylib alternative therefore do not need to do * will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
* anything special when calling SDL. * \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order.
* On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications
* using a dynamic framework or .dylib must ensure it is included in its
* application bundle.
* *
* \note On non-Apple devices, SDL requires you to either not link to the * \note On non-Apple devices, application linking with a static libvulkan is
* Vulkan loader or link to a dynamic library version. This limitation * not supported. Either do not link to the Vulkan loader or link to a
* may be removed in a future version of SDL. * dynamic library version.
* *
* \note This function will fail if there are no working Vulkan drivers * \note This function will fail if there are no working Vulkan drivers
* installed. * installed.

View File

@ -39,7 +39,13 @@
#include <dlfcn.h> #include <dlfcn.h>
#define DEFAULT_MOLTENVK "libMoltenVK.dylib" const char* defaultPaths[] = {
"vulkan.framework/vulkan",
"libvulkan.1.dylib",
"MoltenVK.framework/MoltenVK",
"libMoltenVK.dylib"
};
/* Since libSDL is most likely a .dylib, need RTLD_DEFAULT not RTLD_SELF. */ /* Since libSDL is most likely a .dylib, need RTLD_DEFAULT not RTLD_SELF. */
#define DEFAULT_HANDLE RTLD_DEFAULT #define DEFAULT_HANDLE RTLD_DEFAULT
@ -52,7 +58,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) { if (_this->vulkan_config.loader_handle) {
SDL_SetError("MoltenVK/Vulkan already loaded"); SDL_SetError("Vulkan/MoltenVK already loaded");
return -1; return -1;
} }
@ -60,6 +66,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
if (!path) { if (!path) {
path = SDL_getenv("SDL_VULKAN_LIBRARY"); path = SDL_getenv("SDL_VULKAN_LIBRARY");
} }
if (!path) { if (!path) {
/* MoltenVK framework, currently, v0.17.0, has a static library and is /* MoltenVK framework, currently, v0.17.0, has a static library and is
* the recommended way to use the package. There is likely no object to * the recommended way to use the package. There is likely no object to
@ -72,16 +79,31 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
if (vkGetInstanceProcAddr) { if (vkGetInstanceProcAddr) {
_this->vulkan_config.loader_handle = DEFAULT_HANDLE; _this->vulkan_config.loader_handle = DEFAULT_HANDLE;
} else { } else {
if (!path) { const char** paths;
/* Look for the .dylib packaged with the application instead. */ int numPaths;
path = DEFAULT_MOLTENVK; int i;
if (path) {
paths = &path;
numPaths = 1;
} else {
/* Look for framework or .dylib packaged with the application
* instead. */
paths = defaultPaths;
numPaths = SDL_arraysize(defaultPaths);
} }
_this->vulkan_config.loader_handle = SDL_LoadObject(path); for (i=0; i < numPaths; i++) {
if (!_this->vulkan_config.loader_handle) { _this->vulkan_config.loader_handle = SDL_LoadObject(paths[i]);
return -1; if (_this->vulkan_config.loader_handle)
break;
else
continue;
} }
SDL_strlcpy(_this->vulkan_config.loader_path, path, if (i == numPaths)
return -1;
SDL_strlcpy(_this->vulkan_config.loader_path, paths[i],
SDL_arraysize(_this->vulkan_config.loader_path)); SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
@ -90,7 +112,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
if (!vkGetInstanceProcAddr) { if (!vkGetInstanceProcAddr) {
SDL_SetError("Failed to find %s in either executable or %s: %s", SDL_SetError("Failed to find %s in either executable or %s: %s",
"vkGetInstanceProcAddr", "vkGetInstanceProcAddr",
DEFAULT_MOLTENVK, _this->vulkan_config.loader_path,
(const char *) dlerror()); (const char *) dlerror());
goto fail; goto fail;
} }