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.
*
* \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.
*
* 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
* 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
* Vulkan functions used in your program from the dynamic library using
* \note It is fairly common for Vulkan applications to link with \a libvulkan
* 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
* \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
* the vkGetInstanceProcAddr address within all the mach-o images of
* the current process. This is because the currently (v0.17.0)
* recommended MoltenVK (Vulkan on Metal) usage is as a static library.
* If it is not found then SDL will attempt to load \c libMoltenVK.dylib.
* Applications using the dylib alternative therefore do not need to do
* anything special when calling SDL.
* the current process. This is because it is fairly common for Vulkan
* applications to link with libvulkan (and historically MoltenVK was
* provided as a static library). If it is not found then, on macOS, SDL
* will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
* \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
* Vulkan loader or link to a dynamic library version. This limitation
* may be removed in a future version of SDL.
* \note On non-Apple devices, application linking with a static libvulkan is
* not supported. Either do not link to the Vulkan loader or link to a
* dynamic library version.
*
* \note This function will fail if there are no working Vulkan drivers
* installed.

View file

@ -39,7 +39,13 @@
#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. */
#define DEFAULT_HANDLE RTLD_DEFAULT
@ -52,7 +58,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) {
SDL_SetError("MoltenVK/Vulkan already loaded");
SDL_SetError("Vulkan/MoltenVK already loaded");
return -1;
}
@ -60,6 +66,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
if (!path) {
path = SDL_getenv("SDL_VULKAN_LIBRARY");
}
if (!path) {
/* 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
@ -68,20 +75,35 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
(PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE,
"vkGetInstanceProcAddr");
}
if (vkGetInstanceProcAddr) {
_this->vulkan_config.loader_handle = DEFAULT_HANDLE;
} else {
if (!path) {
/* Look for the .dylib packaged with the application instead. */
path = DEFAULT_MOLTENVK;
const char** paths;
int numPaths;
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);
if (!_this->vulkan_config.loader_handle) {
return -1;
for (i=0; i < numPaths; i++) {
_this->vulkan_config.loader_handle = SDL_LoadObject(paths[i]);
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));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
@ -90,7 +112,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
if (!vkGetInstanceProcAddr) {
SDL_SetError("Failed to find %s in either executable or %s: %s",
"vkGetInstanceProcAddr",
DEFAULT_MOLTENVK,
_this->vulkan_config.loader_path,
(const char *) dlerror());
goto fail;
}