mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 01:24:41 -06:00
Vulkan: add support for custom drivers on android
This commit is contained in:
parent
4f64e1186f
commit
6705714211
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -25,3 +25,6 @@
|
||||
[submodule "dependencies/xbyak_aarch64"]
|
||||
path = dependencies/xbyak_aarch64
|
||||
url = https://github.com/fujitsu/xbyak_aarch64
|
||||
[submodule "dependencies/libadrenotools"]
|
||||
path = dependencies/libadrenotools
|
||||
url = https://github.com/bylaws/libadrenotools
|
||||
|
||||
@ -286,4 +286,10 @@ if (NOT ZArchive_FOUND)
|
||||
add_subdirectory("dependencies/ZArchive" EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
if(CEMU_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)")
|
||||
add_subdirectory("dependencies/libadrenotools" EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
1
dependencies/libadrenotools
vendored
Submodule
1
dependencies/libadrenotools
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 8fae8ce254dfc1344527e05301e43f37dea2df80
|
||||
@ -623,6 +623,9 @@ if(ANDROID)
|
||||
Filesystem/fscDeviceAndroidSAF.cpp
|
||||
Filesystem/fscDeviceAndroidSAF.h
|
||||
)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)")
|
||||
target_link_libraries(CemuCafe PRIVATE adrenotools)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CEMU_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)")
|
||||
|
||||
@ -275,6 +275,17 @@ bool GameProfile::Load(uint64_t title_id)
|
||||
}
|
||||
|
||||
}
|
||||
#if BOOST_PLAT_ANDROID
|
||||
else if (boost::iequals(iniParser.GetCurrentSectionName(), "AndroidDriver"))
|
||||
{
|
||||
gameProfile_loadEnumOption(iniParser, "mode", m_driverSetting.mode);
|
||||
|
||||
if (m_driverSetting.mode == DriverSettingMode::Custom)
|
||||
{
|
||||
m_driverSetting.customPath = iniParser.FindOption("customPath");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -329,6 +340,14 @@ void GameProfile::Save(uint64_t title_id)
|
||||
|
||||
fs->writeLine("");
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
fs->writeLine("[AndroidDriver]");
|
||||
fs->writeLine(fmt::format("{} = {}", "mode", m_driverSetting.mode).c_str());
|
||||
if (m_driverSetting.mode == DriverSettingMode::Custom && m_driverSetting.customPath.has_value())
|
||||
fs->writeLine(fmt::format("{} = {}", "customPath", m_driverSetting.customPath.value()).c_str());
|
||||
fs->writeLine("");
|
||||
#endif
|
||||
|
||||
#undef WRITE_OPTIONAL_ENTRY
|
||||
#undef WRITE_ENTRY
|
||||
#undef WRITE_ENTRY_NUMBERED
|
||||
|
||||
@ -43,6 +43,28 @@ public:
|
||||
|
||||
[[nodiscard]] const std::array< std::optional<std::string>, 8>& GetControllerProfile() const { return m_controllerProfile; }
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
struct DriverSetting
|
||||
{
|
||||
DriverSettingMode mode = DriverSettingMode::Global;
|
||||
std::optional<std::string> customPath;
|
||||
};
|
||||
|
||||
[[nodiscard]] DriverSetting GetDriverSetting() const
|
||||
{
|
||||
return m_driverSetting;
|
||||
}
|
||||
|
||||
void SetDriverSetting(DriverSetting driverSetting)
|
||||
{
|
||||
m_driverSetting = driverSetting;
|
||||
}
|
||||
|
||||
private:
|
||||
DriverSetting m_driverSetting;
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
uint64_t m_title_id = 0;
|
||||
bool m_is_loaded = false;
|
||||
|
||||
@ -144,10 +144,114 @@ bool InitializeDeviceVulkan(VkDevice device)
|
||||
|
||||
#else
|
||||
|
||||
void* g_vulkan_so = nullptr;
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
bool SupportsLoadingCustomDriver()
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
std::error_code ec;
|
||||
return fs::exists("/dev/kgsl-3d0", ec);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
|
||||
constexpr auto CUSTOM_DRIVER_LIB_NAME = "custom_vulkan.so";
|
||||
|
||||
#include <adrenotools/driver.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "Cafe/GameProfile/GameProfile.h"
|
||||
|
||||
std::string get_custom_driver_lib_name(const fs::path& driver_path)
|
||||
{
|
||||
static constexpr auto LIB_NAME_MEMBER = "libraryName";
|
||||
std::ifstream in(driver_path / "meta.json");
|
||||
if (!in.is_open())
|
||||
return {};
|
||||
rapidjson::IStreamWrapper str(in);
|
||||
rapidjson::Document doc;
|
||||
doc.ParseStream(str);
|
||||
|
||||
if (!doc.HasMember(LIB_NAME_MEMBER) || !doc[LIB_NAME_MEMBER].IsString())
|
||||
return {};
|
||||
|
||||
std::string lib_name = doc[LIB_NAME_MEMBER].GetString();
|
||||
|
||||
std::error_code ec;
|
||||
if (!fs::exists(driver_path / lib_name, ec))
|
||||
return {};
|
||||
|
||||
return lib_name;
|
||||
}
|
||||
|
||||
std::optional<std::string> get_custom_driver_path()
|
||||
{
|
||||
const auto& driverSetting = g_current_game_profile->GetDriverSetting();
|
||||
if (driverSetting.mode == DriverSettingMode::System)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
if (driverSetting.mode == DriverSettingMode::Custom &&
|
||||
driverSetting.customPath.has_value() &&
|
||||
fs::exists(driverSetting.customPath.value(), ec))
|
||||
{
|
||||
return driverSetting.customPath;
|
||||
}
|
||||
|
||||
return GetConfig().custom_driver_path;
|
||||
}
|
||||
|
||||
void* load_custom_driver()
|
||||
{
|
||||
std::optional<std::string> driver_path = get_custom_driver_path();
|
||||
|
||||
if (!driver_path.has_value() || driver_path->empty())
|
||||
return nullptr;
|
||||
std::string driver_name = get_custom_driver_lib_name(driver_path.value());
|
||||
if (driver_name.empty())
|
||||
return nullptr;
|
||||
|
||||
std::error_code ec;
|
||||
fs::copy(fs::path(driver_path.value()) / driver_name, ActiveSettings::GetInternalPath(CUSTOM_DRIVER_LIB_NAME), fs::copy_options::overwrite_existing, ec);
|
||||
|
||||
void* vulkan_so = adrenotools_open_libvulkan(
|
||||
RTLD_NOW | RTLD_LOCAL,
|
||||
ADRENOTOOLS_DRIVER_CUSTOM,
|
||||
nullptr,
|
||||
(ActiveSettings::GetNativeLibPath().string() + "/").c_str(),
|
||||
(ActiveSettings::GetInternalPath().string() + "/").c_str(),
|
||||
CUSTOM_DRIVER_LIB_NAME,
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (!vulkan_so)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to load custom driver");
|
||||
return nullptr;
|
||||
}
|
||||
cemuLog_log(LogType::Force, "Loaded custom driver");
|
||||
return vulkan_so;
|
||||
}
|
||||
#endif // __aarch64__
|
||||
|
||||
#endif // BOOST_PLAT_ANDROID
|
||||
|
||||
void* dlopen_vulkan_loader()
|
||||
{
|
||||
#if BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
void* vulkan_so = dlopen("libvulkan.so", RTLD_NOW);
|
||||
static void* vulkan_so = nullptr;
|
||||
#if BOOST_PLAT_ANDROID && defined(__aarch64__)
|
||||
vulkan_so = load_custom_driver();
|
||||
if (vulkan_so)
|
||||
return vulkan_so;
|
||||
#endif
|
||||
vulkan_so = dlopen("libvulkan.so", RTLD_NOW);
|
||||
if(!vulkan_so)
|
||||
vulkan_so = dlopen("libvulkan.so.1", RTLD_NOW);
|
||||
#elif BOOST_OS_MACOS
|
||||
@ -158,17 +262,19 @@ void* dlopen_vulkan_loader()
|
||||
|
||||
bool InitializeGlobalVulkan()
|
||||
{
|
||||
void* vulkan_so = dlopen_vulkan_loader();
|
||||
g_vulkan_so = dlopen_vulkan_loader();
|
||||
|
||||
if(g_vulkan_available)
|
||||
if (g_vulkan_available)
|
||||
return true;
|
||||
|
||||
if (!vulkan_so)
|
||||
if (!g_vulkan_so)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Vulkan loader not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void* vulkan_so = g_vulkan_so;
|
||||
|
||||
#define VKFUNC_INIT
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||
|
||||
@ -177,14 +283,30 @@ bool InitializeGlobalVulkan()
|
||||
cemuLog_log(LogType::Force, "vkEnumerateInstanceVersion not available. Outdated graphics driver or Vulkan runtime?");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
g_vulkan_available = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CleanupGlobalVulkan()
|
||||
{
|
||||
if (g_vulkan_so)
|
||||
{
|
||||
dlclose(g_vulkan_so);
|
||||
g_vulkan_so = nullptr;
|
||||
}
|
||||
|
||||
g_vulkan_available = false;
|
||||
|
||||
#if BOOST_PLAT_ANDROID && defined(__aarch64__)
|
||||
std::error_code ec;
|
||||
fs::remove(ActiveSettings::GetInternalPath(CUSTOM_DRIVER_LIB_NAME), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool InitializeInstanceVulkan(VkInstance instance)
|
||||
{
|
||||
void* vulkan_so = dlopen_vulkan_loader();
|
||||
void* vulkan_so = g_vulkan_so;
|
||||
if (!vulkan_so)
|
||||
return false;
|
||||
|
||||
@ -196,7 +318,7 @@ bool InitializeInstanceVulkan(VkInstance instance)
|
||||
|
||||
bool InitializeDeviceVulkan(VkDevice device)
|
||||
{
|
||||
void* vulkan_so = dlopen_vulkan_loader();
|
||||
void* vulkan_so = g_vulkan_so;
|
||||
if (!vulkan_so)
|
||||
return false;
|
||||
|
||||
|
||||
@ -10,6 +10,11 @@
|
||||
bool InitializeGlobalVulkan();
|
||||
bool InitializeInstanceVulkan(VkInstance instance);
|
||||
bool InitializeDeviceVulkan(VkDevice device);
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
bool SupportsLoadingCustomDriver();
|
||||
#endif
|
||||
|
||||
extern bool g_vulkan_available;
|
||||
|
||||
#endif
|
||||
|
||||
@ -2244,10 +2244,10 @@ void VulkanRenderer::SubmitCommandBuffer(VkSemaphore signalSemaphore, VkSemaphor
|
||||
const VkPipelineStageFlags semWaitStageMask[2] = { VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT };
|
||||
VkSemaphore waitSemArray[2];
|
||||
submitInfo.waitSemaphoreCount = 0;
|
||||
if (m_numSubmittedCmdBuffers > 0)
|
||||
waitSemArray[submitInfo.waitSemaphoreCount++] = prevSem; // wait on semaphore from previous submit
|
||||
if (waitSemaphore != VK_NULL_HANDLE)
|
||||
waitSemArray[submitInfo.waitSemaphoreCount++] = waitSemaphore;
|
||||
if (m_numSubmittedCmdBuffers > 0)
|
||||
waitSemArray[submitInfo.waitSemaphoreCount++] = prevSem; // wait on semaphore from previous submit
|
||||
submitInfo.pWaitDstStageMask = semWaitStageMask;
|
||||
submitInfo.pWaitSemaphores = waitSemArray;
|
||||
|
||||
|
||||
@ -301,3 +301,14 @@ fs::path ActiveSettings::GetDefaultMLCPath()
|
||||
return GetUserDataPath("mlc01");
|
||||
}
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
void ActiveSettings::SetNativeLibPath(const fs::path& nativeLibPath)
|
||||
{
|
||||
s_native_lib_path = nativeLibPath;
|
||||
}
|
||||
|
||||
void ActiveSettings::SetInternalDir(const fs::path& internalDirPath)
|
||||
{
|
||||
s_internal_dir_path = internalDirPath;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -56,6 +56,15 @@ public:
|
||||
|
||||
[[nodiscard]] static fs::path GetMlcPath();
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
template <typename ...TArgs>
|
||||
[[nodiscard]] static fs::path GetNativeLibPath(TArgs&&... args){ return GetPath(s_native_lib_path, std::forward<TArgs>(args)...); };
|
||||
|
||||
template <typename ...TArgs>
|
||||
[[nodiscard]] static fs::path GetInternalPath(TArgs&&... args){ return GetPath(s_internal_dir_path, std::forward<TArgs>(args)...); };
|
||||
#endif
|
||||
|
||||
|
||||
template <typename ...TArgs>
|
||||
[[nodiscard]] static fs::path GetMlcPath(TArgs&&... args){ return GetPath(GetMlcPath(), std::forward<TArgs>(args)...); };
|
||||
static bool IsCustomMlcPath();
|
||||
@ -73,8 +82,17 @@ private:
|
||||
inline static fs::path s_data_path;
|
||||
inline static fs::path s_executable_filename; // cemu.exe
|
||||
inline static fs::path s_mlc_path;
|
||||
#if BOOST_PLAT_ANDROID
|
||||
inline static fs::path s_native_lib_path;
|
||||
inline static fs::path s_internal_dir_path;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
static void SetNativeLibPath(const fs::path& nativeLibPath);
|
||||
static void SetInternalDir(const fs::path& internalDirPath);
|
||||
#endif
|
||||
// can be called before Init
|
||||
[[nodiscard]] static bool IsPortableMode();
|
||||
|
||||
|
||||
@ -290,6 +290,11 @@ XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
|
||||
emulated_usb_devices.emulate_infinity_base = usbdevices.get("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base);
|
||||
emulated_usb_devices.emulate_dimensions_toypad = usbdevices.get("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad);
|
||||
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
custom_driver_path = parser.get("custom_driver_path", "");
|
||||
#endif
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
@ -454,6 +459,10 @@ XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
|
||||
usbdevices.set("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base.GetValue());
|
||||
usbdevices.set("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad.GetValue());
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
config.set("custom_driver_path", custom_driver_path.GetValue());
|
||||
#endif
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@ -213,6 +213,16 @@ enum class CrashDump
|
||||
ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled);
|
||||
#endif
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
enum class DriverSettingMode
|
||||
{
|
||||
Global,
|
||||
System,
|
||||
Custom,
|
||||
};
|
||||
ENABLE_ENUM_ITERATORS(DriverSettingMode, DriverSettingMode::Global, DriverSettingMode::Custom);
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<PrecompiledShaderOption> : formatter<string_view> {
|
||||
template <typename FormatContext>
|
||||
@ -419,6 +429,10 @@ struct CemuConfig
|
||||
#undef DISABLE_SCREENSAVER_DEFAULT
|
||||
ConfigValue<bool> play_boot_sound{false};
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
ConfigValue<std::string> custom_driver_path{};
|
||||
#endif
|
||||
|
||||
std::vector<std::string> game_paths;
|
||||
std::mutex game_cache_entries_mutex;
|
||||
std::vector<GameEntry> game_cache_entries;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user