add closing emulation(starting a new one is still broken), disabled audio

This commit is contained in:
Emmanuel Hansen 2023-07-29 09:40:50 +00:00
parent a050e5c6c0
commit 2999275ed2
13 changed files with 194 additions and 33 deletions

View File

@ -72,7 +72,9 @@ namespace LibRyujinx
var init = Initialize(path, enableDebugLogs);
AudioDriver = new OboeHardwareDeviceDriver();
// AudioDriver = new OboeHardwareDeviceDriver();
_surfaceEvent?.Set();
_surfaceEvent = new ManualResetEvent(false);
@ -151,6 +153,18 @@ namespace LibRyujinx
return LoadApplication(path);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceSignalEmulationClose")]
public static void JniSignalEmulationCloseNative(JEnvRef jEnv, JObjectLocalRef jObj)
{
SignalEmulationClose();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceCloseEmulation")]
public static void JniCloseEmulationNative(JEnvRef jEnv, JObjectLocalRef jObj)
{
CloseEmulation();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoadDescriptor")]
public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
{

View File

@ -1,6 +1,8 @@
using ARMeilleure.Translation;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Input.HLE;
using Silk.NET.Vulkan;
using System;
using System.IO;
using System.Runtime.InteropServices;
@ -168,5 +170,41 @@ namespace LibRyujinx
return true;
}
public static void SignalEmulationClose()
{
_isStopped = true;
_isActive = false;
debug_break(2);
}
public static void CloseEmulation()
{
if (SwitchDevice == null)
return;
_npadManager?.Dispose();
_npadManager = null;
_touchScreenManager?.Dispose();
_touchScreenManager = null;
SwitchDevice?.InputManager?.Dispose();
SwitchDevice.InputManager = null;
_inputManager = null;
_surfaceEvent?.Set();
if (Renderer != null)
{
_gpuDoneEvent.WaitOne();
_gpuDoneEvent.Dispose();
_gpuDoneEvent = null;
SwitchDevice?.DisposeContext();
Renderer = null;
}
}
}
}

View File

@ -3,6 +3,7 @@ using LibRyujinx.Shared;
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
@ -21,6 +22,7 @@ namespace LibRyujinx
private static CancellationTokenSource _gpuCancellationTokenSource;
private static SwapBuffersCallback? _swapBuffersCallback;
private static NativeGraphicsInterop _nativeGraphicsInterop;
private static ManualResetEvent _gpuDoneEvent;
public delegate void SwapBuffersCallback();
public delegate IntPtr GetProcAddress(string name);
@ -146,12 +148,14 @@ namespace LibRyujinx
return;
}
var device = SwitchDevice!.EmulationContext!;
_gpuDoneEvent = new ManualResetEvent(true);
device.Gpu.Renderer.Initialize(GraphicsDebugLevel.None);
_gpuCancellationTokenSource = new CancellationTokenSource();
device.Gpu.Renderer.RunLoop(() =>
{
_gpuDoneEvent.Reset();
device.Gpu.SetGpuThread();
device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
Translator.IsReadyForTranslation.Set();
@ -162,9 +166,11 @@ namespace LibRyujinx
{
if (_isStopped)
{
return;
break;
}
debug_break(1);
if (Ryujinx.Common.SystemInfo.SystemInfo.IsBionic)
{
setRenderingThread();
@ -182,6 +188,13 @@ namespace LibRyujinx
device.PresentFrame(() => _swapBuffersCallback?.Invoke());
}
}
if (device.Gpu.Renderer is ThreadedRenderer threaded)
{
threaded.FlushThreadedCommands();
}
_gpuDoneEvent.Set();
});
}

View File

@ -30,7 +30,7 @@ namespace LibRyujinx
private static VirtualTouchScreenDriver? _touchScreenDriver;
private static TouchScreenManager? _touchScreenManager;
private static InputManager? _inputManager;
private static NpadManager _npadManager;
private static NpadManager? _npadManager;
private static InputConfig[] _configs;
public static void InitializeInput(int width, int height)

View File

@ -641,7 +641,9 @@ namespace LibRyujinx
internal void DisposeContext()
{
EmulationContext?.Dispose();
EmulationContext?.DisposeGpu();
EmulationContext = null;
LibRyujinx.Renderer = null;
}
}

View File

@ -222,5 +222,6 @@ Java_org_ryujinx_android_NativeHelpers_loadDriver(JNIEnv *env, jobject thiz,
extern "C"
void debug_break(int code){
if(code >= 3)
int r = 0;
}

View File

@ -12,6 +12,7 @@ import java.io.File
import kotlin.concurrent.thread
class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
private var _isClosed: Boolean = false
private var _renderingThreadWatcher: Thread? = null
private var _height: Int = 0
private var _width: Int = 0
@ -21,14 +22,9 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
private var _isInit: Boolean = false
private var _isStarted: Boolean = false
private var _nativeWindow: Long = 0
private var _nativeHelper: NativeHelpers = NativeHelpers()
private var _nativeRyujinx: RyujinxNative = RyujinxNative()
companion object {
var gameModel: GameModel? = null
}
init {
holder.addCallback(this)
}
@ -37,6 +33,8 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
if(_isClosed)
return
start(holder)
if(_width != width || _height != height)
@ -59,8 +57,17 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
}
private fun start(surfaceHolder: SurfaceHolder) {
fun close(){
_isClosed = true
_isInit = false
_isStarted = false
_updateThread?.join()
_renderingThreadWatcher?.join()
}
private fun start(surfaceHolder: SurfaceHolder) {
mainViewModel.gameHost = this
if(_isStarted)
return;
@ -119,6 +126,7 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
mainViewModel.performanceManager?.initializeRenderingSession(threadId)
}
}
mainViewModel.performanceManager?.closeCurrentRenderingSession()
}
}
_nativeRyujinx.graphicsRendererRunLoop()

