Snapdragon 8 Elite (& Adreno 8xx) Fixes

See merge request kenji-nx/ryujinx!20
This commit is contained in:
BeZide
2026-01-22 03:33:26 -06:00
committed by KeatonTheBot
parent 6f5b351fa0
commit 6840ae0c5c
26 changed files with 511 additions and 201 deletions
@@ -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}")
@@ -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()