mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Implement custom driver loading for ARM64 Android devices
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__)
|
||||
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -96,6 +96,7 @@ android {
|
||||
jniLibs {
|
||||
excludes += ['lib/arm64-v8a/libopenxr_loader.so']
|
||||
}
|
||||
jniLibs.useLegacyPackaging = true
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
+1
Submodule ext/libadrenotools added at deec5f75ee
Reference in New Issue
Block a user