summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar t8952023-12-10 20:45:02 -0500
committerGravatar t8952023-12-12 17:25:37 -0500
commitf2eb3c579f2de15410681014b47779d44d77fd48 (patch)
treeda874862efd26f0ebfdc84e7ea9b56d295032dde
parentandroid: Add per-game settings (diff)
downloadyuzu-f2eb3c579f2de15410681014b47779d44d77fd48.tar.gz
yuzu-f2eb3c579f2de15410681014b47779d44d77fd48.tar.xz
yuzu-f2eb3c579f2de15410681014b47779d44d77fd48.zip
android: Add per-game drivers
Diffstat (limited to '')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt18
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt24
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt15
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt17
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt175
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt10
-rw-r--r--src/android/app/src/main/jni/android_config.cpp19
-rw-r--r--src/android/app/src/main/jni/android_config.h2
-rw-r--r--src/android/app/src/main/jni/android_settings.h3
-rw-r--r--src/android/app/src/main/res/navigation/home_navigation.xml11
-rw-r--r--src/common/settings.cpp2
-rw-r--r--src/common/settings_common.h1
14 files changed, 218 insertions, 95 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
index 0e818cab9..d290a656c 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
@@ -42,7 +42,7 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
42 if (driverViewModel.selectedDriver > position) { 42 if (driverViewModel.selectedDriver > position) {
43 driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1) 43 driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1)
44 } 44 }
45 if (GpuDriverHelper.customDriverData == driverData.second) { 45 if (GpuDriverHelper.customDriverSettingData == driverData.second) {
46 driverViewModel.setSelectedDriverIndex(0) 46 driverViewModel.setSelectedDriverIndex(0)
47 } 47 }
48 driverViewModel.driversToDelete.add(driverData.first) 48 driverViewModel.driversToDelete.add(driverData.first)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt
index df21d74b2..cc71254dc 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt
@@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment
15import androidx.fragment.app.activityViewModels 15import androidx.fragment.app.activityViewModels
16import androidx.lifecycle.lifecycleScope 16import androidx.lifecycle.lifecycleScope
17import androidx.navigation.findNavController 17import androidx.navigation.findNavController
18import androidx.navigation.fragment.navArgs
18import androidx.recyclerview.widget.GridLayoutManager 19import androidx.recyclerview.widget.GridLayoutManager
19import com.google.android.material.transition.MaterialSharedAxis 20import com.google.android.material.transition.MaterialSharedAxis
20import kotlinx.coroutines.flow.collectLatest 21import kotlinx.coroutines.flow.collectLatest
@@ -36,6 +37,8 @@ class DriverManagerFragment : Fragment() {
36 private val homeViewModel: HomeViewModel by activityViewModels() 37 private val homeViewModel: HomeViewModel by activityViewModels()
37 private val driverViewModel: DriverViewModel by activityViewModels() 38 private val driverViewModel: DriverViewModel by activityViewModels()
38 39
40 private val args by navArgs<DriverManagerFragmentArgs>()
41
39 override fun onCreate(savedInstanceState: Bundle?) { 42 override fun onCreate(savedInstanceState: Bundle?) {
40 super.onCreate(savedInstanceState) 43 super.onCreate(savedInstanceState)
41 enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) 44 enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
@@ -57,7 +60,9 @@ class DriverManagerFragment : Fragment() {
57 homeViewModel.setNavigationVisibility(visible = false, animated = true) 60 homeViewModel.setNavigationVisibility(visible = false, animated = true)
58 homeViewModel.setStatusBarShadeVisibility(visible = false) 61 homeViewModel.setStatusBarShadeVisibility(visible = false)
59 62
60 if (!driverViewModel.isInteractionAllowed) { 63 driverViewModel.onOpenDriverManager(args.game)
64
65 if (!driverViewModel.isInteractionAllowed.value) {
61 DriversLoadingDialogFragment().show( 66 DriversLoadingDialogFragment().show(
62 childFragmentManager, 67 childFragmentManager,
63 DriversLoadingDialogFragment.TAG 68 DriversLoadingDialogFragment.TAG
@@ -102,10 +107,9 @@ class DriverManagerFragment : Fragment() {
102 setInsets() 107 setInsets()
103 } 108 }
104 109
105 // Start installing requested driver 110 override fun onDestroy() {
106 override fun onStop() { 111 super.onDestroy()
107 super.onStop() 112 driverViewModel.onCloseDriverManager(args.game)
108 driverViewModel.onCloseDriverManager()
109 } 113 }
110 114
111 private fun setInsets() = 115 private fun setInsets() =
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt
index f8c34346a..6a47b29f0 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt
@@ -47,25 +47,9 @@ class DriversLoadingDialogFragment : DialogFragment() {
47 viewLifecycleOwner.lifecycleScope.apply { 47 viewLifecycleOwner.lifecycleScope.apply {
48 launch { 48 launch {
49 repeatOnLifecycle(Lifecycle.State.RESUMED) { 49 repeatOnLifecycle(Lifecycle.State.RESUMED) {
50 driverViewModel.areDriversLoading.collect { checkForDismiss() } 50 driverViewModel.isInteractionAllowed.collect { if (it) dismiss() }
51 } 51 }
52 } 52 }
53 launch {
54 repeatOnLifecycle(Lifecycle.State.RESUMED) {
55 driverViewModel.isDriverReady.collect { checkForDismiss() }
56 }
57 }
58 launch {
59 repeatOnLifecycle(Lifecycle.State.RESUMED) {
60 driverViewModel.isDeletingDrivers.collect { checkForDismiss() }
61 }
62 }
63 }
64 }
65
66 private fun checkForDismiss() {
67 if (driverViewModel.isInteractionAllowed) {
68 dismiss()
69 } 53 }
70 } 54 }
71 55
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 6466442d5..c40f5f41a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -352,15 +352,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
352 } 352 }
353 launch { 353 launch {
354 repeatOnLifecycle(Lifecycle.State.RESUMED) { 354 repeatOnLifecycle(Lifecycle.State.RESUMED) {
355 driverViewModel.isDriverReady.collect { 355 driverViewModel.isInteractionAllowed.collect {
356 if (it && !emulationState.isRunning) { 356 if (it) {
357 if (!DirectoryInitialization.areDirectoriesReady) { 357 onEmulationStart()
358 DirectoryInitialization.start()
359 }
360
361 updateScreenLayout()
362
363 emulationState.run(emulationActivity!!.isActivityRecreated)
364 } 358 }
365 } 359 }
366 } 360 }
@@ -368,6 +362,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
368 } 362 }
369 } 363 }
370 364
365 private fun onEmulationStart() {
366 if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
367 if (!DirectoryInitialization.areDirectoriesReady) {
368 DirectoryInitialization.start()
369 }
370
371 updateScreenLayout()
372
373 emulationState.run(emulationActivity!!.isActivityRecreated)
374 }
375 }
376
371 override fun onConfigurationChanged(newConfig: Configuration) { 377 override fun onConfigurationChanged(newConfig: Configuration) {
372 super.onConfigurationChanged(newConfig) 378 super.onConfigurationChanged(newConfig)
373 if (_binding == null) { 379 if (_binding == null) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
index 485989e2e..e062425a1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
@@ -148,6 +148,21 @@ class GamePropertiesFragment : Fragment() {
148 } 148 }
149 ) 149 )
150 150
151 if (GpuDriverHelper.supportsCustomDriverLoading()) {
152 add(
153 SubmenuProperty(
154 R.string.gpu_driver_manager,
155 R.string.install_gpu_driver_description,
156 R.drawable.ic_build,
157 detailsFlow = driverViewModel.selectedDriverTitle
158 ) {
159 val action = GamePropertiesFragmentDirections
160 .actionPerGamePropertiesFragmentToDriverManagerFragment(args.game)
161 binding.root.findNavController().navigate(action)
162 }
163 )
164 }
165
151 if (!args.game.isHomebrew) { 166 if (!args.game.isHomebrew) {
152 add( 167 add(
153 SubmenuProperty( 168 SubmenuProperty(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
index 3addc2e63..6ddd758e6 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
@@ -68,6 +68,9 @@ class HomeSettingsFragment : Fragment() {
68 } 68 }
69 69
70 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 70 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
71 super.onViewCreated(view, savedInstanceState)
72 homeViewModel.setNavigationVisibility(visible = true, animated = true)
73 homeViewModel.setStatusBarShadeVisibility(visible = true)
71 mainActivity = requireActivity() as MainActivity 74 mainActivity = requireActivity() as MainActivity
72 75
73 val optionsList: MutableList<HomeSetting> = mutableListOf<HomeSetting>().apply { 76 val optionsList: MutableList<HomeSetting> = mutableListOf<HomeSetting>().apply {
@@ -91,13 +94,14 @@ class HomeSettingsFragment : Fragment() {
91 R.string.install_gpu_driver_description, 94 R.string.install_gpu_driver_description,
92 R.drawable.ic_build, 95 R.drawable.ic_build,
93 { 96 {
94 binding.root.findNavController() 97 val action = HomeSettingsFragmentDirections
95 .navigate(R.id.action_homeSettingsFragment_to_driverManagerFragment) 98 .actionHomeSettingsFragmentToDriverManagerFragment(null)
99 binding.root.findNavController().navigate(action)
96 }, 100 },
97 { GpuDriverHelper.supportsCustomDriverLoading() }, 101 { GpuDriverHelper.supportsCustomDriverLoading() },
98 R.string.custom_driver_not_supported, 102 R.string.custom_driver_not_supported,
99 R.string.custom_driver_not_supported_description, 103 R.string.custom_driver_not_supported_description,
100 driverViewModel.selectedDriverMetadata 104 driverViewModel.selectedDriverTitle
101 ) 105 )
102 ) 106 )
103 add( 107 add(
@@ -212,8 +216,11 @@ class HomeSettingsFragment : Fragment() {
212 override fun onStart() { 216 override fun onStart() {
213 super.onStart() 217 super.onStart()
214 exitTransition = null 218 exitTransition = null
215 homeViewModel.setNavigationVisibility(visible = true, animated = true) 219 }
216 homeViewModel.setStatusBarShadeVisibility(visible = true) 220
221 override fun onResume() {
222 super.onResume()
223 driverViewModel.updateDriverNameForGame(null)
217 } 224 }
218 225
219 override fun onDestroyView() { 226 override fun onDestroyView() {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
index 62945ad65..76accf8f3 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
@@ -7,81 +7,83 @@ import androidx.lifecycle.ViewModel
7import androidx.lifecycle.viewModelScope 7import androidx.lifecycle.viewModelScope
8import kotlinx.coroutines.Dispatchers 8import kotlinx.coroutines.Dispatchers
9import kotlinx.coroutines.flow.MutableStateFlow 9import kotlinx.coroutines.flow.MutableStateFlow
10import kotlinx.coroutines.flow.SharingStarted
10import kotlinx.coroutines.flow.StateFlow 11import kotlinx.coroutines.flow.StateFlow
12import kotlinx.coroutines.flow.combine
13import kotlinx.coroutines.flow.stateIn
11import kotlinx.coroutines.launch 14import kotlinx.coroutines.launch
12import kotlinx.coroutines.withContext 15import kotlinx.coroutines.withContext
13import org.yuzu.yuzu_emu.R 16import org.yuzu.yuzu_emu.R
14import org.yuzu.yuzu_emu.YuzuApplication 17import org.yuzu.yuzu_emu.YuzuApplication
18import org.yuzu.yuzu_emu.features.settings.model.StringSetting
19import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
15import org.yuzu.yuzu_emu.utils.FileUtil 20import org.yuzu.yuzu_emu.utils.FileUtil
16import org.yuzu.yuzu_emu.utils.GpuDriverHelper 21import org.yuzu.yuzu_emu.utils.GpuDriverHelper
17import org.yuzu.yuzu_emu.utils.GpuDriverMetadata 22import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
23import org.yuzu.yuzu_emu.utils.NativeConfig
18import java.io.BufferedOutputStream 24import java.io.BufferedOutputStream
19import java.io.File 25import java.io.File
20 26
21class DriverViewModel : ViewModel() { 27class DriverViewModel : ViewModel() {
22 private val _areDriversLoading = MutableStateFlow(false) 28 private val _areDriversLoading = MutableStateFlow(false)
23 val areDriversLoading: StateFlow<Boolean> get() = _areDriversLoading
24
25 private val _isDriverReady = MutableStateFlow(true) 29 private val _isDriverReady = MutableStateFlow(true)
26 val isDriverReady: StateFlow<Boolean> get() = _isDriverReady
27
28 private val _isDeletingDrivers = MutableStateFlow(false) 30 private val _isDeletingDrivers = MutableStateFlow(false)
29 val isDeletingDrivers: StateFlow<Boolean> get() = _isDeletingDrivers
30 31
31 private val _driverList = MutableStateFlow(mutableListOf<Pair<String, GpuDriverMetadata>>()) 32 val isInteractionAllowed: StateFlow<Boolean> =
33 combine(
34 _areDriversLoading,
35 _isDriverReady,
36 _isDeletingDrivers
37 ) { loading, ready, deleting ->
38 !loading && ready && !deleting
39 }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false)
40
41 private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers())
32 val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList 42 val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList
33 43
34 var previouslySelectedDriver = 0 44 var previouslySelectedDriver = 0
35 var selectedDriver = -1 45 var selectedDriver = -1
36 46
37 private val _selectedDriverMetadata = 47 // Used for showing which driver is currently installed within the driver manager card
38 MutableStateFlow( 48 private val _selectedDriverTitle = MutableStateFlow("")
39 GpuDriverHelper.customDriverData.name 49 val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle
40 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
41 )
42 val selectedDriverMetadata: StateFlow<String> get() = _selectedDriverMetadata
43 50
44 private val _newDriverInstalled = MutableStateFlow(false) 51 private val _newDriverInstalled = MutableStateFlow(false)
45 val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled 52 val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled
46 53
47 val driversToDelete = mutableListOf<String>() 54 val driversToDelete = mutableListOf<String>()
48 55
49 val isInteractionAllowed
50 get() = !areDriversLoading.value && isDriverReady.value && !isDeletingDrivers.value
51
52 init { 56 init {
53 _areDriversLoading.value = true 57 val currentDriverMetadata = GpuDriverHelper.installedCustomDriverData
54 viewModelScope.launch { 58 findSelectedDriver(currentDriverMetadata)
55 withContext(Dispatchers.IO) { 59
56 val drivers = GpuDriverHelper.getDrivers() 60 // If a user had installed a driver before the manager was implemented, this zips
57 val currentDriverMetadata = GpuDriverHelper.customDriverData 61 // the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can
58 for (i in drivers.indices) { 62 // be indexed and exported as expected.
59 if (drivers[i].second == currentDriverMetadata) { 63 if (selectedDriver == -1) {
60 setSelectedDriverIndex(i) 64 val driverToSave =
61 break 65 File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip")
62 } 66 driverToSave.createNewFile()
63 } 67 FileUtil.zipFromInternalStorage(
64 68 File(GpuDriverHelper.driverInstallationPath!!),
65 // If a user had installed a driver before the manager was implemented, this zips 69 GpuDriverHelper.driverInstallationPath!!,
66 // the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can 70 BufferedOutputStream(driverToSave.outputStream())
67 // be indexed and exported as expected. 71 )
68 if (selectedDriver == -1) { 72 _driverList.value.add(Pair(driverToSave.path, currentDriverMetadata))
69 val driverToSave = 73 setSelectedDriverIndex(_driverList.value.size - 1)
70 File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip") 74 }
71 driverToSave.createNewFile()
72 FileUtil.zipFromInternalStorage(
73 File(GpuDriverHelper.driverInstallationPath!!),
74 GpuDriverHelper.driverInstallationPath!!,
75 BufferedOutputStream(driverToSave.outputStream())
76 )
77 drivers.add(Pair(driverToSave.path, currentDriverMetadata))
78 setSelectedDriverIndex(drivers.size - 1)
79 }
80 75
81 _driverList.value = drivers 76 // If a user had installed a driver before the config was reworked to be multiplatform,
82 _areDriversLoading.value = false 77 // we have save the path of the previously selected driver to the new setting.
83 } 78 if (StringSetting.DRIVER_PATH.getString(true).isEmpty() && selectedDriver > 0 &&
79 StringSetting.DRIVER_PATH.global
80 ) {
81 StringSetting.DRIVER_PATH.setString(_driverList.value[selectedDriver].first)
82 NativeConfig.saveGlobalConfig()
83 } else {
84 findSelectedDriver(GpuDriverHelper.customDriverSettingData)
84 } 85 }
86 updateDriverNameForGame(null)
85 } 87 }
86 88
87 fun setSelectedDriverIndex(value: Int) { 89 fun setSelectedDriverIndex(value: Int) {
@@ -98,9 +100,9 @@ class DriverViewModel : ViewModel() {
98 fun addDriver(driverData: Pair<String, GpuDriverMetadata>) { 100 fun addDriver(driverData: Pair<String, GpuDriverMetadata>) {
99 val driverIndex = _driverList.value.indexOfFirst { it == driverData } 101 val driverIndex = _driverList.value.indexOfFirst { it == driverData }
100 if (driverIndex == -1) { 102 if (driverIndex == -1) {
101 setSelectedDriverIndex(_driverList.value.size)
102 _driverList.value.add(driverData) 103 _driverList.value.add(driverData)
103 _selectedDriverMetadata.value = driverData.second.name 104 setSelectedDriverIndex(_driverList.value.size - 1)
105 _selectedDriverTitle.value = driverData.second.name
104 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) 106 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
105 } else { 107 } else {
106 setSelectedDriverIndex(driverIndex) 108 setSelectedDriverIndex(driverIndex)
@@ -111,8 +113,31 @@ class DriverViewModel : ViewModel() {
111 _driverList.value.remove(driverData) 113 _driverList.value.remove(driverData)
112 } 114 }
113 115
114 fun onCloseDriverManager() { 116 fun onOpenDriverManager(game: Game?) {
117 if (game != null) {
118 SettingsFile.loadCustomConfig(game)
119 }
120
121 val driverPath = StringSetting.DRIVER_PATH.getString()
122 if (driverPath.isEmpty()) {
123 setSelectedDriverIndex(0)
124 } else {
125 findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath)))
126 }
127 }
128
129 fun onCloseDriverManager(game: Game?) {
115 _isDeletingDrivers.value = true 130 _isDeletingDrivers.value = true
131 StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first)
132 updateDriverNameForGame(game)
133 if (game == null) {
134 NativeConfig.saveGlobalConfig()
135 } else {
136 NativeConfig.savePerGameConfig()
137 NativeConfig.unloadPerGameConfig()
138 NativeConfig.reloadGlobalConfig()
139 }
140
116 viewModelScope.launch { 141 viewModelScope.launch {
117 withContext(Dispatchers.IO) { 142 withContext(Dispatchers.IO) {
118 driversToDelete.forEach { 143 driversToDelete.forEach {
@@ -125,23 +150,29 @@ class DriverViewModel : ViewModel() {
125 _isDeletingDrivers.value = false 150 _isDeletingDrivers.value = false
126 } 151 }
127 } 152 }
153 }
154
155 // It is the Emulation Fragment's responsibility to load per-game settings so that this function
156 // knows what driver to load.
157 fun onLaunchGame() {
158 _isDriverReady.value = false
128 159
129 if (GpuDriverHelper.customDriverData == driverList.value[selectedDriver].second) { 160 val selectedDriverFile = File(StringSetting.DRIVER_PATH.getString())
161 val selectedDriverMetadata = GpuDriverHelper.customDriverSettingData
162 if (GpuDriverHelper.installedCustomDriverData == selectedDriverMetadata) {
130 return 163 return
131 } 164 }
132 165
133 _isDriverReady.value = false
134 viewModelScope.launch { 166 viewModelScope.launch {
135 withContext(Dispatchers.IO) { 167 withContext(Dispatchers.IO) {
136 if (selectedDriver == 0) { 168 if (selectedDriverMetadata.name == null) {
137 GpuDriverHelper.installDefaultDriver() 169 GpuDriverHelper.installDefaultDriver()
138 setDriverReady() 170 setDriverReady()
139 return@withContext 171 return@withContext
140 } 172 }
141 173
142 val driverToInstall = File(driverList.value[selectedDriver].first) 174 if (selectedDriverFile.exists()) {
143 if (driverToInstall.exists()) { 175 GpuDriverHelper.installCustomDriver(selectedDriverFile)
144 GpuDriverHelper.installCustomDriver(driverToInstall)
145 } else { 176 } else {
146 GpuDriverHelper.installDefaultDriver() 177 GpuDriverHelper.installDefaultDriver()
147 } 178 }
@@ -150,9 +181,43 @@ class DriverViewModel : ViewModel() {
150 } 181 }
151 } 182 }
152 183
184 private fun findSelectedDriver(currentDriverMetadata: GpuDriverMetadata) {
185 if (driverList.value.size == 1) {
186 setSelectedDriverIndex(0)
187 return
188 }
189
190 driverList.value.forEachIndexed { i: Int, driver: Pair<String, GpuDriverMetadata> ->
191 if (driver.second == currentDriverMetadata) {
192 setSelectedDriverIndex(i)
193 return
194 }
195 }
196 }
197
198 fun updateDriverNameForGame(game: Game?) {
199 if (!GpuDriverHelper.supportsCustomDriverLoading()) {
200 return
201 }
202
203 if (game == null || NativeConfig.isPerGameConfigLoaded()) {
204 updateName()
205 } else {
206 SettingsFile.loadCustomConfig(game)
207 updateName()
208 NativeConfig.unloadPerGameConfig()
209 NativeConfig.reloadGlobalConfig()
210 }
211 }
212
213 private fun updateName() {
214 _selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name
215 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
216 }
217
153 private fun setDriverReady() { 218 private fun setDriverReady() {
154 _isDriverReady.value = true 219 _isDriverReady.value = true
155 _selectedDriverMetadata.value = GpuDriverHelper.customDriverData.name 220 _selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name
156 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) 221 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
157 } 222 }
158} 223}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
index f6882ce6c..685272288 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
@@ -10,6 +10,8 @@ import java.io.File
10import java.io.IOException 10import java.io.IOException
11import org.yuzu.yuzu_emu.NativeLibrary 11import org.yuzu.yuzu_emu.NativeLibrary
12import org.yuzu.yuzu_emu.YuzuApplication 12import org.yuzu.yuzu_emu.YuzuApplication
13import org.yuzu.yuzu_emu.features.settings.model.StringSetting
14import java.io.FileNotFoundException
13import java.util.zip.ZipException 15import java.util.zip.ZipException
14import java.util.zip.ZipFile 16import java.util.zip.ZipFile
15 17
@@ -44,7 +46,7 @@ object GpuDriverHelper {
44 NativeLibrary.initializeGpuDriver( 46 NativeLibrary.initializeGpuDriver(
45 hookLibPath, 47 hookLibPath,
46 driverInstallationPath, 48 driverInstallationPath,
47 customDriverData.libraryName, 49 installedCustomDriverData.libraryName,
48 fileRedirectionPath 50 fileRedirectionPath
49 ) 51 )
50 } 52 }
@@ -190,6 +192,7 @@ object GpuDriverHelper {
190 } 192 }
191 } 193 }
192 } catch (_: ZipException) { 194 } catch (_: ZipException) {
195 } catch (_: FileNotFoundException) {
193 } 196 }
194 return GpuDriverMetadata() 197 return GpuDriverMetadata()
195 } 198 }
@@ -197,9 +200,12 @@ object GpuDriverHelper {
197 external fun supportsCustomDriverLoading(): Boolean 200 external fun supportsCustomDriverLoading(): Boolean
198 201
199 // Parse the custom driver metadata to retrieve the name. 202 // Parse the custom driver metadata to retrieve the name.
200 val customDriverData: GpuDriverMetadata 203 val installedCustomDriverData: GpuDriverMetadata
201 get() = GpuDriverMetadata(File(driverInstallationPath + META_JSON_FILENAME)) 204 get() = GpuDriverMetadata(File(driverInstallationPath + META_JSON_FILENAME))
202 205
206 val customDriverSettingData: GpuDriverMetadata
207 get() = getMetadataFromZip(File(StringSetting.DRIVER_PATH.getString()))
208
203 fun initializeDirectories() { 209 fun initializeDirectories() {
204 // Ensure the file redirection directory exists. 210 // Ensure the file redirection directory exists.
205 val fileRedirectionDir = File(fileRedirectionPath!!) 211 val fileRedirectionDir = File(fileRedirectionPath!!)
diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp
index 767d8ea83..9c3a5a9b2 100644
--- a/src/android/app/src/main/jni/android_config.cpp
+++ b/src/android/app/src/main/jni/android_config.cpp
@@ -36,6 +36,7 @@ void AndroidConfig::ReadAndroidValues() {
36 ReadAndroidUIValues(); 36 ReadAndroidUIValues();
37 ReadUIValues(); 37 ReadUIValues();
38 } 38 }
39 ReadDriverValues();
39} 40}
40 41
41void AndroidConfig::ReadAndroidUIValues() { 42void AndroidConfig::ReadAndroidUIValues() {
@@ -57,6 +58,7 @@ void AndroidConfig::ReadUIValues() {
57void AndroidConfig::ReadPathValues() { 58void AndroidConfig::ReadPathValues() {
58 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); 59 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
59 60
61 AndroidSettings::values.game_dirs.clear();
60 const int gamedirs_size = BeginArray(std::string("gamedirs")); 62 const int gamedirs_size = BeginArray(std::string("gamedirs"));
61 for (int i = 0; i < gamedirs_size; ++i) { 63 for (int i = 0; i < gamedirs_size; ++i) {
62 SetArrayIndex(i); 64 SetArrayIndex(i);
@@ -71,11 +73,20 @@ void AndroidConfig::ReadPathValues() {
71 EndGroup(); 73 EndGroup();
72} 74}
73 75
76void AndroidConfig::ReadDriverValues() {
77 BeginGroup(Settings::TranslateCategory(Settings::Category::GpuDriver));
78
79 ReadCategory(Settings::Category::GpuDriver);
80
81 EndGroup();
82}
83
74void AndroidConfig::SaveAndroidValues() { 84void AndroidConfig::SaveAndroidValues() {
75 if (global) { 85 if (global) {
76 SaveAndroidUIValues(); 86 SaveAndroidUIValues();
77 SaveUIValues(); 87 SaveUIValues();
78 } 88 }
89 SaveDriverValues();
79 90
80 WriteToIni(); 91 WriteToIni();
81} 92}
@@ -111,6 +122,14 @@ void AndroidConfig::SavePathValues() {
111 EndGroup(); 122 EndGroup();
112} 123}
113 124
125void AndroidConfig::SaveDriverValues() {
126 BeginGroup(Settings::TranslateCategory(Settings::Category::GpuDriver));
127
128 WriteCategory(Settings::Category::GpuDriver);
129
130 EndGroup();
131}
132
114std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { 133std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) {
115 auto& map = Settings::values.linkage.by_category; 134 auto& map = Settings::values.linkage.by_category;
116 if (map.contains(category)) { 135 if (map.contains(category)) {
diff --git a/src/android/app/src/main/jni/android_config.h b/src/android/app/src/main/jni/android_config.h
index f490be016..2c12874e1 100644
--- a/src/android/app/src/main/jni/android_config.h
+++ b/src/android/app/src/main/jni/android_config.h
@@ -17,6 +17,7 @@ public:
17protected: 17protected:
18 void ReadAndroidValues(); 18 void ReadAndroidValues();
19 void ReadAndroidUIValues(); 19 void ReadAndroidUIValues();
20 void ReadDriverValues();
20 void ReadHidbusValues() override {} 21 void ReadHidbusValues() override {}
21 void ReadDebugControlValues() override {} 22 void ReadDebugControlValues() override {}
22 void ReadPathValues() override; 23 void ReadPathValues() override;
@@ -28,6 +29,7 @@ protected:
28 29
29 void SaveAndroidValues(); 30 void SaveAndroidValues();
30 void SaveAndroidUIValues(); 31 void SaveAndroidUIValues();
32 void SaveDriverValues();
31 void SaveHidbusValues() override {} 33 void SaveHidbusValues() override {}
32 void SaveDebugControlValues() override {} 34 void SaveDebugControlValues() override {}
33 void SavePathValues() override; 35 void SavePathValues() override;
diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h
index fc0523206..3733f5a3c 100644
--- a/src/android/app/src/main/jni/android_settings.h
+++ b/src/android/app/src/main/jni/android_settings.h
@@ -30,6 +30,9 @@ struct Values {
30 Settings::Specialization::Default, 30 Settings::Specialization::Default,
31 true, 31 true,
32 true}; 32 true};
33
34 Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path",
35 Settings::Category::GpuDriver};
33}; 36};
34 37
35extern Values values; 38extern Values values;
diff --git a/src/android/app/src/main/res/navigation/home_navigation.xml b/src/android/app/src/main/res/navigation/home_navigation.xml
index 226cf5600..37a03a8d1 100644
--- a/src/android/app/src/main/res/navigation/home_navigation.xml
+++ b/src/android/app/src/main/res/navigation/home_navigation.xml
@@ -111,7 +111,13 @@
111 <fragment 111 <fragment
112 android:id="@+id/driverManagerFragment" 112 android:id="@+id/driverManagerFragment"
113 android:name="org.yuzu.yuzu_emu.fragments.DriverManagerFragment" 113 android:name="org.yuzu.yuzu_emu.fragments.DriverManagerFragment"
114 android:label="DriverManagerFragment" /> 114 android:label="DriverManagerFragment" >
115 <argument
116 android:name="game"
117 app:argType="org.yuzu.yuzu_emu.model.Game"
118 app:nullable="true"
119 android:defaultValue="@null" />
120 </fragment>
115 <fragment 121 <fragment
116 android:id="@+id/appletLauncherFragment" 122 android:id="@+id/appletLauncherFragment"
117 android:name="org.yuzu.yuzu_emu.fragments.AppletLauncherFragment" 123 android:name="org.yuzu.yuzu_emu.fragments.AppletLauncherFragment"
@@ -141,6 +147,9 @@
141 <action 147 <action
142 android:id="@+id/action_perGamePropertiesFragment_to_addonsFragment" 148 android:id="@+id/action_perGamePropertiesFragment_to_addonsFragment"
143 app:destination="@id/addonsFragment" /> 149 app:destination="@id/addonsFragment" />
150 <action
151 android:id="@+id/action_perGamePropertiesFragment_to_driverManagerFragment"
152 app:destination="@id/driverManagerFragment" />
144 </fragment> 153 </fragment>
145 <action 154 <action
146 android:id="@+id/action_global_perGamePropertiesFragment" 155 android:id="@+id/action_global_perGamePropertiesFragment"
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 88f509ba7..ea52bbfa6 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -211,6 +211,8 @@ const char* TranslateCategory(Category category) {
211 case Category::Debugging: 211 case Category::Debugging:
212 case Category::DebuggingGraphics: 212 case Category::DebuggingGraphics:
213 return "Debugging"; 213 return "Debugging";
214 case Category::GpuDriver:
215 return "GpuDriver";
214 case Category::Miscellaneous: 216 case Category::Miscellaneous:
215 return "Miscellaneous"; 217 return "Miscellaneous";
216 case Category::Network: 218 case Category::Network:
diff --git a/src/common/settings_common.h b/src/common/settings_common.h
index 344c04439..c82e17495 100644
--- a/src/common/settings_common.h
+++ b/src/common/settings_common.h
@@ -26,6 +26,7 @@ enum class Category : u32 {
26 DataStorage, 26 DataStorage,
27 Debugging, 27 Debugging,
28 DebuggingGraphics, 28 DebuggingGraphics,
29 GpuDriver,
29 Miscellaneous, 30 Miscellaneous,
30 Network, 31 Network,
31 WebService, 32 WebService,