Implement custom driver loading for ARM64 Android devices

This commit is contained in:
Dzmitry Dubrova
2023-12-12 19:26:22 +03:00
parent a8b8e44de1
commit a461800973
18 changed files with 177 additions and 12 deletions
+3
View File
@@ -53,3 +53,6 @@
[submodule "ext/libchdr"]
path = ext/libchdr
url = https://github.com/rtissera/libchdr.git
[submodule "ext/libadrenotools"]
path = ext/libadrenotools
url = https://github.com/bylaws/libadrenotools.git
+6
View File
@@ -874,6 +874,12 @@ setup_target_project(Common Common)
target_link_libraries(Common Ext::Snappy cpu_features)
if(ARM64)
if(ANDROID)
target_link_libraries(Common adrenotools)
endif()
endif()
if(USING_GLES2 OR (USING_EGL AND NOT USING_FBDEV))
find_package(X11)
endif()
+1
View File
@@ -313,5 +313,6 @@ const char *Android_ErrorToString(StorageError error) {
// Very hacky.
std::string g_extFilesDir = "(IF YOU SEE THIS THERE'S A BUG)";
std::string g_externalDir = "(IF YOU SEE THIS THERE'S A BUG (2))";
std::string g_nativeLibDir = "(IF YOU SEE THIS THERE'S A BUG (3))";
#endif
+1
View File
@@ -33,6 +33,7 @@ inline StorageError StorageErrorFromInt(int ival) {
extern std::string g_extFilesDir;
extern std::string g_externalDir;
extern std::string g_nativeLibDir;
#if PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__)
+2 -1
View File
@@ -5,6 +5,7 @@
#include <cstring>
#include <iostream>
#include "Core/Config.h"
#include "Common/System/System.h"
#include "Common/System/Display.h"
#include "Common/Log.h"
@@ -132,7 +133,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
#endif
#endif
if (flags_ & VULKAN_FLAG_VALIDATE) {
if ((flags_ & VULKAN_FLAG_VALIDATE) && g_Config.customDriver.empty()) {
if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
// Enable the validation layers
for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) {
+43 -7
View File
@@ -20,15 +20,24 @@
#include <string>
#include <cstring>
#include "Core/Config.h"
#include "Common/Data/Format/JSONReader.h"
#include "Common/GPU/Vulkan/VulkanLoader.h"
#include "Common/Log.h"
#include "Common/System/System.h"
#include "Common/VR/PPSSPPVR.h"
#include "Common/File/FileUtil.h"
#if !PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(SWITCH)
#include <dlfcn.h>
#endif
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
#include "File/AndroidStorage.h"
#include <adrenotools/driver.h>
#endif
namespace PPSSPP_VK {
PFN_vkCreateInstance vkCreateInstance;
PFN_vkDestroyInstance vkDestroyInstance;
@@ -289,13 +298,40 @@ static VulkanLibraryHandle VulkanLoadLibrary(const char *logname) {
return LoadLibrary(L"vulkan-1.dll");
#else
void *lib = nullptr;
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
if (lib) {
INFO_LOG(G3D, "%s: Library loaded ('%s')", logname, so_names[i]);
break;
}
}
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
if (!g_Config.customDriver.empty() && g_Config.customDriver != "Default") {
const Path driverPath = g_Config.internalDataDirectory / "drivers" / g_Config.customDriver;
json::JsonReader meta = json::JsonReader((driverPath / "meta.json").c_str());
if (meta.ok()) {
std::string driverLibName = meta.root().get("libraryName")->value.toString();
Path tempDir = g_Config.internalDataDirectory / "temp";
Path fileRedirectDir = g_Config.internalDataDirectory / "vk_file_redirect";
File::CreateDir(tempDir);
File::CreateDir(fileRedirectDir);
lib = adrenotools_open_libvulkan(
RTLD_NOW | RTLD_LOCAL, ADRENOTOOLS_DRIVER_FILE_REDIRECT | ADRENOTOOLS_DRIVER_CUSTOM,
(std::string(tempDir.c_str()) + "/").c_str(),g_nativeLibDir.c_str(),
(std::string(driverPath.c_str()) + "/").c_str(),driverLibName.c_str(),
(std::string(fileRedirectDir.c_str()) + "/").c_str(),nullptr);
}
}
#endif
if (!lib) {
ERROR_LOG(G3D, "Failed to load custom driver");
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
if (lib) {
INFO_LOG(G3D, "%s: Library loaded ('%s')", logname, so_names[i]);
break;
}
}
}
return lib;
#endif
}
+3
View File
@@ -588,6 +588,9 @@ static const ConfigSetting graphicsSettings[] = {
ConfigSetting("CardboardYShift", &g_Config.iCardboardYShift, 0, CfgFlag::PER_GAME),
ConfigSetting("iShowStatusFlags", &g_Config.iShowStatusFlags, 0, CfgFlag::PER_GAME),
ConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend, &GPUBackendTranslator::To, &GPUBackendTranslator::From, CfgFlag::DEFAULT | CfgFlag::REPORT),
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
ConfigSetting("CustomDriver", &g_Config.customDriver, "", CfgFlag::DEFAULT),
#endif
ConfigSetting("FailedGraphicsBackends", &g_Config.sFailedGPUBackends, "", CfgFlag::DEFAULT),
ConfigSetting("DisabledGraphicsBackends", &g_Config.sDisabledGPUBackends, "", CfgFlag::DEFAULT),
ConfigSetting("VulkanDevice", &g_Config.sVulkanDevice, "", CfgFlag::DEFAULT),
+1
View File
@@ -146,6 +146,7 @@ public:
// GFX
int iGPUBackend;
std::string customDriver;
std::string sFailedGPUBackends;
std::string sDisabledGPUBackends;
// We have separate device parameters for each backend so it doesn't get erased if you switch backends.
+97
View File
@@ -57,6 +57,8 @@
#include "UI/RetroAchievementScreens.h"
#include "Common/File/FileUtil.h"
#include "Common/File/VFS/ZipFileReader.h"
#include "Common/Data/Format/JSONReader.h"
#include "Common/File/AndroidContentURI.h"
#include "Common/OSVersion.h"
#include "Common/TimeUtil.h"
@@ -91,9 +93,20 @@
#if PPSSPP_PLATFORM(ANDROID)
#include "android/jni/AndroidAudio.h"
#include "Common/File/AndroidStorage.h"
extern AndroidAudioState *g_audioState;
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
GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, bool editThenRestore)
@@ -269,6 +282,27 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
// If we're not the first instance, can't save the setting, and it requires a restart, so...
renderingBackendChoice->SetEnabled(false);
}
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
if (GetGPUBackend() == GPUBackend::VULKAN && SupportsCustomDriver()) {
const Path driverPath = g_Config.internalDataDirectory / "drivers";
std::vector<File::FileInfo> listing;
File::GetFilesInDir(driverPath, &listing);
std::vector<std::string> availableDrivers;
availableDrivers.push_back("Default");
for (auto driver : listing) {
availableDrivers.push_back(driver.name);
}
auto driverChoice = graphicsSettings->Add(new PopupMultiChoiceDynamic(&g_Config.customDriver, gr->T("Current GPU Driver"), availableDrivers, I18NCat::NONE, screenManager()));
driverChoice->OnChoice.Handle(this, &GameSettingsScreen::OnCustomDriverChange);
auto customDriverInstallChoice = graphicsSettings->Add(new Choice(gr->T("Install Custom Driver...")));
customDriverInstallChoice->OnClick.Handle(this, &GameSettingsScreen::OnCustomDriverInstall);
}
#endif
#endif
// Backends that don't allow a device choice will only expose one device.
@@ -1215,6 +1249,69 @@ void GameSettingsScreen::CreateVRSettings(UI::ViewGroup *vrSettings) {
vrSettings->Add(new PopupMultiChoice(&g_Config.iCameraPitch, vr->T("Camera type"), cameraPitchModes, 0, 3, I18NCat::NONE, screenManager()));
}
UI::EventReturn GameSettingsScreen::OnCustomDriverChange(UI::EventParams &e) {
auto di = GetI18NCategory(I18NCat::DIALOG);
screenManager()->push(new PromptScreen(gamePath_, di->T("Changing this setting requires PPSSPP to restart."), di->T("Restart"), di->T("Cancel"), [=](bool yes) {
if (yes) {
TriggerRestart("GameSettingsScreen::CustomDriverYes");
}
}));
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnCustomDriverInstall(UI::EventParams &e) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
System_BrowseForFile(gr->T("Install Custom Driver..."), BrowseFileType::ANY, [this](const std::string &value, int) {
const Path driverPath = g_Config.internalDataDirectory / "drivers";
if (!value.empty()) {
Path zipPath = Path(value);
if (zipPath.GetFileExtension() == ".zip") {
ZipFileReader *zipFileReader = ZipFileReader::Create(zipPath, "");
size_t metaDataSize;
uint8_t *metaData = zipFileReader->ReadFile("meta.json", &metaDataSize);
Path tempMeta = Path(g_Config.internalDataDirectory / "meta.json");
File::CreateEmptyFile(tempMeta);
File::WriteDataToFile(false, metaData, metaDataSize, tempMeta);
delete[] metaData;
json::JsonReader meta = json::JsonReader((g_Config.internalDataDirectory / "meta.json").c_str());
if (meta.ok()) {
std::string driverName = meta.root().get("name")->value.toString();
Path newCustomDriver = driverPath / driverName;
File::CreateFullPath(newCustomDriver);
std::vector<File::FileInfo> zipListing;
zipFileReader->GetFileListing("", &zipListing, nullptr);
for (auto file : zipListing) {
File::CreateEmptyFile(newCustomDriver / file.name);
size_t size;
uint8_t *data = zipFileReader->ReadFile(file.name.c_str(), &size);
File::WriteDataToFile(false, data, size, newCustomDriver / file.name);
delete[] data;
}
File::Delete(tempMeta);
RecreateViews();
}
}
}
});
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) {
g_Config.UpdateAfterSettingAutoFrameSkip();
return UI::EVENT_DONE;
+2
View File
@@ -98,6 +98,8 @@ private:
UI::EventReturn OnRenderingBackend(UI::EventParams &e);
UI::EventReturn OnRenderingDevice(UI::EventParams &e);
UI::EventReturn OnInflightFramesChoice(UI::EventParams &e);
UI::EventReturn OnCustomDriverChange(UI::EventParams &e);
UI::EventReturn OnCustomDriverInstall(UI::EventParams &e);
UI::EventReturn OnCameraDeviceChange(UI::EventParams& e);
UI::EventReturn OnMicDeviceChange(UI::EventParams& e);
UI::EventReturn OnAudioDevice(UI::EventParams &e);
+2 -1
View File
@@ -47,7 +47,8 @@
android:isGame="true"
android:banner="@drawable/tv_banner"
android:requestLegacyExternalStorage="true"
android:preserveLegacyExternalStorage="true">
android:preserveLegacyExternalStorage="true"
android:extractNativeLibs="true">
<meta-data android:name="android.max_aspect" android:value="2.4" />
<activity
android:name=".PpssppActivity"
+1
View File
@@ -96,6 +96,7 @@ android {
jniLibs {
excludes += ['lib/arm64-v8a/libopenxr_loader.so']
}
jniLibs.useLegacyPackaging = true
}
sourceSets {
main {
+1
View File
@@ -22,6 +22,7 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../../ext/armips/ext/tinyformat \
$(LOCAL_PATH)/../../ext/libchdr/deps/lzma-22.01/include \
$(LOCAL_PATH)/../../ext/libchdr/include \
$(LOCAL_PATH)/../../ext/libadrenotools/include \
$(LOCAL_PATH)
LOCAL_STATIC_LIBRARIES := libzip glslang-build miniupnp-build
+4 -1
View File
@@ -137,6 +137,7 @@ static std::string boardName;
std::string g_externalDir; // Original external dir (root of Android storage).
std::string g_extFilesDir; // App private external dir.
std::string g_nativeLibDir; // App native library dir
static std::vector<std::string> g_additionalStorageDirs;
@@ -705,7 +706,7 @@ static void parse_args(std::vector<std::string> &args, const std::string value)
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
(JNIEnv * env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
jstring jdataDir, jstring jexternalStorageDir, jstring jexternalFilesDir, jstring jadditionalStorageDirs, jstring jcacheDir, jstring jshortcutParam,
jstring jdataDir, jstring jexternalStorageDir, jstring jexternalFilesDir, jstring jNativeLibDir, jstring jadditionalStorageDirs, jstring jcacheDir, jstring jshortcutParam,
jint jAndroidVersion, jstring jboard) {
SetCurrentThreadName("androidInit");
@@ -732,9 +733,11 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
std::string externalStorageDir = GetJavaString(env, jexternalStorageDir);
std::string additionalStorageDirsString = GetJavaString(env, jadditionalStorageDirs);
std::string externalFilesDir = GetJavaString(env, jexternalFilesDir);
std::string nativeLibDir = GetJavaString(env, jNativeLibDir);
g_externalDir = externalStorageDir;
g_extFilesDir = externalFilesDir;
g_nativeLibDir = nativeLibDir;
if (!additionalStorageDirsString.empty()) {
SplitString(additionalStorageDirsString, ':', g_additionalStorageDirs);
@@ -401,6 +401,7 @@ public abstract class NativeActivity extends Activity {
String extStorageDir = Environment.getExternalStorageDirectory().getAbsolutePath();
File externalFiles = this.getExternalFilesDir(null);
String externalFilesDir = externalFiles == null ? "" : externalFiles.getAbsolutePath();
String nativeLibDir = getApplicationLibraryDir(appInfo);
Log.i(TAG, "Ext storage: " + extStorageState + " " + extStorageDir);
Log.i(TAG, "Ext files dir: " + externalFilesDir);
@@ -443,7 +444,7 @@ public abstract class NativeActivity extends Activity {
overrideShortcutParam = null;
NativeApp.audioConfig(optimalFramesPerBuffer, optimalSampleRate);
NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, extStorageDir, externalFilesDir, additionalStorageDirs, cacheDir, shortcut, Build.VERSION.SDK_INT, Build.BOARD);
NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, extStorageDir, externalFilesDir, nativeLibDir, additionalStorageDirs, cacheDir, shortcut, Build.VERSION.SDK_INT, Build.BOARD);
// Allow C++ to tell us to use JavaGL or not.
javaGL = "true".equalsIgnoreCase(NativeApp.queryConfig("androidJavaGL"));
+1 -1
View File
@@ -13,7 +13,7 @@ public class NativeApp {
public static final int DEVICE_TYPE_DESKTOP = 2;
public static final int DEVICE_TYPE_VR = 3;
public static native void init(String model, int deviceType, String languageRegion, String apkPath, String dataDir, String externalStorageDir, String extFilesDir, String additionalStorageDirs, String cacheDir, String shortcutParam, int androidVersion, String board);
public static native void init(String model, int deviceType, String languageRegion, String apkPath, String dataDir, String externalStorageDir, String extFilesDir, String nativeLibDir, String additionalStorageDirs, String cacheDir, String shortcutParam, int androidVersion, String board);
public static native void audioInit();
public static native void audioShutdown();
public static native void audioConfig(int optimalFramesPerBuffer, int optimalSampleRate);
+6
View File
@@ -39,3 +39,9 @@ if(USE_DISCORD AND NOT IOS AND NOT LIBRETRO)
endif()
add_subdirectory(libchdr-build)
if(ANDROID)
if (ARM64)
add_subdirectory(libadrenotools)
endif()
endif()
Submodule ext/libadrenotools added at deec5f75ee