From dd65871f150952a3383a293822a2443332a885f3 Mon Sep 17 00:00:00 2001 From: amwatson Date: Tue, 19 Mar 2024 14:12:22 -0500 Subject: [PATCH] [NativeLibrary] do not release surface in SurfaceDestroyed when VR (surface is managed by swapchain) --- .../java/org/citra/citra_emu/NativeLibrary.kt | 2 +- .../citra_emu/fragments/EmulationFragment.kt | 15 +++++++++------ .../java/org/citra/citra_emu/vr/utils/VRUtils.kt | 7 +++++++ src/android/app/src/main/jni/native.cpp | 12 ++++++++++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt index 2fa77aaa4..cfad42254 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt @@ -124,7 +124,7 @@ object NativeLibrary { external fun run(path: String) // Surface Handling - external fun surfaceChanged(surf: Surface) + external fun surfaceChanged(surf: Surface, shouldReleaseSurface: Boolean) external fun surfaceDestroyed() external fun doFrame() diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt index 6ec5e35b6..23f1b6632 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt @@ -67,7 +67,7 @@ import org.citra.citra_emu.utils.EmulationLifecycleUtil import org.citra.citra_emu.utils.Log import org.citra.citra_emu.utils.ViewUtils import org.citra.citra_emu.viewmodel.EmulationViewModel -import org.citra.citra_emu.vr.VrActivity +import org.citra.citra_emu.vr.utils.VRUtils class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback { private val preferences: SharedPreferences @@ -165,7 +165,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram return } - if (activity !is VrActivity) { + if (!VRUtils.isVR(activity)) { Log.debug("[EmulationFragment] non-VR mode: adding surface callback"); binding.surfaceEmulation.holder.addCallback(this) } else { @@ -420,7 +420,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram fun surfaceCreated(surface : Surface) { Log.debug("[EmulationFragment] Surface created"); - emulationState.newSurface(surface) + emulationState.newSurface(surface, VRUtils.isVR(emulationActivity)) } private fun togglePause() { @@ -873,7 +873,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height) - emulationState.newSurface(holder.surface) + emulationState.newSurface(holder.surface, !VRUtils.isVR(emulationActivity)) } override fun surfaceDestroyed(holder: SurfaceHolder) { @@ -924,6 +924,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram private class EmulationState(private val gamePath: String) { private var state: State private var surface: Surface? = null + private var isVrSurface : Boolean = false; init { // Starting state is stopped. @@ -999,8 +1000,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram // Surface callbacks @Synchronized - fun newSurface(surface: Surface?) { + fun newSurface(surface: Surface?, isVrSurface: Boolean) { this.surface = surface + this.isVrSurface = isVrSurface if (this.surface != null) { runWithValidSurface() } @@ -1012,6 +1014,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram Log.warning("[EmulationFragment] clearSurface called, but surface already null.") } else { surface = null + isVrSurface = false Log.debug("[EmulationFragment] Surface destroyed.") when (state) { State.RUNNING -> { @@ -1031,7 +1034,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } private fun runWithValidSurface() { - NativeLibrary.surfaceChanged(surface!!) + NativeLibrary.surfaceChanged(surface!!, isVrSurface) when (state) { State.STOPPED -> { Thread({ diff --git a/src/android/app/src/main/java/org/citra/citra_emu/vr/utils/VRUtils.kt b/src/android/app/src/main/java/org/citra/citra_emu/vr/utils/VRUtils.kt index c0a14de59..b45f5a3d3 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/vr/utils/VRUtils.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/vr/utils/VRUtils.kt @@ -1,9 +1,11 @@ package org.citra.citra_emu.vr.utils +import android.app.Activity import android.view.KeyEvent import org.citra.citra_emu.NativeLibrary import org.citra.citra_emu.R import org.citra.citra_emu.features.settings.model.Settings +import org.citra.citra_emu.vr.VrActivity object VRUtils { val hMDType: Int @@ -81,6 +83,11 @@ object VRUtils { } } + @JvmStatic + fun isVR(mainActivity: Activity?) : Boolean { + return mainActivity is VrActivity + } + const val PREF_RELEASE_VERSION_NAME_LAUNCH_CURRENT = "VR_ReleaseVersionName_LaunchCurrent" const val PREF_RELEASE_VERSION_NAME_LAUNCH_PREV = "VR_ReleaseVersionName_LaunchPrev" } diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index ecf068cb9..4536ba1a2 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -67,6 +67,10 @@ namespace { ANativeWindow* s_surf; +// VR-SPECIFIC: +// false when using VR mode, as the surface is allocated by the OpenXR swapchain. +// True otherwise. +bool s_should_release_surface = true; std::shared_ptr vulkan_library{}; std::unique_ptr window; @@ -290,8 +294,9 @@ extern "C" { void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, [[maybe_unused]] jobject obj, - jobject surf) { + jobject surf, jboolean should_release_surface) { s_surf = ANativeWindow_fromSurface(env, surf); + s_should_release_surface = should_release_surface; if (window) { window->OnSurfaceChanged(s_surf); @@ -307,7 +312,10 @@ void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, void Java_org_citra_citra_1emu_NativeLibrary_surfaceDestroyed([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) { - ANativeWindow_release(s_surf); + + if (s_should_release_surface) { + ANativeWindow_release(s_surf); + } s_surf = nullptr; if (window) { window->OnSurfaceChanged(s_surf);