summaryrefslogtreecommitdiff
path: root/Source/Android
diff options
context:
space:
mode:
authorRobin Kertels <robin.kertels@gmail.com>2023-06-01 00:05:06 +0200
committerRobin Kertels <robin.kertels@gmail.com>2023-06-11 13:52:34 +0200
commit23bebc5270bfd5a149aeb8bb5a3a2dd4433bd5e1 (patch)
tree45e378d45f19381a1a92a5e71ee38780f78cc687 /Source/Android
parent35bb663c2abfba0208931b85d779ed5a0084c7e8 (diff)
VideoBackends:Vulkan: Allow loading custom drivers on Android
... using libadrenotools
Diffstat (limited to 'Source/Android')
-rw-r--r--Source/Android/app/build.gradle7
-rw-r--r--Source/Android/app/src/main/AndroidManifest.xml10
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt6
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java60
-rw-r--r--Source/Android/app/src/main/res/values/strings.xml12
-rw-r--r--Source/Android/jni/CMakeLists.txt7
-rw-r--r--Source/Android/jni/GpuDriver.cpp147
-rw-r--r--Source/Android/jni/MainAndroid.cpp9
8 files changed, 236 insertions, 22 deletions
diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle
index 36ed3baf02..3ad867b2a6 100644
--- a/Source/Android/app/build.gradle
+++ b/Source/Android/app/build.gradle
@@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
+ id 'org.jetbrains.kotlin.plugin.serialization' version "1.7.20"
}
task copyProfile (type: Copy) {
@@ -110,6 +111,7 @@ android {
externalNativeBuild {
cmake {
path "../../../CMakeLists.txt"
+ version "3.22.1+"
}
}
namespace 'org.dolphinemu.dolphinemu'
@@ -122,7 +124,7 @@ android {
abiFilters "arm64-v8a", "x86_64" //, "armeabi-v7a", "x86"
// Remove the line below if you want to build the C++ unit tests
- targets "main"
+ //targets "main", "hook_impl", "main_hook", "gsl_alloc_hook", "file_redirect_hook"
}
}
}
@@ -160,6 +162,9 @@ dependencies {
// For loading game covers from disk and GameTDB
implementation 'io.coil-kt:coil:2.2.2'
+ // For loading custom GPU drivers
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
+
implementation 'com.nononsenseapps:filepicker:4.2.1'
}
diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml
index f470bafee7..db35188e6e 100644
--- a/Source/Android/app/src/main/AndroidManifest.xml
+++ b/Source/Android/app/src/main/AndroidManifest.xml
@@ -41,7 +41,8 @@
android:supportsRtl="true"
android:isGame="true"
android:banner="@drawable/banner_tv"
- android:hasFragileUserData="true">
+ android:hasFragileUserData="true"
+ android:extractNativeLibs="true">
<meta-data
android:name="android.max_aspect"
android:value="2.1"/>
@@ -83,6 +84,13 @@
android:label="@string/settings"/>
<activity
+ android:name=".features.settings.ui.GpuDriverActivity"
+ android:exported="false"
+ android:configChanges="orientation|screenSize"
+ android:theme="@style/Theme.Dolphin.Main"
+ android:label="@string/settings"/>
+
+ <activity
android:name=".features.cheats.ui.CheatsActivity"
android:exported="false"
android:theme="@style/Theme.Dolphin.Main"
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt
index bb479267c9..7833e83542 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt
@@ -62,6 +62,12 @@ enum class StringSetting(
Settings.SECTION_GFX_ENHANCEMENTS,
"PostProcessingShader",
""
+ ),
+ GFX_DRIVER_LIB_NAME(
+ Settings.FILE_GFX,
+ Settings.SECTION_GFX_SETTINGS,
+ "DriverLibName",
+ ""
);
override val isOverridden: Boolean
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java
index f2bb93d476..d5b34f21da 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java
@@ -18,18 +18,17 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.preference.PreferenceManager;
-import org.dolphinemu.dolphinemu.NativeLibrary;
-import org.dolphinemu.dolphinemu.R;
-import org.dolphinemu.dolphinemu.activities.EmulationActivity;
-import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
-import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
-
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import org.dolphinemu.dolphinemu.NativeLibrary;
+import org.dolphinemu.dolphinemu.R;
+import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
+import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
+
/**
* A class that spawns its own thread in order perform initialization.
*
@@ -46,6 +45,7 @@ public final class DirectoryInitialization
private static volatile boolean areDirectoriesAvailable = false;
private static String userPath;
private static String sysPath;
+ private static String driverPath;
private static boolean isUsingLegacyUserDirectory = false;
public enum DirectoryInitializationState
@@ -88,8 +88,7 @@ public final class DirectoryInitialization
directoryState.postValue(DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED);
}
- @Nullable
- private static File getLegacyUserDirectoryPath()
+ @Nullable private static File getLegacyUserDirectoryPath()
{
File externalPath = Environment.getExternalStorageDirectory();
if (externalPath == null)
@@ -98,8 +97,7 @@ public final class DirectoryInitialization
return new File(externalPath, "dolphin-emu");
}
- @Nullable
- public static File getUserDirectoryPath(Context context)
+ @Nullable public static File getUserDirectoryPath(Context context)
{
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
return null;
@@ -107,8 +105,8 @@ public final class DirectoryInitialization
isUsingLegacyUserDirectory =
preferLegacyUserDirectory(context) && PermissionsHandler.hasWriteAccess(context);
- return isUsingLegacyUserDirectory ?
- getLegacyUserDirectoryPath() : context.getExternalFilesDir(null);
+ return isUsingLegacyUserDirectory ? getLegacyUserDirectoryPath() :
+ context.getExternalFilesDir(null);
}
private static boolean setDolphinUserDirectory(Context context)
@@ -153,6 +151,19 @@ public final class DirectoryInitialization
// Let the native code know where the Sys directory is.
sysPath = sysDirectory.getPath();
SetSysDirectory(sysPath);
+
+ File driverDirectory = new File(context.getFilesDir(), "GPUDrivers");
+ driverDirectory.mkdirs();
+ File driverExtractedDir = new File(driverDirectory, "Extracted");
+ driverExtractedDir.mkdirs();
+ File driverTmpDir = new File(driverDirectory, "Tmp");
+ driverTmpDir.mkdirs();
+ File driverFileRedirectDir = new File(driverDirectory, "FileRedirect");
+ driverFileRedirectDir.mkdirs();
+
+ SetGpuDriverDirectories(driverDirectory.getPath(),
+ context.getApplicationInfo().nativeLibraryDir);
+ DirectoryInitialization.driverPath = driverExtractedDir.getAbsolutePath();
}
private static void deleteDirectoryRecursively(@NonNull final File file)
@@ -213,6 +224,16 @@ public final class DirectoryInitialization
return sysPath;
}
+ public static String getExtractedDriverDirectory()
+ {
+ if (!areDirectoriesAvailable)
+ {
+ throw new IllegalStateException(
+ "DirectoryInitialization must run before accessing the driver directory!");
+ }
+ return driverPath;
+ }
+
public static File getGameListCache(Context context)
{
return new File(context.getExternalCacheDir(), "gamelist.cache");
@@ -235,16 +256,14 @@ public final class DirectoryInitialization
}
catch (IOException e)
{
- Log.error("[DirectoryInitialization] Failed to copy asset file: " + asset +
- e.getMessage());
+ Log.error("[DirectoryInitialization] Failed to copy asset file: " + asset + e.getMessage());
}
return false;
}
private static void copyAssetFolder(String assetFolder, File outputFolder, Context context)
{
- Log.verbose("[DirectoryInitialization] Copying Folder " + assetFolder + " to " +
- outputFolder);
+ Log.verbose("[DirectoryInitialization] Copying Folder " + assetFolder + " to " + outputFolder);
try
{
@@ -267,8 +286,7 @@ public final class DirectoryInitialization
}
createdFolder = true;
}
- copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file),
- context);
+ copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file), context);
copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), context);
}
}
@@ -340,8 +358,8 @@ public final class DirectoryInitialization
private static boolean preferLegacyUserDirectory(Context context)
{
return PermissionsHandler.isExternalStorageLegacy() &&
- !PermissionsHandler.isWritePermissionDenied() &&
- isExternalFilesDirEmpty(context) && legacyUserDirectoryExists();
+ !PermissionsHandler.isWritePermissionDenied() && isExternalFilesDirEmpty(context) &&
+ legacyUserDirectoryExists();
}
public static boolean isUsingLegacyUserDirectory()
@@ -389,4 +407,6 @@ public final class DirectoryInitialization
}
private static native void SetSysDirectory(String path);
+
+ private static native void SetGpuDriverDirectories(String path, String libPath);
}
diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml
index 8a2b8dd1b2..5fcd3e9b40 100644
--- a/Source/Android/app/src/main/res/values/strings.xml
+++ b/Source/Android/app/src/main/res/values/strings.xml
@@ -841,6 +841,18 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="about_github"><a href="https://github.com/dolphin-emu/dolphin">GitHub</a></string>
<string name="about_support"><a href="https://forums.dolphin-emu.org/">Support</a></string>
<string name="about_copyright_warning">\u00A9 2003–2015+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.</string>
+ <string name="system_driver">System driver</string>
+ <string name="system_driver_desc">The GPU driver that is part of the OS.</string>
+
+ <!-- Custom GPU drivers -->
+ <string name="gpu_driver_submenu">GPU driver</string>
+ <string name="gpu_driver_install_inprogress">Installing the GPU driver…</string>
+ <string name="gpu_driver_install_success">GPU driver installed successfully</string>
+ <string name="gpu_driver_install_invalid_archive">Failed to unzip the provided driver package</string>
+ <string name="gpu_driver_install_missing_metadata">The supplied driver package is invalid due to missing metadata</string>
+ <string name="gpu_driver_install_invalid_metadata">The supplied driver package contains invalid metadata, it may be corrupted</string>
+ <string name="gpu_driver_install_unsupported_android_version">Your device doesn\'t meet the minimum Android version requirements for the supplied driver</string>
+ <string name="gpu_driver_install_already_installed">The supplied driver package is already installled</string>
<!-- Emulated USB Devices -->
<string name="emulated_usb_devices">Emulated USB Devices</string>
diff --git a/Source/Android/jni/CMakeLists.txt b/Source/Android/jni/CMakeLists.txt
index bc48ec26db..7218c64924 100644
--- a/Source/Android/jni/CMakeLists.txt
+++ b/Source/Android/jni/CMakeLists.txt
@@ -30,6 +30,7 @@ add_library(main SHARED
RiivolutionPatches.cpp
SkylanderConfig.cpp
WiiUtils.cpp
+ GpuDriver.cpp
)
target_link_libraries(main
@@ -50,6 +51,12 @@ PRIVATE
"-Wl,--no-whole-archive"
)
+target_include_directories(main
+PRIVATE
+ ${CMAKE_SOURCE_DIR}/Externals/libadrenotools/include
+ ${CMAKE_SOURCE_DIR}/Externals/VulkanMemoryAllocator/include
+)
+
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/)
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/)
file(COPY ${CMAKE_SOURCE_DIR}/Data/Sys DESTINATION ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/)
diff --git a/Source/Android/jni/GpuDriver.cpp b/Source/Android/jni/GpuDriver.cpp
new file mode 100644
index 0000000000..0631ce81cb
--- /dev/null
+++ b/Source/Android/jni/GpuDriver.cpp
@@ -0,0 +1,147 @@
+// Copyright 2023 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// Based on: Skyline Emulator Project
+// SPDX-License-Identifier: MPL-2.0
+// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
+
+#include <jni.h>
+
+#include "Common/IniFile.h"
+#include "jni/AndroidCommon/AndroidCommon.h"
+#include "jni/AndroidCommon/IDCache.h"
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <unistd.h>
+#include "adrenotools/driver.h"
+
+#include "VideoBackends/Vulkan/VulkanContext.h"
+#include "VideoBackends/Vulkan/VulkanLoader.h"
+
+extern "C" {
+
+#if defined(_M_ARM_64)
+
+JNIEXPORT jobjectArray JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_getSystemDriverInfo(JNIEnv* env,
+ jobject)
+{
+ if (!Vulkan::LoadVulkanLibrary(true))
+ {
+ return nullptr;
+ }
+
+ u32 vk_api_version = 0;
+ VkInstance instance = Vulkan::VulkanContext::CreateVulkanInstance(WindowSystemType::Headless,
+ false, false, &vk_api_version);
+ if (!instance)
+ {
+ return nullptr;
+ }
+
+ if (!Vulkan::LoadVulkanInstanceFunctions(instance))
+ {
+ vkDestroyInstance(instance, nullptr);
+ return nullptr;
+ }
+
+ Vulkan::VulkanContext::GPUList gpu_list = Vulkan::VulkanContext::EnumerateGPUs(instance);
+
+ if (gpu_list.empty())
+ {
+ vkDestroyInstance(instance, nullptr);
+ Vulkan::UnloadVulkanLibrary();
+ return nullptr;
+ }
+
+ VkPhysicalDeviceProperties properties;
+ vkGetPhysicalDeviceProperties(gpu_list.front(), &properties);
+
+ std::string driverId;
+ if (vkGetPhysicalDeviceProperties2 && vk_api_version >= VK_VERSION_1_1)
+ {
+ VkPhysicalDeviceDriverProperties driverProperties;
+ driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
+ driverProperties.pNext = nullptr;
+ VkPhysicalDeviceProperties2 properties2;
+ properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ properties2.pNext = &driverProperties;
+ vkGetPhysicalDeviceProperties2(gpu_list.front(), &properties2);
+ driverId = fmt::format("{}", driverProperties.driverID);
+ }
+ else
+ {
+ driverId = "Unknown";
+ }
+
+ std::string driverVersion =
+ fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(properties.driverVersion),
+ VK_API_VERSION_MINOR(properties.driverVersion),
+ VK_API_VERSION_PATCH(properties.driverVersion));
+
+ vkDestroyInstance(instance, nullptr);
+ Vulkan::UnloadVulkanLibrary();
+
+ auto array = env->NewObjectArray(2, env->FindClass("java/lang/String"), nullptr);
+ env->SetObjectArrayElement(array, 0, ToJString(env, driverId));
+ env->SetObjectArrayElement(array, 1, ToJString(env, driverVersion));
+ return array;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_supportsCustomDriverLoading(
+ JNIEnv* env, jobject instance)
+{
+ // If the KGSL device exists custom drivers can be loaded using adrenotools
+ return Vulkan::SupportsCustomDriver();
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_supportsForceMaxGpuClocks(
+ JNIEnv* env, jobject instance)
+{
+ // If the KGSL device exists adrenotools can be used to set GPU turbo mode
+ return Vulkan::SupportsCustomDriver();
+}
+
+JNIEXPORT void JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_forceMaxGpuClocks(
+ JNIEnv* env, jobject instance, jboolean enable)
+{
+ adrenotools_set_turbo(enable);
+}
+
+#else
+
+JNIEXPORT jobjectArray JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_getSystemDriverInfo(
+ JNIEnv* env, jobject instance)
+{
+ auto array = env->NewObjectArray(0, env->FindClass("java/lang/String"), nullptr);
+ return array;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_supportsCustomDriverLoading(
+ JNIEnv* env, jobject instance)
+{
+ return false;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_supportsForceMaxGpuClocks(
+ JNIEnv* env, jobject instance)
+{
+ return false;
+}
+
+JNIEXPORT void JNICALL
+Java_org_dolphinemu_dolphinemu_utils_GpuDriverHelper_00024Companion_forceMaxGpuClocks(
+ JNIEnv* env, jobject instance, jboolean enable)
+{
+}
+
+#endif
+}
diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp
index 30f0f5995e..d73c9f3d75 100644
--- a/Source/Android/jni/MainAndroid.cpp
+++ b/Source/Android/jni/MainAndroid.cpp
@@ -371,6 +371,15 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_utils_DirectoryInitializat
File::SetSysDirectory(path);
}
+JNIEXPORT void JNICALL
+Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_SetGpuDriverDirectories(
+ JNIEnv* env, jclass, jstring jPath, jstring jLibPath)
+{
+ const std::string path = GetJString(env, jPath);
+ const std::string lib_path = GetJString(env, jLibPath);
+ File::SetGpuDriverDirectories(path, lib_path);
+}
+
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(
JNIEnv* env, jclass, jstring jDirectory)
{