From 59c34f10aa4fdbe0657e5af433af1e68f4e696ec Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Tue, 10 Sep 2024 08:36:27 +0000 Subject: [PATCH] android - replace surface pointer query with jni callback --- src/LibRyujinx/Android/Interop.cs | 36 +++++++++++++--- src/LibRyujinx/Android/Jni/JniHelper.cs | 14 +++++++ src/LibRyujinx/Android/JniExportedMethods.cs | 19 +-------- .../app/src/main/cpp/ryujinx.cpp | 42 ------------------- .../main/java/org/ryujinx/android/GameHost.kt | 23 +++++++--- .../java/org/ryujinx/android/NativeHelpers.kt | 2 - .../java/org/ryujinx/android/RyujinxNative.kt | 13 +++++- src/RyujinxAndroid/gradle.properties | 2 +- 8 files changed, 76 insertions(+), 75 deletions(-) diff --git a/src/LibRyujinx/Android/Interop.cs b/src/LibRyujinx/Android/Interop.cs index edbe5bf41..8fa2ad97d 100644 --- a/src/LibRyujinx/Android/Interop.cs +++ b/src/LibRyujinx/Android/Interop.cs @@ -29,7 +29,9 @@ namespace LibRyujinx.Android ("test", "()V"), ("updateUiHandler", "(JJJIIIIJJ)V"), ("frameEnded", "()V"), - ("updateProgress", "(JF)V") + ("updateProgress", "(JF)V"), + ("getSurfacePtr", "()J"), + ("getWindowHandle", "()J") }; internal static void Initialize(JEnvRef jniEnv) @@ -82,7 +84,7 @@ namespace LibRyujinx.Android } } - private static void CallMethod(string name, string descriptor, params JValue[] values) + private static void CallVoidMethod(string name, string descriptor, params JValue[] values) { using var env = JniEnv.Create(); if (_methodCache.TryGetValue((name, descriptor), out var method)) @@ -94,26 +96,48 @@ namespace LibRyujinx.Android } } + private static JLong CallLongMethod(string name, string descriptor, params JValue[] values) + { + using var env = JniEnv.Create(); + if (_methodCache.TryGetValue((name, descriptor), out var method)) + { + if (descriptor.EndsWith("J")) + return JniHelper.CallStaticLongMethod(env.Env, (JClassLocalRef)(_classId.Value.Value), method, values) ?? (JLong)(-1); + } + + return (JLong)(-1); + } + public static void Test() { - CallMethod("test", "()V"); + CallVoidMethod("test", "()V"); } public static void FrameEnded(double time) { - CallMethod("frameEnded", "()V"); + CallVoidMethod("frameEnded", "()V"); } public static void UpdateProgress(string info, float progress) { using var infoPtr = new TempNativeString(info); - CallMethod("updateProgress", "(JF)V", new JValue[] + CallVoidMethod("updateProgress", "(JF)V", new JValue[] { JValue.Create(infoPtr.AsBytes()), JValue.Create(progress.AsBytes()) }); } + public static JLong GetSurfacePtr() + { + return CallLongMethod("getSurfacePtr", "()J"); + } + + public static JLong GetWindowsHandle() + { + return CallLongMethod("getWindowHandle", "()J"); + } + public static void UpdateUiHandler(string newTitle, string newMessage, string newWatermark, @@ -129,7 +153,7 @@ namespace LibRyujinx.Android using var watermarkPointer = new TempNativeString(newWatermark); using var subtitlePointer = new TempNativeString(newSubtitle); using var newInitialPointer = new TempNativeString(newInitialText); - CallMethod("updateUiHandler", "(JJJIIIIJJ)V", new JValue[] + CallVoidMethod("updateUiHandler", "(JJJIIIIJJ)V", new JValue[] { JValue.Create(titlePointer.AsBytes()), JValue.Create(messagePointer.AsBytes()), diff --git a/src/LibRyujinx/Android/Jni/JniHelper.cs b/src/LibRyujinx/Android/Jni/JniHelper.cs index 8838491cd..fced8b22d 100644 --- a/src/LibRyujinx/Android/Jni/JniHelper.cs +++ b/src/LibRyujinx/Android/Jni/JniHelper.cs @@ -220,6 +220,20 @@ internal static class JniHelper JObjectLocalRef jObject = callStaticObjectMethod(jEnv, jClass, jMethodId, fArgs.ValuePointer); return !JniHelper.ExceptionCheck(jEnv) ? jObject : null; } + public static JLong? CallStaticLongMethod(JEnvRef jEnv, JClassLocalRef jClass, JMethodId jMethodId, + params JValue[] args) + { + ref readonly JEnvValue value = ref jEnv.Environment; + ref JNativeInterface jInterface = ref value.Functions; + + IntPtr callStaticLongMethodPtr = jInterface.CallStaticLongMethodAPointer; + CallStaticLongMethodADelegate callStaticLongMethod = + callStaticLongMethodPtr.GetUnsafeDelegate()!; + + using IReadOnlyFixedMemory.IDisposable fArgs = args.AsMemory().GetFixedContext(); + JLong jLong = callStaticLongMethod(jEnv, jClass, jMethodId, fArgs.ValuePointer); + return !JniHelper.ExceptionCheck(jEnv) ? jLong : null; + } public static void CallVoidMethod(JEnvRef jEnv, JObjectLocalRef jObject, JMethodId jMethodId, params JValue[] args) { ref readonly JEnvValue value = ref jEnv.Environment; diff --git a/src/LibRyujinx/Android/JniExportedMethods.cs b/src/LibRyujinx/Android/JniExportedMethods.cs index 93d80a47d..7e1070f8b 100644 --- a/src/LibRyujinx/Android/JniExportedMethods.cs +++ b/src/LibRyujinx/Android/JniExportedMethods.cs @@ -21,7 +21,6 @@ namespace LibRyujinx { public static partial class LibRyujinx { - private static ManualResetEvent _surfaceEvent; private static long _surfacePtr; private static long _window = 0; @@ -59,10 +58,6 @@ namespace LibRyujinx Interop.Test(); - _surfaceEvent?.Set(); - - _surfaceEvent = new ManualResetEvent(false); - return init; } @@ -259,16 +254,6 @@ namespace LibRyujinx }); } - [UnmanagedCallersOnly(EntryPoint = "graphicsSetSurface")] - public static void JniSetSurface(long surfacePtr, long window) - { - Logger.Trace?.Print(LogClass.Application, "Jni Function Call"); - _surfacePtr = surfacePtr; - _window = window; - - _surfaceEvent.Set(); - } - [UnmanagedCallersOnly(EntryPoint = "graphicsInitializeRenderer")] public unsafe static bool JnaGraphicsInitializeRenderer(char** extensionsArray, int extensionsLength, @@ -294,8 +279,8 @@ namespace LibRyujinx CreateSurface createSurfaceFunc = instance => { - _surfaceEvent.WaitOne(); - _surfaceEvent.Reset(); + _surfacePtr = Interop.GetSurfacePtr(); + _window = Interop.GetWindowsHandle(); var api = VulkanLoader?.GetApi() ?? Vk.GetApi(); if (api.TryGetInstanceExtension(new Instance(instance), out KhrAndroidSurface surfaceExtension)) diff --git a/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp b/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp index 6f7fe0c62..3272c3143 100644 --- a/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp +++ b/src/RyujinxAndroid/app/src/main/cpp/ryujinx.cpp @@ -21,29 +21,9 @@ #include #include -JNIEnv *_rendererEnv = nullptr; std::chrono::time_point _currentTimePoint; - -JNIEnv *getEnv(bool isRenderer) { - JNIEnv *env; - if (isRenderer) { - env = _rendererEnv; - } - - if (env != nullptr) - return env; - - auto result = _vm->AttachCurrentThread(&env, NULL); - - return env; -} - -void detachEnv() { - auto result = _vm->DetachCurrentThread(); -} - extern "C" { JNIEXPORT jlong JNICALL @@ -66,28 +46,6 @@ Java_org_ryujinx_android_NativeHelpers_releaseNativeWindow( ANativeWindow_release(nativeWindow); } -JNIEXPORT void JNICALL -Java_org_ryujinx_android_NativeHelpers_attachCurrentThread( - JNIEnv *env, - jobject instance) { - JavaVM *jvm = NULL; - env->GetJavaVM(&jvm); - - if (jvm != NULL) - jvm->AttachCurrentThread(&env, NULL); -} - -JNIEXPORT void JNICALL -Java_org_ryujinx_android_NativeHelpers_detachCurrentThread( - JNIEnv *env, - jobject instance) { - JavaVM *jvm = NULL; - env->GetJavaVM(&jvm); - - if (jvm != NULL) - jvm->DetachCurrentThread(); -} - long createSurface(long native_surface, long instance) { auto nativeWindow = (ANativeWindow *) native_surface; VkSurfaceKHR surface; 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 444fb1296..6fed55e81 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 @@ -12,6 +12,7 @@ import kotlin.concurrent.thread @SuppressLint("ViewConstructor") class GameHost(context: Context?, private val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback { + private var _currentWindow: Long = -1 private var isProgressHidden: Boolean = false private var progress: MutableState? = null private var progressValue: MutableState? = null @@ -25,12 +26,22 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su private var _guestThread: Thread? = null private var _isInit: Boolean = false private var _isStarted: Boolean = false - private val nativeWindow: NativeWindow + private val _nativeWindow: NativeWindow + + val currentSurface:Long + get() { + return _currentWindow + } + + val currentWindowhandle: Long + get() { + return _nativeWindow.nativePointer + } init { holder.addCallback(this) - nativeWindow = NativeWindow(this) + _nativeWindow = NativeWindow(this) mainViewModel.gameHost = this } @@ -53,18 +64,18 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { if (_isClosed) return - start(holder) if (_width != width || _height != height) { - val window = nativeWindow.requeryWindowHandle() - RyujinxNative.jnaInstance.graphicsSetSurface(window, nativeWindow.nativePointer) + _currentWindow = _nativeWindow.requeryWindowHandle() - nativeWindow.swapInterval = 0 + _nativeWindow.swapInterval = 0 } _width = width _height = height + start(holder) + RyujinxNative.jnaInstance.graphicsRendererSetSize( width, height 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 f04c0c45a..d6e749324 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,8 +15,6 @@ class NativeHelpers { external fun releaseNativeWindow(window: Long) external fun getCreateSurfacePtr(): Long external fun getNativeWindow(surface: Surface): Long - external fun attachCurrentThread() - external fun detachCurrentThread() external fun loadDriver( nativeLibPath: String, 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 7436d6575..3787fa414 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 @@ -58,7 +58,6 @@ interface RyujinxNativeJna : Library { fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int) fun inputSetAccelerometerData(x: Float, y: Float, z: Float, id: Int) fun inputSetGyroData(x: Float, y: Float, z: Float, id: Int) - fun graphicsSetSurface(surface: Long, window: Long) fun deviceCloseEmulation() fun deviceSignalEmulationClose() fun userGetOpenedUser(): String @@ -104,6 +103,18 @@ class RyujinxNative { MainActivity.frameEnded() } + @JvmStatic + fun getSurfacePtr() : Long + { + return MainActivity.mainViewModel?.gameHost?.currentSurface ?: -1 + } + + @JvmStatic + fun getWindowHandle() : Long + { + return MainActivity.mainViewModel?.gameHost?.currentWindowhandle ?: -1 + } + @JvmStatic fun updateProgress(infoPtr : Long, progress: Float) { diff --git a/src/RyujinxAndroid/gradle.properties b/src/RyujinxAndroid/gradle.properties index c44b8e8e2..cb15bc25e 100644 --- a/src/RyujinxAndroid/gradle.properties +++ b/src/RyujinxAndroid/gradle.properties @@ -24,7 +24,7 @@ android.nonTransitiveRClass=true # Build configuration # It needs to be set to either "debug" or "release" and can also be overriden on a per build basis # by adding -Dorg.ryujinx.config=NAME to the command line. -org.ryujinx.config=debug +org.ryujinx.config=release # Controls stripping of symbols from libryujinx # Setting this property to auto causes symbols to be stripped for release builds, # but not for debug builds.