Fixed bug 4570 - Support Vulkan Portability rather than MoltenVK specifically

Dzmitry Malyshau

Current code, search paths, and error messages are written to only consider MoltenVK on macOS as a Vulkan Portability implementation. It's not the only implementation available to the users. gfx-portability [1] has been shown to run a number of titles well, including Dota2, Dolphin Emulator, and vkQuake3, often out-performing MoltenVK in frame rate and stability (see Dolphin benchmark [2]).

There is no reason for SDL to be that specific, it's not using any MVK-specific functions other than the WSI initialization ("VK_MVK_macos_surface"). gfx-portability exposes this extension as well, and a more generic WSI extension is in process. It would be good if SDL was written in a more generic way that expect a Vulkan Portability library as opposed to MoltenVK specifically.

[1] https://github.com/gfx-rs/portability
[2] https://gfx-rs.github.io/2019/03/22/dolphin-macos-performance.html
This commit is contained in:
Sam Lantinga 2019-06-11 18:13:46 -07:00
parent 3e9bf28413
commit 69d27a69cd
4 changed files with 39 additions and 25 deletions

View File

@ -218,7 +218,7 @@
#endif #endif
/* Enable Vulkan support */ /* Enable Vulkan support */
/* Metal/MoltenVK/Vulkan only supported on 64-bit architectures with 10.11+ */ /* Metal/Vulkan Portability only supported on 64-bit architectures with 10.11+ */
#if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100) #if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
#define SDL_VIDEO_VULKAN 1 #define SDL_VIDEO_VULKAN 1
#else #else

View File

@ -98,8 +98,8 @@ typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */
* applications to link with libvulkan (and historically MoltenVK was * applications to link with libvulkan (and historically MoltenVK was
* provided as a static library). If it is not found then, on macOS, SDL * 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, * will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
* \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order. * followed by \c libvulkan.dylib, in that order.
* On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications * On iOS SDL will attempt to load \c libvulkan.dylib only. Applications
* using a dynamic framework or .dylib must ensure it is included in its * using a dynamic framework or .dylib must ensure it is included in its
* application bundle. * application bundle.
* *

View File

@ -42,6 +42,7 @@
const char* defaultPaths[] = { const char* defaultPaths[] = {
"vulkan.framework/vulkan", "vulkan.framework/vulkan",
"libvulkan.1.dylib", "libvulkan.1.dylib",
"libvulkan.dylib",
"MoltenVK.framework/MoltenVK", "MoltenVK.framework/MoltenVK",
"libMoltenVK.dylib" "libMoltenVK.dylib"
}; };
@ -58,7 +59,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) {
return SDL_SetError("Vulkan/MoltenVK already loaded"); return SDL_SetError("Vulkan Portability library is already loaded.");
} }
/* Load the Vulkan loader library */ /* Load the Vulkan loader library */
@ -67,9 +68,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
} }
if (!path) { if (!path) {
/* MoltenVK framework, currently, v0.17.0, has a static library and is /* Handle the case where Vulkan Portability is linked statically. */
* the recommended way to use the package. There is likely no object to
* load. */
vkGetInstanceProcAddr = vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE, (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE,
"vkGetInstanceProcAddr"); "vkGetInstanceProcAddr");
@ -99,7 +98,7 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
} }
if (_this->vulkan_config.loader_handle == NULL) { if (_this->vulkan_config.loader_handle == NULL) {
return SDL_SetError("Failed to load Vulkan/MoltenVK library"); return SDL_SetError("Failed to load Vulkan Portability library");
} }
SDL_strlcpy(_this->vulkan_config.loader_path, foundPath, SDL_strlcpy(_this->vulkan_config.loader_path, foundPath,
@ -139,11 +138,11 @@ int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
} }
SDL_free(extensions); SDL_free(extensions);
if (!hasSurfaceExtension) { if (!hasSurfaceExtension) {
SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " SDL_SetError("Installed Vulkan Portability library doesn't implement the "
VK_KHR_SURFACE_EXTENSION_NAME " extension"); VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail; goto fail;
} else if (!hasMacOSSurfaceExtension) { } else if (!hasMacOSSurfaceExtension) {
SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " SDL_SetError("Installed Vulkan Portability library doesn't implement the "
VK_MVK_MACOS_SURFACE_EXTENSION_NAME "extension"); VK_MVK_MACOS_SURFACE_EXTENSION_NAME "extension");
goto fail; goto fail;
} }

