|
|
@ -7,81 +7,83 @@ import androidx.lifecycle.ViewModel |
|
|
import androidx.lifecycle.viewModelScope |
|
|
import androidx.lifecycle.viewModelScope |
|
|
import kotlinx.coroutines.Dispatchers |
|
|
import kotlinx.coroutines.Dispatchers |
|
|
import kotlinx.coroutines.flow.MutableStateFlow |
|
|
import kotlinx.coroutines.flow.MutableStateFlow |
|
|
|
|
|
import kotlinx.coroutines.flow.SharingStarted |
|
|
import kotlinx.coroutines.flow.StateFlow |
|
|
import kotlinx.coroutines.flow.StateFlow |
|
|
|
|
|
import kotlinx.coroutines.flow.combine |
|
|
|
|
|
import kotlinx.coroutines.flow.stateIn |
|
|
import kotlinx.coroutines.launch |
|
|
import kotlinx.coroutines.launch |
|
|
import kotlinx.coroutines.withContext |
|
|
import kotlinx.coroutines.withContext |
|
|
import org.yuzu.yuzu_emu.R |
|
|
import org.yuzu.yuzu_emu.R |
|
|
import org.yuzu.yuzu_emu.YuzuApplication |
|
|
import org.yuzu.yuzu_emu.YuzuApplication |
|
|
|
|
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting |
|
|
|
|
|
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
|
|
import org.yuzu.yuzu_emu.utils.FileUtil |
|
|
import org.yuzu.yuzu_emu.utils.FileUtil |
|
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
|
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
|
|
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata |
|
|
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata |
|
|
|
|
|
import org.yuzu.yuzu_emu.utils.NativeConfig |
|
|
import java.io.BufferedOutputStream |
|
|
import java.io.BufferedOutputStream |
|
|
import java.io.File |
|
|
import java.io.File |
|
|
|
|
|
|
|
|
class DriverViewModel : ViewModel() { |
|
|
class DriverViewModel : ViewModel() { |
|
|
private val _areDriversLoading = MutableStateFlow(false) |
|
|
private val _areDriversLoading = MutableStateFlow(false) |
|
|
val areDriversLoading: StateFlow<Boolean> get() = _areDriversLoading |
|
|
|
|
|
|
|
|
|
|
|
private val _isDriverReady = MutableStateFlow(true) |
|
|
private val _isDriverReady = MutableStateFlow(true) |
|
|
val isDriverReady: StateFlow<Boolean> get() = _isDriverReady |
|
|
|
|
|
|
|
|
|
|
|
private val _isDeletingDrivers = MutableStateFlow(false) |
|
|
private val _isDeletingDrivers = MutableStateFlow(false) |
|
|
val isDeletingDrivers: StateFlow<Boolean> get() = _isDeletingDrivers |
|
|
|
|
|
|
|
|
|
|
|
private val _driverList = MutableStateFlow(mutableListOf<Pair<String, GpuDriverMetadata>>()) |
|
|
|
|
|
|
|
|
val isInteractionAllowed: StateFlow<Boolean> = |
|
|
|
|
|
combine( |
|
|
|
|
|
_areDriversLoading, |
|
|
|
|
|
_isDriverReady, |
|
|
|
|
|
_isDeletingDrivers |
|
|
|
|
|
) { loading, ready, deleting -> |
|
|
|
|
|
!loading && ready && !deleting |
|
|
|
|
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false) |
|
|
|
|
|
|
|
|
|
|
|
private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers()) |
|
|
val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList |
|
|
val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList |
|
|
|
|
|
|
|
|
var previouslySelectedDriver = 0 |
|
|
var previouslySelectedDriver = 0 |
|
|
var selectedDriver = -1 |
|
|
var selectedDriver = -1 |
|
|
|
|
|
|
|
|
private val _selectedDriverMetadata = |
|
|
|
|
|
MutableStateFlow( |
|
|
|
|
|
GpuDriverHelper.customDriverData.name |
|
|
|
|
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) |
|
|
|
|
|
) |
|
|
|
|
|
val selectedDriverMetadata: StateFlow<String> get() = _selectedDriverMetadata |
|
|
|
|
|
|
|
|
// Used for showing which driver is currently installed within the driver manager card |
|
|
|
|
|
private val _selectedDriverTitle = MutableStateFlow("") |
|
|
|
|
|
val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle |
|
|
|
|
|
|
|
|
private val _newDriverInstalled = MutableStateFlow(false) |
|
|
private val _newDriverInstalled = MutableStateFlow(false) |
|
|
val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled |
|
|
val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled |
|
|
|
|
|
|
|
|
val driversToDelete = mutableListOf<String>() |
|
|
val driversToDelete = mutableListOf<String>() |
|
|
|
|
|
|
|
|
val isInteractionAllowed |
|
|
|
|
|
get() = !areDriversLoading.value && isDriverReady.value && !isDeletingDrivers.value |
|
|
|
|
|
|
|
|
|
|
|
init { |
|
|
init { |
|
|
_areDriversLoading.value = true |
|
|
|
|
|
viewModelScope.launch { |
|
|
|
|
|
withContext(Dispatchers.IO) { |
|
|
|
|
|
val drivers = GpuDriverHelper.getDrivers() |
|
|
|
|
|
val currentDriverMetadata = GpuDriverHelper.customDriverData |
|
|
|
|
|
for (i in drivers.indices) { |
|
|
|
|
|
if (drivers[i].second == currentDriverMetadata) { |
|
|
|
|
|
setSelectedDriverIndex(i) |
|
|
|
|
|
break |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// If a user had installed a driver before the manager was implemented, this zips |
|
|
|
|
|
// the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can |
|
|
|
|
|
// be indexed and exported as expected. |
|
|
|
|
|
if (selectedDriver == -1) { |
|
|
|
|
|
val driverToSave = |
|
|
|
|
|
File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip") |
|
|
|
|
|
driverToSave.createNewFile() |
|
|
|
|
|
FileUtil.zipFromInternalStorage( |
|
|
|
|
|
File(GpuDriverHelper.driverInstallationPath!!), |
|
|
|
|
|
GpuDriverHelper.driverInstallationPath!!, |
|
|
|
|
|
BufferedOutputStream(driverToSave.outputStream()) |
|
|
|
|
|
) |
|
|
|
|
|
drivers.add(Pair(driverToSave.path, currentDriverMetadata)) |
|
|
|
|
|
setSelectedDriverIndex(drivers.size - 1) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
val currentDriverMetadata = GpuDriverHelper.installedCustomDriverData |
|
|
|
|
|
findSelectedDriver(currentDriverMetadata) |
|
|
|
|
|
|
|
|
|
|
|
// If a user had installed a driver before the manager was implemented, this zips |
|
|
|
|
|
// the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can |
|
|
|
|
|
// be indexed and exported as expected. |
|
|
|
|
|
if (selectedDriver == -1) { |
|
|
|
|
|
val driverToSave = |
|
|
|
|
|
File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip") |
|
|
|
|
|
driverToSave.createNewFile() |
|
|
|
|
|
FileUtil.zipFromInternalStorage( |
|
|
|
|
|
File(GpuDriverHelper.driverInstallationPath!!), |
|
|
|
|
|
GpuDriverHelper.driverInstallationPath!!, |
|
|
|
|
|
BufferedOutputStream(driverToSave.outputStream()) |
|
|
|
|
|
) |
|
|
|
|
|
_driverList.value.add(Pair(driverToSave.path, currentDriverMetadata)) |
|
|
|
|
|
setSelectedDriverIndex(_driverList.value.size - 1) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
_driverList.value = drivers |
|
|
|
|
|
_areDriversLoading.value = false |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// If a user had installed a driver before the config was reworked to be multiplatform, |
|
|
|
|
|
// we have save the path of the previously selected driver to the new setting. |
|
|
|
|
|
if (StringSetting.DRIVER_PATH.getString(true).isEmpty() && selectedDriver > 0 && |
|
|
|
|
|
StringSetting.DRIVER_PATH.global |
|
|
|
|
|
) { |
|
|
|
|
|
StringSetting.DRIVER_PATH.setString(_driverList.value[selectedDriver].first) |
|
|
|
|
|
NativeConfig.saveGlobalConfig() |
|
|
|
|
|
} else { |
|
|
|
|
|
findSelectedDriver(GpuDriverHelper.customDriverSettingData) |
|
|
} |
|
|
} |
|
|
|
|
|
updateDriverNameForGame(null) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fun setSelectedDriverIndex(value: Int) { |
|
|
fun setSelectedDriverIndex(value: Int) { |
|
|
@ -98,9 +100,9 @@ class DriverViewModel : ViewModel() { |
|
|
fun addDriver(driverData: Pair<String, GpuDriverMetadata>) { |
|
|
fun addDriver(driverData: Pair<String, GpuDriverMetadata>) { |
|
|
val driverIndex = _driverList.value.indexOfFirst { it == driverData } |
|
|
val driverIndex = _driverList.value.indexOfFirst { it == driverData } |
|
|
if (driverIndex == -1) { |
|
|
if (driverIndex == -1) { |
|
|
setSelectedDriverIndex(_driverList.value.size) |
|
|
|
|
|
_driverList.value.add(driverData) |
|
|
_driverList.value.add(driverData) |
|
|
_selectedDriverMetadata.value = driverData.second.name |
|
|
|
|
|
|
|
|
setSelectedDriverIndex(_driverList.value.size - 1) |
|
|
|
|
|
_selectedDriverTitle.value = driverData.second.name |
|
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) |
|
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) |
|
|
} else { |
|
|
} else { |
|
|
setSelectedDriverIndex(driverIndex) |
|
|
setSelectedDriverIndex(driverIndex) |
|
|
@ -111,8 +113,31 @@ class DriverViewModel : ViewModel() { |
|
|
_driverList.value.remove(driverData) |
|
|
_driverList.value.remove(driverData) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fun onCloseDriverManager() { |
|
|
|
|
|
|
|
|
fun onOpenDriverManager(game: Game?) { |
|
|
|
|
|
if (game != null) { |
|
|
|
|
|
SettingsFile.loadCustomConfig(game) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val driverPath = StringSetting.DRIVER_PATH.getString() |
|
|
|
|
|
if (driverPath.isEmpty()) { |
|
|
|
|
|
setSelectedDriverIndex(0) |
|
|
|
|
|
} else { |
|
|
|
|
|
findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath))) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun onCloseDriverManager(game: Game?) { |
|
|
_isDeletingDrivers.value = true |
|
|
_isDeletingDrivers.value = true |
|
|
|
|
|
StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first) |
|
|
|
|
|
updateDriverNameForGame(game) |
|
|
|
|
|
if (game == null) { |
|
|
|
|
|
NativeConfig.saveGlobalConfig() |
|
|
|
|
|
} else { |
|
|
|
|
|
NativeConfig.savePerGameConfig() |
|
|
|
|
|
NativeConfig.unloadPerGameConfig() |
|
|
|
|
|
NativeConfig.reloadGlobalConfig() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
viewModelScope.launch { |
|
|
viewModelScope.launch { |
|
|
withContext(Dispatchers.IO) { |
|
|
withContext(Dispatchers.IO) { |
|
|
driversToDelete.forEach { |
|
|
driversToDelete.forEach { |
|
|
@ -125,23 +150,29 @@ class DriverViewModel : ViewModel() { |
|
|
_isDeletingDrivers.value = false |
|
|
_isDeletingDrivers.value = false |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// It is the Emulation Fragment's responsibility to load per-game settings so that this function |
|
|
|
|
|
// knows what driver to load. |
|
|
|
|
|
fun onLaunchGame() { |
|
|
|
|
|
_isDriverReady.value = false |
|
|
|
|
|
|
|
|
if (GpuDriverHelper.customDriverData == driverList.value[selectedDriver].second) { |
|
|
|
|
|
|
|
|
val selectedDriverFile = File(StringSetting.DRIVER_PATH.getString()) |
|
|
|
|
|
val selectedDriverMetadata = GpuDriverHelper.customDriverSettingData |
|
|
|
|
|
if (GpuDriverHelper.installedCustomDriverData == selectedDriverMetadata) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
_isDriverReady.value = false |
|
|
|
|
|
viewModelScope.launch { |
|
|
viewModelScope.launch { |
|
|
withContext(Dispatchers.IO) { |
|
|
withContext(Dispatchers.IO) { |
|
|
if (selectedDriver == 0) { |
|
|
|
|
|
|
|
|
if (selectedDriverMetadata.name == null) { |
|
|
GpuDriverHelper.installDefaultDriver() |
|
|
GpuDriverHelper.installDefaultDriver() |
|
|
setDriverReady() |
|
|
setDriverReady() |
|
|
return@withContext |
|
|
return@withContext |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
val driverToInstall = File(driverList.value[selectedDriver].first) |
|
|
|
|
|
if (driverToInstall.exists()) { |
|
|
|
|
|
GpuDriverHelper.installCustomDriver(driverToInstall) |
|
|
|
|
|
|
|
|
if (selectedDriverFile.exists()) { |
|
|
|
|
|
GpuDriverHelper.installCustomDriver(selectedDriverFile) |
|
|
} else { |
|
|
} else { |
|
|
GpuDriverHelper.installDefaultDriver() |
|
|
GpuDriverHelper.installDefaultDriver() |
|
|
} |
|
|
} |
|
|
@ -150,9 +181,43 @@ class DriverViewModel : ViewModel() { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun findSelectedDriver(currentDriverMetadata: GpuDriverMetadata) { |
|
|
|
|
|
if (driverList.value.size == 1) { |
|
|
|
|
|
setSelectedDriverIndex(0) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
driverList.value.forEachIndexed { i: Int, driver: Pair<String, GpuDriverMetadata> -> |
|
|
|
|
|
if (driver.second == currentDriverMetadata) { |
|
|
|
|
|
setSelectedDriverIndex(i) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun updateDriverNameForGame(game: Game?) { |
|
|
|
|
|
if (!GpuDriverHelper.supportsCustomDriverLoading()) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (game == null || NativeConfig.isPerGameConfigLoaded()) { |
|
|
|
|
|
updateName() |
|
|
|
|
|
} else { |
|
|
|
|
|
SettingsFile.loadCustomConfig(game) |
|
|
|
|
|
updateName() |
|
|
|
|
|
NativeConfig.unloadPerGameConfig() |
|
|
|
|
|
NativeConfig.reloadGlobalConfig() |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun updateName() { |
|
|
|
|
|
_selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name |
|
|
|
|
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private fun setDriverReady() { |
|
|
private fun setDriverReady() { |
|
|
_isDriverReady.value = true |
|
|
_isDriverReady.value = true |
|
|
_selectedDriverMetadata.value = GpuDriverHelper.customDriverData.name |
|
|
|
|
|
|
|
|
_selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name |
|
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) |
|
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |