VideoBackends:Vulkan: Allow loading custom drivers on Android

... using libadrenotools
This commit is contained in:
Robin Kertels
2023-06-01 00:05:06 +02:00
parent 35bb663c2a
commit 23bebc5270
24 changed files with 399 additions and 29 deletions

View File

@ -163,3 +163,10 @@
// Subdirs in Config
#define GRAPHICSMOD_CONFIG_DIR "GraphicMods"
// GPU drivers
#define GPU_DRIVERS "GpuDrivers"
#define GPU_DRIVERS_EXTRACTED "Extracted"
#define GPU_DRIVERS_TMP "Tmp"
#define GPU_DRIVERS_HOOK "Hook"
#define GPU_DRIVERS_FILE_REDIRECT "FileRedirect"

View File

@ -24,11 +24,22 @@ DynamicLibrary::DynamicLibrary(const char* filename)
Open(filename);
}
DynamicLibrary::DynamicLibrary(void* handle)
{
m_handle = handle;
}
DynamicLibrary::~DynamicLibrary()
{
Close();
}
DynamicLibrary& DynamicLibrary::operator=(void* handle)
{
m_handle = handle;
return *this;
}
std::string DynamicLibrary::GetUnprefixedFilename(const char* filename)
{
#if defined(_WIN32)

View File

@ -21,6 +21,8 @@ public:
// Automatically loads the specified library. Call IsOpen() to check validity before use.
DynamicLibrary(const char* filename);
DynamicLibrary(void* handle);
// Closes the library.
~DynamicLibrary();
@ -30,6 +32,8 @@ public:
DynamicLibrary& operator=(const DynamicLibrary&) = delete;
DynamicLibrary& operator=(DynamicLibrary&&) = delete;
DynamicLibrary& operator=(void*);
// Returns the specified library name with the platform-specific suffix added.
static std::string GetUnprefixedFilename(const char* filename);

View File

@ -66,6 +66,8 @@ namespace File
{
#ifdef ANDROID
static std::string s_android_sys_directory;
static std::string s_android_driver_directory;
static std::string s_android_lib_directory;
#endif
#ifdef __APPLE__
@ -796,6 +798,34 @@ void SetSysDirectory(const std::string& path)
s_android_sys_directory);
s_android_sys_directory = path;
}
void SetGpuDriverDirectories(const std::string& path, const std::string& lib_path)
{
INFO_LOG_FMT(COMMON, "Setting Driver directory to {} and library path to {}", path, lib_path);
ASSERT_MSG(COMMON, s_android_driver_directory.empty(), "Driver directory already set to {}",
s_android_driver_directory);
ASSERT_MSG(COMMON, s_android_lib_directory.empty(), "Library directory already set to {}",
s_android_lib_directory);
s_android_driver_directory = path;
s_android_lib_directory = lib_path;
}
const std::string GetGpuDriverDirectory(unsigned int dir_index)
{
switch (dir_index)
{
case D_GPU_DRIVERS_EXTRACTED:
return s_android_driver_directory + DIR_SEP GPU_DRIVERS_EXTRACTED DIR_SEP;
case D_GPU_DRIVERS_TMP:
return s_android_driver_directory + DIR_SEP GPU_DRIVERS_TMP DIR_SEP;
case D_GPU_DRIVERS_HOOKS:
return s_android_lib_directory;
case D_GPU_DRIVERS_FILE_REDIRECT:
return s_android_driver_directory + DIR_SEP GPU_DRIVERS_FILE_REDIRECT DIR_SEP;
}
return "";
}
#endif
static std::string s_user_paths[NUM_PATH_INDICES];

View File

@ -67,6 +67,10 @@ enum
D_GBAUSER_IDX,
D_GBASAVES_IDX,
D_WIISDCARDSYNCFOLDER_IDX,
D_GPU_DRIVERS_EXTRACTED,
D_GPU_DRIVERS_TMP,
D_GPU_DRIVERS_HOOKS,
D_GPU_DRIVERS_FILE_REDIRECT,
FIRST_FILE_USER_PATH_IDX,
F_DOLPHINCONFIG_IDX = FIRST_FILE_USER_PATH_IDX,
F_GCPADCONFIG_IDX,
@ -228,6 +232,8 @@ const std::string& GetSysDirectory();
#ifdef ANDROID
void SetSysDirectory(const std::string& path);
void SetGpuDriverDirectories(const std::string& path, const std::string& lib_path);
const std::string GetGpuDriverDirectory(unsigned int dir_index);
#endif
#ifdef __APPLE__

