Skip to content

Commit

Permalink
Support official Vulkan SDK for macOS.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Mark Callow committed Feb 26, 2018
1 parent f9f45d0 commit be6ca78
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 25 deletions.
41 changes: 27 additions & 14 deletions include/SDL_vulkan.h
Expand Up @@ -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.
*
* \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.
* 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, 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.
Expand Down
44 changes: 33 additions & 11 deletions src/video/cocoa/SDL_cocoavulkan.m
Expand Up @@ -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

Expand All @@ -52,14 +58,15 @@ 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;
}

/* Load the Vulkan loader library */
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
Expand All @@ -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");
Expand All @@ -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;
}
Expand Down

0 comments on commit be6ca78

Please sign in to comment.