From 108fb2380a4f9a681a709b5142d85e51764a2b50 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Tue, 11 Jul 2023 17:24:48 +0000 Subject: [PATCH] test --- .gitmodules | 2 +- src/LibRyujinx/Android/JniExportedMethods.cs | 12 ++- src/LibRyujinx/LibRyujinx.Graphics.cs | 2 +- src/LibRyujinx/VulkanLoader.cs | 96 +++++++++++++++++++ src/RyujinxAndroid/app/build.gradle | 3 + .../app/src/main/cpp/CMakeLists.txt | 9 +- .../app/src/main/cpp/libraries/adrenotools | 1 + src/RyujinxAndroid/app/src/main/cpp/ryuijnx.h | 3 + .../app/src/main/cpp/ryujinx.cpp | 45 ++++++++- .../main/java/org/ryujinx/android/GameHost.kt | 18 +++- .../java/org/ryujinx/android/MainActivity.kt | 2 + .../java/org/ryujinx/android/NativeHelpers.kt | 2 + .../java/org/ryujinx/android/RyujinxNative.kt | 3 +- .../org/ryujinx/android/views/SettingViews.kt | 4 +- 14 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 src/LibRyujinx/VulkanLoader.cs create mode 160000 src/RyujinxAndroid/app/src/main/cpp/libraries/adrenotools diff --git a/.gitmodules b/.gitmodules index b45683853..3b9fa893b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "libadrenotools"] path = src/RyujinxAndroid/app/src/main/cpp/libraries/adrenotools - url = https://github.com/bylaws/libadrenotools/ \ No newline at end of file + url = https://github.com/bylaws/libadrenotools.git diff --git a/src/LibRyujinx/Android/JniExportedMethods.cs b/src/LibRyujinx/Android/JniExportedMethods.cs index 77f5518f9..f9b054ca6 100644 --- a/src/LibRyujinx/Android/JniExportedMethods.cs +++ b/src/LibRyujinx/Android/JniExportedMethods.cs @@ -31,6 +31,8 @@ namespace LibRyujinx private static ManualResetEvent _surfaceEvent; private static long _surfacePtr; + public static VulkanLoader? VulkanLoader { get; private set; } + [DllImport("libryujinxjni")] private extern static IntPtr getStringPointer(JEnvRef jEnv, JStringLocalRef s); @@ -213,7 +215,8 @@ namespace LibRyujinx public unsafe static JBoolean JniInitializeGraphicsRendererNative(JEnvRef jEnv, JObjectLocalRef jObj, JArrayLocalRef extensionsArray, - JLong surfacePtr) + JLong surfacePtr, + JLong driverHandle) { if (Renderer != null) { @@ -252,12 +255,17 @@ namespace LibRyujinx _surfacePtr = surfacePtr; + if((long)driverHandle != 0) + { + VulkanLoader = new VulkanLoader((IntPtr)(long)driverHandle); + } + CreateSurface createSurfaceFunc = instance => { _surfaceEvent.WaitOne(); _surfaceEvent.Reset(); - var api = Vk.GetApi(); + var api = VulkanLoader?.GetApi() ?? Vk.GetApi(); if (api.TryGetInstanceExtension(new Instance(instance), out KhrAndroidSurface surfaceExtension)) { var createInfo = new AndroidSurfaceCreateInfoKHR diff --git a/src/LibRyujinx/LibRyujinx.Graphics.cs b/src/LibRyujinx/LibRyujinx.Graphics.cs index 21fc7ad51..b18fab34c 100644 --- a/src/LibRyujinx/LibRyujinx.Graphics.cs +++ b/src/LibRyujinx/LibRyujinx.Graphics.cs @@ -91,7 +91,7 @@ namespace LibRyujinx } else if (graphicsBackend == GraphicsBackend.Vulkan) { - Renderer = new VulkanRenderer(Vk.GetApi(), (instance, vk) => new SurfaceKHR((ulong?)createSurfaceFunc(instance.Handle)), + Renderer = new VulkanRenderer(VulkanLoader?.GetApi() ?? Vk.GetApi(), (instance, vk) => new SurfaceKHR((ulong?)createSurfaceFunc(instance.Handle)), () => requiredExtensions, null); } diff --git a/src/LibRyujinx/VulkanLoader.cs b/src/LibRyujinx/VulkanLoader.cs new file mode 100644 index 000000000..e9a3d7c1b --- /dev/null +++ b/src/LibRyujinx/VulkanLoader.cs @@ -0,0 +1,96 @@ +using Ryujinx.Common.Logging; +using Silk.NET.Core.Contexts; +using Silk.NET.Vulkan; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace LibRyujinx +{ + public class VulkanLoader : IDisposable + { + private delegate IntPtr GetInstanceProcAddress(IntPtr instance, IntPtr name); + private delegate IntPtr GetDeviceProcAddress(IntPtr device, IntPtr name); + + private IntPtr _loadedLibrary = IntPtr.Zero; + private GetInstanceProcAddress _getInstanceProcAddr; + private GetDeviceProcAddress _getDeviceProcAddr; + + public void Dispose() + { + if (_loadedLibrary != IntPtr.Zero) + { + NativeLibrary.Free(_loadedLibrary); + _loadedLibrary = IntPtr.Zero; + } + } + + public VulkanLoader(IntPtr driver) + { + _loadedLibrary = driver; + + if(_loadedLibrary != IntPtr.Zero) + { + var instanceGetProc = NativeLibrary.GetExport(_loadedLibrary, "vkGetInstanceProcAddr"); + var deviceProc = NativeLibrary.GetExport(_loadedLibrary, "vkGetDeviceProcAddr"); + + _getInstanceProcAddr = Marshal.GetDelegateForFunctionPointer(instanceGetProc); + _getDeviceProcAddr = Marshal.GetDelegateForFunctionPointer(deviceProc); + } + } + + public Vk GetApi() + { + + if (_loadedLibrary == IntPtr.Zero) + { + return Vk.GetApi(); + } + var ctx = new MultiNativeContext(new INativeContext[1]); + var ret = new Vk(ctx); + ctx.Contexts[0] = new LamdaNativeContext + ( + x => + { + var xPtr = Marshal.StringToHGlobalAnsi(x); + try + { + nint ptr = default; + ptr = _getInstanceProcAddr(ret.CurrentInstance.GetValueOrDefault().Handle, xPtr); + + if (ptr == default) + { + ptr = _getInstanceProcAddr(IntPtr.Zero, xPtr); + + if (ptr == default) + { + var currentDevice = ret.CurrentDevice.GetValueOrDefault().Handle; + if (currentDevice != IntPtr.Zero) + { + ptr = _getDeviceProcAddr(currentDevice, xPtr); + } + + if (ptr == default) + { + Logger.Warning?.Print(LogClass.Gpu, $"Failed to get function pointer: {x}"); + } + + } + } + + return ptr; + } + finally + { + Marshal.FreeHGlobal(xPtr); + } + } + ); + return ret; + } + } +} diff --git a/src/RyujinxAndroid/app/build.gradle b/src/RyujinxAndroid/app/build.gradle index 002f49345..1fd744ef2 100644 --- a/src/RyujinxAndroid/app/build.gradle +++ b/src/RyujinxAndroid/app/build.gradle @@ -59,6 +59,9 @@ android { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' } + jniLibs { + keepDebugSymbols += '**/libryujinx.so' + } } externalNativeBuild { cmake { diff --git a/src/RyujinxAndroid/app/src/main/cpp/CMakeLists.txt b/src/RyujinxAndroid/app/src/main/cpp/CMakeLists.txt index 3060d2fb4..6ae2af030 100644 --- a/src/RyujinxAndroid/app/src/main/cpp/CMakeLists.txt +++ b/src/RyujinxAndroid/app/src/main/cpp/CMakeLists.txt @@ -10,6 +10,11 @@ cmake_minimum_required(VERSION 3.22.1) project("ryujinxjni") +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +add_subdirectory("libraries/adrenotools") + # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. @@ -52,4 +57,6 @@ target_link_libraries( # Specifies the target library. oboe::oboe ${log-lib} -lvulkan - -landroid) + -landroid + adrenotools + ) diff --git a/src/RyujinxAndroid/app/src/main/cpp/libraries/adrenotools b/src/RyujinxAndroid/app/src/main/cpp/libraries/adrenotools new file mode 160000 index 000000000..deec5f75e --- /dev/null +++ b/src/RyujinxAndroid/app/src/main/cpp/libraries/adrenotools @@ -0,0 +1 @@ +Subproject commit deec5f75ee1a8ccbe32c8780b1d17284fc87b0f1 diff --git a/src/RyujinxAndroid/app/src/main/cpp/ryuijnx.h b/src/RyujinxAndroid/app/src/main/cpp/ryuijnx.h index 8770e3e87..b9573694c 100644 --- a/src/RyujinxAndroid/app/src/main/cpp/ryuijnx.h +++ b/src/RyujinxAndroid/app/src/main/cpp/ryuijnx.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,8 @@ #include "vulkan_wrapper.h" #include #include +#include +#include "libraries/adrenotools/include/adrenotools/driver.h" // A macro to pass call to Vulkan and check for return value for success #define CALL_VK(func) \ diff --git a/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp b/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp index ad7e4b0b9..33ca59517 100644 --- a/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp +++ b/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp @@ -179,13 +179,52 @@ Java_org_ryujinx_android_MainActivity_initVm(JNIEnv *env, jobject thiz) { } extern "C" -void onFrameEnd(double time){ +void onFrameEnd(double time) { auto env = getEnv(true); auto cl = env->FindClass("org/ryujinx/android/MainActivity"); - _updateFrameTime = env->GetStaticMethodID( cl , "updateRenderSessionPerformance", "(J)V"); + _updateFrameTime = env->GetStaticMethodID(cl, "updateRenderSessionPerformance", "(J)V"); auto now = std::chrono::high_resolution_clock::now(); - auto nano = std::chrono::duration_cast(now-_currentTimePoint).count(); + auto nano = std::chrono::duration_cast( + now - _currentTimePoint).count(); env->CallStaticVoidMethod(cl, _updateFrameTime, nano); +} + +extern "C" +JNIEXPORT jlong JNICALL +Java_org_ryujinx_android_NativeHelpers_loadDriver(JNIEnv *env, jobject thiz, + jstring driver_path, + jstring native_lib_path, + jstring private_apps_path, + jstring public_apps_path, + jstring driver_name) { + auto driverPath = getStringPointer(env, driver_path); + auto libPath = getStringPointer(env, native_lib_path); + auto privateAppsPath = getStringPointer(env, private_apps_path); + auto driverName = getStringPointer(env, driver_name); + auto publicPath = getStringPointer(env, public_apps_path); + + std::string redirectPath = publicPath; + + redirectPath += "gpu/vk_file_redirect/"; + + auto handle = adrenotools_open_libvulkan( + RTLD_NOW, + ADRENOTOOLS_DRIVER_CUSTOM, + nullptr, + libPath, + privateAppsPath, + driverName, + nullptr,//redirectPath.c_str(), + nullptr + ); + + delete driverPath; + delete libPath; + delete privateAppsPath; + delete driverName; + delete publicPath; + + return (jlong)handle; } \ No newline at end of file diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt index 1ac670f0c..ba481aa89 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt @@ -7,6 +7,8 @@ import android.view.SurfaceView import org.ryujinx.android.viewmodels.GameModel import org.ryujinx.android.viewmodels.MainViewModel import org.ryujinx.android.viewmodels.QuickSettings +import org.ryujinx.android.viewmodels.VulkanDriverViewModel +import java.io.File import kotlin.concurrent.thread class GameHost(context: Context?, val controller: GameController, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback { @@ -85,9 +87,23 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo nativeInterop!!.VkCreateSurface = nativeHelpers.getCreateSurfacePtr() nativeInterop!!.SurfaceHandle = window + var driverViewModel = VulkanDriverViewModel(mainViewModel.activity); + driverViewModel.getAvailableDrivers() + + var driverHandle = 0L; + + if(driverViewModel.selected.isNotEmpty()) { + var privatePath = mainViewModel.activity.filesDir; + var privateDriverPath = privatePath.absolutePath + "/driver/" + var driver = File(driverViewModel.selected) + driver.copyTo(File(privateDriverPath + driver.name), true) + driverHandle = NativeHelpers().loadDriver(driverViewModel.selected, mainViewModel.activity.applicationInfo.nativeLibraryDir!!, privateDriverPath, mainViewModel.activity.getExternalFilesDir(null)!!.absolutePath, driver.name) + } + success = _nativeRyujinx.graphicsInitializeRenderer( nativeInterop!!.VkRequiredExtensions!!, - window + window, + driverHandle ) diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt index 0a8ce1c68..e0e7c790e 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt @@ -25,8 +25,10 @@ import androidx.core.view.WindowInsetsControllerCompat import com.anggrayudi.storage.SimpleStorageHelper import org.ryujinx.android.ui.theme.RyujinxAndroidTheme import org.ryujinx.android.viewmodels.MainViewModel +import org.ryujinx.android.viewmodels.VulkanDriverViewModel import org.ryujinx.android.views.HomeViews import org.ryujinx.android.views.MainView +import java.io.File class MainActivity : ComponentActivity() { diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/NativeHelpers.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/NativeHelpers.kt index 32ff5f1d3..0dd4e41fc 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/NativeHelpers.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/NativeHelpers.kt @@ -15,4 +15,6 @@ class NativeHelpers { external fun getNativeWindow(surface:Surface) : Long external fun attachCurrentThread() : Unit external fun detachCurrentThread() : Unit + + external fun loadDriver(driverPath:String, nativeLibPath:String, privateAppsPath:String, publicAppsPath:String, driverName:String) : Long } \ No newline at end of file diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt index 7400d309a..1d6a953b1 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt @@ -25,7 +25,8 @@ class RyujinxNative { external fun graphicsInitialize(configuration: GraphicsConfiguration): Boolean external fun graphicsInitializeRenderer( extensions: Array, - surface: Long + surface: Long, + driver: Long ): Boolean external fun deviceLoad(game: String): Boolean diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/SettingViews.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/SettingViews.kt index ae7823747..9675d8f3b 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/SettingViews.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/SettingViews.kt @@ -279,7 +279,7 @@ class SettingViews { enableTextureRecompression.value = !enableTextureRecompression.value }) } - /*Row( + Row( modifier = Modifier .fillMaxWidth() .padding(8.dp), @@ -423,7 +423,7 @@ class SettingViews { Text(text = "Drivers") } } - */ + } } ExpandableView(onCardArrowClick = { }, title = "Input") {