mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-30 05:50:07 +02:00
Snapdragon 8 Elite (& Adreno 8xx) Fixes
See merge request kenji-nx/ryujinx!20
This commit is contained in:
@@ -169,6 +169,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
ghLog("surfaceDestroyed → shutdownBinding()")
|
||||
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
||||
// Always bind and unbind (prevents leaks when swiping away tasks)
|
||||
shutdownBinding()
|
||||
// The actual emulator termination happens via close() / Exit Game
|
||||
@@ -178,6 +179,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
super.onWindowVisibilityChanged(visibility)
|
||||
if (visibility != android.view.View.VISIBLE) {
|
||||
ghLog("window not visible → shutdownBinding()")
|
||||
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
||||
shutdownBinding()
|
||||
}
|
||||
}
|
||||
@@ -290,7 +292,12 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
}
|
||||
|
||||
private fun runGame() {
|
||||
KenjinxNative.graphicsRendererRunLoop()
|
||||
mainViewModel.onEmulationStarted()
|
||||
try {
|
||||
KenjinxNative.graphicsRendererRunLoop()
|
||||
} finally {
|
||||
mainViewModel.onEmulationStopped()
|
||||
}
|
||||
game?.close()
|
||||
}
|
||||
|
||||
@@ -307,7 +314,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
try {
|
||||
if (emuBound && _startedViaService) {
|
||||
emuBinder?.stopEmulation {
|
||||
try { KenjinxNative.deviceCloseEmulation() } catch (_: Throwable) {}
|
||||
// Close is handled in the service hard-close path.
|
||||
}
|
||||
}
|
||||
} catch (_: Throwable) { }
|
||||
@@ -315,6 +322,12 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
// Fallback: Terminate local thread
|
||||
try { _updateThread?.join(200) } catch (_: Throwable) {}
|
||||
try { _renderingThreadWatcher?.join(200) } catch (_: Throwable) {}
|
||||
try { _guestThread?.join(1000) } catch (_: Throwable) {}
|
||||
|
||||
if (!(emuBound && _startedViaService)) {
|
||||
try { KenjinxNative.deviceCloseEmulation() } catch (_: Throwable) {}
|
||||
mainViewModel.onEmulationStopped()
|
||||
}
|
||||
|
||||
// Release the bond
|
||||
shutdownBinding()
|
||||
@@ -488,11 +501,13 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
|
||||
emuBinder?.startEmulation {
|
||||
try {
|
||||
mainViewModel.onEmulationStarted()
|
||||
KenjinxNative.graphicsRendererRunLoop()
|
||||
} catch (t: Throwable) {
|
||||
Log.e("GameHost", "RunLoop crash in service", t)
|
||||
} finally {
|
||||
_startedViaService = false
|
||||
mainViewModel.onEmulationStopped()
|
||||
}
|
||||
}
|
||||
ghLog("RunLoop started in EmulationService")
|
||||
|
||||
@@ -71,6 +71,7 @@ interface KenjinxNativeJna : Library {
|
||||
fun deviceReinitEmulation()
|
||||
fun deviceSignalEmulationClose()
|
||||
|
||||
fun detachWindow()
|
||||
// >>> Rendering-related additions for the toggle:
|
||||
fun deviceWaitForGpuDone(timeoutMs: Int)
|
||||
fun deviceRecreateSwapchain()
|
||||
@@ -279,10 +280,10 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
|
||||
} catch (_: Throwable) {}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun detachWindow() {
|
||||
override fun detachWindow() {
|
||||
try { graphicsSetPresentEnabled(false) } catch (_: Throwable) {}
|
||||
try { deviceWaitForGpuDone(100) } catch (_: Throwable) {}
|
||||
try { jnaInstance.detachWindow() } catch (_: Throwable) {}
|
||||
try { deviceSetWindowHandle(0) } catch (_: Throwable) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -409,8 +409,8 @@ class MainActivity : BaseActivity() {
|
||||
setAudioForegroundState(false)
|
||||
if (MainActivity.mainViewModel?.rendererReady == true) {
|
||||
try {
|
||||
KenjinxNative.graphicsSetPresentEnabled(false)
|
||||
Log.d(TAG_FG, "present=DISABLED (onTrimMemory:$level)")
|
||||
setPresentEnabled(false, "onTrimMemory:$level")
|
||||
KenjinxNative.detachWindow()
|
||||
} catch (_: Throwable) {}
|
||||
} else {
|
||||
Log.d(TAG_FG, "skip disable present (onTrimMemory) — rendererReady=${MainActivity.mainViewModel?.rendererReady}")
|
||||
|
||||
+43
-1
@@ -2,6 +2,7 @@ package org.kenjinx.android.viewmodels
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.net.Uri
|
||||
import android.os.SystemClock
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.navigation.NavHostController
|
||||
@@ -23,6 +24,7 @@ import org.kenjinx.android.KenjinxNative
|
||||
import org.kenjinx.android.PerformanceMonitor
|
||||
import org.kenjinx.android.SystemLanguage
|
||||
import org.kenjinx.android.UiHandler
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import java.util.TimeZone
|
||||
|
||||
@@ -52,6 +54,8 @@ class MainViewModel(val activity: MainActivity) {
|
||||
private var showLoading: MutableState<Boolean>? = null
|
||||
private var refreshUser: MutableState<Boolean>? = null
|
||||
@Volatile var rendererReady: Boolean = false
|
||||
@Volatile var emulationRunning: Boolean = false
|
||||
@Volatile var emulationClosing: Boolean = false
|
||||
|
||||
// Default Game Folder
|
||||
var defaultGameFolderUri: Uri? = null
|
||||
@@ -84,15 +88,47 @@ class MainViewModel(val activity: MainActivity) {
|
||||
}
|
||||
|
||||
fun closeGame() {
|
||||
emulationClosing = true
|
||||
KenjinxNative.deviceSignalEmulationClose()
|
||||
gameHost?.close()
|
||||
KenjinxNative.deviceCloseEmulation()
|
||||
motionSensorManager?.unregister()
|
||||
physicalControllerManager?.disconnect()
|
||||
motionSensorManager?.setControllerId(-1)
|
||||
rendererReady = false
|
||||
}
|
||||
|
||||
internal fun onEmulationStarted() {
|
||||
emulationRunning = true
|
||||
}
|
||||
|
||||
internal fun onEmulationStopped() {
|
||||
emulationRunning = false
|
||||
emulationClosing = false
|
||||
}
|
||||
|
||||
private fun waitForEmulationStop(timeoutMs: Long): Boolean {
|
||||
if (!emulationRunning) {
|
||||
emulationClosing = false
|
||||
return true
|
||||
}
|
||||
|
||||
val deadline = SystemClock.uptimeMillis() + timeoutMs
|
||||
while (emulationRunning && SystemClock.uptimeMillis() < deadline) {
|
||||
try { Thread.sleep(50) } catch (_: Throwable) {}
|
||||
}
|
||||
|
||||
if (emulationRunning) {
|
||||
Log.w("MainViewModel", "Emulation still running after timeout; forcing close.")
|
||||
try { KenjinxNative.deviceCloseEmulation() } catch (_: Throwable) {}
|
||||
emulationRunning = false
|
||||
emulationClosing = false
|
||||
return true
|
||||
}
|
||||
|
||||
emulationClosing = false
|
||||
return true
|
||||
}
|
||||
|
||||
// ---- Load language/region from Preferences (Defaults: AmericanEnglish/USA) ----
|
||||
private fun loadSystemLanguage(): SystemLanguage {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
@@ -108,6 +144,12 @@ class MainViewModel(val activity: MainActivity) {
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
fun loadGame(game: GameModel, overrideSettings: Boolean? = false, forceNceAndPptc: Boolean? = false): Int {
|
||||
if (emulationClosing || emulationRunning) {
|
||||
if (!waitForEmulationStop(5000)) {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
KenjinxNative.deviceReinitEmulation()
|
||||
MainActivity.mainViewModel?.activity?.uiHandler = UiHandler()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user