View File

@ -12,6 +12,7 @@ import android.view.KeyEvent
import android.view.MotionEvent
import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.activity.addCallback
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
@ -62,15 +63,22 @@ class MainActivity : ComponentActivity() {
external fun getRenderingThreadId() : Long
external fun initVm()
fun setFullScreen() {
fun setFullScreen(fullscreen: Boolean) {
requestedOrientation =
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
if (fullscreen) ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_FULL_USER
val insets = WindowCompat.getInsetsController(window, window.decorView)
insets.apply {
insets.hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
insets.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
if (fullscreen) {
insets.hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
insets.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
} else {
insets.show(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
insets.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_DEFAULT
}
}
}
@ -95,7 +103,8 @@ class MainActivity : ComponentActivity() {
@SuppressLint("RestrictedApi")
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
event?.apply {
return physicalControllerManager.onKeyEvent(this)
if(physicalControllerManager.onKeyEvent(this))
return true;
}
return super.dispatchKeyEvent(event)
}

View File

@ -48,4 +48,6 @@ class RyujinxNative {
external fun inputConnectGamepad(index: Int): Int
external fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int): Unit
external fun graphicsSetSurface(surface: Long)
external fun deviceCloseEmulation()
external fun deviceSignalEmulationClose()
}

View File

@ -6,10 +6,6 @@ import android.os.Build
import android.os.PerformanceHintManager
import androidx.compose.runtime.MutableState
import androidx.navigation.NavHostController
import com.anggrayudi.storage.extension.launchOnUiThread
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import org.ryujinx.android.GameController
import org.ryujinx.android.GameHost
import org.ryujinx.android.GraphicsConfiguration
@ -24,6 +20,7 @@ import java.io.File
@SuppressLint("WrongConstant")
class MainViewModel(val activity: MainActivity) {
var gameHost: GameHost? = null
var controller: GameController? = null
var performanceManager: PerformanceManager? = null
var selected: GameModel? = null
@ -42,9 +39,19 @@ class MainViewModel(val activity: MainActivity) {
}
}
suspend fun loadGame(game:GameModel) : Boolean {
GameHost.gameModel = game
fun closeGame() {
RyujinxNative().deviceSignalEmulationClose()
gameHost?.close()
RyujinxNative().deviceCloseEmulation()
goBack()
activity.setFullScreen(false)
}
fun goBack(){
navController?.popBackStack()
}
fun loadGame(game:GameModel) : Boolean {
var nativeRyujinx = RyujinxNative()
val path = game.getPath() ?: return false
@ -129,8 +136,6 @@ class MainViewModel(val activity: MainActivity) {
if(!success)
return false
activity.physicalControllerManager.connect()
return true
}
@ -163,4 +168,7 @@ class MainViewModel(val activity: MainActivity) {
fun setGameController(controller: GameController) {
this.controller = controller
}
fun backCalled() {
}
}

View File

@ -310,7 +310,7 @@ class HomeViews {
val success = viewModel.mainViewModel?.loadGame(gameModel) ?: false
if(success) {
launchOnUiThread {
viewModel.mainViewModel?.activity?.setFullScreen()
viewModel.mainViewModel?.activity?.setFullScreen(true)
viewModel.mainViewModel?.navController?.navigate("game")
}
}

View File

@ -1,13 +1,25 @@
package org.ryujinx.android.views
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -71,6 +83,7 @@ class MainView {
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun GameOverlay(mainViewModel: MainViewModel) {
Box(modifier = Modifier.fillMaxSize()) {
@ -135,6 +148,57 @@ class MainView {
)
}
}
var showBackNotice = remember {
mutableStateOf(false)
}
BackHandler {
showBackNotice.value = true
}
if (showBackNotice.value) {
AlertDialog(onDismissRequest = { showBackNotice.value = false }) {
Column {
Surface(
modifier = Modifier
.wrapContentWidth()
.wrapContentHeight(),
shape = MaterialTheme.shapes.large,
tonalElevation = AlertDialogDefaults.TonalElevation
) {
Column {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(text = "Are you sure you want to exit the game?")
Text(text = "All unsaved data will be lost!")
}
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Button(onClick = {
mainViewModel.closeGame()
}, modifier = Modifier.padding(16.dp)) {
Text(text = "Exit Game")
}
Button(onClick = {
showBackNotice.value = false
}, modifier = Modifier.padding(16.dp)) {
Text(text = "Dismiss")
}
}
}
}
}
}
}
}
}

View File

@ -135,16 +135,6 @@ class SettingViews {
})
}) { contentPadding ->
Column(modifier = Modifier.padding(contentPadding)) {
BackHandler {
settingsViewModel.save(
isHostMapped,
useNce, enableVsync, enableDocked, enablePtc, ignoreMissingServices,
enableShaderCache,
enableTextureRecompression,
resScale,
useVirtualController
)
}
ExpandableView(onCardArrowClick = { }, title = "System") {
Column(modifier = Modifier.fillMaxWidth()) {
Row(
@ -462,6 +452,18 @@ class SettingViews {
}
}
}
BackHandler() {
settingsViewModel.save(
isHostMapped,
useNce, enableVsync, enableDocked, enablePtc, ignoreMissingServices,
enableShaderCache,
enableTextureRecompression,
resScale,
useVirtualController
)
settingsViewModel.navController.popBackStack()
}
}
}