Vulkan: Use Common::DynamicLibrary

This commit is contained in:
Stenzek 2019-03-09 23:31:34 +10:00
parent a4f7c04470
commit f6641b7e4f
1 changed files with 28 additions and 122 deletions

View File

@ -7,18 +7,13 @@
#include <cstdlib>
#include "Common/CommonFuncs.h"
#include "Common/DynamicLibrary.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "VideoBackends/Vulkan/VulkanLoader.h"
#if defined(_WIN32)
#include <Windows.h>
#else
#include <dlfcn.h>
#endif
#define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name;
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) PFN_##name name;
#define VULKAN_DEVICE_ENTRY_POINT(name, required) PFN_##name name;
@ -40,145 +35,56 @@ static void ResetVulkanLibraryFunctionPointers()
#undef VULKAN_MODULE_ENTRY_POINT
}
#if defined(_WIN32)
static Common::DynamicLibrary s_vulkan_module;
static HMODULE vulkan_module;
static std::atomic_int vulkan_module_ref_count = {0};
bool LoadVulkanLibrary()
static std::string GetVulkanLibraryFilename()
{
// Not thread safe if a second thread calls the loader whilst the first is still in-progress.
if (vulkan_module)
{
vulkan_module_ref_count++;
return true;
}
vulkan_module = LoadLibraryA("vulkan-1.dll");
if (!vulkan_module)
{
ERROR_LOG(VIDEO, "Failed to load vulkan-1.dll");
return false;
}
bool required_functions_missing = false;
auto LoadFunction = [&](FARPROC* func_ptr, const char* name, bool is_required) {
*func_ptr = GetProcAddress(vulkan_module, name);
if (!(*func_ptr) && is_required)
{
ERROR_LOG(VIDEO, "Vulkan: Failed to load required module function %s", name);
required_functions_missing = true;
}
};
#define VULKAN_MODULE_ENTRY_POINT(name, required) \
LoadFunction(reinterpret_cast<FARPROC*>(&name), #name, required);
#include "VideoBackends/Vulkan/VulkanEntryPoints.inl"
#undef VULKAN_MODULE_ENTRY_POINT
if (required_functions_missing)
{
ResetVulkanLibraryFunctionPointers();
FreeLibrary(vulkan_module);
vulkan_module = nullptr;
return false;
}
vulkan_module_ref_count++;
return true;
}
void UnloadVulkanLibrary()
{
if ((--vulkan_module_ref_count) > 0)
return;
ResetVulkanLibraryFunctionPointers();
FreeLibrary(vulkan_module);
vulkan_module = nullptr;
}
#else
static void* vulkan_module;
static std::atomic_int vulkan_module_ref_count = {0};
bool LoadVulkanLibrary()
{
// Not thread safe if a second thread calls the loader whilst the first is still in-progress.
if (vulkan_module)
{
vulkan_module_ref_count++;
return true;
}
#if defined(__APPLE__)
#ifdef __APPLE__
// Check if a path to a specific Vulkan library has been specified.
char* libvulkan_env = getenv("LIBVULKAN_PATH");
if (libvulkan_env)
vulkan_module = dlopen(libvulkan_env, RTLD_NOW);
if (!vulkan_module)
{
// Use the libvulkan.dylib from the application bundle.
std::string path = File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
vulkan_module = dlopen(path.c_str(), RTLD_NOW);
}
return std::string(libvulkan_env);
// Use the libvulkan.dylib from the application bundle.
return File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
#else
// Names of libraries to search. Desktop should use libvulkan.so.1 or libvulkan.so.
static const char* search_lib_names[] = {"libvulkan.so.1", "libvulkan.so"};
for (size_t i = 0; i < ArraySize(search_lib_names); i++)
{
vulkan_module = dlopen(search_lib_names[i], RTLD_NOW);
if (vulkan_module)
break;
}
return Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
#endif
}
if (!vulkan_module)
bool LoadVulkanLibrary()
{
if (!s_vulkan_module.IsOpen())
{
ERROR_LOG(VIDEO, "Failed to load or locate libvulkan.so");
return false;
}
bool required_functions_missing = false;
auto LoadFunction = [&](void** func_ptr, const char* name, bool is_required) {
*func_ptr = dlsym(vulkan_module, name);
if (!(*func_ptr) && is_required)
const std::string filename = GetVulkanLibraryFilename();
if (!s_vulkan_module.Open(filename.c_str()))
{
ERROR_LOG(VIDEO, "Vulkan: Failed to load required module function %s", name);
required_functions_missing = true;
ERROR_LOG(VIDEO, "Failed to load %s", filename.c_str());
return false;
}
};
}
#define VULKAN_MODULE_ENTRY_POINT(name, required) \
LoadFunction(reinterpret_cast<void**>(&name), #name, required);
if (!s_vulkan_module.GetSymbol(#name, &name) && required) \
{ \
ERROR_LOG(VIDEO, "Vulkan: Failed to load required module function %s", #name); \
ResetVulkanLibraryFunctionPointers(); \
s_vulkan_module.Close(); \
return false; \
}
#include "VideoBackends/Vulkan/VulkanEntryPoints.inl"
#undef VULKAN_MODULE_ENTRY_POINT
if (required_functions_missing)
{
ResetVulkanLibraryFunctionPointers();
dlclose(vulkan_module);
vulkan_module = nullptr;
return false;
}
vulkan_module_ref_count++;
return true;
}
void UnloadVulkanLibrary()
{
if ((--vulkan_module_ref_count) > 0)
return;
ResetVulkanLibraryFunctionPointers();
dlclose(vulkan_module);
vulkan_module = nullptr;
s_vulkan_module.Close();
if (!s_vulkan_module.IsOpen())
ResetVulkanLibraryFunctionPointers();
}
#endif
bool LoadVulkanInstanceFunctions(VkInstance instance)
{
bool required_functions_missing = false;