forked from MeloNX/MeloNX
add closing emulation(starting a new one is still broken), disabled audio
This commit is contained in:
parent
4ea06abd71
commit
d25e5cefd8
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -641,7 +641,9 @@ namespace LibRyujinx
|
||||
internal void DisposeContext()
|
||||
{
|
||||
EmulationContext?.Dispose();
|
||||
EmulationContext?.DisposeGpu();
|
||||
EmulationContext = null;
|
||||
LibRyujinx.Renderer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
@ -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() {
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user