dolphin/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp

223 lines
6.7 KiB
C++
Raw Normal View History

2016-08-13 12:57:50 +00:00
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <atomic>
#include <cstdarg>
#include <cstdlib>
2016-08-13 12:57:50 +00:00
#include "Common/CommonFuncs.h"
2019-03-09 13:31:34 +00:00
#include "Common/DynamicLibrary.h"
#include "Common/FileUtil.h"
2016-08-13 12:57:50 +00:00
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "VideoBackends/Vulkan/VulkanLoader.h"
#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;
#include "VideoBackends/Vulkan/VulkanEntryPoints.inl"
#undef VULKAN_DEVICE_ENTRY_POINT
#undef VULKAN_INSTANCE_ENTRY_POINT
#undef VULKAN_MODULE_ENTRY_POINT
namespace Vulkan
{
static void ResetVulkanLibraryFunctionPointers()
{
#define VULKAN_MODULE_ENTRY_POINT(name, required) name = nullptr;
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) name = nullptr;
#define VULKAN_DEVICE_ENTRY_POINT(name, required) name = nullptr;
#include "VideoBackends/Vulkan/VulkanEntryPoints.inl"
#undef VULKAN_DEVICE_ENTRY_POINT
#undef VULKAN_INSTANCE_ENTRY_POINT
#undef VULKAN_MODULE_ENTRY_POINT
}
2019-03-09 13:31:34 +00:00
static Common::DynamicLibrary s_vulkan_module;
2016-08-13 12:57:50 +00:00
static bool OpenVulkanLibrary()
2016-08-13 12:57:50 +00:00
{
2019-03-09 13:31:34 +00:00
#ifdef __APPLE__
// Check if a path to a specific Vulkan library has been specified.
char* libvulkan_env = getenv("LIBVULKAN_PATH");
if (libvulkan_env && s_vulkan_module.Open(libvulkan_env))
return true;
2019-03-09 13:31:34 +00:00
// Use the libvulkan.dylib from the application bundle.
std::string filename = File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
return s_vulkan_module.Open(filename.c_str());
#else
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
if (s_vulkan_module.Open(filename.c_str()))
return true;
// Android devices may not have libvulkan.so.1, only libvulkan.so.
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
return s_vulkan_module.Open(filename.c_str());
#endif
2019-03-09 13:31:34 +00:00
}
2016-08-13 12:57:50 +00:00
2019-03-09 13:31:34 +00:00
bool LoadVulkanLibrary()
{
if (!s_vulkan_module.IsOpen() && !OpenVulkanLibrary())
return false;
2016-08-13 12:57:50 +00:00
#define VULKAN_MODULE_ENTRY_POINT(name, required) \
2019-03-09 13:31:34 +00:00
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; \
}
2016-08-13 12:57:50 +00:00
#include "VideoBackends/Vulkan/VulkanEntryPoints.inl"
#undef VULKAN_MODULE_ENTRY_POINT
return true;
}
void UnloadVulkanLibrary()
{
2019-03-09 13:31:34 +00:00
s_vulkan_module.Close();
if (!s_vulkan_module.IsOpen())
ResetVulkanLibraryFunctionPointers();
2016-08-13 12:57:50 +00:00
}
2016-08-13 12:57:50 +00:00
bool LoadVulkanInstanceFunctions(VkInstance instance)
{
bool required_functions_missing = false;
auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) {
*func_ptr = vkGetInstanceProcAddr(instance, name);
if (!(*func_ptr) && is_required)
{
ERROR_LOG(VIDEO, "Vulkan: Failed to load required instance function %s", name);
required_functions_missing = true;
}
};
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) \
LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required);
#include "VideoBackends/Vulkan/VulkanEntryPoints.inl"
#undef VULKAN_INSTANCE_ENTRY_POINT
return !required_functions_missing;
}
bool LoadVulkanDeviceFunctions(VkDevice device)
{
bool required_functions_missing = false;
auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) {
*func_ptr = vkGetDeviceProcAddr(device, name);
if (!(*func_ptr) && is_required)
{
ERROR_LOG(VIDEO, "Vulkan: Failed to load required device function %s", name);
required_functions_missing = true;
}
};
#define VULKAN_DEVICE_ENTRY_POINT(name, required) \
LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required);
#include "VideoBackends/Vulkan/VulkanEntryPoints.inl"
#undef VULKAN_DEVICE_ENTRY_POINT
return !required_functions_missing;
}
const char* VkResultToString(VkResult res)
{
switch (res)
{
case VK_SUCCESS:
return "VK_SUCCESS";
case VK_NOT_READY:
return "VK_NOT_READY";
case VK_TIMEOUT:
return "VK_TIMEOUT";
case VK_EVENT_SET:
return "VK_EVENT_SET";
case VK_EVENT_RESET:
return "VK_EVENT_RESET";
case VK_INCOMPLETE:
return "VK_INCOMPLETE";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED:
return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_DEVICE_LOST:
return "VK_ERROR_DEVICE_LOST";
case VK_ERROR_MEMORY_MAP_FAILED:
return "VK_ERROR_MEMORY_MAP_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT:
return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "VK_ERROR_FEATURE_NOT_PRESENT";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK_ERROR_TOO_MANY_OBJECTS:
return "VK_ERROR_TOO_MANY_OBJECTS";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK_ERROR_SURFACE_LOST_KHR:
return "VK_ERROR_SURFACE_LOST_KHR";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
case VK_SUBOPTIMAL_KHR:
return "VK_SUBOPTIMAL_KHR";
case VK_ERROR_OUT_OF_DATE_KHR:
return "VK_ERROR_OUT_OF_DATE_KHR";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "VK_ERROR_VALIDATION_FAILED_EXT";
case VK_ERROR_INVALID_SHADER_NV:
return "VK_ERROR_INVALID_SHADER_NV";
default:
return "UNKNOWN_VK_RESULT";
}
}
void LogVulkanResult(int level, const char* func_name, VkResult res, const char* msg, ...)
{
std::va_list ap;
va_start(ap, msg);
std::string real_msg = StringFromFormatV(msg, ap);
va_end(ap);
real_msg = StringFromFormat("(%s) %s (%d: %s)", func_name, real_msg.c_str(),
static_cast<int>(res), VkResultToString(res));
GENERIC_LOG(LogTypes::VIDEO, static_cast<LogTypes::LOG_LEVELS>(level), "%s", real_msg.c_str());
}
} // namespace Vulkan