diff options
| author | Robin Kertels <robin.kertels@gmail.com> | 2023-06-01 00:05:06 +0200 |
|---|---|---|
| committer | Robin Kertels <robin.kertels@gmail.com> | 2023-06-11 13:52:34 +0200 |
| commit | 23bebc5270bfd5a149aeb8bb5a3a2dd4433bd5e1 (patch) | |
| tree | 45e378d45f19381a1a92a5e71ee38780f78cc687 /Source/Android | |
| parent | 35bb663c2abfba0208931b85d779ed5a0084c7e8 (diff) | |
VideoBackends:Vulkan: Allow loading custom drivers on Android
... using libadrenotools
Diffstat (limited to 'Source/Android')
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) { |