View File

@ -111,6 +111,8 @@ const Info<bool> GFX_PREFER_GLES{{System::GFX, "Settings", "PreferGLES"}, false}
const Info<bool> GFX_MODS_ENABLE{{System::GFX, "Settings", "EnableMods"}, false};
const Info<std::string> GFX_DRIVER_LIB_NAME{{System::GFX, "Settings", "DriverLibName"}, ""};
// Graphics.Enhancements
const Info<TextureFilteringMode> GFX_ENHANCE_FORCE_TEXTURE_FILTERING{
@ -171,4 +173,5 @@ const Info<bool> GFX_HACK_NO_MIPMAPPING{{System::GFX, "Hacks", "NoMipmapping"},
// Graphics.GameSpecific
const Info<bool> GFX_PERF_QUERIES_ENABLE{{System::GFX, "GameSpecific", "PerfQueriesEnable"}, false};
} // namespace Config

View File

@ -148,4 +148,8 @@ extern const Info<bool> GFX_HACK_NO_MIPMAPPING;
extern const Info<bool> GFX_PERF_QUERIES_ENABLE;
// Android custom GPU drivers
extern const Info<std::string> GFX_DRIVER_LIB_NAME;
} // namespace Config

View File

@ -48,11 +48,19 @@ PRIVATE
xxhash
)
if (ANDROID AND _M_ARM_64)
target_link_libraries(videovulkan
PRIVATE
adrenotools
)
endif()
# Only include the Vulkan headers when building the Vulkan backend
target_include_directories(videovulkan
PRIVATE
${CMAKE_SOURCE_DIR}/Externals/Vulkan/Include
${CMAKE_SOURCE_DIR}/Externals/VulkanMemoryAllocator/include
${CMAKE_SOURCE_DIR}/Externals/libadrenotools/include
)
if(MSVC)

View File

@ -143,7 +143,18 @@ VkInstance VulkanContext::CreateVulkanInstance(WindowSystemType wstype, bool ena
{
// The device itself may not support 1.1, so we check that before using any 1.1 functionality.
app_info.apiVersion = VK_MAKE_VERSION(1, 1, 0);
WARN_LOG_FMT(HOST_GPU, "Using Vulkan 1.1, supported: {}.{}",
VK_VERSION_MAJOR(supported_api_version),
VK_VERSION_MINOR(supported_api_version));
}
else
{
WARN_LOG_FMT(HOST_GPU, "Using Vulkan 1.0");
}
}
else
{
WARN_LOG_FMT(HOST_GPU, "Using Vulkan 1.0");
}
*out_vk_api_version = app_info.apiVersion;

View File

