From a050e5c6c06e5fa869afd526a43812cddb3a4e44 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Fri, 28 Jul 2023 19:42:34 +0000 Subject: [PATCH] separate game loading from surface creation --- src/LibRyujinx/Android/JniExportedMethods.cs | 5 - src/RyujinxAndroid/app/build.gradle | 3 - .../main/java/org/ryujinx/android/GameHost.kt | 85 +------------- .../java/org/ryujinx/android/RyujinxNative.kt | 3 +- .../android/viewmodels/MainViewModel.kt | 108 ++++++++++++++++-- .../org/ryujinx/android/views/HomeViews.kt | 56 ++++++++- .../org/ryujinx/android/views/MainView.kt | 2 +- 7 files changed, 158 insertions(+), 104 deletions(-) diff --git a/src/LibRyujinx/Android/JniExportedMethods.cs b/src/LibRyujinx/Android/JniExportedMethods.cs index 7aa30cd8c..fbdfb8a63 100644 --- a/src/LibRyujinx/Android/JniExportedMethods.cs +++ b/src/LibRyujinx/Android/JniExportedMethods.cs @@ -218,7 +218,6 @@ namespace LibRyujinx public unsafe static JBoolean JniInitializeGraphicsRendererNative(JEnvRef jEnv, JObjectLocalRef jObj, JArrayLocalRef extensionsArray, - JLong surfacePtr, JLong driverHandle) { if (Renderer != null) @@ -254,10 +253,6 @@ namespace LibRyujinx extensions.Add(GetString(jEnv, ext)); } - _surfaceEvent.Set(); - - _surfacePtr = surfacePtr; - if((long)driverHandle != 0) { VulkanLoader = new VulkanLoader((IntPtr)(long)driverHandle); diff --git a/src/RyujinxAndroid/app/build.gradle b/src/RyujinxAndroid/app/build.gradle index 1fd744ef2..002f49345 100644 --- a/src/RyujinxAndroid/app/build.gradle +++ b/src/RyujinxAndroid/app/build.gradle @@ -59,9 +59,6 @@ android { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' } - jniLibs { - keepDebugSymbols += '**/libryujinx.so' - } } externalNativeBuild { cmake { diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt index 2bbb99804..c22f34722 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt @@ -37,11 +37,9 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie } override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { - val isStarted = _isStarted - start(holder) - if(isStarted && (_width != width || _height != height)) + if(_width != width || _height != height) { val nativeHelpers = NativeHelpers() val window = nativeHelpers.getNativeWindow(holder.surface) @@ -62,85 +60,14 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie } private fun start(surfaceHolder: SurfaceHolder) { - val game = gameModel ?: return - val path = game.getPath() ?: return - if (_isStarted) - return - var surface = surfaceHolder.surface - - val settings = QuickSettings(mainViewModel.activity) - - var success = _nativeRyujinx.graphicsInitialize(GraphicsConfiguration().apply { - EnableShaderCache = settings.enableShaderCache - EnableTextureRecompression = settings.enableTextureRecompression - ResScale = settings.resScale - }) - - - val nativeHelpers = NativeHelpers() - val window = nativeHelpers.getNativeWindow(surfaceHolder.surface) - nativeInterop = NativeGraphicsInterop() - nativeInterop!!.VkRequiredExtensions = arrayOf( - "VK_KHR_surface", "VK_KHR_android_surface" - ) - nativeInterop!!.VkCreateSurface = nativeHelpers.getCreateSurfacePtr() - nativeInterop!!.SurfaceHandle = window - - var driverViewModel = VulkanDriverViewModel(mainViewModel.activity); - var drivers = driverViewModel.getAvailableDrivers() - - var driverHandle = 0L; - - if(driverViewModel.selected.isNotEmpty()) { - var metaData = drivers.find { it.driverPath == driverViewModel.selected } - - metaData?.apply { - var privatePath = mainViewModel.activity.filesDir; - var privateDriverPath = privatePath.canonicalPath + "/driver/" - val pD = File(privateDriverPath) - if(pD.exists()) - pD.deleteRecursively() - - pD.mkdirs() - - var driver = File(driverViewModel.selected) - var parent = driver.parentFile - for (file in parent.walkTopDown()){ - if(file.absolutePath == parent.absolutePath) - continue - file.copyTo(File(privateDriverPath + file.name), true) - } - - driverHandle = NativeHelpers().loadDriver(mainViewModel.activity.applicationInfo.nativeLibraryDir!! + "/", privateDriverPath, this.libraryName) - } - - } - - success = _nativeRyujinx.graphicsInitializeRenderer( - nativeInterop!!.VkRequiredExtensions!!, - window, - driverHandle - ) - - - success = _nativeRyujinx.deviceInitialize( - settings.isHostMapped, - settings.useNce, - SystemLanguage.AmericanEnglish.ordinal, - RegionCode.USA.ordinal, - settings.enableVsync, - settings.enableDocked, - settings.enablePtc, - false, - "UTC", - settings.ignoreMissingServices - ) - - success = _nativeRyujinx.deviceLoad(path) + if(_isStarted) + return; _nativeRyujinx.inputInitialize(width, height) + val settings = QuickSettings(mainViewModel.activity) + if(!settings.useVirtualController){ mainViewModel.controller?.setVisible(false) } @@ -158,7 +85,7 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie _guestThread = thread(start = true) { runGame() } - _isStarted = success + _isStarted = true _updateThread = thread(start = true) { var c = 0 diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt index 1d6a953b1..aeba312eb 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/RyujinxNative.kt @@ -25,7 +25,6 @@ class RyujinxNative { external fun graphicsInitialize(configuration: GraphicsConfiguration): Boolean external fun graphicsInitializeRenderer( extensions: Array, - surface: Long, driver: Long ): Boolean @@ -48,5 +47,5 @@ class RyujinxNative { external fun inputSetButtonReleased(button: Int, id: Int): Unit external fun inputConnectGamepad(index: Int): Int external fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int): Unit - external fun graphicsSetSurface(surface: Long): String + external fun graphicsSetSurface(surface: Long) } \ No newline at end of file diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt index 2c1641787..33e924915 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt @@ -6,10 +6,21 @@ 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 import org.ryujinx.android.MainActivity +import org.ryujinx.android.NativeGraphicsInterop +import org.ryujinx.android.NativeHelpers import org.ryujinx.android.PerformanceManager +import org.ryujinx.android.RegionCode +import org.ryujinx.android.RyujinxNative +import org.ryujinx.android.SystemLanguage +import java.io.File @SuppressLint("WrongConstant") class MainViewModel(val activity: MainActivity) { @@ -19,7 +30,7 @@ class MainViewModel(val activity: MainActivity) { private var gameTimeState: MutableState? = null private var gameFpsState: MutableState? = null private var fifoState: MutableState? = null - private var navController : NavHostController? = null + var navController : NavHostController? = null var homeViewModel: HomeViewModel = HomeViewModel(activity, this) @@ -31,15 +42,96 @@ class MainViewModel(val activity: MainActivity) { } } - fun loadGame(game:GameModel) { - val controller = navController?: return - activity.setFullScreen() + suspend fun loadGame(game:GameModel) : Boolean { GameHost.gameModel = game - controller.navigate("game") - } - fun setNavController(controller: NavHostController) { - navController = controller + var nativeRyujinx = RyujinxNative() + + val path = game.getPath() ?: return false + + val settings = QuickSettings(activity) + + var success = nativeRyujinx.graphicsInitialize(GraphicsConfiguration().apply { + EnableShaderCache = settings.enableShaderCache + EnableTextureRecompression = settings.enableTextureRecompression + ResScale = settings.resScale + }) + + if(!success) + return false + + val nativeHelpers = NativeHelpers() + var nativeInterop = NativeGraphicsInterop() + nativeInterop!!.VkRequiredExtensions = arrayOf( + "VK_KHR_surface", "VK_KHR_android_surface" + ) + nativeInterop!!.VkCreateSurface = nativeHelpers.getCreateSurfacePtr() + nativeInterop!!.SurfaceHandle = 0 + + var driverViewModel = VulkanDriverViewModel(activity); + var drivers = driverViewModel.getAvailableDrivers() + + var driverHandle = 0L; + + if (driverViewModel.selected.isNotEmpty()) { + var metaData = drivers.find { it.driverPath == driverViewModel.selected } + + metaData?.apply { + var privatePath = activity.filesDir; + var privateDriverPath = privatePath.canonicalPath + "/driver/" + val pD = File(privateDriverPath) + if (pD.exists()) + pD.deleteRecursively() + + pD.mkdirs() + + var driver = File(driverViewModel.selected) + var parent = driver.parentFile + for (file in parent.walkTopDown()) { + if (file.absolutePath == parent.absolutePath) + continue + file.copyTo(File(privateDriverPath + file.name), true) + } + + driverHandle = NativeHelpers().loadDriver( + activity.applicationInfo.nativeLibraryDir!! + "/", + privateDriverPath, + this.libraryName + ) + } + + } + + success = nativeRyujinx.graphicsInitializeRenderer( + nativeInterop!!.VkRequiredExtensions!!, + driverHandle + ) + if(!success) + return false + + success = nativeRyujinx.deviceInitialize( + settings.isHostMapped, + settings.useNce, + SystemLanguage.AmericanEnglish.ordinal, + RegionCode.USA.ordinal, + settings.enableVsync, + settings.enableDocked, + settings.enablePtc, + false, + "UTC", + settings.ignoreMissingServices + ) + if(!success) + return false + + success = nativeRyujinx.deviceLoad(path) + + if(!success) + return false + + activity.physicalControllerManager.connect() + + return true } fun setStatStates( diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt index 8a2c1c3dc..f52029ab5 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt @@ -32,6 +32,7 @@ import androidx.compose.material3.FabPosition import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Scaffold @@ -55,10 +56,14 @@ import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogWindowProvider import androidx.compose.ui.zIndex import androidx.navigation.NavHostController import coil.compose.AsyncImage +import com.anggrayudi.storage.extension.launchOnUiThread +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import org.ryujinx.android.MainActivity import org.ryujinx.android.R import org.ryujinx.android.viewmodels.GameModel @@ -143,14 +148,16 @@ class HomeViews { Column { TextButton(onClick = { navController.navigate("settings") - }, modifier = Modifier.fillMaxWidth() + }, modifier = Modifier + .fillMaxWidth() .align(Alignment.Start), ) { Icon( Icons.Filled.Settings, contentDescription = "Settings" ) - Text(text = "Settings", modifier = Modifier.padding(16.dp) + Text(text = "Settings", modifier = Modifier + .padding(16.dp) .align(Alignment.CenterVertically)) } } @@ -167,6 +174,7 @@ class HomeViews { val sheetState = rememberModalBottomSheetState() val scope = rememberCoroutineScope() val showBottomSheet = remember { mutableStateOf(false) } + val showLoading = remember { mutableStateOf(false) } Scaffold( modifier = Modifier.fillMaxSize(), @@ -198,11 +206,30 @@ class HomeViews { items(list) { it.titleName?.apply { if (this.isNotEmpty()) - GameItem(it, viewModel, showBottomSheet) + GameItem(it, viewModel, showBottomSheet, showLoading) } } } } + + if(showLoading.value){ + AlertDialog(onDismissRequest = { }) { + Card(modifier = Modifier + .padding(16.dp) + .fillMaxWidth(), + shape = MaterialTheme.shapes.medium) { + Column(modifier = Modifier + .padding(16.dp) + .fillMaxWidth()) { + Text(text = "Loading") + LinearProgressIndicator(modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp)) + } + + } + } + } if(showBottomSheet.value) { ModalBottomSheet(onDismissRequest = { @@ -264,15 +291,32 @@ class HomeViews { @OptIn(ExperimentalFoundationApi::class) @Composable - fun GameItem(gameModel: GameModel, viewModel: HomeViewModel, showSheet : MutableState) { - Card(shape = MaterialTheme.shapes.medium, + fun GameItem( + gameModel: GameModel, + viewModel: HomeViewModel, + showSheet: MutableState, + showLoading: MutableState + ) { + Surface(shape = MaterialTheme.shapes.medium, modifier = Modifier .fillMaxWidth() .padding(8.dp) .combinedClickable( onClick = { if (gameModel.titleId.isNullOrEmpty() || gameModel.titleId != "0000000000000000") { - viewModel.mainViewModel?.loadGame(gameModel) + runBlocking { + launch { + showLoading.value = true + val success = viewModel.mainViewModel?.loadGame(gameModel) ?: false + if(success) { + launchOnUiThread { + viewModel.mainViewModel?.activity?.setFullScreen() + viewModel.mainViewModel?.navController?.navigate("game") + } + } + showLoading.value = false + } + } } }, onLongClick = { diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt index 752b2c193..06a4f8c36 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt @@ -42,7 +42,7 @@ class MainView { @Composable fun Main(mainViewModel: MainViewModel) { val navController = rememberNavController() - mainViewModel.setNavController(navController) + mainViewModel.navController = navController NavHost(navController = navController, startDestination = "home") { composable("home") { HomeViews.Home(mainViewModel.homeViewModel, navController) }