|
|
|
@ -7,81 +7,83 @@ import androidx.lifecycle.ViewModel
|
|
|
|
|
import androidx.lifecycle.viewModelScope
|
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
|
|
|
import kotlinx.coroutines.flow.SharingStarted
|
|
|
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
|
|
|
import kotlinx.coroutines.flow.combine
|
|
|
|
|
import kotlinx.coroutines.flow.stateIn
|
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
|
import kotlinx.coroutines.withContext
|
|
|
|
|
import org.yuzu.yuzu_emu.R
|
|
|
|
|
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.GpuDriverHelper
|
|
|
|
|
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
|
|
|
|
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
|
|
|
|
import java.io.BufferedOutputStream
|
|
|
|
|
import java.io.File
|
|
|
|
|
|
|
|
|
|
class DriverViewModel : ViewModel() {
|
|
|
|
|
private val _areDriversLoading = MutableStateFlow(false)
|
|
|
|
|
val areDriversLoading: StateFlow<Boolean> get() = _areDriversLoading
|
|
|
|
|
|
|
|
|
|
private val _isDriverReady = MutableStateFlow(true)
|
|
|
|
|
val isDriverReady: StateFlow<Boolean> get() = _isDriverReady
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
var previouslySelectedDriver = 0
|
|
|
|
|
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)
|
|
|
|
|
val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled
|
|
|
|
|
|
|
|
|
|
val driversToDelete = mutableListOf<String>()
|
|
|
|
|
|
|
|
|
|
val isInteractionAllowed
|
|
|
|
|
get() = !areDriversLoading.value && isDriverReady.value && !isDeletingDrivers.value
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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())
|
|
|
|
|
)
|
|
|
|
|
drivers.add(Pair(driverToSave.path, currentDriverMetadata))
|
|
|
|
|
setSelectedDriverIndex(drivers.size - 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_driverList.value = drivers
|
|
|
|
|
_areDriversLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
@ -98,9 +100,9 @@ class DriverViewModel : ViewModel() {
|
|
|
|
|
fun addDriver(driverData: Pair<String, GpuDriverMetadata>) {
|
|
|
|
|
val driverIndex = _driverList.value.indexOfFirst { it == driverData }
|
|
|
|
|
if (driverIndex == -1) {
|
|
|
|
|
setSelectedDriverIndex(_driverList.value.size)
|
|
|
|
|
_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)
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedDriverIndex(driverIndex)
|
|
|
|
@ -111,8 +113,31 @@ class DriverViewModel : ViewModel() {
|
|
|
|
|
_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
|
|
|
|
|
StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first)
|
|
|
|
|
updateDriverNameForGame(game)
|
|
|
|
|
if (game == null) {
|
|
|
|
|
NativeConfig.saveGlobalConfig()
|
|
|
|
|
} else {
|
|
|
|
|
NativeConfig.savePerGameConfig()
|
|
|
|
|
NativeConfig.unloadPerGameConfig()
|
|
|
|
|
NativeConfig.reloadGlobalConfig()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewModelScope.launch {
|
|
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
|
driversToDelete.forEach {
|
|
|
|
@ -125,23 +150,29 @@ class DriverViewModel : ViewModel() {
|
|
|
|
|
_isDeletingDrivers.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GpuDriverHelper.customDriverData == driverList.value[selectedDriver].second) {
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
val selectedDriverFile = File(StringSetting.DRIVER_PATH.getString())
|
|
|
|
|
val selectedDriverMetadata = GpuDriverHelper.customDriverSettingData
|
|
|
|
|
if (GpuDriverHelper.installedCustomDriverData == selectedDriverMetadata) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_isDriverReady.value = false
|
|
|
|
|
viewModelScope.launch {
|
|
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
|
if (selectedDriver == 0) {
|
|
|
|
|
if (selectedDriverMetadata.name == null) {
|
|
|
|
|
GpuDriverHelper.installDefaultDriver()
|
|
|
|
|
setDriverReady()
|
|
|
|
|
return@withContext
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val driverToInstall = File(driverList.value[selectedDriver].first)
|
|
|
|
|
if (driverToInstall.exists()) {
|
|
|
|
|
GpuDriverHelper.installCustomDriver(driverToInstall)
|
|
|
|
|
if (selectedDriverFile.exists()) {
|
|
|
|
|
GpuDriverHelper.installCustomDriver(selectedDriverFile)
|
|
|
|
|
} else {
|
|
|
|
|
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() {
|
|
|
|
|
_isDriverReady.value = true
|
|
|
|
|
_selectedDriverMetadata.value = GpuDriverHelper.customDriverData.name
|
|
|
|
|
_selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name
|
|
|
|
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|