diff options
| author | 2023-12-10 20:45:02 -0500 | |
|---|---|---|
| committer | 2023-12-12 17:25:37 -0500 | |
| commit | f2eb3c579f2de15410681014b47779d44d77fd48 (patch) | |
| tree | da874862efd26f0ebfdc84e7ea9b56d295032dde | |
| parent | android: Add per-game settings (diff) | |
| download | yuzu-f2eb3c579f2de15410681014b47779d44d77fd48.tar.gz yuzu-f2eb3c579f2de15410681014b47779d44d77fd48.tar.xz yuzu-f2eb3c579f2de15410681014b47779d44d77fd48.zip | |
android: Add per-game drivers
Diffstat (limited to '')
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 | |||
| 15 | import androidx.fragment.app.activityViewModels | 15 | import androidx.fragment.app.activityViewModels |
| 16 | import androidx.lifecycle.lifecycleScope | 16 | import androidx.lifecycle.lifecycleScope |
| 17 | import androidx.navigation.findNavController | 17 | import androidx.navigation.findNavController |
| 18 | import androidx.navigation.fragment.navArgs | ||
| 18 | import androidx.recyclerview.widget.GridLayoutManager | 19 | import androidx.recyclerview.widget.GridLayoutManager |
| 19 | import com.google.android.material.transition.MaterialSharedAxis | 20 | import com.google.android.material.transition.MaterialSharedAxis |
| 20 | import kotlinx.coroutines.flow.collectLatest | 21 | import 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 | |||
| 7 | import androidx.lifecycle.viewModelScope | 7 | import androidx.lifecycle.viewModelScope |
| 8 | import kotlinx.coroutines.Dispatchers | 8 | import kotlinx.coroutines.Dispatchers |
| 9 | import kotlinx.coroutines.flow.MutableStateFlow | 9 | import kotlinx.coroutines.flow.MutableStateFlow |
| 10 | import kotlinx.coroutines.flow.SharingStarted | ||
| 10 | import kotlinx.coroutines.flow.StateFlow | 11 | import kotlinx.coroutines.flow.StateFlow |
| 12 | import kotlinx.coroutines.flow.combine | ||
| 13 | import kotlinx.coroutines.flow.stateIn | ||
| 11 | import kotlinx.coroutines.launch | 14 | import kotlinx.coroutines.launch |
| 12 | import kotlinx.coroutines.withContext | 15 | import kotlinx.coroutines.withContext |
| 13 | import org.yuzu.yuzu_emu.R | 16 | import org.yuzu.yuzu_emu.R |
| 14 | import org.yuzu.yuzu_emu.YuzuApplication | 17 | import org.yuzu.yuzu_emu.YuzuApplication |
| 18 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | ||
| 19 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | ||
| 15 | import org.yuzu.yuzu_emu.utils.FileUtil | 20 | import org.yuzu.yuzu_emu.utils.FileUtil |
| 16 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 21 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
| 17 | import org.yuzu.yuzu_emu.utils.GpuDriverMetadata | 22 | import org.yuzu.yuzu_emu.utils.GpuDriverMetadata |
| 23 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 18 | import java.io.BufferedOutputStream | 24 | import java.io.BufferedOutputStream |
| 19 | import java.io.File | 25 | import java.io.File |
| 20 | 26 | ||
| 21 | class DriverViewModel : ViewModel() { | 27 | class 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 | |||
| 10 | import java.io.IOException | 10 | import java.io.IOException |
| 11 | import org.yuzu.yuzu_emu.NativeLibrary | 11 | import org.yuzu.yuzu_emu.NativeLibrary |
| 12 | import org.yuzu.yuzu_emu.YuzuApplication | 12 | import org.yuzu.yuzu_emu.YuzuApplication |
| 13 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | ||
| 14 | import java.io.FileNotFoundException | ||
| 13 | import java.util.zip.ZipException | 15 | import java.util.zip.ZipException |
| 14 | import java.util.zip.ZipFile | 16 | import 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 | ||
| 41 | void AndroidConfig::ReadAndroidUIValues() { | 42 | void AndroidConfig::ReadAndroidUIValues() { |
| @@ -57,6 +58,7 @@ void AndroidConfig::ReadUIValues() { | |||
| 57 | void AndroidConfig::ReadPathValues() { | 58 | void 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 | ||
| 76 | void AndroidConfig::ReadDriverValues() { | ||
| 77 | BeginGroup(Settings::TranslateCategory(Settings::Category::GpuDriver)); | ||
| 78 | |||
| 79 | ReadCategory(Settings::Category::GpuDriver); | ||
| 80 | |||
| 81 | EndGroup(); | ||
| 82 | } | ||
| 83 | |||
| 74 | void AndroidConfig::SaveAndroidValues() { | 84 | void 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 | ||
| 125 | void AndroidConfig::SaveDriverValues() { | ||
| 126 | BeginGroup(Settings::TranslateCategory(Settings::Category::GpuDriver)); | ||
| 127 | |||
| 128 | WriteCategory(Settings::Category::GpuDriver); | ||
| 129 | |||
| 130 | EndGroup(); | ||
| 131 | } | ||
| 132 | |||
| 114 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { | 133 | std::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: | |||
| 17 | protected: | 17 | protected: |
| 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 | ||
| 35 | extern Values values; | 38 | extern 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, |