@ -8,11 +8,18 @@
#include <cstdarg>
#include <cstdlib>
#if defined(ANDROID)
#include <adrenotools/driver.h>
#include <dlfcn.h>
#endif
#include "Common/CommonFuncs.h"
#include "Common/DynamicLibrary.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "VideoCommon/VideoConfig.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;
@ -36,9 +43,9 @@ static void ResetVulkanLibraryFunctionPointers()
static Common::DynamicLibrary s_vulkan_module;
static bool OpenVulkanLibrary()
static bool OpenVulkanLibrary(bool force_system_library)
{
#ifdef __APPLE__
#if defined(__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))
@ -48,6 +55,35 @@ static bool OpenVulkanLibrary()
std::string filename = File::GetBundleDirectory() + "/Contents/Frameworks/libMoltenVK.dylib";
return s_vulkan_module.Open(filename.c_str());
#else
#if defined(ANDROID) && _M_ARM_64
const std::string& driver_lib_name = g_Config.customDriverLibraryName;
if (!force_system_library && !driver_lib_name.empty() && SupportsCustomDriver())
{
std::string tmp_dir = File::GetGpuDriverDirectory(D_GPU_DRIVERS_TMP);
std::string hook_dir = File::GetGpuDriverDirectory(D_GPU_DRIVERS_HOOKS);
std::string file_redirect_dir = File::GetGpuDriverDirectory(D_GPU_DRIVERS_FILE_REDIRECT);
std::string driver_dir = File::GetGpuDriverDirectory(D_GPU_DRIVERS_EXTRACTED);
INFO_LOG_FMT(HOST_GPU, "Loading driver: {}", driver_lib_name);
s_vulkan_module = adrenotools_open_libvulkan(
RTLD_NOW, ADRENOTOOLS_DRIVER_FILE_REDIRECT | ADRENOTOOLS_DRIVER_CUSTOM, tmp_dir.c_str(),
hook_dir.c_str(), driver_dir.c_str(), driver_lib_name.c_str(), file_redirect_dir.c_str(),
nullptr);
if (s_vulkan_module.IsOpen())
{
INFO_LOG_FMT(HOST_GPU, "Successfully loaded driver: {}", driver_lib_name);
return true;
}
else
{
WARN_LOG_FMT(HOST_GPU, "Loading driver {} failed.", driver_lib_name);
}
}
#endif
WARN_LOG_FMT(HOST_GPU, "Loading system driver");
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
if (s_vulkan_module.Open(filename.c_str()))
return true;
@ -58,9 +94,9 @@ static bool OpenVulkanLibrary()
#endif
}
bool LoadVulkanLibrary()
bool LoadVulkanLibrary(bool force_system_library)
{
if (!s_vulkan_module.IsOpen() && !OpenVulkanLibrary())
if (!s_vulkan_module.IsOpen() && !OpenVulkanLibrary(force_system_library))
return false;
#define VULKAN_MODULE_ENTRY_POINT(name, required) \
@ -91,7 +127,7 @@ bool LoadVulkanInstanceFunctions(VkInstance instance)
*func_ptr = vkGetInstanceProcAddr(instance, name);
if (!(*func_ptr) && is_required)
{
ERROR_LOG_FMT(VIDEO, "Vulkan: Failed to load required instance function {}", name);
ERROR_LOG_FMT(HOST_GPU, "Vulkan: Failed to load required instance function {}", name);
required_functions_missing = true;
}
};
@ -111,7 +147,7 @@ bool LoadVulkanDeviceFunctions(VkDevice device)
*func_ptr = vkGetDeviceProcAddr(device, name);
if (!(*func_ptr) && is_required)
{
ERROR_LOG_FMT(VIDEO, "Vulkan: Failed to load required device function {}", name);
ERROR_LOG_FMT(HOST_GPU, "Vulkan: Failed to load required device function {}", name);
required_functions_missing = true;
}
};
@ -212,4 +248,18 @@ void LogVulkanResult(Common::Log::LogLevel level, const char* func_name, VkResul
static_cast<int>(res), VkResultToString(res));
}
#ifdef ANDROID
static bool CheckKgslPresent()
{
constexpr auto KgslPath{"/dev/kgsl-3d0"};
return access(KgslPath, F_OK) == 0;
}
bool SupportsCustomDriver()
{
return android_get_device_api_level() >= 28 && CheckKgslPresent();
}
#endif
} // namespace Vulkan

View File

@ -23,6 +23,10 @@
#include "vulkan/vulkan.h"
#ifdef ANDROID
#include <unistd.h>
#endif
// Currently, exclusive fullscreen is only supported on Windows.
#if defined(WIN32)
#define SUPPORTS_VULKAN_EXCLUSIVE_FULLSCREEN 1
@ -78,11 +82,15 @@
namespace Vulkan
{
bool LoadVulkanLibrary();
bool LoadVulkanLibrary(bool force_system_library = false);
bool LoadVulkanInstanceFunctions(VkInstance instance);
bool LoadVulkanDeviceFunctions(VkDevice device);
void UnloadVulkanLibrary();
#ifdef ANDROID
bool SupportsCustomDriver();
#endif
const char* VkResultToString(VkResult res);
void LogVulkanResult(Common::Log::LogLevel level, const char* func_name, VkResult res,
const char* msg);

View File

@ -172,6 +172,8 @@ void VideoConfig::Refresh()
bPerfQueriesEnable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE);
bGraphicMods = Config::Get(Config::GFX_MODS_ENABLE);
customDriverLibraryName = Config::Get(Config::GFX_DRIVER_LIB_NAME);
}
void VideoConfig::VerifyValidity()

View File

@ -214,6 +214,9 @@ struct VideoConfig final
int iShaderCompilerThreads = 0;
int iShaderPrecompilerThreads = 0;
// Loading custom drivers on Android
std::string customDriverLibraryName;
// Static config per API
// TODO: Move this out of VideoConfig
struct