Support official Vulkan SDK for macOS.
authorMark Callow <libsdl.org@callow.im>
Sun, 25 Feb 2018 23:02:09 -0800
changeset 11906d97ab6d12404
parent 11905 29bf3038a246
child 11907 4d9a8db6baf6
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.
include/SDL_vulkan.h
src/video/cocoa/SDL_cocoavulkan.m
     1.1 --- a/include/SDL_vulkan.h	Sun Feb 25 19:51:34 2018 -0800
     1.2 +++ b/include/SDL_vulkan.h	Sun Feb 25 23:02:09 2018 -0800
     1.3 @@ -69,30 +69,43 @@
     1.4   *  \brief Dynamically load a Vulkan loader library.
     1.5   *
     1.6   *  \param [in] path The platform dependent Vulkan loader library name, or
     1.7 - *              \c NULL to open the default Vulkan loader library.
     1.8 + *              \c NULL.
     1.9   *
    1.10   *  \return \c 0 on success, or \c -1 if the library couldn't be loaded.
    1.11   *
    1.12 - *  This should be done after initializing the video driver, but before
    1.13 + *  If \a path is NULL SDL will use the value of the environment variable
    1.14 + *  \c SDL_VULKAN_LIBRARY, if set, otherwise it loads the default Vulkan
    1.15 + *  loader library.
    1.16 + *
    1.17 + *  This should be called after initializing the video driver, but before
    1.18   *  creating any Vulkan windows. If no Vulkan loader library is loaded, the
    1.19   *  default library will be loaded upon creation of the first Vulkan window.
    1.20   *
    1.21 - *  \note If you specify a non-NULL \a path, you should retrieve all of the
    1.22 - *        Vulkan functions used in your program from the dynamic library using
    1.23 + *  \note It is fairly common for Vulkan applications to link with \a libvulkan
    1.24 + *        instead of explicitly loading it at run time. This will work with
    1.25 + *        SDL provided the application links to a dynamic library and both it
    1.26 + *        and SDL use the same search path.
    1.27 + *
    1.28 + *  \note If you specify a non-NULL \c path, an application should retrieve all
    1.29 + *        of the Vulkan functions it uses from the dynamic library using
    1.30   *        \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee
    1.31 - *        \a path points to the same vulkan loader library that you linked to.
    1.32 + *        \c path points to the same vulkan loader library the application
    1.33 + *        linked to.
    1.34   *
    1.35   *  \note On Apple devices, if \a path is NULL, SDL will attempt to find
    1.36   *        the vkGetInstanceProcAddr address within all the mach-o images of
    1.37 - *        the current process. This is because the currently (v0.17.0)
    1.38 - *        recommended MoltenVK (Vulkan on Metal) usage is as a static library.
    1.39 - *        If it is not found then SDL will attempt to load \c libMoltenVK.dylib.
    1.40 - *        Applications using the dylib alternative therefore do not need to do
    1.41 - *        anything special when calling SDL.
    1.42 + *        the current process. This is because it is fairly common for Vulkan
    1.43 + *        applications to link with libvulkan (and historically MoltenVK was
    1.44 + *        provided as a static library). If it is not found then, on macOS, SDL
    1.45 + *        will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
    1.46 + *        \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order.
    1.47 + *        On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications
    1.48 + *        using a dynamic framework or .dylib must ensure it is included in its
    1.49 + *        application bundle.
    1.50   *
    1.51 - *  \note On non-Apple devices, SDL requires you to either not link to the
    1.52 - *        Vulkan loader or link to a dynamic library version. This limitation
    1.53 - *        may be removed in a future version of SDL.
    1.54 + *  \note On non-Apple devices, application linking with a static libvulkan is
    1.55 + *        not supported. Either do not link to the Vulkan loader or link to a
    1.56 + *        dynamic library version.
    1.57   *
    1.58   *  \note This function will fail if there are no working Vulkan drivers
    1.59   *        installed.
     2.1 --- a/src/video/cocoa/SDL_cocoavulkan.m	Sun Feb 25 19:51:34 2018 -0800
     2.2 +++ b/src/video/cocoa/SDL_cocoavulkan.m	Sun Feb 25 23:02:09 2018 -0800
     2.3 @@ -39,7 +39,13 @@
     2.4  
     2.5  #include <dlfcn.h>
     2.6  
     2.7 -#define DEFAULT_MOLTENVK  "libMoltenVK.dylib"
     2.8 +const char* defaultPaths[] = {
     2.9 +    "vulkan.framework/vulkan",
    2.10 +    "libvulkan.1.dylib",
    2.11 +    "MoltenVK.framework/MoltenVK",
    2.12 +    "libMoltenVK.dylib"
    2.13 +};
    2.14 +
    2.15  /* Since libSDL is most likely a .dylib, need RTLD_DEFAULT not RTLD_SELF. */
    2.16  #define DEFAULT_HANDLE RTLD_DEFAULT
    2.17  
    2.18 @@ -52,7 +58,7 @@
    2.19      PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
    2.20  
    2.21      if (_this->vulkan_config.loader_handle) {
    2.22 -        SDL_SetError("MoltenVK/Vulkan already loaded");
    2.23 +        SDL_SetError("Vulkan/MoltenVK already loaded");
    2.24          return -1;
    2.25      }
    2.26  
    2.27 @@ -60,6 +66,7 @@
    2.28      if (!path) {
    2.29          path = SDL_getenv("SDL_VULKAN_LIBRARY");
    2.30      }
    2.31 +
    2.32      if (!path) {
    2.33          /* MoltenVK framework, currently, v0.17.0, has a static library and is
    2.34           * the recommended way to use the package. There is likely no object to
    2.35 @@ -68,20 +75,35 @@
    2.36           (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE,
    2.37                                            "vkGetInstanceProcAddr");
    2.38      }
    2.39 -    
    2.40 +
    2.41      if (vkGetInstanceProcAddr) {
    2.42          _this->vulkan_config.loader_handle = DEFAULT_HANDLE;
    2.43      } else {
    2.44 -        if (!path) {
    2.45 -            /* Look for the .dylib packaged with the application instead. */
    2.46 -            path = DEFAULT_MOLTENVK;
    2.47 +        const char** paths;
    2.48 +        int numPaths;
    2.49 +        int i;
    2.50 +
    2.51 +        if (path) {
    2.52 +            paths = &path;
    2.53 +            numPaths = 1;
    2.54 +        } else {
    2.55 +            /* Look for framework or .dylib packaged with the application
    2.56 +             * instead. */
    2.57 +            paths = defaultPaths;
    2.58 +            numPaths = SDL_arraysize(defaultPaths);
    2.59          }
    2.60          
    2.61 -        _this->vulkan_config.loader_handle = SDL_LoadObject(path);
    2.62 -        if (!_this->vulkan_config.loader_handle) {
    2.63 +        for (i=0; i < numPaths; i++) {
    2.64 +            _this->vulkan_config.loader_handle = SDL_LoadObject(paths[i]);
    2.65 +            if (_this->vulkan_config.loader_handle)
    2.66 +                break;
    2.67 +            else
    2.68 +                continue;
    2.69 +        }
    2.70 +        if (i == numPaths)
    2.71              return -1;
    2.72 -        }
    2.73 -        SDL_strlcpy(_this->vulkan_config.loader_path, path,
    2.74 +
    2.75 +        SDL_strlcpy(_this->vulkan_config.loader_path, paths[i],
    2.76                      SDL_arraysize(_this->vulkan_config.loader_path));
    2.77          vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
    2.78              _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
    2.79 @@ -90,7 +112,7 @@
    2.80      if (!vkGetInstanceProcAddr) {
    2.81          SDL_SetError("Failed to find %s in either executable or %s: %s",
    2.82                       "vkGetInstanceProcAddr",
    2.83 -                     DEFAULT_MOLTENVK,
    2.84 +                     _this->vulkan_config.loader_path,
    2.85                       (const char *) dlerror());
    2.86          goto fail;
    2.87      }