mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 21:30:19 -06:00
VideoBackends:Vulkan: Allow loading custom drivers on Android
... using libadrenotools
This commit is contained in:
@ -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'
|
||||
}
|
||||
|
||||
|
@ -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"/>
|
||||
@ -82,6 +83,13 @@
|
||||
android:theme="@style/Theme.Dolphin.Main"
|
||||
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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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/)
|
||||
|
147
Source/Android/jni/GpuDriver.cpp
Normal file
147
Source/Android/jni/GpuDriver.cpp
Normal file
@ -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
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user