Browse Source

chore: DRY up pause and capture, debug resume

pull/3651/head
xXJSONDeruloXx 1 week ago
parent
commit
3a391e5730
No known key found for this signature in database GPG Key ID: 629F3E618E280D7F
  1. 85
      src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt

85
src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt

@ -739,10 +739,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (emulationState.isPaused) { if (emulationState.isPaused) {
resumeEmulationFromUi() resumeEmulationFromUi()
} else { } else {
emulationState.pause()
updatePauseMenuEntry(true)
capturePausedFrameFromCore()
updatePausedFrameVisibility()
pauseEmulationAndCaptureFrame()
} }
binding.inGameMenu.requestFocus() binding.inGameMenu.requestFocus()
true true
@ -1208,6 +1205,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
private fun pauseEmulationAndCaptureFrame() {
emulationState.pause()
updatePauseMenuEntry(true)
capturePausedFrameFromCore()
updatePausedFrameVisibility()
}
private fun capturePausedFrameFromCore() { private fun capturePausedFrameFromCore() {
lifecycleScope.launch(Dispatchers.Default) { lifecycleScope.launch(Dispatchers.Default) {
val frameData = NativeLibrary.getAppletCaptureBuffer() val frameData = NativeLibrary.getAppletCaptureBuffer()
@ -1243,28 +1247,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private fun updatePausedFrameVisibility() { private fun updatePausedFrameVisibility() {
val b = _binding ?: return val b = _binding ?: return
val shouldShowPaused = this::emulationState.isInitialized && emulationState.isPaused
b.pausedIcon.setVisible(shouldShowPaused)
if (!shouldShowPaused) {
b.pausedFrameImage.setVisible(false)
b.pausedFrameImage.setImageDrawable(null)
return
}
val showPausedUi = this::emulationState.isInitialized && emulationState.isPaused
b.pausedIcon.setVisible(showPausedUi)
val bitmap = pausedFrameBitmap ?: run {
b.pausedFrameImage.setVisible(false)
b.pausedFrameImage.setImageDrawable(null)
return
}
val bitmap = if (showPausedUi) pausedFrameBitmap else null
b.pausedFrameImage.setImageBitmap(bitmap) b.pausedFrameImage.setImageBitmap(bitmap)
b.pausedFrameImage.setVisible(true)
b.pausedFrameImage.setVisible(bitmap != null)
} }
private fun resumeEmulationFromUi() { private fun resumeEmulationFromUi() {
clearPausedFrame() clearPausedFrame()
emulationState.run(false, explicitResume = true)
updatePauseMenuEntry(false)
emulationState.resume()
updatePauseMenuEntry(emulationState.isPaused)
updatePausedFrameVisibility() updatePausedFrameVisibility()
} }
@ -1369,12 +1363,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
override fun onPause() { override fun onPause() {
if (this::emulationState.isInitialized) { if (this::emulationState.isInitialized) {
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) { if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
emulationState.pause()
updatePauseMenuEntry(true)
capturePausedFrameFromCore()
}
pauseEmulationAndCaptureFrame()
} else {
updatePausedFrameVisibility() updatePausedFrameVisibility()
} }
}
super.onPause() super.onPause()
} }
@ -2159,11 +2152,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
@Synchronized @Synchronized
fun run(
isActivityRecreated: Boolean,
programIndex: Int = 0,
explicitResume: Boolean = false
) {
fun run(isActivityRecreated: Boolean, programIndex: Int = 0) {
if (isActivityRecreated) { if (isActivityRecreated) {
if (NativeLibrary.isRunning()) { if (NativeLibrary.isRunning()) {
state = State.PAUSED state = State.PAUSED
@ -2174,10 +2163,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
// If the surface is set, run now. Otherwise, wait for it to get set. // If the surface is set, run now. Otherwise, wait for it to get set.
if (surface != null) { if (surface != null) {
runWithValidSurface(programIndex, explicitResume)
runWithValidSurface(programIndex)
} }
} }
@Synchronized
fun resume() {
if (state != State.PAUSED) {
Log.warning("[EmulationFragment] Resume called while emulation is not paused.")
return
}
if (!emulationCanStart.invoke()) {
return
}
val currentSurface = surface
if (currentSurface == null || !currentSurface.isValid) {
Log.debug("[EmulationFragment] Resume requested with invalid surface.")
return
}
NativeLibrary.surfaceChanged(currentSurface)
Log.debug("[EmulationFragment] Resuming emulation.")
NativeLibrary.unpauseEmulation()
NativeLibrary.playTimeManagerStart()
state = State.RUNNING
}
@Synchronized @Synchronized
fun changeProgram(programIndex: Int) { fun changeProgram(programIndex: Int) {
emulationThread.join() emulationThread.join()
@ -2235,7 +2246,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
private fun runWithValidSurface(programIndex: Int = 0, explicitResume: Boolean = false) {
private fun runWithValidSurface(programIndex: Int = 0) {
if (!emulationCanStart.invoke()) { if (!emulationCanStart.invoke()) {
return return
} }
@ -2253,26 +2264,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
NativeLibrary.run(gamePath, programIndex, true) NativeLibrary.run(gamePath, programIndex, true)
}, "NativeEmulation") }, "NativeEmulation")
emulationThread.start() emulationThread.start()
state = State.RUNNING
} }
State.PAUSED -> { State.PAUSED -> {
if (!explicitResume) {
Log.debug( Log.debug(
"[EmulationFragment] Surface restored while emulation paused; " + "[EmulationFragment] Surface restored while emulation paused; " +
"deferring native surface update until explicit resume."
"waiting for explicit resume."
) )
return
}
NativeLibrary.surfaceChanged(currentSurface)
Log.debug("[EmulationFragment] Resuming emulation.")
NativeLibrary.unpauseEmulation()
NativeLibrary.playTimeManagerStart()
} }
else -> Log.debug("[EmulationFragment] Bug, run called while already running.") else -> Log.debug("[EmulationFragment] Bug, run called while already running.")
} }
state = State.RUNNING
} }
private enum class State { private enum class State {

Loading…
Cancel
Save