View File

@ -39,7 +39,10 @@
#include <dlfcn.h> #include <dlfcn.h>
#define DEFAULT_MOLTENVK "libMoltenVK.dylib" const char* defaultPaths[] = {
"libvulkan.dylib",
};
/* Since libSDL is static, could use RTLD_SELF. Using RTLD_DEFAULT is future /* Since libSDL is static, could use RTLD_SELF. Using RTLD_DEFAULT is future
* proofing. */ * proofing. */
#define DEFAULT_HANDLE RTLD_DEFAULT #define DEFAULT_HANDLE RTLD_DEFAULT
@ -53,7 +56,7 @@ int UIKit_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) {
return SDL_SetError("MoltenVK/Vulkan already loaded"); return SDL_SetError("Vulkan Portability library is already loaded.");
} }
/* Load the Vulkan loader library */ /* Load the Vulkan loader library */
@ -62,9 +65,7 @@ int UIKit_Vulkan_LoadLibrary(_THIS, const char *path)
} }
if (!path) { if (!path) {
/* MoltenVK framework, currently, v0.17.0, has a static library and is /* Handle the case where Vulkan Portability is linked statically. */
* the recommended way to use the package. There is likely no object to
* load. */
vkGetInstanceProcAddr = vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE, (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE,
"vkGetInstanceProcAddr"); "vkGetInstanceProcAddr");
@ -73,15 +74,29 @@ int UIKit_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;
const char *foundPath = NULL;
int numPaths;
int i;
if (path) {
paths = &path;
numPaths = 1;
} else {
/* Look for the .dylib packaged with the application instead. */ /* Look for the .dylib packaged with the application instead. */
path = DEFAULT_MOLTENVK; paths = defaultPaths;
numPaths = SDL_arraysize(defaultPaths);
} }
_this->vulkan_config.loader_handle = SDL_LoadObject(path); for (i = 0; i < numPaths && _this->vulkan_config.loader_handle == NULL; i++) {
if (!_this->vulkan_config.loader_handle) { foundPath = paths[i];
return -1; _this->vulkan_config.loader_handle = SDL_LoadObject(foundPath);
} }
if (_this->vulkan_config.loader_handle == NULL) {
return SDL_SetError("Failed to load Vulkan Portability library");
}
SDL_strlcpy(_this->vulkan_config.loader_path, path, SDL_strlcpy(_this->vulkan_config.loader_path, path,
SDL_arraysize(_this->vulkan_config.loader_path)); SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = vkGetInstanceProcAddr =
@ -93,7 +108,7 @@ int UIKit_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, "linked Vulkan Portability library",
(const char *) dlerror()); (const char *) dlerror());
goto fail; goto fail;
} }
@ -128,11 +143,11 @@ int UIKit_Vulkan_LoadLibrary(_THIS, const char *path)
SDL_free(extensions); SDL_free(extensions);
if (!hasSurfaceExtension) { if (!hasSurfaceExtension) {
SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " SDL_SetError("Installed Vulkan Portability doesn't implement the "
VK_KHR_SURFACE_EXTENSION_NAME " extension"); VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail; goto fail;
} else if (!hasIOSSurfaceExtension) { } else if (!hasIOSSurfaceExtension) {
SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " SDL_SetError("Installed Vulkan Portability doesn't implement the "
VK_MVK_IOS_SURFACE_EXTENSION_NAME "extension"); VK_MVK_IOS_SURFACE_EXTENSION_NAME "extension");
goto fail; goto fail;
} }