diff options
Diffstat (limited to 'src')
114 files changed, 3570 insertions, 3786 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2ca4904a..e04d2418b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -187,6 +187,7 @@ add_subdirectory(audio_core) | |||
| 187 | add_subdirectory(video_core) | 187 | add_subdirectory(video_core) |
| 188 | add_subdirectory(network) | 188 | add_subdirectory(network) |
| 189 | add_subdirectory(input_common) | 189 | add_subdirectory(input_common) |
| 190 | add_subdirectory(frontend_common) | ||
| 190 | add_subdirectory(shader_recompiler) | 191 | add_subdirectory(shader_recompiler) |
| 191 | 192 | ||
| 192 | if (YUZU_ROOM) | 193 | if (YUZU_ROOM) |
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 021b070e0..5721327e7 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts | |||
| @@ -219,7 +219,6 @@ dependencies { | |||
| 219 | implementation("io.coil-kt:coil:2.2.2") | 219 | implementation("io.coil-kt:coil:2.2.2") |
| 220 | implementation("androidx.core:core-splashscreen:1.0.1") | 220 | implementation("androidx.core:core-splashscreen:1.0.1") |
| 221 | implementation("androidx.window:window:1.2.0-beta03") | 221 | implementation("androidx.window:window:1.2.0-beta03") |
| 222 | implementation("org.ini4j:ini4j:0.5.4") | ||
| 223 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") | 222 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") |
| 224 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") | 223 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") |
| 225 | implementation("androidx.navigation:navigation-fragment-ktx:2.7.4") | 224 | implementation("androidx.navigation:navigation-fragment-ktx:2.7.4") |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 9ebd6c732..f2ba2504c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | |||
| @@ -230,8 +230,6 @@ object NativeLibrary { | |||
| 230 | */ | 230 | */ |
| 231 | external fun onTouchReleased(finger_id: Int) | 231 | external fun onTouchReleased(finger_id: Int) |
| 232 | 232 | ||
| 233 | external fun reloadSettings() | ||
| 234 | |||
| 235 | external fun initGameIni(gameID: String?) | 233 | external fun initGameIni(gameID: String?) |
| 236 | 234 | ||
| 237 | external fun setAppDirectory(directory: String) | 235 | external fun setAppDirectory(directory: String) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 2bf0e1b0d..d005c656e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt | |||
| @@ -7,7 +7,7 @@ import android.text.TextUtils | |||
| 7 | import android.widget.Toast | 7 | import android.widget.Toast |
| 8 | import org.yuzu.yuzu_emu.R | 8 | import org.yuzu.yuzu_emu.R |
| 9 | import org.yuzu.yuzu_emu.YuzuApplication | 9 | import org.yuzu.yuzu_emu.YuzuApplication |
| 10 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 10 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 11 | 11 | ||
| 12 | object Settings { | 12 | object Settings { |
| 13 | private val context get() = YuzuApplication.appContext | 13 | private val context get() = YuzuApplication.appContext |
| @@ -19,7 +19,7 @@ object Settings { | |||
| 19 | context.getString(R.string.ini_saved), | 19 | context.getString(R.string.ini_saved), |
| 20 | Toast.LENGTH_SHORT | 20 | Toast.LENGTH_SHORT |
| 21 | ).show() | 21 | ).show() |
| 22 | SettingsFile.saveFile(SettingsFile.FILE_NAME_CONFIG) | 22 | NativeConfig.saveSettings() |
| 23 | } else { | 23 | } else { |
| 24 | // TODO: Save custom game settings | 24 | // TODO: Save custom game settings |
| 25 | Toast.makeText( | 25 | Toast.makeText( |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt index c73edd50e..48bdbdd75 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt | |||
| @@ -21,7 +21,6 @@ import androidx.navigation.navArgs | |||
| 21 | import com.google.android.material.color.MaterialColors | 21 | import com.google.android.material.color.MaterialColors |
| 22 | import kotlinx.coroutines.flow.collectLatest | 22 | import kotlinx.coroutines.flow.collectLatest |
| 23 | import kotlinx.coroutines.launch | 23 | import kotlinx.coroutines.launch |
| 24 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 25 | import java.io.IOException | 24 | import java.io.IOException |
| 26 | import org.yuzu.yuzu_emu.R | 25 | import org.yuzu.yuzu_emu.R |
| 27 | import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding | 26 | import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding |
| @@ -165,11 +164,12 @@ class SettingsActivity : AppCompatActivity() { | |||
| 165 | settingsViewModel.shouldSave = false | 164 | settingsViewModel.shouldSave = false |
| 166 | 165 | ||
| 167 | // Delete settings file because the user may have changed values that do not exist in the UI | 166 | // Delete settings file because the user may have changed values that do not exist in the UI |
| 167 | NativeConfig.unloadConfig() | ||
| 168 | val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG) | 168 | val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG) |
| 169 | if (!settingsFile.delete()) { | 169 | if (!settingsFile.delete()) { |
| 170 | throw IOException("Failed to delete $settingsFile") | 170 | throw IOException("Failed to delete $settingsFile") |
| 171 | } | 171 | } |
| 172 | NativeLibrary.reloadSettings() | 172 | NativeConfig.initializeConfig() |
| 173 | 173 | ||
| 174 | Toast.makeText( | 174 | Toast.makeText( |
| 175 | applicationContext, | 175 | applicationContext, |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt index 2b04d666a..3ae5b4653 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt | |||
| @@ -3,15 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.utils | 4 | package org.yuzu.yuzu_emu.features.settings.utils |
| 5 | 5 | ||
| 6 | import android.widget.Toast | ||
| 7 | import java.io.* | 6 | import java.io.* |
| 8 | import org.ini4j.Wini | ||
| 9 | import org.yuzu.yuzu_emu.R | ||
| 10 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 11 | import org.yuzu.yuzu_emu.features.settings.model.* | ||
| 12 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | 7 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization |
| 13 | import org.yuzu.yuzu_emu.utils.Log | ||
| 14 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 15 | 8 | ||
| 16 | /** | 9 | /** |
| 17 | * Contains static methods for interacting with .ini files in which settings are stored. | 10 | * Contains static methods for interacting with .ini files in which settings are stored. |
| @@ -19,41 +12,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig | |||
| 19 | object SettingsFile { | 12 | object SettingsFile { |
| 20 | const val FILE_NAME_CONFIG = "config" | 13 | const val FILE_NAME_CONFIG = "config" |
| 21 | 14 | ||
| 22 | /** | ||
| 23 | * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error | ||
| 24 | * telling why it failed. | ||
| 25 | * | ||
| 26 | * @param fileName The target filename without a path or extension. | ||
| 27 | */ | ||
| 28 | fun saveFile(fileName: String) { | ||
| 29 | val ini = getSettingsFile(fileName) | ||
| 30 | try { | ||
| 31 | val wini = Wini(ini) | ||
| 32 | for (specificCategory in Settings.Category.values()) { | ||
| 33 | val categoryHeader = NativeConfig.getConfigHeader(specificCategory.ordinal) | ||
| 34 | for (setting in Settings.settingsList) { | ||
| 35 | if (setting.key!!.isEmpty()) continue | ||
| 36 | |||
| 37 | val settingCategoryHeader = | ||
| 38 | NativeConfig.getConfigHeader(setting.category.ordinal) | ||
| 39 | val iniSetting: String? = wini.get(categoryHeader, setting.key) | ||
| 40 | if (iniSetting != null || settingCategoryHeader == categoryHeader) { | ||
| 41 | wini.put(settingCategoryHeader, setting.key, setting.valueAsString) | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | wini.store() | ||
| 46 | } catch (e: IOException) { | ||
| 47 | Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message) | ||
| 48 | val context = YuzuApplication.appContext | ||
| 49 | Toast.makeText( | ||
| 50 | context, | ||
| 51 | context.getString(R.string.error_saving, fileName, e.message), | ||
| 52 | Toast.LENGTH_SHORT | ||
| 53 | ).show() | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | fun getSettingsFile(fileName: String): File = | 15 | fun getSettingsFile(fileName: String): File = |
| 58 | File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini") | 16 | File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini") |
| 59 | } | 17 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index ace5dddea..bd2f4cd25 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | |||
| @@ -625,6 +625,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 625 | } | 625 | } |
| 626 | 626 | ||
| 627 | // Clear existing user data | 627 | // Clear existing user data |
| 628 | NativeConfig.unloadConfig() | ||
| 628 | File(DirectoryInitialization.userDirectory!!).deleteRecursively() | 629 | File(DirectoryInitialization.userDirectory!!).deleteRecursively() |
| 629 | 630 | ||
| 630 | // Copy archive to internal storage | 631 | // Copy archive to internal storage |
| @@ -643,6 +644,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 643 | 644 | ||
| 644 | // Reinitialize relevant data | 645 | // Reinitialize relevant data |
| 645 | NativeLibrary.initializeSystem(true) | 646 | NativeLibrary.initializeSystem(true) |
| 647 | NativeConfig.initializeConfig() | ||
| 646 | gamesViewModel.reloadGames(false) | 648 | gamesViewModel.reloadGames(false) |
| 647 | 649 | ||
| 648 | return@newInstance getString(R.string.user_data_import_success) | 650 | return@newInstance getString(R.string.user_data_import_success) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt index 5e9a1176a..21270fc84 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt | |||
| @@ -16,6 +16,7 @@ object DirectoryInitialization { | |||
| 16 | if (!areDirectoriesReady) { | 16 | if (!areDirectoriesReady) { |
| 17 | initializeInternalStorage() | 17 | initializeInternalStorage() |
| 18 | NativeLibrary.initializeSystem(false) | 18 | NativeLibrary.initializeSystem(false) |
| 19 | NativeConfig.initializeConfig() | ||
| 19 | areDirectoriesReady = true | 20 | areDirectoriesReady = true |
| 20 | } | 21 | } |
| 21 | } | 22 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt index 47bde5081..e63382e1d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt | |||
| @@ -27,6 +27,8 @@ object InputHandler { | |||
| 27 | 0x054C -> getInputDS5ButtonKey(event.keyCode) | 27 | 0x054C -> getInputDS5ButtonKey(event.keyCode) |
| 28 | 0x057E -> getInputJoyconButtonKey(event.keyCode) | 28 | 0x057E -> getInputJoyconButtonKey(event.keyCode) |
| 29 | 0x1532 -> getInputRazerButtonKey(event.keyCode) | 29 | 0x1532 -> getInputRazerButtonKey(event.keyCode) |
| 30 | 0x3537 -> getInputRedmagicButtonKey(event.keyCode) | ||
| 31 | 0x358A -> getInputBackboneLabsButtonKey(event.keyCode) | ||
| 30 | else -> getInputGenericButtonKey(event.keyCode) | 32 | else -> getInputGenericButtonKey(event.keyCode) |
| 31 | } | 33 | } |
| 32 | 34 | ||
| @@ -227,6 +229,42 @@ object InputHandler { | |||
| 227 | } | 229 | } |
| 228 | } | 230 | } |
| 229 | 231 | ||
| 232 | private fun getInputRedmagicButtonKey(key: Int): Int { | ||
| 233 | return when (key) { | ||
| 234 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B | ||
| 235 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A | ||
| 236 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 237 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X | ||
| 238 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 239 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 240 | KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL | ||
| 241 | KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR | ||
| 242 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 243 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 244 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 245 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 246 | else -> -1 | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | private fun getInputBackboneLabsButtonKey(key: Int): Int { | ||
| 251 | return when (key) { | ||
| 252 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B | ||
| 253 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A | ||
| 254 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 255 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X | ||
| 256 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 257 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 258 | KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL | ||
| 259 | KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR | ||
| 260 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 261 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 262 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 263 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 264 | else -> -1 | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 230 | private fun getInputGenericButtonKey(key: Int): Int { | 268 | private fun getInputGenericButtonKey(key: Int): Int { |
| 231 | return when (key) { | 269 | return when (key) { |
| 232 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_A | 270 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_A |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt index 9425f8b99..87e579fa7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt | |||
| @@ -4,6 +4,30 @@ | |||
| 4 | package org.yuzu.yuzu_emu.utils | 4 | package org.yuzu.yuzu_emu.utils |
| 5 | 5 | ||
| 6 | object NativeConfig { | 6 | object NativeConfig { |
| 7 | /** | ||
| 8 | * Creates a Config object and opens the emulation config. | ||
| 9 | */ | ||
| 10 | @Synchronized | ||
| 11 | external fun initializeConfig() | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Destroys the stored config object. This automatically saves the existing config. | ||
| 15 | */ | ||
| 16 | @Synchronized | ||
| 17 | external fun unloadConfig() | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Reads values saved to the config file and saves them. | ||
| 21 | */ | ||
| 22 | @Synchronized | ||
| 23 | external fun reloadSettings() | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Saves settings values in memory to disk. | ||
| 27 | */ | ||
| 28 | @Synchronized | ||
| 29 | external fun saveSettings() | ||
| 30 | |||
| 7 | external fun getBoolean(key: String, getDefault: Boolean): Boolean | 31 | external fun getBoolean(key: String, getDefault: Boolean): Boolean |
| 8 | external fun setBoolean(key: String, value: Boolean) | 32 | external fun setBoolean(key: String, value: Boolean) |
| 9 | 33 | ||
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 88a570f68..2acc93da8 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt | |||
| @@ -6,9 +6,6 @@ add_library(yuzu-android SHARED | |||
| 6 | android_common/android_common.h | 6 | android_common/android_common.h |
| 7 | applets/software_keyboard.cpp | 7 | applets/software_keyboard.cpp |
| 8 | applets/software_keyboard.h | 8 | applets/software_keyboard.h |
| 9 | config.cpp | ||
| 10 | config.h | ||
| 11 | default_ini.h | ||
| 12 | emu_window/emu_window.cpp | 9 | emu_window/emu_window.cpp |
| 13 | emu_window/emu_window.h | 10 | emu_window/emu_window.h |
| 14 | id_cache.cpp | 11 | id_cache.cpp |
| @@ -16,15 +13,17 @@ add_library(yuzu-android SHARED | |||
| 16 | native.cpp | 13 | native.cpp |
| 17 | native.h | 14 | native.h |
| 18 | native_config.cpp | 15 | native_config.cpp |
| 19 | uisettings.cpp | 16 | android_settings.cpp |
| 20 | game_metadata.cpp | 17 | game_metadata.cpp |
| 21 | native_log.cpp | 18 | native_log.cpp |
| 19 | android_config.cpp | ||
| 20 | android_config.h | ||
| 22 | ) | 21 | ) |
| 23 | 22 | ||
| 24 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) | 23 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) |
| 25 | 24 | ||
| 26 | target_link_libraries(yuzu-android PRIVATE audio_core common core input_common) | 25 | target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common) |
| 27 | target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log) | 26 | target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log) |
| 28 | if (ARCHITECTURE_arm64) | 27 | if (ARCHITECTURE_arm64) |
| 29 | target_link_libraries(yuzu-android PRIVATE adrenotools) | 28 | target_link_libraries(yuzu-android PRIVATE adrenotools) |
| 30 | endif() | 29 | endif() |
diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp new file mode 100644 index 000000000..3041c25c9 --- /dev/null +++ b/src/android/app/src/main/jni/android_config.cpp | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "android_config.h" | ||
| 5 | #include "android_settings.h" | ||
| 6 | #include "common/settings_setting.h" | ||
| 7 | |||
| 8 | AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_type) | ||
| 9 | : Config(config_type) { | ||
| 10 | Initialize(config_name); | ||
| 11 | if (config_type != ConfigType::InputProfile) { | ||
| 12 | ReadAndroidValues(); | ||
| 13 | SaveAndroidValues(); | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | AndroidConfig::~AndroidConfig() { | ||
| 18 | if (global) { | ||
| 19 | AndroidConfig::SaveAllValues(); | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | void AndroidConfig::ReloadAllValues() { | ||
| 24 | Reload(); | ||
| 25 | ReadAndroidValues(); | ||
| 26 | SaveAndroidValues(); | ||
| 27 | } | ||
| 28 | |||
| 29 | void AndroidConfig::SaveAllValues() { | ||
| 30 | Save(); | ||
| 31 | SaveAndroidValues(); | ||
| 32 | } | ||
| 33 | |||
| 34 | void AndroidConfig::ReadAndroidValues() { | ||
| 35 | if (global) { | ||
| 36 | ReadAndroidUIValues(); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | void AndroidConfig::ReadAndroidUIValues() { | ||
| 41 | BeginGroup(Settings::TranslateCategory(Settings::Category::Android)); | ||
| 42 | |||
| 43 | ReadCategory(Settings::Category::Android); | ||
| 44 | |||
| 45 | EndGroup(); | ||
| 46 | } | ||
| 47 | |||
| 48 | void AndroidConfig::SaveAndroidValues() { | ||
| 49 | if (global) { | ||
| 50 | SaveAndroidUIValues(); | ||
| 51 | } | ||
| 52 | |||
| 53 | WriteToIni(); | ||
| 54 | } | ||
| 55 | |||
| 56 | void AndroidConfig::SaveAndroidUIValues() { | ||
| 57 | BeginGroup(Settings::TranslateCategory(Settings::Category::Android)); | ||
| 58 | |||
| 59 | WriteCategory(Settings::Category::Android); | ||
| 60 | |||
| 61 | EndGroup(); | ||
| 62 | } | ||
| 63 | |||
| 64 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { | ||
| 65 | auto& map = Settings::values.linkage.by_category; | ||
| 66 | if (map.contains(category)) { | ||
| 67 | return Settings::values.linkage.by_category[category]; | ||
| 68 | } | ||
| 69 | return AndroidSettings::values.linkage.by_category[category]; | ||
| 70 | } | ||
diff --git a/src/android/app/src/main/jni/android_config.h b/src/android/app/src/main/jni/android_config.h new file mode 100644 index 000000000..e679392fd --- /dev/null +++ b/src/android/app/src/main/jni/android_config.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "frontend_common/config.h" | ||
| 7 | |||
| 8 | class AndroidConfig final : public Config { | ||
| 9 | public: | ||
| 10 | explicit AndroidConfig(const std::string& config_name = "config", | ||
| 11 | ConfigType config_type = ConfigType::GlobalConfig); | ||
| 12 | ~AndroidConfig() override; | ||
| 13 | |||
| 14 | void ReloadAllValues() override; | ||
| 15 | void SaveAllValues() override; | ||
| 16 | |||
| 17 | protected: | ||
| 18 | void ReadAndroidValues(); | ||
| 19 | void ReadAndroidUIValues(); | ||
| 20 | void ReadHidbusValues() override {} | ||
| 21 | void ReadDebugControlValues() override {} | ||
| 22 | void ReadPathValues() override {} | ||
| 23 | void ReadShortcutValues() override {} | ||
| 24 | void ReadUIValues() override {} | ||
| 25 | void ReadUIGamelistValues() override {} | ||
| 26 | void ReadUILayoutValues() override {} | ||
| 27 | void ReadMultiplayerValues() override {} | ||
| 28 | |||
| 29 | void SaveAndroidValues(); | ||
| 30 | void SaveAndroidUIValues(); | ||
| 31 | void SaveHidbusValues() override {} | ||
| 32 | void SaveDebugControlValues() override {} | ||
| 33 | void SavePathValues() override {} | ||
| 34 | void SaveShortcutValues() override {} | ||
| 35 | void SaveUIValues() override {} | ||
| 36 | void SaveUIGamelistValues() override {} | ||
| 37 | void SaveUILayoutValues() override {} | ||
| 38 | void SaveMultiplayerValues() override {} | ||
| 39 | |||
| 40 | std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; | ||
| 41 | }; | ||
diff --git a/src/android/app/src/main/jni/uisettings.cpp b/src/android/app/src/main/jni/android_settings.cpp index f2f0bad50..16023a6b0 100644 --- a/src/android/app/src/main/jni/uisettings.cpp +++ b/src/android/app/src/main/jni/android_settings.cpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "uisettings.h" | 4 | #include "android_settings.h" |
| 5 | 5 | ||
| 6 | namespace AndroidSettings { | 6 | namespace AndroidSettings { |
| 7 | 7 | ||
diff --git a/src/android/app/src/main/jni/uisettings.h b/src/android/app/src/main/jni/android_settings.h index 37bc33918..37bc33918 100644 --- a/src/android/app/src/main/jni/uisettings.h +++ b/src/android/app/src/main/jni/android_settings.h | |||
diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp deleted file mode 100644 index 81120ab0f..000000000 --- a/src/android/app/src/main/jni/config.cpp +++ /dev/null | |||
| @@ -1,330 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <memory> | ||
| 5 | #include <optional> | ||
| 6 | #include <sstream> | ||
| 7 | |||
| 8 | #include <INIReader.h> | ||
| 9 | #include "common/fs/file.h" | ||
| 10 | #include "common/fs/fs.h" | ||
| 11 | #include "common/fs/path_util.h" | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/settings.h" | ||
| 14 | #include "common/settings_enums.h" | ||
| 15 | #include "core/hle/service/acc/profile_manager.h" | ||
| 16 | #include "input_common/main.h" | ||
| 17 | #include "jni/config.h" | ||
| 18 | #include "jni/default_ini.h" | ||
| 19 | #include "uisettings.h" | ||
| 20 | |||
| 21 | namespace FS = Common::FS; | ||
| 22 | |||
| 23 | Config::Config(const std::string& config_name, ConfigType config_type) | ||
| 24 | : type(config_type), global{config_type == ConfigType::GlobalConfig} { | ||
| 25 | Initialize(config_name); | ||
| 26 | } | ||
| 27 | |||
| 28 | Config::~Config() = default; | ||
| 29 | |||
| 30 | bool Config::LoadINI(const std::string& default_contents, bool retry) { | ||
| 31 | void(FS::CreateParentDir(config_loc)); | ||
| 32 | config = std::make_unique<INIReader>(FS::PathToUTF8String(config_loc)); | ||
| 33 | const auto config_loc_str = FS::PathToUTF8String(config_loc); | ||
| 34 | if (config->ParseError() < 0) { | ||
| 35 | if (retry) { | ||
| 36 | LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", | ||
| 37 | config_loc_str); | ||
| 38 | |||
| 39 | void(FS::CreateParentDir(config_loc)); | ||
| 40 | void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents)); | ||
| 41 | |||
| 42 | config = std::make_unique<INIReader>(config_loc_str); | ||
| 43 | |||
| 44 | return LoadINI(default_contents, false); | ||
| 45 | } | ||
| 46 | LOG_ERROR(Config, "Failed."); | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | LOG_INFO(Config, "Successfully loaded {}", config_loc_str); | ||
| 50 | return true; | ||
| 51 | } | ||
| 52 | |||
| 53 | template <> | ||
| 54 | void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) { | ||
| 55 | std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault()); | ||
| 56 | if (setting_value.empty()) { | ||
| 57 | setting_value = setting.GetDefault(); | ||
| 58 | } | ||
| 59 | setting = std::move(setting_value); | ||
| 60 | } | ||
| 61 | |||
| 62 | template <> | ||
| 63 | void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) { | ||
| 64 | setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); | ||
| 65 | } | ||
| 66 | |||
| 67 | template <typename Type, bool ranged> | ||
| 68 | void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) { | ||
| 69 | setting = static_cast<Type>( | ||
| 70 | config->GetInteger(group, setting.GetLabel(), static_cast<long>(setting.GetDefault()))); | ||
| 71 | } | ||
| 72 | |||
| 73 | void Config::ReadValues() { | ||
| 74 | ReadSetting("ControlsGeneral", Settings::values.mouse_enabled); | ||
| 75 | ReadSetting("ControlsGeneral", Settings::values.touch_device); | ||
| 76 | ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled); | ||
| 77 | ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled); | ||
| 78 | ReadSetting("ControlsGeneral", Settings::values.vibration_enabled); | ||
| 79 | ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations); | ||
| 80 | ReadSetting("ControlsGeneral", Settings::values.motion_enabled); | ||
| 81 | Settings::values.touchscreen.enabled = | ||
| 82 | config->GetBoolean("ControlsGeneral", "touch_enabled", true); | ||
| 83 | Settings::values.touchscreen.rotation_angle = | ||
| 84 | config->GetInteger("ControlsGeneral", "touch_angle", 0); | ||
| 85 | Settings::values.touchscreen.diameter_x = | ||
| 86 | config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); | ||
| 87 | Settings::values.touchscreen.diameter_y = | ||
| 88 | config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); | ||
| 89 | |||
| 90 | int num_touch_from_button_maps = | ||
| 91 | config->GetInteger("ControlsGeneral", "touch_from_button_map", 0); | ||
| 92 | if (num_touch_from_button_maps > 0) { | ||
| 93 | for (int i = 0; i < num_touch_from_button_maps; ++i) { | ||
| 94 | Settings::TouchFromButtonMap map; | ||
| 95 | map.name = config->Get("ControlsGeneral", | ||
| 96 | std::string("touch_from_button_maps_") + std::to_string(i) + | ||
| 97 | std::string("_name"), | ||
| 98 | "default"); | ||
| 99 | const int num_touch_maps = config->GetInteger( | ||
| 100 | "ControlsGeneral", | ||
| 101 | std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"), | ||
| 102 | 0); | ||
| 103 | map.buttons.reserve(num_touch_maps); | ||
| 104 | |||
| 105 | for (int j = 0; j < num_touch_maps; ++j) { | ||
| 106 | std::string touch_mapping = | ||
| 107 | config->Get("ControlsGeneral", | ||
| 108 | std::string("touch_from_button_maps_") + std::to_string(i) + | ||
| 109 | std::string("_bind_") + std::to_string(j), | ||
| 110 | ""); | ||
| 111 | map.buttons.emplace_back(std::move(touch_mapping)); | ||
| 112 | } | ||
| 113 | |||
| 114 | Settings::values.touch_from_button_maps.emplace_back(std::move(map)); | ||
| 115 | } | ||
| 116 | } else { | ||
| 117 | Settings::values.touch_from_button_maps.emplace_back( | ||
| 118 | Settings::TouchFromButtonMap{"default", {}}); | ||
| 119 | num_touch_from_button_maps = 1; | ||
| 120 | } | ||
| 121 | Settings::values.touch_from_button_map_index = std::clamp( | ||
| 122 | Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); | ||
| 123 | |||
| 124 | ReadSetting("ControlsGeneral", Settings::values.udp_input_servers); | ||
| 125 | |||
| 126 | // Data Storage | ||
| 127 | ReadSetting("Data Storage", Settings::values.use_virtual_sd); | ||
| 128 | FS::SetYuzuPath(FS::YuzuPath::NANDDir, | ||
| 129 | config->Get("Data Storage", "nand_directory", | ||
| 130 | FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | ||
| 131 | FS::SetYuzuPath(FS::YuzuPath::SDMCDir, | ||
| 132 | config->Get("Data Storage", "sdmc_directory", | ||
| 133 | FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | ||
| 134 | FS::SetYuzuPath(FS::YuzuPath::LoadDir, | ||
| 135 | config->Get("Data Storage", "load_directory", | ||
| 136 | FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | ||
| 137 | FS::SetYuzuPath(FS::YuzuPath::DumpDir, | ||
| 138 | config->Get("Data Storage", "dump_directory", | ||
| 139 | FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | ||
| 140 | ReadSetting("Data Storage", Settings::values.gamecard_inserted); | ||
| 141 | ReadSetting("Data Storage", Settings::values.gamecard_current_game); | ||
| 142 | ReadSetting("Data Storage", Settings::values.gamecard_path); | ||
| 143 | |||
| 144 | // System | ||
| 145 | ReadSetting("System", Settings::values.current_user); | ||
| 146 | Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0, | ||
| 147 | Service::Account::MAX_USERS - 1); | ||
| 148 | |||
| 149 | // Disable docked mode by default on Android | ||
| 150 | Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false) | ||
| 151 | ? Settings::ConsoleMode::Docked | ||
| 152 | : Settings::ConsoleMode::Handheld); | ||
| 153 | |||
| 154 | const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false); | ||
| 155 | if (rng_seed_enabled) { | ||
| 156 | Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0)); | ||
| 157 | } else { | ||
| 158 | Settings::values.rng_seed.SetValue(0); | ||
| 159 | } | ||
| 160 | Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled); | ||
| 161 | |||
| 162 | const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false); | ||
| 163 | if (custom_rtc_enabled) { | ||
| 164 | Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0); | ||
| 165 | } else { | ||
| 166 | Settings::values.custom_rtc = 0; | ||
| 167 | } | ||
| 168 | Settings::values.custom_rtc_enabled = custom_rtc_enabled; | ||
| 169 | |||
| 170 | ReadSetting("System", Settings::values.language_index); | ||
| 171 | ReadSetting("System", Settings::values.region_index); | ||
| 172 | ReadSetting("System", Settings::values.time_zone_index); | ||
| 173 | ReadSetting("System", Settings::values.sound_index); | ||
| 174 | |||
| 175 | // Core | ||
| 176 | ReadSetting("Core", Settings::values.use_multi_core); | ||
| 177 | ReadSetting("Core", Settings::values.memory_layout_mode); | ||
| 178 | |||
| 179 | // Cpu | ||
| 180 | ReadSetting("Cpu", Settings::values.cpu_accuracy); | ||
| 181 | ReadSetting("Cpu", Settings::values.cpu_debug_mode); | ||
| 182 | ReadSetting("Cpu", Settings::values.cpuopt_page_tables); | ||
| 183 | ReadSetting("Cpu", Settings::values.cpuopt_block_linking); | ||
| 184 | ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer); | ||
| 185 | ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher); | ||
| 186 | ReadSetting("Cpu", Settings::values.cpuopt_context_elimination); | ||
| 187 | ReadSetting("Cpu", Settings::values.cpuopt_const_prop); | ||
| 188 | ReadSetting("Cpu", Settings::values.cpuopt_misc_ir); | ||
| 189 | ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks); | ||
| 190 | ReadSetting("Cpu", Settings::values.cpuopt_fastmem); | ||
| 191 | ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives); | ||
| 192 | ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives); | ||
| 193 | ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts); | ||
| 194 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma); | ||
| 195 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error); | ||
| 196 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr); | ||
| 197 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan); | ||
| 198 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check); | ||
| 199 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor); | ||
| 200 | |||
| 201 | // Renderer | ||
| 202 | ReadSetting("Renderer", Settings::values.renderer_backend); | ||
| 203 | ReadSetting("Renderer", Settings::values.renderer_debug); | ||
| 204 | ReadSetting("Renderer", Settings::values.renderer_shader_feedback); | ||
| 205 | ReadSetting("Renderer", Settings::values.enable_nsight_aftermath); | ||
| 206 | ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks); | ||
| 207 | ReadSetting("Renderer", Settings::values.vulkan_device); | ||
| 208 | |||
| 209 | ReadSetting("Renderer", Settings::values.resolution_setup); | ||
| 210 | ReadSetting("Renderer", Settings::values.scaling_filter); | ||
| 211 | ReadSetting("Renderer", Settings::values.fsr_sharpening_slider); | ||
| 212 | ReadSetting("Renderer", Settings::values.anti_aliasing); | ||
| 213 | ReadSetting("Renderer", Settings::values.fullscreen_mode); | ||
| 214 | ReadSetting("Renderer", Settings::values.aspect_ratio); | ||
| 215 | ReadSetting("Renderer", Settings::values.max_anisotropy); | ||
| 216 | ReadSetting("Renderer", Settings::values.use_speed_limit); | ||
| 217 | ReadSetting("Renderer", Settings::values.speed_limit); | ||
| 218 | ReadSetting("Renderer", Settings::values.use_disk_shader_cache); | ||
| 219 | ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); | ||
| 220 | ReadSetting("Renderer", Settings::values.vsync_mode); | ||
| 221 | ReadSetting("Renderer", Settings::values.shader_backend); | ||
| 222 | ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); | ||
| 223 | ReadSetting("Renderer", Settings::values.nvdec_emulation); | ||
| 224 | ReadSetting("Renderer", Settings::values.use_fast_gpu_time); | ||
| 225 | ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache); | ||
| 226 | |||
| 227 | ReadSetting("Renderer", Settings::values.bg_red); | ||
| 228 | ReadSetting("Renderer", Settings::values.bg_green); | ||
| 229 | ReadSetting("Renderer", Settings::values.bg_blue); | ||
| 230 | |||
| 231 | // Use GPU accuracy normal by default on Android | ||
| 232 | Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger( | ||
| 233 | "Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal))); | ||
| 234 | |||
| 235 | // Use GPU default anisotropic filtering on Android | ||
| 236 | Settings::values.max_anisotropy = | ||
| 237 | static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1)); | ||
| 238 | |||
| 239 | // Disable ASTC compute by default on Android | ||
| 240 | Settings::values.accelerate_astc.SetValue( | ||
| 241 | config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu | ||
| 242 | : Settings::AstcDecodeMode::Cpu); | ||
| 243 | |||
| 244 | // Enable asynchronous presentation by default on Android | ||
| 245 | Settings::values.async_presentation = | ||
| 246 | config->GetBoolean("Renderer", "async_presentation", true); | ||
| 247 | |||
| 248 | // Disable force_max_clock by default on Android | ||
| 249 | Settings::values.renderer_force_max_clock = | ||
| 250 | config->GetBoolean("Renderer", "force_max_clock", false); | ||
| 251 | |||
| 252 | // Disable use_reactive_flushing by default on Android | ||
| 253 | Settings::values.use_reactive_flushing = | ||
| 254 | config->GetBoolean("Renderer", "use_reactive_flushing", false); | ||
| 255 | |||
| 256 | // Audio | ||
| 257 | ReadSetting("Audio", Settings::values.sink_id); | ||
| 258 | ReadSetting("Audio", Settings::values.audio_output_device_id); | ||
| 259 | ReadSetting("Audio", Settings::values.volume); | ||
| 260 | |||
| 261 | // Miscellaneous | ||
| 262 | // log_filter has a different default here than from common | ||
| 263 | Settings::values.log_filter = "*:Info"; | ||
| 264 | ReadSetting("Miscellaneous", Settings::values.use_dev_keys); | ||
| 265 | |||
| 266 | // Debugging | ||
| 267 | Settings::values.record_frame_times = | ||
| 268 | config->GetBoolean("Debugging", "record_frame_times", false); | ||
| 269 | ReadSetting("Debugging", Settings::values.dump_exefs); | ||
| 270 | ReadSetting("Debugging", Settings::values.dump_nso); | ||
| 271 | ReadSetting("Debugging", Settings::values.enable_fs_access_log); | ||
| 272 | ReadSetting("Debugging", Settings::values.reporting_services); | ||
| 273 | ReadSetting("Debugging", Settings::values.quest_flag); | ||
| 274 | ReadSetting("Debugging", Settings::values.use_debug_asserts); | ||
| 275 | ReadSetting("Debugging", Settings::values.use_auto_stub); | ||
| 276 | ReadSetting("Debugging", Settings::values.disable_macro_jit); | ||
| 277 | ReadSetting("Debugging", Settings::values.disable_macro_hle); | ||
| 278 | ReadSetting("Debugging", Settings::values.use_gdbstub); | ||
| 279 | ReadSetting("Debugging", Settings::values.gdbstub_port); | ||
| 280 | |||
| 281 | const auto title_list = config->Get("AddOns", "title_ids", ""); | ||
| 282 | std::stringstream ss(title_list); | ||
| 283 | std::string line; | ||
| 284 | while (std::getline(ss, line, '|')) { | ||
| 285 | const auto title_id = std::strtoul(line.c_str(), nullptr, 16); | ||
| 286 | const auto disabled_list = config->Get("AddOns", "disabled_" + line, ""); | ||
| 287 | |||
| 288 | std::stringstream inner_ss(disabled_list); | ||
| 289 | std::string inner_line; | ||
| 290 | std::vector<std::string> out; | ||
| 291 | while (std::getline(inner_ss, inner_line, '|')) { | ||
| 292 | out.push_back(inner_line); | ||
| 293 | } | ||
| 294 | |||
| 295 | Settings::values.disabled_addons.insert_or_assign(title_id, out); | ||
| 296 | } | ||
| 297 | |||
| 298 | // Web Service | ||
| 299 | ReadSetting("WebService", Settings::values.enable_telemetry); | ||
| 300 | ReadSetting("WebService", Settings::values.web_api_url); | ||
| 301 | ReadSetting("WebService", Settings::values.yuzu_username); | ||
| 302 | ReadSetting("WebService", Settings::values.yuzu_token); | ||
| 303 | |||
| 304 | // Network | ||
| 305 | ReadSetting("Network", Settings::values.network_interface); | ||
| 306 | |||
| 307 | // Android | ||
| 308 | ReadSetting("Android", AndroidSettings::values.picture_in_picture); | ||
| 309 | ReadSetting("Android", AndroidSettings::values.screen_layout); | ||
| 310 | } | ||
| 311 | |||
| 312 | void Config::Initialize(const std::string& config_name) { | ||
| 313 | const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); | ||
| 314 | const auto config_file = fmt::format("{}.ini", config_name); | ||
| 315 | |||
| 316 | switch (type) { | ||
| 317 | case ConfigType::GlobalConfig: | ||
| 318 | config_loc = FS::PathToUTF8String(fs_config_loc / config_file); | ||
| 319 | break; | ||
| 320 | case ConfigType::PerGameConfig: | ||
| 321 | config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); | ||
| 322 | break; | ||
| 323 | case ConfigType::InputProfile: | ||
| 324 | config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); | ||
| 325 | LoadINI(DefaultINI::android_config_file); | ||
| 326 | return; | ||
| 327 | } | ||
| 328 | LoadINI(DefaultINI::android_config_file); | ||
| 329 | ReadValues(); | ||
| 330 | } | ||
diff --git a/src/android/app/src/main/jni/config.h b/src/android/app/src/main/jni/config.h deleted file mode 100644 index e1e8f47ed..000000000 --- a/src/android/app/src/main/jni/config.h +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <filesystem> | ||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | #include <string> | ||
| 10 | |||
| 11 | #include "common/settings.h" | ||
| 12 | |||
| 13 | class INIReader; | ||
| 14 | |||
| 15 | class Config { | ||
| 16 | bool LoadINI(const std::string& default_contents = "", bool retry = true); | ||
| 17 | |||
| 18 | public: | ||
| 19 | enum class ConfigType { | ||
| 20 | GlobalConfig, | ||
| 21 | PerGameConfig, | ||
| 22 | InputProfile, | ||
| 23 | }; | ||
| 24 | |||
| 25 | explicit Config(const std::string& config_name = "config", | ||
| 26 | ConfigType config_type = ConfigType::GlobalConfig); | ||
| 27 | ~Config(); | ||
| 28 | |||
| 29 | void Initialize(const std::string& config_name); | ||
| 30 | |||
| 31 | private: | ||
| 32 | /** | ||
| 33 | * Applies a value read from the config to a Setting. | ||
| 34 | * | ||
| 35 | * @param group The name of the INI group | ||
| 36 | * @param setting The yuzu setting to modify | ||
| 37 | */ | ||
| 38 | template <typename Type, bool ranged> | ||
| 39 | void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting); | ||
| 40 | |||
| 41 | void ReadValues(); | ||
| 42 | |||
| 43 | const ConfigType type; | ||
| 44 | std::unique_ptr<INIReader> config; | ||
| 45 | std::string config_loc; | ||
| 46 | const bool global; | ||
| 47 | }; | ||
diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h deleted file mode 100644 index d81422a74..000000000 --- a/src/android/app/src/main/jni/default_ini.h +++ /dev/null | |||
| @@ -1,511 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | namespace DefaultINI { | ||
| 7 | |||
| 8 | const char* android_config_file = R"( | ||
| 9 | |||
| 10 | [ControlsP0] | ||
| 11 | # The input devices and parameters for each Switch native input | ||
| 12 | # The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ... | ||
| 13 | # It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." | ||
| 14 | # Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values | ||
| 15 | |||
| 16 | # Indicates if this player should be connected at boot | ||
| 17 | connected= | ||
| 18 | |||
| 19 | # for button input, the following devices are available: | ||
| 20 | # - "keyboard" (default) for keyboard input. Required parameters: | ||
| 21 | # - "code": the code of the key to bind | ||
| 22 | # - "sdl" for joystick input using SDL. Required parameters: | ||
| 23 | # - "guid": SDL identification GUID of the joystick | ||
| 24 | # - "port": the index of the joystick to bind | ||
| 25 | # - "button"(optional): the index of the button to bind | ||
| 26 | # - "hat"(optional): the index of the hat to bind as direction buttons | ||
| 27 | # - "axis"(optional): the index of the axis to bind | ||
| 28 | # - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" | ||
| 29 | # - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is | ||
| 30 | # triggered if the axis value crosses | ||
| 31 | # - "direction"(only used for axis): "+" means the button is triggered when the axis value | ||
| 32 | # is greater than the threshold; "-" means the button is triggered when the axis value | ||
| 33 | # is smaller than the threshold | ||
| 34 | button_a= | ||
| 35 | button_b= | ||
| 36 | button_x= | ||
| 37 | button_y= | ||
| 38 | button_lstick= | ||
| 39 | button_rstick= | ||
| 40 | button_l= | ||
| 41 | button_r= | ||
| 42 | button_zl= | ||
| 43 | button_zr= | ||
| 44 | button_plus= | ||
| 45 | button_minus= | ||
| 46 | button_dleft= | ||
| 47 | button_dup= | ||
| 48 | button_dright= | ||
| 49 | button_ddown= | ||
| 50 | button_lstick_left= | ||
| 51 | button_lstick_up= | ||
| 52 | button_lstick_right= | ||
| 53 | button_lstick_down= | ||
| 54 | button_sl= | ||
| 55 | button_sr= | ||
| 56 | button_home= | ||
| 57 | button_screenshot= | ||
| 58 | |||
| 59 | # for analog input, the following devices are available: | ||
| 60 | # - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: | ||
| 61 | # - "up", "down", "left", "right": sub-devices for each direction. | ||
| 62 | # Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" | ||
| 63 | # - "modifier": sub-devices as a modifier. | ||
| 64 | # - "modifier_scale": a float number representing the applied modifier scale to the analog input. | ||
| 65 | # Must be in range of 0.0-1.0. Defaults to 0.5 | ||
| 66 | # - "sdl" for joystick input using SDL. Required parameters: | ||
| 67 | # - "guid": SDL identification GUID of the joystick | ||
| 68 | # - "port": the index of the joystick to bind | ||
| 69 | # - "axis_x": the index of the axis to bind as x-axis (default to 0) | ||
| 70 | # - "axis_y": the index of the axis to bind as y-axis (default to 1) | ||
| 71 | lstick= | ||
| 72 | rstick= | ||
| 73 | |||
| 74 | # for motion input, the following devices are available: | ||
| 75 | # - "keyboard" (default) for emulating random motion input from buttons. Required parameters: | ||
| 76 | # - "code": the code of the key to bind | ||
| 77 | # - "sdl" for motion input using SDL. Required parameters: | ||
| 78 | # - "guid": SDL identification GUID of the joystick | ||
| 79 | # - "port": the index of the joystick to bind | ||
| 80 | # - "motion": the index of the motion sensor to bind | ||
| 81 | # - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters: | ||
| 82 | # - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001" | ||
| 83 | # - "port": the port of the cemu hook server | ||
| 84 | # - "pad": the index of the joystick | ||
| 85 | # - "motion": the index of the motion sensor of the joystick to bind | ||
| 86 | motionleft= | ||
| 87 | motionright= | ||
| 88 | |||
| 89 | [ControlsGeneral] | ||
| 90 | # To use the debug_pad, prepend `debug_pad_` before each button setting above. | ||
| 91 | # i.e. debug_pad_button_a= | ||
| 92 | |||
| 93 | # Enable debug pad inputs to the guest | ||
| 94 | # 0 (default): Disabled, 1: Enabled | ||
| 95 | debug_pad_enabled = | ||
| 96 | |||
| 97 | # Whether to enable or disable vibration | ||
| 98 | # 0: Disabled, 1 (default): Enabled | ||
| 99 | vibration_enabled= | ||
| 100 | |||
| 101 | # Whether to enable or disable accurate vibrations | ||
| 102 | # 0 (default): Disabled, 1: Enabled | ||
| 103 | enable_accurate_vibrations= | ||
| 104 | |||
| 105 | # Enables controller motion inputs | ||
| 106 | # 0: Disabled, 1 (default): Enabled | ||
| 107 | motion_enabled = | ||
| 108 | |||
| 109 | # Defines the udp device's touch screen coordinate system for cemuhookudp devices | ||
| 110 | # - "min_x", "min_y", "max_x", "max_y" | ||
| 111 | touch_device= | ||
| 112 | |||
| 113 | # for mapping buttons to touch inputs. | ||
| 114 | #touch_from_button_map=1 | ||
| 115 | #touch_from_button_maps_0_name=default | ||
| 116 | #touch_from_button_maps_0_count=2 | ||
| 117 | #touch_from_button_maps_0_bind_0=foo | ||
| 118 | #touch_from_button_maps_0_bind_1=bar | ||
| 119 | # etc. | ||
| 120 | |||
| 121 | # List of Cemuhook UDP servers, delimited by ','. | ||
| 122 | # Default: 127.0.0.1:26760 | ||
| 123 | # Example: 127.0.0.1:26760,123.4.5.67:26761 | ||
| 124 | udp_input_servers = | ||
| 125 | |||
| 126 | # Enable controlling an axis via a mouse input. | ||
| 127 | # 0 (default): Off, 1: On | ||
| 128 | mouse_panning = | ||
| 129 | |||
| 130 | # Set mouse sensitivity. | ||
| 131 | # Default: 1.0 | ||
| 132 | mouse_panning_sensitivity = | ||
| 133 | |||
| 134 | # Emulate an analog control stick from keyboard inputs. | ||
| 135 | # 0 (default): Disabled, 1: Enabled | ||
| 136 | emulate_analog_keyboard = | ||
| 137 | |||
| 138 | # Enable mouse inputs to the guest | ||
| 139 | # 0 (default): Disabled, 1: Enabled | ||
| 140 | mouse_enabled = | ||
| 141 | |||
| 142 | # Enable keyboard inputs to the guest | ||
| 143 | # 0 (default): Disabled, 1: Enabled | ||
| 144 | keyboard_enabled = | ||
| 145 | |||
| 146 | [Core] | ||
| 147 | # Whether to use multi-core for CPU emulation | ||
| 148 | # 0: Disabled, 1 (default): Enabled | ||
| 149 | use_multi_core = | ||
| 150 | |||
| 151 | # Enable unsafe extended guest system memory layout (8GB DRAM) | ||
| 152 | # 0 (default): Disabled, 1: Enabled | ||
| 153 | use_unsafe_extended_memory_layout = | ||
| 154 | |||
| 155 | [Cpu] | ||
| 156 | # Adjusts various optimizations. | ||
| 157 | # Auto-select mode enables choice unsafe optimizations. | ||
| 158 | # Accurate enables only safe optimizations. | ||
| 159 | # Unsafe allows any unsafe optimizations. | ||
| 160 | # 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations | ||
| 161 | cpu_accuracy = | ||
| 162 | |||
| 163 | # Allow disabling safe optimizations. | ||
| 164 | # 0 (default): Disabled, 1: Enabled | ||
| 165 | cpu_debug_mode = | ||
| 166 | |||
| 167 | # Enable inline page tables optimization (faster guest memory access) | ||
| 168 | # 0: Disabled, 1 (default): Enabled | ||
| 169 | cpuopt_page_tables = | ||
| 170 | |||
| 171 | # Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) | ||
| 172 | # 0: Disabled, 1 (default): Enabled | ||
| 173 | cpuopt_block_linking = | ||
| 174 | |||
| 175 | # Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) | ||
| 176 | # 0: Disabled, 1 (default): Enabled | ||
| 177 | cpuopt_return_stack_buffer = | ||
| 178 | |||
| 179 | # Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) | ||
| 180 | # 0: Disabled, 1 (default): Enabled | ||
| 181 | cpuopt_fast_dispatcher = | ||
| 182 | |||
| 183 | # Enable context elimination CPU Optimization (reduce host memory use for guest context) | ||
| 184 | # 0: Disabled, 1 (default): Enabled | ||
| 185 | cpuopt_context_elimination = | ||
| 186 | |||
| 187 | # Enable constant propagation CPU optimization (basic IR optimization) | ||
| 188 | # 0: Disabled, 1 (default): Enabled | ||
| 189 | cpuopt_const_prop = | ||
| 190 | |||
| 191 | # Enable miscellaneous CPU optimizations (basic IR optimization) | ||
| 192 | # 0: Disabled, 1 (default): Enabled | ||
| 193 | cpuopt_misc_ir = | ||
| 194 | |||
| 195 | # Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) | ||
| 196 | # 0: Disabled, 1 (default): Enabled | ||
| 197 | cpuopt_reduce_misalign_checks = | ||
| 198 | |||
| 199 | # Enable Host MMU Emulation (faster guest memory access) | ||
| 200 | # 0: Disabled, 1 (default): Enabled | ||
| 201 | cpuopt_fastmem = | ||
| 202 | |||
| 203 | # Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access) | ||
| 204 | # 0: Disabled, 1 (default): Enabled | ||
| 205 | cpuopt_fastmem_exclusives = | ||
| 206 | |||
| 207 | # Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access) | ||
| 208 | # 0: Disabled, 1 (default): Enabled | ||
| 209 | cpuopt_recompile_exclusives = | ||
| 210 | |||
| 211 | # Enable optimization to ignore invalid memory accesses (faster guest memory access) | ||
| 212 | # 0: Disabled, 1 (default): Enabled | ||
| 213 | cpuopt_ignore_memory_aborts = | ||
| 214 | |||
| 215 | # Enable unfuse FMA (improve performance on CPUs without FMA) | ||
| 216 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 217 | # 0: Disabled, 1 (default): Enabled | ||
| 218 | cpuopt_unsafe_unfuse_fma = | ||
| 219 | |||
| 220 | # Enable faster FRSQRTE and FRECPE | ||
| 221 | # Only enabled if cpu_accuracy is set to Unsafe. | ||
| 222 | # 0: Disabled, 1 (default): Enabled | ||
| 223 | cpuopt_unsafe_reduce_fp_error = | ||
| 224 | |||
| 225 | # Enable faster ASIMD instructions (32 bits only) | ||
| 226 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 227 | # 0: Disabled, 1 (default): Enabled | ||
| 228 | cpuopt_unsafe_ignore_standard_fpcr = | ||
| 229 | |||
| 230 | # Enable inaccurate NaN handling | ||
| 231 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 232 | # 0: Disabled, 1 (default): Enabled | ||
| 233 | cpuopt_unsafe_inaccurate_nan = | ||
| 234 | |||
| 235 | # Disable address space checks (64 bits only) | ||
| 236 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 237 | # 0: Disabled, 1 (default): Enabled | ||
| 238 | cpuopt_unsafe_fastmem_check = | ||
| 239 | |||
| 240 | # Enable faster exclusive instructions | ||
| 241 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 242 | # 0: Disabled, 1 (default): Enabled | ||
| 243 | cpuopt_unsafe_ignore_global_monitor = | ||
| 244 | |||
| 245 | [Renderer] | ||
| 246 | # Which backend API to use. | ||
| 247 | # 0: OpenGL (unsupported), 1 (default): Vulkan, 2: Null | ||
| 248 | backend = | ||
| 249 | |||
| 250 | # Whether to enable asynchronous presentation (Vulkan only) | ||
| 251 | # 0: Off, 1 (default): On | ||
| 252 | async_presentation = | ||
| 253 | |||
| 254 | # Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied). | ||
| 255 | # 0 (default): Disabled, 1: Enabled | ||
| 256 | force_max_clock = | ||
| 257 | |||
| 258 | # Enable graphics API debugging mode. | ||
| 259 | # 0 (default): Disabled, 1: Enabled | ||
| 260 | debug = | ||
| 261 | |||
| 262 | # Enable shader feedback. | ||
| 263 | # 0 (default): Disabled, 1: Enabled | ||
| 264 | renderer_shader_feedback = | ||
| 265 | |||
| 266 | # Enable Nsight Aftermath crash dumps | ||
| 267 | # 0 (default): Disabled, 1: Enabled | ||
| 268 | nsight_aftermath = | ||
| 269 | |||
| 270 | # Disable shader loop safety checks, executing the shader without loop logic changes | ||
| 271 | # 0 (default): Disabled, 1: Enabled | ||
| 272 | disable_shader_loop_safety_checks = | ||
| 273 | |||
| 274 | # Which Vulkan physical device to use (defaults to 0) | ||
| 275 | vulkan_device = | ||
| 276 | |||
| 277 | # 0: 0.5x (360p/540p) [EXPERIMENTAL] | ||
| 278 | # 1: 0.75x (540p/810p) [EXPERIMENTAL] | ||
| 279 | # 2 (default): 1x (720p/1080p) | ||
| 280 | # 3: 2x (1440p/2160p) | ||
| 281 | # 4: 3x (2160p/3240p) | ||
| 282 | # 5: 4x (2880p/4320p) | ||
| 283 | # 6: 5x (3600p/5400p) | ||
| 284 | # 7: 6x (4320p/6480p) | ||
| 285 | resolution_setup = | ||
| 286 | |||
| 287 | # Pixel filter to use when up- or down-sampling rendered frames. | ||
| 288 | # 0: Nearest Neighbor | ||
| 289 | # 1 (default): Bilinear | ||
| 290 | # 2: Bicubic | ||
| 291 | # 3: Gaussian | ||
| 292 | # 4: ScaleForce | ||
| 293 | # 5: AMD FidelityFX™️ Super Resolution [Vulkan Only] | ||
| 294 | scaling_filter = | ||
| 295 | |||
| 296 | # Anti-Aliasing (AA) | ||
| 297 | # 0 (default): None, 1: FXAA | ||
| 298 | anti_aliasing = | ||
| 299 | |||
| 300 | # Whether to use fullscreen or borderless window mode | ||
| 301 | # 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen | ||
| 302 | fullscreen_mode = | ||
| 303 | |||
| 304 | # Aspect ratio | ||
| 305 | # 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window | ||
| 306 | aspect_ratio = | ||
| 307 | |||
| 308 | # Anisotropic filtering | ||
| 309 | # 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x | ||
| 310 | max_anisotropy = | ||
| 311 | |||
| 312 | # Whether to enable VSync or not. | ||
| 313 | # OpenGL: Values other than 0 enable VSync | ||
| 314 | # Vulkan: FIFO is selected if the requested mode is not supported by the driver. | ||
| 315 | # FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. | ||
| 316 | # FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. | ||
| 317 | # Mailbox can have lower latency than FIFO and does not tear but may drop frames. | ||
| 318 | # Immediate (no synchronization) just presents whatever is available and can exhibit tearing. | ||
| 319 | # 0: Immediate (Off), 1 (Default): Mailbox (On), 2: FIFO, 3: FIFO Relaxed | ||
| 320 | use_vsync = | ||
| 321 | |||
| 322 | # Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is | ||
| 323 | # not available and GLASM is selected, GLSL will be used. | ||
| 324 | # 0: GLSL, 1 (default): GLASM, 2: SPIR-V | ||
| 325 | shader_backend = | ||
| 326 | |||
| 327 | # Whether to allow asynchronous shader building. | ||
| 328 | # 0 (default): Off, 1: On | ||
| 329 | use_asynchronous_shaders = | ||
| 330 | |||
| 331 | # Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. | ||
| 332 | # 0 (default): Off, 1: On | ||
| 333 | use_reactive_flushing = | ||
| 334 | |||
| 335 | # NVDEC emulation. | ||
| 336 | # 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding | ||
| 337 | nvdec_emulation = | ||
| 338 | |||
| 339 | # Accelerate ASTC texture decoding. | ||
| 340 | # 0 (default): Off, 1: On | ||
| 341 | accelerate_astc = | ||
| 342 | |||
| 343 | # Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value | ||
| 344 | # 0: Off, 1: On (default) | ||
| 345 | use_speed_limit = | ||
| 346 | |||
| 347 | # Limits the speed of the game to run no faster than this value as a percentage of target speed | ||
| 348 | # 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) | ||
| 349 | speed_limit = | ||
| 350 | |||
| 351 | # Whether to use disk based shader cache | ||
| 352 | # 0: Off, 1 (default): On | ||
| 353 | use_disk_shader_cache = | ||
| 354 | |||
| 355 | # Which gpu accuracy level to use | ||
| 356 | # 0 (default): Normal, 1: High, 2: Extreme (Very slow) | ||
| 357 | gpu_accuracy = | ||
| 358 | |||
| 359 | # Whether to use asynchronous GPU emulation | ||
| 360 | # 0 : Off (slow), 1 (default): On (fast) | ||
| 361 | use_asynchronous_gpu_emulation = | ||
| 362 | |||
| 363 | # Inform the guest that GPU operations completed more quickly than they did. | ||
| 364 | # 0: Off, 1 (default): On | ||
| 365 | use_fast_gpu_time = | ||
| 366 | |||
| 367 | # Force unmodified buffers to be flushed, which can cost performance. | ||
| 368 | # 0: Off (default), 1: On | ||
| 369 | use_pessimistic_flushes = | ||
| 370 | |||
| 371 | # Whether to use garbage collection or not for GPU caches. | ||
| 372 | # 0 (default): Off, 1: On | ||
| 373 | use_caches_gc = | ||
| 374 | |||
| 375 | # The clear color for the renderer. What shows up on the sides of the bottom screen. | ||
| 376 | # Must be in range of 0-255. Defaults to 0 for all. | ||
| 377 | bg_red = | ||
| 378 | bg_blue = | ||
| 379 | bg_green = | ||
| 380 | |||
| 381 | [Audio] | ||
| 382 | # Which audio output engine to use. | ||
| 383 | # auto (default): Auto-select | ||
| 384 | # cubeb: Cubeb audio engine (if available) | ||
| 385 | # sdl2: SDL2 audio engine (if available) | ||
| 386 | # null: No audio output | ||
| 387 | output_engine = | ||
| 388 | |||
| 389 | # Which audio device to use. | ||
| 390 | # auto (default): Auto-select | ||
| 391 | output_device = | ||
| 392 | |||
| 393 | # Output volume. | ||
| 394 | # 100 (default): 100%, 0; mute | ||
| 395 | volume = | ||
| 396 | |||
| 397 | [Data Storage] | ||
| 398 | # Whether to create a virtual SD card. | ||
| 399 | # 1: Yes, 0 (default): No | ||
| 400 | use_virtual_sd = | ||
| 401 | |||
| 402 | # Whether or not to enable gamecard emulation | ||
| 403 | # 1: Yes, 0 (default): No | ||
| 404 | gamecard_inserted = | ||
| 405 | |||
| 406 | # Whether or not the gamecard should be emulated as the current game | ||
| 407 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 408 | # 1: Yes, 0 (default): No | ||
| 409 | gamecard_current_game = | ||
| 410 | |||
| 411 | # Path to an XCI file to use as the gamecard | ||
| 412 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 413 | # If 'gamecard_current_game' is 1 this setting is irrelevant | ||
| 414 | gamecard_path = | ||
| 415 | |||
| 416 | [System] | ||
| 417 | # Whether the system is docked | ||
| 418 | # 1 (default): Yes, 0: No | ||
| 419 | use_docked_mode = | ||
| 420 | |||
| 421 | # Sets the seed for the RNG generator built into the switch | ||
| 422 | # rng_seed will be ignored and randomly generated if rng_seed_enabled is false | ||
| 423 | rng_seed_enabled = | ||
| 424 | rng_seed = | ||
| 425 | |||
| 426 | # Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service | ||
| 427 | # This will auto-increment, with the time set being the time the game is started | ||
| 428 | # This override will only occur if custom_rtc_enabled is true, otherwise the current time is used | ||
| 429 | custom_rtc_enabled = | ||
| 430 | custom_rtc = | ||
| 431 | |||
| 432 | # Sets the systems language index | ||
| 433 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, | ||
| 434 | # 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, | ||
| 435 | # 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese | ||
| 436 | language_index = | ||
| 437 | |||
| 438 | # The system region that yuzu will use during emulation | ||
| 439 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | ||
| 440 | region_index = | ||
| 441 | |||
| 442 | # The system time zone that yuzu will use during emulation | ||
| 443 | # 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone | ||
| 444 | time_zone_index = | ||
| 445 | |||
| 446 | # Sets the sound output mode. | ||
| 447 | # 0: Mono, 1 (default): Stereo, 2: Surround | ||
| 448 | sound_index = | ||
| 449 | |||
| 450 | [Miscellaneous] | ||
| 451 | # A filter which removes logs below a certain logging level. | ||
| 452 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | ||
| 453 | log_filter = *:Trace | ||
| 454 | |||
| 455 | # Use developer keys | ||
| 456 | # 0 (default): Disabled, 1: Enabled | ||
| 457 | use_dev_keys = | ||
| 458 | |||
| 459 | [Debugging] | ||
| 460 | # Record frame time data, can be found in the log directory. Boolean value | ||
| 461 | record_frame_times = | ||
| 462 | # Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them | ||
| 463 | dump_exefs=false | ||
| 464 | # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them | ||
| 465 | dump_nso=false | ||
| 466 | # Determines whether or not yuzu will save the filesystem access log. | ||
| 467 | enable_fs_access_log=false | ||
| 468 | # Enables verbose reporting services | ||
| 469 | reporting_services = | ||
| 470 | # Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode | ||
| 471 | # false: Retail/Normal Mode (default), true: Kiosk Mode | ||
| 472 | quest_flag = | ||
| 473 | # Determines whether debug asserts should be enabled, which will throw an exception on asserts. | ||
| 474 | # false: Disabled (default), true: Enabled | ||
| 475 | use_debug_asserts = | ||
| 476 | # Determines whether unimplemented HLE service calls should be automatically stubbed. | ||
| 477 | # false: Disabled (default), true: Enabled | ||
| 478 | use_auto_stub = | ||
| 479 | # Enables/Disables the macro JIT compiler | ||
| 480 | disable_macro_jit=false | ||
| 481 | # Determines whether to enable the GDB stub and wait for the debugger to attach before running. | ||
| 482 | # false: Disabled (default), true: Enabled | ||
| 483 | use_gdbstub=false | ||
| 484 | # The port to use for the GDB server, if it is enabled. | ||
| 485 | gdbstub_port=6543 | ||
| 486 | |||
| 487 | [WebService] | ||
| 488 | # Whether or not to enable telemetry | ||
| 489 | # 0: No, 1 (default): Yes | ||
| 490 | enable_telemetry = | ||
| 491 | # URL for Web API | ||
| 492 | web_api_url = https://api.yuzu-emu.org | ||
| 493 | # Username and token for yuzu Web Service | ||
| 494 | # See https://profile.yuzu-emu.org/ for more info | ||
| 495 | yuzu_username = | ||
| 496 | yuzu_token = | ||
| 497 | |||
| 498 | [Network] | ||
| 499 | # Name of the network interface device to use with yuzu LAN play. | ||
| 500 | # e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo' | ||
| 501 | # e.g. On Windows: 'Ethernet', 'Wi-Fi' | ||
| 502 | network_interface = | ||
| 503 | |||
| 504 | [AddOns] | ||
| 505 | # Used to disable add-ons | ||
| 506 | # List of title IDs of games that will have add-ons disabled (separated by '|'): | ||
| 507 | title_ids = | ||
| 508 | # For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') | ||
| 509 | # e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey | ||
| 510 | )"; | ||
| 511 | } // namespace DefaultINI | ||
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 64663b084..617288ae4 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -52,8 +52,8 @@ | |||
| 52 | #include "core/hle/service/am/applets/applets.h" | 52 | #include "core/hle/service/am/applets/applets.h" |
| 53 | #include "core/hle/service/filesystem/filesystem.h" | 53 | #include "core/hle/service/filesystem/filesystem.h" |
| 54 | #include "core/loader/loader.h" | 54 | #include "core/loader/loader.h" |
| 55 | #include "frontend_common/config.h" | ||
| 55 | #include "jni/android_common/android_common.h" | 56 | #include "jni/android_common/android_common.h" |
| 56 | #include "jni/config.h" | ||
| 57 | #include "jni/id_cache.h" | 57 | #include "jni/id_cache.h" |
| 58 | #include "jni/native.h" | 58 | #include "jni/native.h" |
| 59 | #include "video_core/renderer_base.h" | 59 | #include "video_core/renderer_base.h" |
| @@ -664,8 +664,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c | |||
| 664 | 664 | ||
| 665 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, | 665 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, |
| 666 | jboolean reload) { | 666 | jboolean reload) { |
| 667 | // Create the default config.ini. | ||
| 668 | Config{}; | ||
| 669 | // Initialize the emulated system. | 667 | // Initialize the emulated system. |
| 670 | if (!reload) { | 668 | if (!reload) { |
| 671 | EmulationSession::GetInstance().System().Initialize(); | 669 | EmulationSession::GetInstance().System().Initialize(); |
| @@ -680,17 +678,6 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl | |||
| 680 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( | 678 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( |
| 681 | JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {} | 679 | JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {} |
| 682 | 680 | ||
| 683 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { | ||
| 684 | Config{}; | ||
| 685 | } | ||
| 686 | |||
| 687 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz, | ||
| 688 | jstring j_game_id) { | ||
| 689 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||
| 690 | |||
| 691 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); | ||
| 692 | } | ||
| 693 | |||
| 694 | jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) { | 681 | jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) { |
| 695 | jdoubleArray j_stats = env->NewDoubleArray(4); | 682 | jdoubleArray j_stats = env->NewDoubleArray(4); |
| 696 | 683 | ||
diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp index 8a704960c..8e81816e5 100644 --- a/src/android/app/src/main/jni/native_config.cpp +++ b/src/android/app/src/main/jni/native_config.cpp | |||
| @@ -5,11 +5,14 @@ | |||
| 5 | 5 | ||
| 6 | #include <jni.h> | 6 | #include <jni.h> |
| 7 | 7 | ||
| 8 | #include "android_config.h" | ||
| 9 | #include "android_settings.h" | ||
| 8 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 9 | #include "common/settings.h" | 11 | #include "common/settings.h" |
| 12 | #include "frontend_common/config.h" | ||
| 10 | #include "jni/android_common/android_common.h" | 13 | #include "jni/android_common/android_common.h" |
| 11 | #include "jni/config.h" | 14 | |
| 12 | #include "uisettings.h" | 15 | std::unique_ptr<AndroidConfig> config; |
| 13 | 16 | ||
| 14 | template <typename T> | 17 | template <typename T> |
| 15 | Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { | 18 | Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { |
| @@ -28,6 +31,22 @@ Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { | |||
| 28 | 31 | ||
| 29 | extern "C" { | 32 | extern "C" { |
| 30 | 33 | ||
| 34 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeConfig(JNIEnv* env, jobject obj) { | ||
| 35 | config = std::make_unique<AndroidConfig>(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadConfig(JNIEnv* env, jobject obj) { | ||
| 39 | config.reset(); | ||
| 40 | } | ||
| 41 | |||
| 42 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadSettings(JNIEnv* env, jobject obj) { | ||
| 43 | config->AndroidConfig::ReloadAllValues(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveSettings(JNIEnv* env, jobject obj) { | ||
| 47 | config->AndroidConfig::SaveAllValues(); | ||
| 48 | } | ||
| 49 | |||
| 31 | jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj, | 50 | jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj, |
| 32 | jstring jkey, jboolean getDefault) { | 51 | jstring jkey, jboolean getDefault) { |
| 33 | auto setting = getSetting<bool>(env, jkey); | 52 | auto setting = getSetting<bool>(env, jkey); |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e216eb3de..57cbb9d07 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -174,6 +174,15 @@ if(ANDROID) | |||
| 174 | ) | 174 | ) |
| 175 | endif() | 175 | endif() |
| 176 | 176 | ||
| 177 | if (UNIX) | ||
| 178 | target_sources(common PRIVATE | ||
| 179 | linux/gamemode.cpp | ||
| 180 | linux/gamemode.h | ||
| 181 | ) | ||
| 182 | |||
| 183 | target_link_libraries(common PRIVATE gamemode) | ||
| 184 | endif() | ||
| 185 | |||
| 177 | if(ARCHITECTURE_x86_64) | 186 | if(ARCHITECTURE_x86_64) |
| 178 | target_sources(common | 187 | target_sources(common |
| 179 | PRIVATE | 188 | PRIVATE |
diff --git a/src/common/linux/gamemode.cpp b/src/common/linux/gamemode.cpp new file mode 100644 index 000000000..8876d8dc4 --- /dev/null +++ b/src/common/linux/gamemode.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <gamemode_client.h> | ||
| 5 | |||
| 6 | #include "common/linux/gamemode.h" | ||
| 7 | #include "common/settings.h" | ||
| 8 | |||
| 9 | namespace Common::Linux { | ||
| 10 | |||
| 11 | void StartGamemode() { | ||
| 12 | if (Settings::values.enable_gamemode) { | ||
| 13 | if (gamemode_request_start() < 0) { | ||
| 14 | LOG_WARNING(Frontend, "Failed to start gamemode: {}", gamemode_error_string()); | ||
| 15 | } else { | ||
| 16 | LOG_INFO(Frontend, "Started gamemode"); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | void StopGamemode() { | ||
| 22 | if (Settings::values.enable_gamemode) { | ||
| 23 | if (gamemode_request_end() < 0) { | ||
| 24 | LOG_WARNING(Frontend, "Failed to stop gamemode: {}", gamemode_error_string()); | ||
| 25 | } else { | ||
| 26 | LOG_INFO(Frontend, "Stopped gamemode"); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | void SetGamemodeState(bool state) { | ||
| 32 | if (state) { | ||
| 33 | StartGamemode(); | ||
| 34 | } else { | ||
| 35 | StopGamemode(); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace Common::Linux | ||
diff --git a/src/common/linux/gamemode.h b/src/common/linux/gamemode.h new file mode 100644 index 000000000..b80646ae2 --- /dev/null +++ b/src/common/linux/gamemode.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | namespace Common::Linux { | ||
| 7 | |||
| 8 | /** | ||
| 9 | * Start the (Feral Interactive) Linux gamemode if it is installed and it is activated | ||
| 10 | */ | ||
| 11 | void StartGamemode(); | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Stop the (Feral Interactive) Linux gamemode if it is installed and it is activated | ||
| 15 | */ | ||
| 16 | void StopGamemode(); | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Start or stop the (Feral Interactive) Linux gamemode if it is installed and it is activated | ||
| 20 | * @param state The new state the gamemode should have | ||
| 21 | */ | ||
| 22 | void SetGamemodeState(bool state); | ||
| 23 | |||
| 24 | } // namespace Common::Linux | ||
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 51717be06..3e829253f 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -206,9 +206,9 @@ const char* TranslateCategory(Category category) { | |||
| 206 | case Category::UiAudio: | 206 | case Category::UiAudio: |
| 207 | return "UiAudio"; | 207 | return "UiAudio"; |
| 208 | case Category::UiLayout: | 208 | case Category::UiLayout: |
| 209 | return "UiLayout"; | 209 | return "UILayout"; |
| 210 | case Category::UiGameList: | 210 | case Category::UiGameList: |
| 211 | return "UiGameList"; | 211 | return "UIGameList"; |
| 212 | case Category::Screenshots: | 212 | case Category::Screenshots: |
| 213 | return "Screenshots"; | 213 | return "Screenshots"; |
| 214 | case Category::Shortcuts: | 214 | case Category::Shortcuts: |
| @@ -219,6 +219,8 @@ const char* TranslateCategory(Category category) { | |||
| 219 | return "Services"; | 219 | return "Services"; |
| 220 | case Category::Paths: | 220 | case Category::Paths: |
| 221 | return "Paths"; | 221 | return "Paths"; |
| 222 | case Category::Linux: | ||
| 223 | return "Linux"; | ||
| 222 | case Category::MaxEnum: | 224 | case Category::MaxEnum: |
| 223 | break; | 225 | break; |
| 224 | } | 226 | } |
diff --git a/src/common/settings.h b/src/common/settings.h index e899f1ae6..6425cd98f 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -232,7 +232,11 @@ struct Values { | |||
| 232 | SwitchableSetting<bool> use_asynchronous_gpu_emulation{ | 232 | SwitchableSetting<bool> use_asynchronous_gpu_emulation{ |
| 233 | linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer}; | 233 | linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer}; |
| 234 | SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage, | 234 | SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage, |
| 235 | #ifdef ANDROID | ||
| 236 | AstcDecodeMode::Cpu, | ||
| 237 | #else | ||
| 235 | AstcDecodeMode::Gpu, | 238 | AstcDecodeMode::Gpu, |
| 239 | #endif | ||
| 236 | AstcDecodeMode::Cpu, | 240 | AstcDecodeMode::Cpu, |
| 237 | AstcDecodeMode::CpuAsynchronous, | 241 | AstcDecodeMode::CpuAsynchronous, |
| 238 | "accelerate_astc", | 242 | "accelerate_astc", |
| @@ -304,7 +308,11 @@ struct Values { | |||
| 304 | linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true}; | 308 | linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true}; |
| 305 | 309 | ||
| 306 | SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage, | 310 | SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage, |
| 311 | #ifdef ANDROID | ||
| 312 | GpuAccuracy::Normal, | ||
| 313 | #else | ||
| 307 | GpuAccuracy::High, | 314 | GpuAccuracy::High, |
| 315 | #endif | ||
| 308 | GpuAccuracy::Normal, | 316 | GpuAccuracy::Normal, |
| 309 | GpuAccuracy::Extreme, | 317 | GpuAccuracy::Extreme, |
| 310 | "gpu_accuracy", | 318 | "gpu_accuracy", |
| @@ -313,20 +321,38 @@ struct Values { | |||
| 313 | true, | 321 | true, |
| 314 | true}; | 322 | true}; |
| 315 | GpuAccuracy current_gpu_accuracy{GpuAccuracy::High}; | 323 | GpuAccuracy current_gpu_accuracy{GpuAccuracy::High}; |
| 316 | SwitchableSetting<AnisotropyMode, true> max_anisotropy{ | 324 | SwitchableSetting<AnisotropyMode, true> max_anisotropy{linkage, |
| 317 | linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16, | 325 | #ifdef ANDROID |
| 318 | "max_anisotropy", Category::RendererAdvanced}; | 326 | AnisotropyMode::Default, |
| 327 | #else | ||
| 328 | AnisotropyMode::Automatic, | ||
| 329 | #endif | ||
| 330 | AnisotropyMode::Automatic, | ||
| 331 | AnisotropyMode::X16, | ||
| 332 | "max_anisotropy", | ||
| 333 | Category::RendererAdvanced}; | ||
| 319 | SwitchableSetting<AstcRecompression, true> astc_recompression{linkage, | 334 | SwitchableSetting<AstcRecompression, true> astc_recompression{linkage, |
| 320 | AstcRecompression::Uncompressed, | 335 | AstcRecompression::Uncompressed, |
| 321 | AstcRecompression::Uncompressed, | 336 | AstcRecompression::Uncompressed, |
| 322 | AstcRecompression::Bc3, | 337 | AstcRecompression::Bc3, |
| 323 | "astc_recompression", | 338 | "astc_recompression", |
| 324 | Category::RendererAdvanced}; | 339 | Category::RendererAdvanced}; |
| 325 | SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation", | 340 | SwitchableSetting<bool> async_presentation{linkage, |
| 326 | Category::RendererAdvanced}; | 341 | #ifdef ANDROID |
| 342 | true, | ||
| 343 | #else | ||
| 344 | false, | ||
| 345 | #endif | ||
| 346 | "async_presentation", Category::RendererAdvanced}; | ||
| 327 | SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock", | 347 | SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock", |
| 328 | Category::RendererAdvanced}; | 348 | Category::RendererAdvanced}; |
| 329 | SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing", | 349 | SwitchableSetting<bool> use_reactive_flushing{linkage, |
| 350 | #ifdef ANDROID | ||
| 351 | false, | ||
| 352 | #else | ||
| 353 | true, | ||
| 354 | #endif | ||
| 355 | "use_reactive_flushing", | ||
| 330 | Category::RendererAdvanced}; | 356 | Category::RendererAdvanced}; |
| 331 | SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", | 357 | SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", |
| 332 | Category::RendererAdvanced}; | 358 | Category::RendererAdvanced}; |
| @@ -358,6 +384,8 @@ struct Values { | |||
| 358 | Category::RendererDebug}; | 384 | Category::RendererDebug}; |
| 359 | // TODO: remove this once AMDVLK supports VK_EXT_depth_bias_control | 385 | // TODO: remove this once AMDVLK supports VK_EXT_depth_bias_control |
| 360 | bool renderer_amdvlk_depth_bias_workaround{}; | 386 | bool renderer_amdvlk_depth_bias_workaround{}; |
| 387 | Setting<bool> disable_buffer_reorder{linkage, false, "disable_buffer_reorder", | ||
| 388 | Category::RendererDebug}; | ||
| 361 | 389 | ||
| 362 | // System | 390 | // System |
| 363 | SwitchableSetting<Language, true> language_index{linkage, | 391 | SwitchableSetting<Language, true> language_index{linkage, |
| @@ -390,13 +418,20 @@ struct Values { | |||
| 390 | Setting<s32> current_user{linkage, 0, "current_user", Category::System}; | 418 | Setting<s32> current_user{linkage, 0, "current_user", Category::System}; |
| 391 | 419 | ||
| 392 | SwitchableSetting<ConsoleMode> use_docked_mode{linkage, | 420 | SwitchableSetting<ConsoleMode> use_docked_mode{linkage, |
| 421 | #ifdef ANDROID | ||
| 422 | ConsoleMode::Handheld, | ||
| 423 | #else | ||
| 393 | ConsoleMode::Docked, | 424 | ConsoleMode::Docked, |
| 425 | #endif | ||
| 394 | "use_docked_mode", | 426 | "use_docked_mode", |
| 395 | Category::System, | 427 | Category::System, |
| 396 | Specialization::Radio, | 428 | Specialization::Radio, |
| 397 | true, | 429 | true, |
| 398 | true}; | 430 | true}; |
| 399 | 431 | ||
| 432 | // Linux | ||
| 433 | SwitchableSetting<bool> enable_gamemode{linkage, true, "enable_gamemode", Category::Linux}; | ||
| 434 | |||
| 400 | // Controls | 435 | // Controls |
| 401 | InputSetting<std::array<PlayerInput, 10>> players; | 436 | InputSetting<std::array<PlayerInput, 10>> players; |
| 402 | 437 | ||
diff --git a/src/common/settings_common.h b/src/common/settings_common.h index 7943223eb..344c04439 100644 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h | |||
| @@ -41,6 +41,7 @@ enum class Category : u32 { | |||
| 41 | Multiplayer, | 41 | Multiplayer, |
| 42 | Services, | 42 | Services, |
| 43 | Paths, | 43 | Paths, |
| 44 | Linux, | ||
| 44 | MaxEnum, | 45 | MaxEnum, |
| 45 | }; | 46 | }; |
| 46 | 47 | ||
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index a72df034e..c7b48a58d 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -167,6 +167,11 @@ protected: | |||
| 167 | */ | 167 | */ |
| 168 | std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const; | 168 | std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const; |
| 169 | 169 | ||
| 170 | /** | ||
| 171 | * Clip the provided coordinates to be inside the touchscreen area. | ||
| 172 | */ | ||
| 173 | std::pair<u32, u32> ClipToTouchScreen(u32 new_x, u32 new_y) const; | ||
| 174 | |||
| 170 | WindowSystemInfo window_info; | 175 | WindowSystemInfo window_info; |
| 171 | 176 | ||
| 172 | bool strict_context_required = false; | 177 | bool strict_context_required = false; |
| @@ -181,11 +186,6 @@ private: | |||
| 181 | // By default, ignore this request and do nothing. | 186 | // By default, ignore this request and do nothing. |
| 182 | } | 187 | } |
| 183 | 188 | ||
| 184 | /** | ||
| 185 | * Clip the provided coordinates to be inside the touchscreen area. | ||
| 186 | */ | ||
| 187 | std::pair<u32, u32> ClipToTouchScreen(u32 new_x, u32 new_y) const; | ||
| 188 | |||
| 189 | Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout | 189 | Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout |
| 190 | 190 | ||
| 191 | u32 client_area_width; ///< Current client width, should be set by window impl. | 191 | u32 client_area_width; ///< Current client width, should be set by window impl. |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index a22015ada..a6e681e15 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -509,9 +509,11 @@ void EmulatedController::ReloadInput() { | |||
| 509 | }); | 509 | }); |
| 510 | } | 510 | } |
| 511 | turbo_button_state = 0; | 511 | turbo_button_state = 0; |
| 512 | is_initalized = true; | ||
| 512 | } | 513 | } |
| 513 | 514 | ||
| 514 | void EmulatedController::UnloadInput() { | 515 | void EmulatedController::UnloadInput() { |
| 516 | is_initalized = false; | ||
| 515 | for (auto& button : button_devices) { | 517 | for (auto& button : button_devices) { |
| 516 | button.reset(); | 518 | button.reset(); |
| 517 | } | 519 | } |
| @@ -1207,6 +1209,9 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { | |||
| 1207 | } | 1209 | } |
| 1208 | 1210 | ||
| 1209 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { | 1211 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { |
| 1212 | if (!is_initalized) { | ||
| 1213 | return false; | ||
| 1214 | } | ||
| 1210 | if (device_index >= output_devices.size()) { | 1215 | if (device_index >= output_devices.size()) { |
| 1211 | return false; | 1216 | return false; |
| 1212 | } | 1217 | } |
| @@ -1242,6 +1247,10 @@ bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { | |||
| 1242 | const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); | 1247 | const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); |
| 1243 | const auto& player = Settings::values.players.GetValue()[player_index]; | 1248 | const auto& player = Settings::values.players.GetValue()[player_index]; |
| 1244 | 1249 | ||
| 1250 | if (!is_initalized) { | ||
| 1251 | return false; | ||
| 1252 | } | ||
| 1253 | |||
| 1245 | if (!player.vibration_enabled) { | 1254 | if (!player.vibration_enabled) { |
| 1246 | return false; | 1255 | return false; |
| 1247 | } | 1256 | } |
| @@ -1261,6 +1270,10 @@ Common::Input::DriverResult EmulatedController::SetPollingMode( | |||
| 1261 | EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) { | 1270 | EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) { |
| 1262 | LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index); | 1271 | LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index); |
| 1263 | 1272 | ||
| 1273 | if (!is_initalized) { | ||
| 1274 | return Common::Input::DriverResult::InvalidHandle; | ||
| 1275 | } | ||
| 1276 | |||
| 1264 | auto& left_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Left)]; | 1277 | auto& left_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Left)]; |
| 1265 | auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1278 | auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1266 | auto& nfc_output_device = output_devices[3]; | 1279 | auto& nfc_output_device = output_devices[3]; |
| @@ -1306,6 +1319,10 @@ bool EmulatedController::SetCameraFormat( | |||
| 1306 | Core::IrSensor::ImageTransferProcessorFormat camera_format) { | 1319 | Core::IrSensor::ImageTransferProcessorFormat camera_format) { |
| 1307 | LOG_INFO(Service_HID, "Set camera format {}", camera_format); | 1320 | LOG_INFO(Service_HID, "Set camera format {}", camera_format); |
| 1308 | 1321 | ||
| 1322 | if (!is_initalized) { | ||
| 1323 | return false; | ||
| 1324 | } | ||
| 1325 | |||
| 1309 | auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1326 | auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1310 | auto& camera_output_device = output_devices[2]; | 1327 | auto& camera_output_device = output_devices[2]; |
| 1311 | 1328 | ||
| @@ -1329,6 +1346,11 @@ void EmulatedController::SetRingParam(Common::ParamPackage param) { | |||
| 1329 | } | 1346 | } |
| 1330 | 1347 | ||
| 1331 | bool EmulatedController::HasNfc() const { | 1348 | bool EmulatedController::HasNfc() const { |
| 1349 | |||
| 1350 | if (!is_initalized) { | ||
| 1351 | return false; | ||
| 1352 | } | ||
| 1353 | |||
| 1332 | const auto& nfc_output_device = output_devices[3]; | 1354 | const auto& nfc_output_device = output_devices[3]; |
| 1333 | 1355 | ||
| 1334 | switch (npad_type) { | 1356 | switch (npad_type) { |
| @@ -1366,6 +1388,10 @@ bool EmulatedController::RemoveNfcHandle() { | |||
| 1366 | } | 1388 | } |
| 1367 | 1389 | ||
| 1368 | bool EmulatedController::StartNfcPolling() { | 1390 | bool EmulatedController::StartNfcPolling() { |
| 1391 | if (!is_initalized) { | ||
| 1392 | return false; | ||
| 1393 | } | ||
| 1394 | |||
| 1369 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1395 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1370 | auto& nfc_virtual_output_device = output_devices[3]; | 1396 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1371 | 1397 | ||
| @@ -1377,6 +1403,10 @@ bool EmulatedController::StartNfcPolling() { | |||
| 1377 | } | 1403 | } |
| 1378 | 1404 | ||
| 1379 | bool EmulatedController::StopNfcPolling() { | 1405 | bool EmulatedController::StopNfcPolling() { |
| 1406 | if (!is_initalized) { | ||
| 1407 | return false; | ||
| 1408 | } | ||
| 1409 | |||
| 1380 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1410 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1381 | auto& nfc_virtual_output_device = output_devices[3]; | 1411 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1382 | 1412 | ||
| @@ -1388,6 +1418,10 @@ bool EmulatedController::StopNfcPolling() { | |||
| 1388 | } | 1418 | } |
| 1389 | 1419 | ||
| 1390 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | 1420 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { |
| 1421 | if (!is_initalized) { | ||
| 1422 | return false; | ||
| 1423 | } | ||
| 1424 | |||
| 1391 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1425 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1392 | auto& nfc_virtual_output_device = output_devices[3]; | 1426 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1393 | 1427 | ||
| @@ -1400,6 +1434,10 @@ bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | |||
| 1400 | 1434 | ||
| 1401 | bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, | 1435 | bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, |
| 1402 | Common::Input::MifareRequest& out_data) { | 1436 | Common::Input::MifareRequest& out_data) { |
| 1437 | if (!is_initalized) { | ||
| 1438 | return false; | ||
| 1439 | } | ||
| 1440 | |||
| 1403 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1441 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1404 | auto& nfc_virtual_output_device = output_devices[3]; | 1442 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1405 | 1443 | ||
| @@ -1412,6 +1450,10 @@ bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& requ | |||
| 1412 | } | 1450 | } |
| 1413 | 1451 | ||
| 1414 | bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { | 1452 | bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { |
| 1453 | if (!is_initalized) { | ||
| 1454 | return false; | ||
| 1455 | } | ||
| 1456 | |||
| 1415 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1457 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1416 | auto& nfc_virtual_output_device = output_devices[3]; | 1458 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1417 | 1459 | ||
| @@ -1423,6 +1465,10 @@ bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& req | |||
| 1423 | } | 1465 | } |
| 1424 | 1466 | ||
| 1425 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { | 1467 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { |
| 1468 | if (!is_initalized) { | ||
| 1469 | return false; | ||
| 1470 | } | ||
| 1471 | |||
| 1426 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1472 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1427 | auto& nfc_virtual_output_device = output_devices[3]; | 1473 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1428 | 1474 | ||
| @@ -1434,6 +1480,10 @@ bool EmulatedController::WriteNfc(const std::vector<u8>& data) { | |||
| 1434 | } | 1480 | } |
| 1435 | 1481 | ||
| 1436 | void EmulatedController::SetLedPattern() { | 1482 | void EmulatedController::SetLedPattern() { |
| 1483 | if (!is_initalized) { | ||
| 1484 | return; | ||
| 1485 | } | ||
| 1486 | |||
| 1437 | for (auto& device : output_devices) { | 1487 | for (auto& device : output_devices) { |
| 1438 | if (!device) { | 1488 | if (!device) { |
| 1439 | continue; | 1489 | continue; |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index ea18c2343..d6e20ab66 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -559,6 +559,7 @@ private: | |||
| 559 | NpadStyleTag supported_style_tag{NpadStyleSet::All}; | 559 | NpadStyleTag supported_style_tag{NpadStyleSet::All}; |
| 560 | bool is_connected{false}; | 560 | bool is_connected{false}; |
| 561 | bool is_configuring{false}; | 561 | bool is_configuring{false}; |
| 562 | bool is_initalized{false}; | ||
| 562 | bool system_buttons_enabled{true}; | 563 | bool system_buttons_enabled{true}; |
| 563 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; | 564 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; |
| 564 | u32 turbo_button_state{0}; | 565 | u32 turbo_button_state{0}; |
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index b379dadeb..3906c0fa4 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp | |||
| @@ -122,7 +122,8 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) | |||
| 122 | Service::NFP::RegisterInfoPrivate register_info{}; | 122 | Service::NFP::RegisterInfoPrivate register_info{}; |
| 123 | std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(), | 123 | std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(), |
| 124 | std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1)); | 124 | std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1)); |
| 125 | 125 | register_info.mii_store_data.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All); | |
| 126 | register_info.mii_store_data.SetNickname({u'y', u'u', u'z', u'u'}); | ||
| 126 | nfp_device->SetRegisterInfoPrivate(register_info); | 127 | nfp_device->SetRegisterInfoPrivate(register_info); |
| 127 | break; | 128 | break; |
| 128 | } | 129 | } |
| @@ -130,7 +131,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) | |||
| 130 | nfp_device->DeleteApplicationArea(); | 131 | nfp_device->DeleteApplicationArea(); |
| 131 | break; | 132 | break; |
| 132 | case Service::NFP::CabinetMode::StartRestorer: | 133 | case Service::NFP::CabinetMode::StartRestorer: |
| 133 | nfp_device->RestoreAmiibo(); | 134 | nfp_device->Restore(); |
| 134 | break; | 135 | break; |
| 135 | case Service::NFP::CabinetMode::StartFormatter: | 136 | case Service::NFP::CabinetMode::StartFormatter: |
| 136 | nfp_device->Format(); | 137 | nfp_device->Format(); |
diff --git a/src/core/hle/service/mii/types/ver3_store_data.cpp b/src/core/hle/service/mii/types/ver3_store_data.cpp index a019cc9f7..c27646fcf 100644 --- a/src/core/hle/service/mii/types/ver3_store_data.cpp +++ b/src/core/hle/service/mii/types/ver3_store_data.cpp | |||
| @@ -98,7 +98,7 @@ void Ver3StoreData::BuildToStoreData(StoreData& out_store_data) const { | |||
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | void Ver3StoreData::BuildFromStoreData(const StoreData& store_data) { | 100 | void Ver3StoreData::BuildFromStoreData(const StoreData& store_data) { |
| 101 | version = 1; | 101 | version = 3; |
| 102 | mii_information.gender.Assign(static_cast<u8>(store_data.GetGender())); | 102 | mii_information.gender.Assign(static_cast<u8>(store_data.GetGender())); |
| 103 | mii_information.favorite_color.Assign(static_cast<u8>(store_data.GetFavoriteColor())); | 103 | mii_information.favorite_color.Assign(static_cast<u8>(store_data.GetFavoriteColor())); |
| 104 | height = store_data.GetHeight(); | 104 | height = store_data.GetHeight(); |
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index e7a00deb3..47516f883 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp | |||
| @@ -401,6 +401,12 @@ Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& time | |||
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) { | 403 | Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) { |
| 404 | bool is_corrupted = false; | ||
| 405 | |||
| 406 | if (model_type != NFP::ModelType::Amiibo) { | ||
| 407 | return ResultInvalidArgument; | ||
| 408 | } | ||
| 409 | |||
| 404 | if (device_state != DeviceState::TagFound) { | 410 | if (device_state != DeviceState::TagFound) { |
| 405 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | 411 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |
| 406 | return ResultWrongDeviceState; | 412 | return ResultWrongDeviceState; |
| @@ -420,26 +426,32 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target | |||
| 420 | if (is_plain_amiibo) { | 426 | if (is_plain_amiibo) { |
| 421 | std::vector<u8> data(sizeof(NFP::NTAG215File)); | 427 | std::vector<u8> data(sizeof(NFP::NTAG215File)); |
| 422 | memcpy(data.data(), &tag_data, sizeof(tag_data)); | 428 | memcpy(data.data(), &tag_data, sizeof(tag_data)); |
| 423 | WriteBackupData(tag_data.uid, data); | 429 | } |
| 424 | 430 | ||
| 425 | device_state = DeviceState::TagMounted; | 431 | if (!is_plain_amiibo && !NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { |
| 426 | mount_target = mount_target_; | 432 | LOG_ERROR(Service_NFP, "Can't decode amiibo"); |
| 427 | return ResultSuccess; | 433 | is_corrupted = true; |
| 428 | } | 434 | } |
| 429 | 435 | ||
| 430 | if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { | 436 | if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) { |
| 431 | bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess(); | 437 | LOG_ERROR(Service_NFP, "Invalid mii data"); |
| 432 | LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup); | 438 | is_corrupted = true; |
| 433 | return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData; | ||
| 434 | } | 439 | } |
| 435 | 440 | ||
| 436 | std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); | 441 | if (!is_corrupted) { |
| 437 | memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); | 442 | std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); |
| 438 | WriteBackupData(encrypted_tag_data.uuid, data); | 443 | memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); |
| 444 | WriteBackupData(encrypted_tag_data.uuid, data); | ||
| 445 | } | ||
| 439 | 446 | ||
| 440 | device_state = DeviceState::TagMounted; | 447 | device_state = DeviceState::TagMounted; |
| 441 | mount_target = mount_target_; | 448 | mount_target = mount_target_; |
| 442 | 449 | ||
| 450 | if (is_corrupted) { | ||
| 451 | bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess(); | ||
| 452 | return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData; | ||
| 453 | } | ||
| 454 | |||
| 443 | return ResultSuccess; | 455 | return ResultSuccess; |
| 444 | } | 456 | } |
| 445 | 457 | ||
| @@ -606,6 +618,17 @@ Result NfcDevice::Restore() { | |||
| 606 | } | 618 | } |
| 607 | } | 619 | } |
| 608 | 620 | ||
| 621 | // Restore mii data in case is corrupted by previous instances of yuzu | ||
| 622 | if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) { | ||
| 623 | LOG_ERROR(Service_NFP, "Regenerating mii data"); | ||
| 624 | Mii::StoreData new_mii{}; | ||
| 625 | new_mii.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All); | ||
| 626 | new_mii.SetNickname({u'y', u'u', u'z', u'u', u'\0'}); | ||
| 627 | |||
| 628 | tag_data.owner_mii.BuildFromStoreData(new_mii); | ||
| 629 | tag_data.mii_extension.SetFromStoreData(new_mii); | ||
| 630 | } | ||
| 631 | |||
| 609 | // Overwrite tag contents with backup and mount the tag | 632 | // Overwrite tag contents with backup and mount the tag |
| 610 | tag_data = temporary_tag_data; | 633 | tag_data = temporary_tag_data; |
| 611 | encrypted_tag_data = temporary_encrypted_tag_data; | 634 | encrypted_tag_data = temporary_encrypted_tag_data; |
| @@ -851,25 +874,6 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe | |||
| 851 | return Flush(); | 874 | return Flush(); |
| 852 | } | 875 | } |
| 853 | 876 | ||
| 854 | Result NfcDevice::RestoreAmiibo() { | ||
| 855 | if (device_state != DeviceState::TagMounted) { | ||
| 856 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 857 | if (device_state == DeviceState::TagRemoved) { | ||
| 858 | return ResultTagRemoved; | ||
| 859 | } | ||
| 860 | return ResultWrongDeviceState; | ||
| 861 | } | ||
| 862 | |||
| 863 | if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) { | ||
| 864 | LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); | ||
| 865 | return ResultWrongDeviceState; | ||
| 866 | } | ||
| 867 | |||
| 868 | // TODO: Load amiibo from backup on system | ||
| 869 | LOG_ERROR(Service_NFP, "Not Implemented"); | ||
| 870 | return ResultSuccess; | ||
| 871 | } | ||
| 872 | |||
| 873 | Result NfcDevice::Format() { | 877 | Result NfcDevice::Format() { |
| 874 | Result result = ResultSuccess; | 878 | Result result = ResultSuccess; |
| 875 | 879 | ||
| @@ -877,7 +881,9 @@ Result NfcDevice::Format() { | |||
| 877 | result = Mount(NFP::ModelType::Amiibo, NFP::MountTarget::All); | 881 | result = Mount(NFP::ModelType::Amiibo, NFP::MountTarget::All); |
| 878 | } | 882 | } |
| 879 | 883 | ||
| 880 | if (result.IsError()) { | 884 | // We are formatting all data. Corruption is not an issue. |
| 885 | if (result.IsError() && | ||
| 886 | (result != ResultCorruptedData && result != ResultCorruptedDataWithBackup)) { | ||
| 881 | return result; | 887 | return result; |
| 882 | } | 888 | } |
| 883 | 889 | ||
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index 0ed1ff34c..d8efe25ec 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h | |||
| @@ -68,7 +68,6 @@ public: | |||
| 68 | 68 | ||
| 69 | Result DeleteRegisterInfo(); | 69 | Result DeleteRegisterInfo(); |
| 70 | Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info); | 70 | Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info); |
| 71 | Result RestoreAmiibo(); | ||
| 72 | Result Format(); | 71 | Result Format(); |
| 73 | 72 | ||
| 74 | Result OpenApplicationArea(u32 access_id); | 73 | Result OpenApplicationArea(u32 access_id); |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 19c667b42..f5edfdc8b 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -19,19 +19,8 @@ | |||
| 19 | 19 | ||
| 20 | namespace Service::Set { | 20 | namespace Service::Set { |
| 21 | 21 | ||
| 22 | namespace { | 22 | Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, |
| 23 | constexpr u64 SYSTEM_VERSION_FILE_MINOR_REVISION_OFFSET = 0x05; | 23 | GetFirmwareVersionType type) { |
| 24 | |||
| 25 | enum class GetFirmwareVersionType { | ||
| 26 | Version1, | ||
| 27 | Version2, | ||
| 28 | }; | ||
| 29 | |||
| 30 | void GetFirmwareVersionImpl(Core::System& system, HLERequestContext& ctx, | ||
| 31 | GetFirmwareVersionType type) { | ||
| 32 | ASSERT_MSG(ctx.GetWriteBufferSize() == 0x100, | ||
| 33 | "FirmwareVersion output buffer must be 0x100 bytes in size!"); | ||
| 34 | |||
| 35 | constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809; | 24 | constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809; |
| 36 | auto& fsc = system.GetFileSystemController(); | 25 | auto& fsc = system.GetFileSystemController(); |
| 37 | 26 | ||
| @@ -52,39 +41,34 @@ void GetFirmwareVersionImpl(Core::System& system, HLERequestContext& ctx, | |||
| 52 | FileSys::SystemArchive::SynthesizeSystemArchive(FirmwareVersionSystemDataId)); | 41 | FileSys::SystemArchive::SynthesizeSystemArchive(FirmwareVersionSystemDataId)); |
| 53 | } | 42 | } |
| 54 | 43 | ||
| 55 | const auto early_exit_failure = [&ctx](std::string_view desc, Result code) { | 44 | const auto early_exit_failure = [](std::string_view desc, Result code) { |
| 56 | LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", | 45 | LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", |
| 57 | desc); | 46 | desc); |
| 58 | IPC::ResponseBuilder rb{ctx, 2}; | 47 | return code; |
| 59 | rb.Push(code); | ||
| 60 | }; | 48 | }; |
| 61 | 49 | ||
| 62 | const auto ver_file = romfs->GetFile("file"); | 50 | const auto ver_file = romfs->GetFile("file"); |
| 63 | if (ver_file == nullptr) { | 51 | if (ver_file == nullptr) { |
| 64 | early_exit_failure("The system version archive didn't contain the file 'file'.", | 52 | return early_exit_failure("The system version archive didn't contain the file 'file'.", |
| 65 | FileSys::ERROR_INVALID_ARGUMENT); | 53 | FileSys::ERROR_INVALID_ARGUMENT); |
| 66 | return; | ||
| 67 | } | 54 | } |
| 68 | 55 | ||
| 69 | auto data = ver_file->ReadAllBytes(); | 56 | auto data = ver_file->ReadAllBytes(); |
| 70 | if (data.size() != 0x100) { | 57 | if (data.size() != sizeof(FirmwareVersionFormat)) { |
| 71 | early_exit_failure("The system version file 'file' was not the correct size.", | 58 | return early_exit_failure("The system version file 'file' was not the correct size.", |
| 72 | FileSys::ERROR_OUT_OF_BOUNDS); | 59 | FileSys::ERROR_OUT_OF_BOUNDS); |
| 73 | return; | ||
| 74 | } | 60 | } |
| 75 | 61 | ||
| 62 | std::memcpy(&out_firmware, data.data(), sizeof(FirmwareVersionFormat)); | ||
| 63 | |||
| 76 | // If the command is GetFirmwareVersion (as opposed to GetFirmwareVersion2), hardware will | 64 | // If the command is GetFirmwareVersion (as opposed to GetFirmwareVersion2), hardware will |
| 77 | // zero out the REVISION_MINOR field. | 65 | // zero out the REVISION_MINOR field. |
| 78 | if (type == GetFirmwareVersionType::Version1) { | 66 | if (type == GetFirmwareVersionType::Version1) { |
| 79 | data[SYSTEM_VERSION_FILE_MINOR_REVISION_OFFSET] = 0; | 67 | out_firmware.revision_minor = 0; |
| 80 | } | 68 | } |
| 81 | 69 | ||
| 82 | ctx.WriteBuffer(data); | 70 | return ResultSuccess; |
| 83 | |||
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 85 | rb.Push(ResultSuccess); | ||
| 86 | } | 71 | } |
| 87 | } // Anonymous namespace | ||
| 88 | 72 | ||
| 89 | void SET_SYS::SetLanguageCode(HLERequestContext& ctx) { | 73 | void SET_SYS::SetLanguageCode(HLERequestContext& ctx) { |
| 90 | IPC::RequestParser rp{ctx}; | 74 | IPC::RequestParser rp{ctx}; |
| @@ -98,12 +82,32 @@ void SET_SYS::SetLanguageCode(HLERequestContext& ctx) { | |||
| 98 | 82 | ||
| 99 | void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) { | 83 | void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) { |
| 100 | LOG_DEBUG(Service_SET, "called"); | 84 | LOG_DEBUG(Service_SET, "called"); |
| 101 | GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version1); | 85 | |
| 86 | FirmwareVersionFormat firmware_data{}; | ||
| 87 | const auto result = | ||
| 88 | GetFirmwareVersionImpl(firmware_data, system, GetFirmwareVersionType::Version1); | ||
| 89 | |||
| 90 | if (result.IsSuccess()) { | ||
| 91 | ctx.WriteBuffer(firmware_data); | ||
| 92 | } | ||
| 93 | |||
| 94 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 95 | rb.Push(result); | ||
| 102 | } | 96 | } |
| 103 | 97 | ||
| 104 | void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) { | 98 | void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) { |
| 105 | LOG_DEBUG(Service_SET, "called"); | 99 | LOG_DEBUG(Service_SET, "called"); |
| 106 | GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version2); | 100 | |
| 101 | FirmwareVersionFormat firmware_data{}; | ||
| 102 | const auto result = | ||
| 103 | GetFirmwareVersionImpl(firmware_data, system, GetFirmwareVersionType::Version2); | ||
| 104 | |||
| 105 | if (result.IsSuccess()) { | ||
| 106 | ctx.WriteBuffer(firmware_data); | ||
| 107 | } | ||
| 108 | |||
| 109 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 110 | rb.Push(result); | ||
| 107 | } | 111 | } |
| 108 | 112 | ||
| 109 | void SET_SYS::GetAccountSettings(HLERequestContext& ctx) { | 113 | void SET_SYS::GetAccountSettings(HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h index 93023c6dd..5f770fd32 100644 --- a/src/core/hle/service/set/set_sys.h +++ b/src/core/hle/service/set/set_sys.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "common/uuid.h" | 6 | #include "common/uuid.h" |
| 7 | #include "core/hle/result.h" | ||
| 7 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 8 | #include "core/hle/service/time/clock_types.h" | 9 | #include "core/hle/service/time/clock_types.h" |
| 9 | 10 | ||
| @@ -12,6 +13,29 @@ class System; | |||
| 12 | } | 13 | } |
| 13 | 14 | ||
| 14 | namespace Service::Set { | 15 | namespace Service::Set { |
| 16 | enum class LanguageCode : u64; | ||
| 17 | enum class GetFirmwareVersionType { | ||
| 18 | Version1, | ||
| 19 | Version2, | ||
| 20 | }; | ||
| 21 | |||
| 22 | struct FirmwareVersionFormat { | ||
| 23 | u8 major; | ||
| 24 | u8 minor; | ||
| 25 | u8 micro; | ||
| 26 | INSERT_PADDING_BYTES(1); | ||
| 27 | u8 revision_major; | ||
| 28 | u8 revision_minor; | ||
| 29 | INSERT_PADDING_BYTES(2); | ||
| 30 | std::array<char, 0x20> platform; | ||
| 31 | std::array<u8, 0x40> version_hash; | ||
| 32 | std::array<char, 0x18> display_version; | ||
| 33 | std::array<char, 0x80> display_title; | ||
| 34 | }; | ||
| 35 | static_assert(sizeof(FirmwareVersionFormat) == 0x100, "FirmwareVersionFormat is an invalid size"); | ||
| 36 | |||
| 37 | Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, | ||
| 38 | GetFirmwareVersionType type); | ||
| 15 | 39 | ||
| 16 | class SET_SYS final : public ServiceFramework<SET_SYS> { | 40 | class SET_SYS final : public ServiceFramework<SET_SYS> { |
| 17 | public: | 41 | public: |
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h index 9fc01ea90..7149fffeb 100644 --- a/src/core/hle/service/time/clock_types.h +++ b/src/core/hle/service/time/clock_types.h | |||
| @@ -11,6 +11,11 @@ | |||
| 11 | #include "core/hle/service/time/errors.h" | 11 | #include "core/hle/service/time/errors.h" |
| 12 | #include "core/hle/service/time/time_zone_types.h" | 12 | #include "core/hle/service/time/time_zone_types.h" |
| 13 | 13 | ||
| 14 | // Defined by WinBase.h on Windows | ||
| 15 | #ifdef GetCurrentTime | ||
| 16 | #undef GetCurrentTime | ||
| 17 | #endif | ||
| 18 | |||
| 14 | namespace Service::Time::Clock { | 19 | namespace Service::Time::Clock { |
| 15 | 20 | ||
| 16 | enum class TimeType : u8 { | 21 | enum class TimeType : u8 { |
diff --git a/src/frontend_common/CMakeLists.txt b/src/frontend_common/CMakeLists.txt new file mode 100644 index 000000000..22e9337c4 --- /dev/null +++ b/src/frontend_common/CMakeLists.txt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | # SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | add_library(frontend_common STATIC | ||
| 5 | config.cpp | ||
| 6 | config.h | ||
| 7 | ) | ||
| 8 | |||
| 9 | create_target_directory_groups(frontend_common) | ||
| 10 | target_link_libraries(frontend_common PUBLIC core SimpleIni::SimpleIni PRIVATE common Boost::headers) | ||
diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp new file mode 100644 index 000000000..7474cb0f9 --- /dev/null +++ b/src/frontend_common/config.cpp | |||
| @@ -0,0 +1,1008 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <array> | ||
| 6 | #include "common/fs/fs.h" | ||
| 7 | #include "common/fs/path_util.h" | ||
| 8 | #include "common/settings.h" | ||
| 9 | #include "common/settings_common.h" | ||
| 10 | #include "common/settings_enums.h" | ||
| 11 | #include "config.h" | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/hle/service/acc/profile_manager.h" | ||
| 14 | #include "core/hle/service/hid/controllers/npad.h" | ||
| 15 | #include "network/network.h" | ||
| 16 | |||
| 17 | #include <boost/algorithm/string/replace.hpp> | ||
| 18 | |||
| 19 | #include "common/string_util.h" | ||
| 20 | |||
| 21 | namespace FS = Common::FS; | ||
| 22 | |||
| 23 | Config::Config(const ConfigType config_type) | ||
| 24 | : type(config_type), global{config_type == ConfigType::GlobalConfig} {} | ||
| 25 | |||
| 26 | void Config::Initialize(const std::string& config_name) { | ||
| 27 | const std::filesystem::path fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); | ||
| 28 | const auto config_file = fmt::format("{}.ini", config_name); | ||
| 29 | |||
| 30 | switch (type) { | ||
| 31 | case ConfigType::GlobalConfig: | ||
| 32 | config_loc = FS::PathToUTF8String(fs_config_loc / config_file); | ||
| 33 | void(FS::CreateParentDir(config_loc)); | ||
| 34 | SetUpIni(); | ||
| 35 | Reload(); | ||
| 36 | break; | ||
| 37 | case ConfigType::PerGameConfig: | ||
| 38 | config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); | ||
| 39 | void(FS::CreateParentDir(config_loc)); | ||
| 40 | SetUpIni(); | ||
| 41 | Reload(); | ||
| 42 | break; | ||
| 43 | case ConfigType::InputProfile: | ||
| 44 | config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); | ||
| 45 | void(FS::CreateParentDir(config_loc)); | ||
| 46 | SetUpIni(); | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | void Config::Initialize(const std::optional<std::string> config_path) { | ||
| 52 | const std::filesystem::path default_sdl_config_path = | ||
| 53 | FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini"; | ||
| 54 | config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path)); | ||
| 55 | void(FS::CreateParentDir(config_loc)); | ||
| 56 | SetUpIni(); | ||
| 57 | Reload(); | ||
| 58 | } | ||
| 59 | |||
| 60 | void Config::WriteToIni() const { | ||
| 61 | FILE* fp = nullptr; | ||
| 62 | #ifdef _WIN32 | ||
| 63 | fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb"); | ||
| 64 | #else | ||
| 65 | fp = fopen(config_loc.c_str(), "wb"); | ||
| 66 | #endif | ||
| 67 | |||
| 68 | if (fp == nullptr) { | ||
| 69 | LOG_ERROR(Frontend, "Config file could not be saved!"); | ||
| 70 | return; | ||
| 71 | } | ||
| 72 | |||
| 73 | CSimpleIniA::FileWriter writer(fp); | ||
| 74 | const SI_Error rc = config->Save(writer, false); | ||
| 75 | if (rc < 0) { | ||
| 76 | LOG_ERROR(Frontend, "Config file could not be saved!"); | ||
| 77 | } | ||
| 78 | fclose(fp); | ||
| 79 | } | ||
| 80 | |||
| 81 | void Config::SetUpIni() { | ||
| 82 | config = std::make_unique<CSimpleIniA>(); | ||
| 83 | config->SetUnicode(true); | ||
| 84 | config->SetSpaces(false); | ||
| 85 | |||
| 86 | FILE* fp = nullptr; | ||
| 87 | #ifdef _WIN32 | ||
| 88 | _wfopen_s(&fp, Common::UTF8ToUTF16W(config_loc).data(), L"rb, ccs=UTF-8"); | ||
| 89 | if (fp == nullptr) { | ||
| 90 | fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb, ccs=UTF-8"); | ||
| 91 | } | ||
| 92 | #else | ||
| 93 | fp = fopen(config_loc.c_str(), "rb"); | ||
| 94 | if (fp == nullptr) { | ||
| 95 | fp = fopen(config_loc.c_str(), "wb"); | ||
| 96 | } | ||
| 97 | #endif | ||
| 98 | |||
| 99 | if (fp == nullptr) { | ||
| 100 | LOG_ERROR(Frontend, "Config file could not be loaded!"); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (SI_Error rc = config->LoadFile(fp); rc < 0) { | ||
| 105 | LOG_ERROR(Frontend, "Config file could not be loaded!"); | ||
| 106 | } | ||
| 107 | fclose(fp); | ||
| 108 | } | ||
| 109 | |||
| 110 | bool Config::IsCustomConfig() const { | ||
| 111 | return type == ConfigType::PerGameConfig; | ||
| 112 | } | ||
| 113 | |||
| 114 | void Config::ReadPlayerValues(const std::size_t player_index) { | ||
| 115 | std::string player_prefix; | ||
| 116 | if (type != ConfigType::InputProfile) { | ||
| 117 | player_prefix.append("player_").append(ToString(player_index)).append("_"); | ||
| 118 | } | ||
| 119 | |||
| 120 | auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 121 | if (IsCustomConfig()) { | ||
| 122 | const auto profile_name = | ||
| 123 | ReadStringSetting(std::string(player_prefix).append("profile_name")); | ||
| 124 | if (profile_name.empty()) { | ||
| 125 | // Use the global input config | ||
| 126 | player = Settings::values.players.GetValue(true)[player_index]; | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | player.profile_name = profile_name; | ||
| 130 | } | ||
| 131 | |||
| 132 | if (player_prefix.empty() && Settings::IsConfiguringGlobal()) { | ||
| 133 | const auto controller = static_cast<Settings::ControllerType>( | ||
| 134 | ReadIntegerSetting(std::string(player_prefix).append("type"), | ||
| 135 | static_cast<u8>(Settings::ControllerType::ProController))); | ||
| 136 | |||
| 137 | if (controller == Settings::ControllerType::LeftJoycon || | ||
| 138 | controller == Settings::ControllerType::RightJoycon) { | ||
| 139 | player.controller_type = controller; | ||
| 140 | } | ||
| 141 | } else { | ||
| 142 | std::string connected_key = player_prefix; | ||
| 143 | player.connected = ReadBooleanSetting(connected_key.append("connected"), | ||
| 144 | std::make_optional(player_index == 0)); | ||
| 145 | |||
| 146 | player.controller_type = static_cast<Settings::ControllerType>( | ||
| 147 | ReadIntegerSetting(std::string(player_prefix).append("type"), | ||
| 148 | static_cast<u8>(Settings::ControllerType::ProController))); | ||
| 149 | |||
| 150 | player.vibration_enabled = ReadBooleanSetting( | ||
| 151 | std::string(player_prefix).append("vibration_enabled"), std::make_optional(true)); | ||
| 152 | |||
| 153 | player.vibration_strength = static_cast<int>( | ||
| 154 | ReadIntegerSetting(std::string(player_prefix).append("vibration_strength"), 100)); | ||
| 155 | |||
| 156 | player.body_color_left = static_cast<u32>(ReadIntegerSetting( | ||
| 157 | std::string(player_prefix).append("body_color_left"), Settings::JOYCON_BODY_NEON_BLUE)); | ||
| 158 | player.body_color_right = static_cast<u32>(ReadIntegerSetting( | ||
| 159 | std::string(player_prefix).append("body_color_right"), Settings::JOYCON_BODY_NEON_RED)); | ||
| 160 | player.button_color_left = static_cast<u32>( | ||
| 161 | ReadIntegerSetting(std::string(player_prefix).append("button_color_left"), | ||
| 162 | Settings::JOYCON_BUTTONS_NEON_BLUE)); | ||
| 163 | player.button_color_right = static_cast<u32>( | ||
| 164 | ReadIntegerSetting(std::string(player_prefix).append("button_color_right"), | ||
| 165 | Settings::JOYCON_BUTTONS_NEON_RED)); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | void Config::ReadTouchscreenValues() { | ||
| 170 | Settings::values.touchscreen.enabled = | ||
| 171 | ReadBooleanSetting(std::string("touchscreen_enabled"), std::make_optional(true)); | ||
| 172 | Settings::values.touchscreen.rotation_angle = | ||
| 173 | static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_angle"), 0)); | ||
| 174 | Settings::values.touchscreen.diameter_x = | ||
| 175 | static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 15)); | ||
| 176 | Settings::values.touchscreen.diameter_y = | ||
| 177 | static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 15)); | ||
| 178 | } | ||
| 179 | |||
| 180 | void Config::ReadAudioValues() { | ||
| 181 | BeginGroup(Settings::TranslateCategory(Settings::Category::Audio)); | ||
| 182 | |||
| 183 | ReadCategory(Settings::Category::Audio); | ||
| 184 | ReadCategory(Settings::Category::UiAudio); | ||
| 185 | |||
| 186 | EndGroup(); | ||
| 187 | } | ||
| 188 | |||
| 189 | void Config::ReadControlValues() { | ||
| 190 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 191 | |||
| 192 | ReadCategory(Settings::Category::Controls); | ||
| 193 | |||
| 194 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 195 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 196 | ReadPlayerValues(p); | ||
| 197 | } | ||
| 198 | |||
| 199 | // Disable docked mode if handheld is selected | ||
| 200 | const auto controller_type = Settings::values.players.GetValue()[0].controller_type; | ||
| 201 | if (controller_type == Settings::ControllerType::Handheld) { | ||
| 202 | Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig()); | ||
| 203 | Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); | ||
| 204 | } | ||
| 205 | |||
| 206 | if (IsCustomConfig()) { | ||
| 207 | EndGroup(); | ||
| 208 | return; | ||
| 209 | } | ||
| 210 | ReadTouchscreenValues(); | ||
| 211 | ReadMotionTouchValues(); | ||
| 212 | |||
| 213 | EndGroup(); | ||
| 214 | } | ||
| 215 | |||
| 216 | void Config::ReadMotionTouchValues() { | ||
| 217 | int num_touch_from_button_maps = BeginArray(std::string("touch_from_button_maps")); | ||
| 218 | |||
| 219 | if (num_touch_from_button_maps > 0) { | ||
| 220 | for (int i = 0; i < num_touch_from_button_maps; ++i) { | ||
| 221 | SetArrayIndex(i); | ||
| 222 | |||
| 223 | Settings::TouchFromButtonMap map; | ||
| 224 | map.name = ReadStringSetting(std::string("name"), std::string("default")); | ||
| 225 | |||
| 226 | const int num_touch_maps = BeginArray(std::string("entries")); | ||
| 227 | map.buttons.reserve(num_touch_maps); | ||
| 228 | for (int j = 0; j < num_touch_maps; j++) { | ||
| 229 | SetArrayIndex(j); | ||
| 230 | std::string touch_mapping = ReadStringSetting(std::string("bind")); | ||
| 231 | map.buttons.emplace_back(std::move(touch_mapping)); | ||
| 232 | } | ||
| 233 | EndArray(); // entries | ||
| 234 | Settings::values.touch_from_button_maps.emplace_back(std::move(map)); | ||
| 235 | } | ||
| 236 | } else { | ||
| 237 | Settings::values.touch_from_button_maps.emplace_back( | ||
| 238 | Settings::TouchFromButtonMap{"default", {}}); | ||
| 239 | num_touch_from_button_maps = 1; | ||
| 240 | } | ||
| 241 | EndArray(); // touch_from_button_maps | ||
| 242 | |||
| 243 | Settings::values.touch_from_button_map_index = std::clamp( | ||
| 244 | Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); | ||
| 245 | } | ||
| 246 | |||
| 247 | void Config::ReadCoreValues() { | ||
| 248 | BeginGroup(Settings::TranslateCategory(Settings::Category::Core)); | ||
| 249 | |||
| 250 | ReadCategory(Settings::Category::Core); | ||
| 251 | |||
| 252 | EndGroup(); | ||
| 253 | } | ||
| 254 | |||
| 255 | void Config::ReadDataStorageValues() { | ||
| 256 | BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); | ||
| 257 | |||
| 258 | FS::SetYuzuPath(FS::YuzuPath::NANDDir, ReadStringSetting(std::string("nand_directory"))); | ||
| 259 | FS::SetYuzuPath(FS::YuzuPath::SDMCDir, ReadStringSetting(std::string("sdmc_directory"))); | ||
| 260 | FS::SetYuzuPath(FS::YuzuPath::LoadDir, ReadStringSetting(std::string("load_directory"))); | ||
| 261 | FS::SetYuzuPath(FS::YuzuPath::DumpDir, ReadStringSetting(std::string("dump_directory"))); | ||
| 262 | FS::SetYuzuPath(FS::YuzuPath::TASDir, ReadStringSetting(std::string("tas_directory"))); | ||
| 263 | |||
| 264 | ReadCategory(Settings::Category::DataStorage); | ||
| 265 | |||
| 266 | EndGroup(); | ||
| 267 | } | ||
| 268 | |||
| 269 | void Config::ReadDebuggingValues() { | ||
| 270 | BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging)); | ||
| 271 | |||
| 272 | // Intentionally not using the QT default setting as this is intended to be changed in the ini | ||
| 273 | Settings::values.record_frame_times = | ||
| 274 | ReadBooleanSetting(std::string("record_frame_times"), std::make_optional(false)); | ||
| 275 | |||
| 276 | ReadCategory(Settings::Category::Debugging); | ||
| 277 | ReadCategory(Settings::Category::DebuggingGraphics); | ||
| 278 | |||
| 279 | EndGroup(); | ||
| 280 | } | ||
| 281 | |||
| 282 | void Config::ReadServiceValues() { | ||
| 283 | BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); | ||
| 284 | |||
| 285 | ReadCategory(Settings::Category::Services); | ||
| 286 | |||
| 287 | EndGroup(); | ||
| 288 | } | ||
| 289 | |||
| 290 | void Config::ReadDisabledAddOnValues() { | ||
| 291 | // Custom config section | ||
| 292 | BeginGroup(std::string("DisabledAddOns")); | ||
| 293 | |||
| 294 | const int size = BeginArray(std::string("")); | ||
| 295 | for (int i = 0; i < size; ++i) { | ||
| 296 | SetArrayIndex(i); | ||
| 297 | const auto title_id = ReadUnsignedIntegerSetting(std::string("title_id"), 0); | ||
| 298 | std::vector<std::string> out; | ||
| 299 | const int d_size = BeginArray("disabled"); | ||
| 300 | for (int j = 0; j < d_size; ++j) { | ||
| 301 | SetArrayIndex(j); | ||
| 302 | out.push_back(ReadStringSetting(std::string("d"), std::string(""))); | ||
| 303 | } | ||
| 304 | EndArray(); // d | ||
| 305 | Settings::values.disabled_addons.insert_or_assign(title_id, out); | ||
| 306 | } | ||
| 307 | EndArray(); // Base disabled addons array - Has no base key | ||
| 308 | |||
| 309 | EndGroup(); | ||
| 310 | } | ||
| 311 | |||
| 312 | void Config::ReadMiscellaneousValues() { | ||
| 313 | BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous)); | ||
| 314 | |||
| 315 | ReadCategory(Settings::Category::Miscellaneous); | ||
| 316 | |||
| 317 | EndGroup(); | ||
| 318 | } | ||
| 319 | |||
| 320 | void Config::ReadCpuValues() { | ||
| 321 | BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu)); | ||
| 322 | |||
| 323 | ReadCategory(Settings::Category::Cpu); | ||
| 324 | ReadCategory(Settings::Category::CpuDebug); | ||
| 325 | ReadCategory(Settings::Category::CpuUnsafe); | ||
| 326 | |||
| 327 | EndGroup(); | ||
| 328 | } | ||
| 329 | |||
| 330 | void Config::ReadRendererValues() { | ||
| 331 | BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer)); | ||
| 332 | |||
| 333 | ReadCategory(Settings::Category::Renderer); | ||
| 334 | ReadCategory(Settings::Category::RendererAdvanced); | ||
| 335 | ReadCategory(Settings::Category::RendererDebug); | ||
| 336 | |||
| 337 | EndGroup(); | ||
| 338 | } | ||
| 339 | |||
| 340 | void Config::ReadScreenshotValues() { | ||
| 341 | BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots)); | ||
| 342 | |||
| 343 | ReadCategory(Settings::Category::Screenshots); | ||
| 344 | FS::SetYuzuPath(FS::YuzuPath::ScreenshotsDir, | ||
| 345 | ReadStringSetting(std::string("screenshot_path"))); | ||
| 346 | |||
| 347 | EndGroup(); | ||
| 348 | } | ||
| 349 | |||
| 350 | void Config::ReadSystemValues() { | ||
| 351 | BeginGroup(Settings::TranslateCategory(Settings::Category::System)); | ||
| 352 | |||
| 353 | ReadCategory(Settings::Category::System); | ||
| 354 | ReadCategory(Settings::Category::SystemAudio); | ||
| 355 | |||
| 356 | EndGroup(); | ||
| 357 | } | ||
| 358 | |||
| 359 | void Config::ReadWebServiceValues() { | ||
| 360 | BeginGroup(Settings::TranslateCategory(Settings::Category::WebService)); | ||
| 361 | |||
| 362 | ReadCategory(Settings::Category::WebService); | ||
| 363 | |||
| 364 | EndGroup(); | ||
| 365 | } | ||
| 366 | |||
| 367 | void Config::ReadNetworkValues() { | ||
| 368 | BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); | ||
| 369 | |||
| 370 | ReadCategory(Settings::Category::Network); | ||
| 371 | |||
| 372 | EndGroup(); | ||
| 373 | } | ||
| 374 | |||
| 375 | void Config::ReadValues() { | ||
| 376 | if (global) { | ||
| 377 | ReadDataStorageValues(); | ||
| 378 | ReadDebuggingValues(); | ||
| 379 | ReadDisabledAddOnValues(); | ||
| 380 | ReadNetworkValues(); | ||
| 381 | ReadServiceValues(); | ||
| 382 | ReadWebServiceValues(); | ||
| 383 | ReadMiscellaneousValues(); | ||
| 384 | } | ||
| 385 | ReadControlValues(); | ||
| 386 | ReadCoreValues(); | ||
| 387 | ReadCpuValues(); | ||
| 388 | ReadRendererValues(); | ||
| 389 | ReadAudioValues(); | ||
| 390 | ReadSystemValues(); | ||
| 391 | } | ||
| 392 | |||
| 393 | void Config::SavePlayerValues(const std::size_t player_index) { | ||
| 394 | std::string player_prefix; | ||
| 395 | if (type != ConfigType::InputProfile) { | ||
| 396 | player_prefix = std::string("player_").append(ToString(player_index)).append("_"); | ||
| 397 | } | ||
| 398 | |||
| 399 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 400 | if (IsCustomConfig()) { | ||
| 401 | if (player.profile_name.empty()) { | ||
| 402 | // No custom profile selected | ||
| 403 | return; | ||
| 404 | } | ||
| 405 | WriteSetting(std::string(player_prefix).append("profile_name"), player.profile_name, | ||
| 406 | std::make_optional(std::string(""))); | ||
| 407 | } | ||
| 408 | |||
| 409 | WriteSetting(std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type), | ||
| 410 | std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); | ||
| 411 | |||
| 412 | if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) { | ||
| 413 | WriteSetting(std::string(player_prefix).append("connected"), player.connected, | ||
| 414 | std::make_optional(player_index == 0)); | ||
| 415 | WriteSetting(std::string(player_prefix).append("vibration_enabled"), | ||
| 416 | player.vibration_enabled, std::make_optional(true)); | ||
| 417 | WriteSetting(std::string(player_prefix).append("vibration_strength"), | ||
| 418 | player.vibration_strength, std::make_optional(100)); | ||
| 419 | WriteSetting(std::string(player_prefix).append("body_color_left"), player.body_color_left, | ||
| 420 | std::make_optional(Settings::JOYCON_BODY_NEON_BLUE)); | ||
| 421 | WriteSetting(std::string(player_prefix).append("body_color_right"), player.body_color_right, | ||
| 422 | std::make_optional(Settings::JOYCON_BODY_NEON_RED)); | ||
| 423 | WriteSetting(std::string(player_prefix).append("button_color_left"), | ||
| 424 | player.button_color_left, | ||
| 425 | std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE)); | ||
| 426 | WriteSetting(std::string(player_prefix).append("button_color_right"), | ||
| 427 | player.button_color_right, | ||
| 428 | std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED)); | ||
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 432 | void Config::SaveTouchscreenValues() { | ||
| 433 | const auto& touchscreen = Settings::values.touchscreen; | ||
| 434 | |||
| 435 | WriteSetting(std::string("touchscreen_enabled"), touchscreen.enabled, std::make_optional(true)); | ||
| 436 | |||
| 437 | WriteSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle, | ||
| 438 | std::make_optional(static_cast<u32>(0))); | ||
| 439 | WriteSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, | ||
| 440 | std::make_optional(static_cast<u32>(15))); | ||
| 441 | WriteSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, | ||
| 442 | std::make_optional(static_cast<u32>(15))); | ||
| 443 | } | ||
| 444 | |||
| 445 | void Config::SaveMotionTouchValues() { | ||
| 446 | BeginArray(std::string("touch_from_button_maps")); | ||
| 447 | for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { | ||
| 448 | SetArrayIndex(static_cast<int>(p)); | ||
| 449 | WriteSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, | ||
| 450 | std::make_optional(std::string("default"))); | ||
| 451 | |||
| 452 | BeginArray(std::string("entries")); | ||
| 453 | for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); | ||
| 454 | ++q) { | ||
| 455 | SetArrayIndex(static_cast<int>(q)); | ||
| 456 | WriteSetting(std::string("bind"), | ||
| 457 | Settings::values.touch_from_button_maps[p].buttons[q]); | ||
| 458 | } | ||
| 459 | EndArray(); // entries | ||
| 460 | } | ||
| 461 | EndArray(); // touch_from_button_maps | ||
| 462 | } | ||
| 463 | |||
| 464 | void Config::SaveValues() { | ||
| 465 | if (global) { | ||
| 466 | SaveDataStorageValues(); | ||
| 467 | SaveDebuggingValues(); | ||
| 468 | SaveDisabledAddOnValues(); | ||
| 469 | SaveNetworkValues(); | ||
| 470 | SaveWebServiceValues(); | ||
| 471 | SaveMiscellaneousValues(); | ||
| 472 | } | ||
| 473 | SaveControlValues(); | ||
| 474 | SaveCoreValues(); | ||
| 475 | SaveCpuValues(); | ||
| 476 | SaveRendererValues(); | ||
| 477 | SaveAudioValues(); | ||
| 478 | SaveSystemValues(); | ||
| 479 | |||
| 480 | WriteToIni(); | ||
| 481 | } | ||
| 482 | |||
| 483 | void Config::SaveAudioValues() { | ||
| 484 | BeginGroup(Settings::TranslateCategory(Settings::Category::Audio)); | ||
| 485 | |||
| 486 | WriteCategory(Settings::Category::Audio); | ||
| 487 | WriteCategory(Settings::Category::UiAudio); | ||
| 488 | |||
| 489 | EndGroup(); | ||
| 490 | } | ||
| 491 | |||
| 492 | void Config::SaveControlValues() { | ||
| 493 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 494 | |||
| 495 | WriteCategory(Settings::Category::Controls); | ||
| 496 | |||
| 497 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 498 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 499 | SavePlayerValues(p); | ||
| 500 | } | ||
| 501 | if (IsCustomConfig()) { | ||
| 502 | EndGroup(); | ||
| 503 | return; | ||
| 504 | } | ||
| 505 | SaveTouchscreenValues(); | ||
| 506 | SaveMotionTouchValues(); | ||
| 507 | |||
| 508 | EndGroup(); | ||
| 509 | } | ||
| 510 | |||
| 511 | void Config::SaveCoreValues() { | ||
| 512 | BeginGroup(Settings::TranslateCategory(Settings::Category::Core)); | ||
| 513 | |||
| 514 | WriteCategory(Settings::Category::Core); | ||
| 515 | |||
| 516 | EndGroup(); | ||
| 517 | } | ||
| 518 | |||
| 519 | void Config::SaveDataStorageValues() { | ||
| 520 | BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); | ||
| 521 | |||
| 522 | WriteSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir), | ||
| 523 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | ||
| 524 | WriteSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir), | ||
| 525 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | ||
| 526 | WriteSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir), | ||
| 527 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | ||
| 528 | WriteSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir), | ||
| 529 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | ||
| 530 | WriteSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir), | ||
| 531 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); | ||
| 532 | |||
| 533 | WriteCategory(Settings::Category::DataStorage); | ||
| 534 | |||
| 535 | EndGroup(); | ||
| 536 | } | ||
| 537 | |||
| 538 | void Config::SaveDebuggingValues() { | ||
| 539 | BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging)); | ||
| 540 | |||
| 541 | // Intentionally not using the QT default setting as this is intended to be changed in the ini | ||
| 542 | WriteSetting(std::string("record_frame_times"), Settings::values.record_frame_times); | ||
| 543 | |||
| 544 | WriteCategory(Settings::Category::Debugging); | ||
| 545 | WriteCategory(Settings::Category::DebuggingGraphics); | ||
| 546 | |||
| 547 | EndGroup(); | ||
| 548 | } | ||
| 549 | |||
| 550 | void Config::SaveNetworkValues() { | ||
| 551 | BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); | ||
| 552 | |||
| 553 | WriteCategory(Settings::Category::Network); | ||
| 554 | |||
| 555 | EndGroup(); | ||
| 556 | } | ||
| 557 | |||
| 558 | void Config::SaveDisabledAddOnValues() { | ||
| 559 | // Custom config section | ||
| 560 | BeginGroup(std::string("DisabledAddOns")); | ||
| 561 | |||
| 562 | int i = 0; | ||
| 563 | BeginArray(std::string("")); | ||
| 564 | for (const auto& elem : Settings::values.disabled_addons) { | ||
| 565 | SetArrayIndex(i); | ||
| 566 | WriteSetting(std::string("title_id"), elem.first, std::make_optional(static_cast<u64>(0))); | ||
| 567 | BeginArray(std::string("disabled")); | ||
| 568 | for (std::size_t j = 0; j < elem.second.size(); ++j) { | ||
| 569 | SetArrayIndex(static_cast<int>(j)); | ||
| 570 | WriteSetting(std::string("d"), elem.second[j], std::make_optional(std::string(""))); | ||
| 571 | } | ||
| 572 | EndArray(); // disabled | ||
| 573 | ++i; | ||
| 574 | } | ||
| 575 | EndArray(); // Base disabled addons array - Has no base key | ||
| 576 | |||
| 577 | EndGroup(); | ||
| 578 | } | ||
| 579 | |||
| 580 | void Config::SaveMiscellaneousValues() { | ||
| 581 | BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous)); | ||
| 582 | |||
| 583 | WriteCategory(Settings::Category::Miscellaneous); | ||
| 584 | |||
| 585 | EndGroup(); | ||
| 586 | } | ||
| 587 | |||
| 588 | void Config::SaveCpuValues() { | ||
| 589 | BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu)); | ||
| 590 | |||
| 591 | WriteCategory(Settings::Category::Cpu); | ||
| 592 | WriteCategory(Settings::Category::CpuDebug); | ||
| 593 | WriteCategory(Settings::Category::CpuUnsafe); | ||
| 594 | |||
| 595 | EndGroup(); | ||
| 596 | } | ||
| 597 | |||
| 598 | void Config::SaveRendererValues() { | ||
| 599 | BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer)); | ||
| 600 | |||
| 601 | WriteCategory(Settings::Category::Renderer); | ||
| 602 | WriteCategory(Settings::Category::RendererAdvanced); | ||
| 603 | WriteCategory(Settings::Category::RendererDebug); | ||
| 604 | |||
| 605 | EndGroup(); | ||
| 606 | } | ||
| 607 | |||
| 608 | void Config::SaveScreenshotValues() { | ||
| 609 | BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots)); | ||
| 610 | |||
| 611 | WriteSetting(std::string("screenshot_path"), | ||
| 612 | FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)); | ||
| 613 | WriteCategory(Settings::Category::Screenshots); | ||
| 614 | |||
| 615 | EndGroup(); | ||
| 616 | } | ||
| 617 | |||
| 618 | void Config::SaveSystemValues() { | ||
| 619 | BeginGroup(Settings::TranslateCategory(Settings::Category::System)); | ||
| 620 | |||
| 621 | WriteCategory(Settings::Category::System); | ||
| 622 | WriteCategory(Settings::Category::SystemAudio); | ||
| 623 | |||
| 624 | EndGroup(); | ||
| 625 | } | ||
| 626 | |||
| 627 | void Config::SaveWebServiceValues() { | ||
| 628 | BeginGroup(Settings::TranslateCategory(Settings::Category::WebService)); | ||
| 629 | |||
| 630 | WriteCategory(Settings::Category::WebService); | ||
| 631 | |||
| 632 | EndGroup(); | ||
| 633 | } | ||
| 634 | |||
| 635 | bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) { | ||
| 636 | std::string full_key = GetFullKey(key, false); | ||
| 637 | if (!default_value.has_value()) { | ||
| 638 | return config->GetBoolValue(GetSection().c_str(), full_key.c_str(), false); | ||
| 639 | } | ||
| 640 | |||
| 641 | if (config->GetBoolValue(GetSection().c_str(), | ||
| 642 | std::string(full_key).append("\\default").c_str(), false)) { | ||
| 643 | return static_cast<bool>(default_value.value()); | ||
| 644 | } else { | ||
| 645 | return config->GetBoolValue(GetSection().c_str(), full_key.c_str(), | ||
| 646 | static_cast<bool>(default_value.value())); | ||
| 647 | } | ||
| 648 | } | ||
| 649 | |||
| 650 | s64 Config::ReadIntegerSetting(const std::string& key, const std::optional<s64> default_value) { | ||
| 651 | std::string full_key = GetFullKey(key, false); | ||
| 652 | if (!default_value.has_value()) { | ||
| 653 | try { | ||
| 654 | return std::stoll( | ||
| 655 | std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0"))); | ||
| 656 | } catch (...) { | ||
| 657 | return 0; | ||
| 658 | } | ||
| 659 | } | ||
| 660 | |||
| 661 | s64 result = 0; | ||
| 662 | if (config->GetBoolValue(GetSection().c_str(), | ||
| 663 | std::string(full_key).append("\\default").c_str(), true)) { | ||
| 664 | result = default_value.value(); | ||
| 665 | } else { | ||
| 666 | try { | ||
| 667 | result = std::stoll(std::string(config->GetValue( | ||
| 668 | GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str()))); | ||
| 669 | } catch (...) { | ||
| 670 | result = default_value.value(); | ||
| 671 | } | ||
| 672 | } | ||
| 673 | return result; | ||
| 674 | } | ||
| 675 | |||
| 676 | u64 Config::ReadUnsignedIntegerSetting(const std::string& key, | ||
| 677 | const std::optional<u64> default_value) { | ||
| 678 | std::string full_key = GetFullKey(key, false); | ||
| 679 | if (!default_value.has_value()) { | ||
| 680 | try { | ||
| 681 | return std::stoull( | ||
| 682 | std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0"))); | ||
| 683 | } catch (...) { | ||
| 684 | return 0; | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | u64 result = 0; | ||
| 689 | if (config->GetBoolValue(GetSection().c_str(), | ||
| 690 | std::string(full_key).append("\\default").c_str(), true)) { | ||
| 691 | result = default_value.value(); | ||
| 692 | } else { | ||
| 693 | try { | ||
| 694 | result = std::stoull(std::string(config->GetValue( | ||
| 695 | GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str()))); | ||
| 696 | } catch (...) { | ||
| 697 | result = default_value.value(); | ||
| 698 | } | ||
| 699 | } | ||
| 700 | return result; | ||
| 701 | } | ||
| 702 | |||
| 703 | double Config::ReadDoubleSetting(const std::string& key, | ||
| 704 | const std::optional<double> default_value) { | ||
| 705 | std::string full_key = GetFullKey(key, false); | ||
| 706 | if (!default_value.has_value()) { | ||
| 707 | return config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), 0); | ||
| 708 | } | ||
| 709 | |||
| 710 | double result; | ||
| 711 | if (config->GetBoolValue(GetSection().c_str(), | ||
| 712 | std::string(full_key).append("\\default").c_str(), true)) { | ||
| 713 | result = default_value.value(); | ||
| 714 | } else { | ||
| 715 | result = | ||
| 716 | config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), default_value.value()); | ||
| 717 | } | ||
| 718 | return result; | ||
| 719 | } | ||
| 720 | |||
| 721 | std::string Config::ReadStringSetting(const std::string& key, | ||
| 722 | const std::optional<std::string> default_value) { | ||
| 723 | std::string result; | ||
| 724 | std::string full_key = GetFullKey(key, false); | ||
| 725 | if (!default_value.has_value()) { | ||
| 726 | result = config->GetValue(GetSection().c_str(), full_key.c_str(), ""); | ||
| 727 | boost::replace_all(result, "\"", ""); | ||
| 728 | return result; | ||
| 729 | } | ||
| 730 | |||
| 731 | if (config->GetBoolValue(GetSection().c_str(), | ||
| 732 | std::string(full_key).append("\\default").c_str(), true)) { | ||
| 733 | result = default_value.value(); | ||
| 734 | } else { | ||
| 735 | result = | ||
| 736 | config->GetValue(GetSection().c_str(), full_key.c_str(), default_value.value().c_str()); | ||
| 737 | } | ||
| 738 | boost::replace_all(result, "\"", ""); | ||
| 739 | boost::replace_all(result, "//", "/"); | ||
| 740 | return result; | ||
| 741 | } | ||
| 742 | |||
| 743 | bool Config::Exists(const std::string& section, const std::string& key) const { | ||
| 744 | const std::string value = config->GetValue(section.c_str(), key.c_str(), ""); | ||
| 745 | return !value.empty(); | ||
| 746 | } | ||
| 747 | |||
| 748 | template <typename Type> | ||
| 749 | void Config::WriteSetting(const std::string& key, const Type& value, | ||
| 750 | const std::optional<Type>& default_value, | ||
| 751 | const std::optional<bool>& use_global) { | ||
| 752 | std::string full_key = GetFullKey(key, false); | ||
| 753 | |||
| 754 | std::string saved_value; | ||
| 755 | std::string string_default; | ||
| 756 | if constexpr (std::is_same_v<Type, std::string>) { | ||
| 757 | saved_value.append(AdjustOutputString(value)); | ||
| 758 | if (default_value.has_value()) { | ||
| 759 | string_default.append(AdjustOutputString(default_value.value())); | ||
| 760 | } | ||
| 761 | } else { | ||
| 762 | saved_value.append(AdjustOutputString(ToString(value))); | ||
| 763 | if (default_value.has_value()) { | ||
| 764 | string_default.append(ToString(default_value.value())); | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | if (default_value.has_value() && use_global.has_value()) { | ||
| 769 | if (!global) { | ||
| 770 | WriteSettingInternal(std::string(full_key).append("\\global"), | ||
| 771 | ToString(use_global.value())); | ||
| 772 | } | ||
| 773 | if (global || use_global.value() == false) { | ||
| 774 | WriteSettingInternal(std::string(full_key).append("\\default"), | ||
| 775 | ToString(string_default == saved_value)); | ||
| 776 | WriteSettingInternal(full_key, saved_value); | ||
| 777 | } | ||
| 778 | } else if (default_value.has_value() && !use_global.has_value()) { | ||
| 779 | WriteSettingInternal(std::string(full_key).append("\\default"), | ||
| 780 | ToString(string_default == saved_value)); | ||
| 781 | WriteSettingInternal(full_key, saved_value); | ||
| 782 | } else { | ||
| 783 | WriteSettingInternal(full_key, saved_value); | ||
| 784 | } | ||
| 785 | } | ||
| 786 | |||
| 787 | void Config::WriteSettingInternal(const std::string& key, const std::string& value) { | ||
| 788 | config->SetValue(GetSection().c_str(), key.c_str(), value.c_str()); | ||
| 789 | } | ||
| 790 | |||
| 791 | void Config::Reload() { | ||
| 792 | ReadValues(); | ||
| 793 | // To apply default value changes | ||
| 794 | SaveValues(); | ||
| 795 | } | ||
| 796 | |||
| 797 | void Config::Save() { | ||
| 798 | SaveValues(); | ||
| 799 | } | ||
| 800 | |||
| 801 | void Config::ClearControlPlayerValues() const { | ||
| 802 | // If key is an empty string, all keys in the current group() are removed. | ||
| 803 | const char* section = Settings::TranslateCategory(Settings::Category::Controls); | ||
| 804 | CSimpleIniA::TNamesDepend keys; | ||
| 805 | config->GetAllKeys(section, keys); | ||
| 806 | for (const auto& key : keys) { | ||
| 807 | if (std::string(config->GetValue(section, key.pItem)).empty()) { | ||
| 808 | config->Delete(section, key.pItem); | ||
| 809 | } | ||
| 810 | } | ||
| 811 | } | ||
| 812 | |||
| 813 | const std::string& Config::GetConfigFilePath() const { | ||
| 814 | return config_loc; | ||
| 815 | } | ||
| 816 | |||
| 817 | void Config::ReadCategory(const Settings::Category category) { | ||
| 818 | const auto& settings = FindRelevantList(category); | ||
| 819 | std::ranges::for_each(settings, [&](const auto& setting) { ReadSettingGeneric(setting); }); | ||
| 820 | } | ||
| 821 | |||
| 822 | void Config::WriteCategory(const Settings::Category category) { | ||
| 823 | const auto& settings = FindRelevantList(category); | ||
| 824 | std::ranges::for_each(settings, [&](const auto& setting) { WriteSettingGeneric(setting); }); | ||
| 825 | } | ||
| 826 | |||
| 827 | void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) { | ||
| 828 | if (!setting->Save() || (!setting->Switchable() && !global)) { | ||
| 829 | return; | ||
| 830 | } | ||
| 831 | |||
| 832 | const std::string key = AdjustKey(setting->GetLabel()); | ||
| 833 | const std::string default_value(setting->DefaultToString()); | ||
| 834 | |||
| 835 | bool use_global = true; | ||
| 836 | if (setting->Switchable() && !global) { | ||
| 837 | use_global = | ||
| 838 | ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true)); | ||
| 839 | setting->SetGlobal(use_global); | ||
| 840 | } | ||
| 841 | |||
| 842 | if (global || !use_global) { | ||
| 843 | const bool is_default = | ||
| 844 | ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true)); | ||
| 845 | if (!is_default) { | ||
| 846 | const std::string setting_string = ReadStringSetting(key, default_value); | ||
| 847 | setting->LoadString(setting_string); | ||
| 848 | } else { | ||
| 849 | // Empty string resets the Setting to default | ||
| 850 | setting->LoadString(""); | ||
| 851 | } | ||
| 852 | } | ||
| 853 | } | ||
| 854 | |||
| 855 | void Config::WriteSettingGeneric(const Settings::BasicSetting* const setting) { | ||
| 856 | if (!setting->Save()) { | ||
| 857 | return; | ||
| 858 | } | ||
| 859 | |||
| 860 | std::string key = AdjustKey(setting->GetLabel()); | ||
| 861 | if (setting->Switchable()) { | ||
| 862 | if (!global) { | ||
| 863 | WriteSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); | ||
| 864 | } | ||
| 865 | if (global || !setting->UsingGlobal()) { | ||
| 866 | WriteSetting(std::string(key).append("\\default"), | ||
| 867 | setting->ToString() == setting->DefaultToString()); | ||
| 868 | WriteSetting(key, setting->ToString()); | ||
| 869 | } | ||
| 870 | } else if (global) { | ||
| 871 | WriteSetting(std::string(key).append("\\default"), | ||
| 872 | setting->ToString() == setting->DefaultToString()); | ||
| 873 | WriteSetting(key, setting->ToString()); | ||
| 874 | } | ||
| 875 | } | ||
| 876 | |||
| 877 | void Config::BeginGroup(const std::string& group) { | ||
| 878 | // You can't begin a group while reading/writing from a config array | ||
| 879 | ASSERT(array_stack.empty()); | ||
| 880 | |||
| 881 | key_stack.push_back(AdjustKey(group)); | ||
| 882 | } | ||
| 883 | |||
| 884 | void Config::EndGroup() { | ||
| 885 | // You can't end a group if you haven't started one yet | ||
| 886 | ASSERT(!key_stack.empty()); | ||
| 887 | |||
| 888 | // You can't end a group when reading/writing from a config array | ||
| 889 | ASSERT(array_stack.empty()); | ||
| 890 | |||
| 891 | key_stack.pop_back(); | ||
| 892 | } | ||
| 893 | |||
| 894 | std::string Config::GetSection() { | ||
| 895 | if (key_stack.empty()) { | ||
| 896 | return std::string{""}; | ||
| 897 | } | ||
| 898 | |||
| 899 | return key_stack.front(); | ||
| 900 | } | ||
| 901 | |||
| 902 | std::string Config::GetGroup() const { | ||
| 903 | if (key_stack.size() <= 1) { | ||
| 904 | return std::string{""}; | ||
| 905 | } | ||
| 906 | |||
| 907 | std::string key; | ||
| 908 | for (size_t i = 1; i < key_stack.size(); ++i) { | ||
| 909 | key.append(key_stack[i]).append("\\"); | ||
| 910 | } | ||
| 911 | return key; | ||
| 912 | } | ||
| 913 | |||
| 914 | std::string Config::AdjustKey(const std::string& key) { | ||
| 915 | std::string adjusted_key(key); | ||
| 916 | boost::replace_all(adjusted_key, "/", "\\"); | ||
| 917 | boost::replace_all(adjusted_key, " ", "%20"); | ||
| 918 | return adjusted_key; | ||
| 919 | } | ||
| 920 | |||
| 921 | std::string Config::AdjustOutputString(const std::string& string) { | ||
| 922 | std::string adjusted_string(string); | ||
| 923 | boost::replace_all(adjusted_string, "\\", "/"); | ||
| 924 | |||
| 925 | // Windows requires that two forward slashes are used at the start of a path for unmapped | ||
| 926 | // network drives so we have to watch for that here | ||
| 927 | if (string.substr(0, 2) == "//") { | ||
| 928 | boost::replace_all(adjusted_string, "//", "/"); | ||
| 929 | adjusted_string.insert(0, "/"); | ||
| 930 | } else { | ||
| 931 | boost::replace_all(adjusted_string, "//", "/"); | ||
| 932 | } | ||
| 933 | |||
| 934 | // Needed for backwards compatibility with QSettings deserialization | ||
| 935 | for (const auto& special_character : special_characters) { | ||
| 936 | if (adjusted_string.find(special_character) != std::string::npos) { | ||
| 937 | adjusted_string.insert(0, "\""); | ||
| 938 | adjusted_string.append("\""); | ||
| 939 | break; | ||
| 940 | } | ||
| 941 | } | ||
| 942 | return adjusted_string; | ||
| 943 | } | ||
| 944 | |||
| 945 | std::string Config::GetFullKey(const std::string& key, bool skipArrayIndex) { | ||
| 946 | if (array_stack.empty()) { | ||
| 947 | return std::string(GetGroup()).append(AdjustKey(key)); | ||
| 948 | } | ||
| 949 | |||
| 950 | std::string array_key; | ||
| 951 | for (size_t i = 0; i < array_stack.size(); ++i) { | ||
| 952 | if (!array_stack[i].name.empty()) { | ||
| 953 | array_key.append(array_stack[i].name).append("\\"); | ||
| 954 | } | ||
| 955 | |||
| 956 | if (!skipArrayIndex || (array_stack.size() - 1 != i && array_stack.size() > 1)) { | ||
| 957 | array_key.append(ToString(array_stack[i].index)).append("\\"); | ||
| 958 | } | ||
| 959 | } | ||
| 960 | std::string final_key = std::string(GetGroup()).append(array_key).append(AdjustKey(key)); | ||
| 961 | return final_key; | ||
| 962 | } | ||
| 963 | |||
| 964 | int Config::BeginArray(const std::string& array) { | ||
| 965 | array_stack.push_back(ConfigArray{AdjustKey(array), 0, 0}); | ||
| 966 | const int size = config->GetLongValue(GetSection().c_str(), | ||
| 967 | GetFullKey(std::string("size"), true).c_str(), 0); | ||
| 968 | array_stack.back().size = size; | ||
| 969 | return size; | ||
| 970 | } | ||
| 971 | |||
| 972 | void Config::EndArray() { | ||
| 973 | // You can't end a config array before starting one | ||
| 974 | ASSERT(!array_stack.empty()); | ||
| 975 | |||
| 976 | // Set the array size to 0 if the array is ended without changing the index | ||
| 977 | int size = 0; | ||
| 978 | if (array_stack.back().index != 0) { | ||
| 979 | size = array_stack.back().size; | ||
| 980 | } | ||
| 981 | |||
| 982 | // Write out the size to config | ||
| 983 | if (key_stack.size() == 1 && array_stack.back().name.empty()) { | ||
| 984 | // Edge-case where the first array created doesn't have a name | ||
| 985 | config->SetValue(GetSection().c_str(), std::string("size").c_str(), ToString(size).c_str()); | ||
| 986 | } else { | ||
| 987 | const auto key = GetFullKey(std::string("size"), true); | ||
| 988 | config->SetValue(GetSection().c_str(), key.c_str(), ToString(size).c_str()); | ||
| 989 | } | ||
| 990 | |||
| 991 | array_stack.pop_back(); | ||
| 992 | } | ||
| 993 | |||
| 994 | void Config::SetArrayIndex(const int index) { | ||
| 995 | // You can't set the array index if you haven't started one yet | ||
| 996 | ASSERT(!array_stack.empty()); | ||
| 997 | |||
| 998 | const int array_index = index + 1; | ||
| 999 | |||
| 1000 | // You can't exceed the known max size of the array by more than 1 | ||
| 1001 | ASSERT(array_stack.front().size + 1 >= array_index); | ||
| 1002 | |||
| 1003 | // Change the config array size to the current index since you may want | ||
| 1004 | // to reduce the number of elements that you read back from the config | ||
| 1005 | // in the future. | ||
| 1006 | array_stack.back().size = array_index; | ||
| 1007 | array_stack.back().index = array_index; | ||
| 1008 | } | ||
diff --git a/src/frontend_common/config.h b/src/frontend_common/config.h new file mode 100644 index 000000000..b3812af17 --- /dev/null +++ b/src/frontend_common/config.h | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <string> | ||
| 8 | #include "common/settings.h" | ||
| 9 | |||
| 10 | #define SI_NO_CONVERSION | ||
| 11 | #include <SimpleIni.h> | ||
| 12 | #include <boost/algorithm/string/replace.hpp> | ||
| 13 | |||
| 14 | // Workaround for conflicting definition in libloaderapi.h caused by SimpleIni | ||
| 15 | #undef LoadString | ||
| 16 | #undef CreateFile | ||
| 17 | #undef DeleteFile | ||
| 18 | #undef CopyFile | ||
| 19 | #undef CreateDirectory | ||
| 20 | #undef MoveFile | ||
| 21 | |||
| 22 | namespace Core { | ||
| 23 | class System; | ||
| 24 | } | ||
| 25 | |||
| 26 | class Config { | ||
| 27 | public: | ||
| 28 | enum class ConfigType { | ||
| 29 | GlobalConfig, | ||
| 30 | PerGameConfig, | ||
| 31 | InputProfile, | ||
| 32 | }; | ||
| 33 | |||
| 34 | virtual ~Config() = default; | ||
| 35 | |||
| 36 | void ClearControlPlayerValues() const; | ||
| 37 | |||
| 38 | [[nodiscard]] const std::string& GetConfigFilePath() const; | ||
| 39 | |||
| 40 | [[nodiscard]] bool Exists(const std::string& section, const std::string& key) const; | ||
| 41 | |||
| 42 | protected: | ||
| 43 | explicit Config(ConfigType config_type = ConfigType::GlobalConfig); | ||
| 44 | |||
| 45 | void Initialize(const std::string& config_name = "config"); | ||
| 46 | void Initialize(std::optional<std::string> config_path); | ||
| 47 | |||
| 48 | void WriteToIni() const; | ||
| 49 | |||
| 50 | void SetUpIni(); | ||
| 51 | [[nodiscard]] bool IsCustomConfig() const; | ||
| 52 | |||
| 53 | void Reload(); | ||
| 54 | void Save(); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Derived config classes must implement this so they can reload all platform-specific | ||
| 58 | * values and global ones. | ||
| 59 | */ | ||
| 60 | virtual void ReloadAllValues() = 0; | ||
| 61 | |||
| 62 | /** | ||
| 63 | * Derived config classes must implement this so they can save all platform-specific | ||
| 64 | * and global values. | ||
| 65 | */ | ||
| 66 | virtual void SaveAllValues() = 0; | ||
| 67 | |||
| 68 | void ReadValues(); | ||
| 69 | void ReadPlayerValues(std::size_t player_index); | ||
| 70 | |||
| 71 | void ReadTouchscreenValues(); | ||
| 72 | void ReadMotionTouchValues(); | ||
| 73 | |||
| 74 | // Read functions bases off the respective config section names. | ||
| 75 | void ReadAudioValues(); | ||
| 76 | void ReadControlValues(); | ||
| 77 | void ReadCoreValues(); | ||
| 78 | void ReadDataStorageValues(); | ||
| 79 | void ReadDebuggingValues(); | ||
| 80 | void ReadServiceValues(); | ||
| 81 | void ReadDisabledAddOnValues(); | ||
| 82 | void ReadMiscellaneousValues(); | ||
| 83 | void ReadCpuValues(); | ||
| 84 | void ReadRendererValues(); | ||
| 85 | void ReadScreenshotValues(); | ||
| 86 | void ReadSystemValues(); | ||
| 87 | void ReadWebServiceValues(); | ||
| 88 | void ReadNetworkValues(); | ||
| 89 | |||
| 90 | // Read platform specific sections | ||
| 91 | virtual void ReadHidbusValues() = 0; | ||
| 92 | virtual void ReadDebugControlValues() = 0; | ||
| 93 | virtual void ReadPathValues() = 0; | ||
| 94 | virtual void ReadShortcutValues() = 0; | ||
| 95 | virtual void ReadUIValues() = 0; | ||
| 96 | virtual void ReadUIGamelistValues() = 0; | ||
| 97 | virtual void ReadUILayoutValues() = 0; | ||
| 98 | virtual void ReadMultiplayerValues() = 0; | ||
| 99 | |||
| 100 | void SaveValues(); | ||
| 101 | void SavePlayerValues(std::size_t player_index); | ||
| 102 | void SaveTouchscreenValues(); | ||
| 103 | void SaveMotionTouchValues(); | ||
| 104 | |||
| 105 | // Save functions based off the respective config section names. | ||
| 106 | void SaveAudioValues(); | ||
| 107 | void SaveControlValues(); | ||
| 108 | void SaveCoreValues(); | ||
| 109 | void SaveDataStorageValues(); | ||
| 110 | void SaveDebuggingValues(); | ||
| 111 | void SaveNetworkValues(); | ||
| 112 | void SaveDisabledAddOnValues(); | ||
| 113 | void SaveMiscellaneousValues(); | ||
| 114 | void SaveCpuValues(); | ||
| 115 | void SaveRendererValues(); | ||
| 116 | void SaveScreenshotValues(); | ||
| 117 | void SaveSystemValues(); | ||
| 118 | void SaveWebServiceValues(); | ||
| 119 | |||
| 120 | // Save platform specific sections | ||
| 121 | virtual void SaveHidbusValues() = 0; | ||
| 122 | virtual void SaveDebugControlValues() = 0; | ||
| 123 | virtual void SavePathValues() = 0; | ||
| 124 | virtual void SaveShortcutValues() = 0; | ||
| 125 | virtual void SaveUIValues() = 0; | ||
| 126 | virtual void SaveUIGamelistValues() = 0; | ||
| 127 | virtual void SaveUILayoutValues() = 0; | ||
| 128 | virtual void SaveMultiplayerValues() = 0; | ||
| 129 | |||
| 130 | virtual std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) = 0; | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Reads a setting from the qt_config. | ||
| 134 | * | ||
| 135 | * @param key The setting's identifier | ||
| 136 | * @param default_value The value to use when the setting is not already present in the config | ||
| 137 | */ | ||
| 138 | bool ReadBooleanSetting(const std::string& key, | ||
| 139 | std::optional<bool> default_value = std::nullopt); | ||
| 140 | s64 ReadIntegerSetting(const std::string& key, std::optional<s64> default_value = std::nullopt); | ||
| 141 | u64 ReadUnsignedIntegerSetting(const std::string& key, | ||
| 142 | std::optional<u64> default_value = std::nullopt); | ||
| 143 | double ReadDoubleSetting(const std::string& key, | ||
| 144 | std::optional<double> default_value = std::nullopt); | ||
| 145 | std::string ReadStringSetting(const std::string& key, | ||
| 146 | std::optional<std::string> default_value = std::nullopt); | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Writes a setting to the qt_config. | ||
| 150 | * | ||
| 151 | * @param key The setting's idetentifier | ||
| 152 | * @param value Value of the setting | ||
| 153 | * @param default_value Default of the setting if not present in config | ||
| 154 | * @param use_global Specifies if the custom or global config should be in use, for custom | ||
| 155 | * configs | ||
| 156 | */ | ||
| 157 | template <typename Type = int> | ||
| 158 | void WriteSetting(const std::string& key, const Type& value, | ||
| 159 | const std::optional<Type>& default_value = std::nullopt, | ||
| 160 | const std::optional<bool>& use_global = std::nullopt); | ||
| 161 | void WriteSettingInternal(const std::string& key, const std::string& value); | ||
| 162 | |||
| 163 | void ReadCategory(Settings::Category category); | ||
| 164 | void WriteCategory(Settings::Category category); | ||
| 165 | void ReadSettingGeneric(Settings::BasicSetting* setting); | ||
| 166 | void WriteSettingGeneric(const Settings::BasicSetting* setting); | ||
| 167 | |||
| 168 | template <typename T> | ||
| 169 | [[nodiscard]] std::string ToString(const T& value_) { | ||
| 170 | if constexpr (std::is_same_v<T, std::string>) { | ||
| 171 | return value_; | ||
| 172 | } else if constexpr (std::is_same_v<T, std::optional<u32>>) { | ||
| 173 | return value_.has_value() ? std::to_string(*value_) : "none"; | ||
| 174 | } else if constexpr (std::is_same_v<T, bool>) { | ||
| 175 | return value_ ? "true" : "false"; | ||
| 176 | } else if constexpr (std::is_same_v<T, u64>) { | ||
| 177 | return std::to_string(static_cast<u64>(value_)); | ||
| 178 | } else { | ||
| 179 | return std::to_string(static_cast<s64>(value_)); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | void BeginGroup(const std::string& group); | ||
| 184 | void EndGroup(); | ||
| 185 | std::string GetSection(); | ||
| 186 | [[nodiscard]] std::string GetGroup() const; | ||
| 187 | static std::string AdjustKey(const std::string& key); | ||
| 188 | static std::string AdjustOutputString(const std::string& string); | ||
| 189 | std::string GetFullKey(const std::string& key, bool skipArrayIndex); | ||
| 190 | int BeginArray(const std::string& array); | ||
| 191 | void EndArray(); | ||
| 192 | void SetArrayIndex(int index); | ||
| 193 | |||
| 194 | const ConfigType type; | ||
| 195 | std::unique_ptr<CSimpleIniA> config; | ||
| 196 | std::string config_loc; | ||
| 197 | const bool global; | ||
| 198 | |||
| 199 | private: | ||
| 200 | inline static std::array<char, 19> special_characters = {'!', '#', '$', '%', '^', '&', '*', | ||
| 201 | '|', ';', '\'', '\"', ',', '<', '.', | ||
| 202 | '>', '?', '`', '~', '='}; | ||
| 203 | |||
| 204 | struct ConfigArray { | ||
| 205 | std::string name; | ||
| 206 | int size; | ||
| 207 | int index; | ||
| 208 | }; | ||
| 209 | std::vector<ConfigArray> array_stack; | ||
| 210 | std::vector<std::string> key_stack; | ||
| 211 | }; | ||
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp index 2705ab140..9319ea007 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "shader_recompiler/backend/glasm/glasm_emit_context.h" | 5 | #include "shader_recompiler/backend/glasm/glasm_emit_context.h" |
| 6 | #include "shader_recompiler/frontend/ir/program.h" | 6 | #include "shader_recompiler/frontend/ir/program.h" |
| 7 | #include "shader_recompiler/frontend/ir/value.h" | 7 | #include "shader_recompiler/frontend/ir/value.h" |
| 8 | #include "shader_recompiler/profile.h" | ||
| 8 | #include "shader_recompiler/runtime_info.h" | 9 | #include "shader_recompiler/runtime_info.h" |
| 9 | 10 | ||
| 10 | namespace Shader::Backend::GLASM { | 11 | namespace Shader::Backend::GLASM { |
| @@ -35,7 +36,9 @@ void GlobalStorageOp(EmitContext& ctx, Register address, bool pointer_based, std | |||
| 35 | continue; | 36 | continue; |
| 36 | } | 37 | } |
| 37 | const auto& ssbo{ctx.info.storage_buffers_descriptors[index]}; | 38 | const auto& ssbo{ctx.info.storage_buffers_descriptors[index]}; |
| 38 | ctx.Add("LDC.U64 DC.x,c{}[{}];" // ssbo_addr | 39 | const u64 ssbo_align_mask{~(ctx.profile.min_ssbo_alignment - 1U)}; |
| 40 | ctx.Add("LDC.U64 DC.x,c{}[{}];" // unaligned_ssbo_addr | ||
| 41 | "AND.U64 DC.x,DC.x,{};" // ssbo_addr = unaligned_ssbo_addr & ssbo_align_mask | ||
| 39 | "LDC.U32 RC.x,c{}[{}];" // ssbo_size_u32 | 42 | "LDC.U32 RC.x,c{}[{}];" // ssbo_size_u32 |
| 40 | "CVT.U64.U32 DC.y,RC.x;" // ssbo_size = ssbo_size_u32 | 43 | "CVT.U64.U32 DC.y,RC.x;" // ssbo_size = ssbo_size_u32 |
| 41 | "ADD.U64 DC.y,DC.y,DC.x;" // ssbo_end = ssbo_addr + ssbo_size | 44 | "ADD.U64 DC.y,DC.y,DC.x;" // ssbo_end = ssbo_addr + ssbo_size |
| @@ -44,8 +47,8 @@ void GlobalStorageOp(EmitContext& ctx, Register address, bool pointer_based, std | |||
| 44 | "AND.U.CC RC.x,RC.x,RC.y;" // cond = a && b | 47 | "AND.U.CC RC.x,RC.x,RC.y;" // cond = a && b |
| 45 | "IF NE.x;" // if cond | 48 | "IF NE.x;" // if cond |
| 46 | "SUB.U64 DC.x,{}.x,DC.x;", // offset = input_addr - ssbo_addr | 49 | "SUB.U64 DC.x,{}.x,DC.x;", // offset = input_addr - ssbo_addr |
| 47 | ssbo.cbuf_index, ssbo.cbuf_offset, ssbo.cbuf_index, ssbo.cbuf_offset + 8, address, | 50 | ssbo.cbuf_index, ssbo.cbuf_offset, ssbo_align_mask, ssbo.cbuf_index, |
| 48 | address, address); | 51 | ssbo.cbuf_offset + 8, address, address, address); |
| 49 | if (pointer_based) { | 52 | if (pointer_based) { |
| 50 | ctx.Add("PK64.U DC.y,c[{}];" // host_ssbo = cbuf | 53 | ctx.Add("PK64.U DC.y,c[{}];" // host_ssbo = cbuf |
| 51 | "ADD.U64 DC.x,DC.x,DC.y;" // host_addr = host_ssbo + offset | 54 | "ADD.U64 DC.x,DC.x,DC.y;" // host_addr = host_ssbo + offset |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index 9ff4028c2..fd9a99449 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -601,7 +601,10 @@ std::string EmitContext::DefineGlobalMemoryFunctions() { | |||
| 601 | addr_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, addr_loc / 16, Swizzle(addr_loc)); | 601 | addr_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, addr_loc / 16, Swizzle(addr_loc)); |
| 602 | size_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, size_loc / 16, Swizzle(size_loc)); | 602 | size_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, size_loc / 16, Swizzle(size_loc)); |
| 603 | } | 603 | } |
| 604 | const auto addr_pack{fmt::format("packUint2x32(uvec2({},{}))", addr_xy[0], addr_xy[1])}; | 604 | const u32 ssbo_align_mask{~(static_cast<u32>(profile.min_ssbo_alignment) - 1U)}; |
| 605 | const auto aligned_low_addr{fmt::format("{}&{}", addr_xy[0], ssbo_align_mask)}; | ||
| 606 | const auto aligned_addr{fmt::format("uvec2({},{})", aligned_low_addr, addr_xy[1])}; | ||
| 607 | const auto addr_pack{fmt::format("packUint2x32({})", aligned_addr)}; | ||
| 605 | const auto addr_statment{fmt::format("uint64_t {}={};", ssbo_addr, addr_pack)}; | 608 | const auto addr_statment{fmt::format("uint64_t {}={};", ssbo_addr, addr_pack)}; |
| 606 | func += addr_statment; | 609 | func += addr_statment; |
| 607 | 610 | ||
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 57df6fc34..3350f1f85 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -891,7 +891,9 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { | |||
| 891 | const Id ssbo_size_pointer{OpAccessChain(uniform_types.U32, cbufs[ssbo.cbuf_index].U32, | 891 | const Id ssbo_size_pointer{OpAccessChain(uniform_types.U32, cbufs[ssbo.cbuf_index].U32, |
| 892 | zero, ssbo_size_cbuf_offset)}; | 892 | zero, ssbo_size_cbuf_offset)}; |
| 893 | 893 | ||
| 894 | const Id ssbo_addr{OpBitcast(U64, OpLoad(U32[2], ssbo_addr_pointer))}; | 894 | const u64 ssbo_align_mask{~(profile.min_ssbo_alignment - 1U)}; |
| 895 | const Id unaligned_addr{OpBitcast(U64, OpLoad(U32[2], ssbo_addr_pointer))}; | ||
| 896 | const Id ssbo_addr{OpBitwiseAnd(U64, unaligned_addr, Constant(U64, ssbo_align_mask))}; | ||
| 895 | const Id ssbo_size{OpUConvert(U64, OpLoad(U32[1], ssbo_size_pointer))}; | 897 | const Id ssbo_size{OpUConvert(U64, OpLoad(U32[1], ssbo_size_pointer))}; |
| 896 | const Id ssbo_end{OpIAdd(U64, ssbo_addr, ssbo_size)}; | 898 | const Id ssbo_end{OpIAdd(U64, ssbo_addr, ssbo_size)}; |
| 897 | const Id cond{OpLogicalAnd(U1, OpUGreaterThanEqual(U1, addr, ssbo_addr), | 899 | const Id cond{OpLogicalAnd(U1, OpUGreaterThanEqual(U1, addr, ssbo_addr), |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 8fac6bad3..321ea625b 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp | |||
| @@ -298,7 +298,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 298 | 298 | ||
| 299 | Optimization::PositionPass(env, program); | 299 | Optimization::PositionPass(env, program); |
| 300 | 300 | ||
| 301 | Optimization::GlobalMemoryToStorageBufferPass(program); | 301 | Optimization::GlobalMemoryToStorageBufferPass(program, host_info); |
| 302 | Optimization::TexturePass(env, program, host_info); | 302 | Optimization::TexturePass(env, program, host_info); |
| 303 | 303 | ||
| 304 | if (Settings::values.resolution_info.active) { | 304 | if (Settings::values.resolution_info.active) { |
diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index 7d2ded907..1b53404fc 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h | |||
| @@ -16,6 +16,7 @@ struct HostTranslateInfo { | |||
| 16 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered | 16 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered |
| 17 | bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers | 17 | bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers |
| 18 | bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS | 18 | bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS |
| 19 | u32 min_ssbo_alignment{}; ///< Minimum alignment supported by the device for SSBOs | ||
| 19 | bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry | 20 | bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry |
| 20 | ///< passthrough shaders | 21 | ///< passthrough shaders |
| 21 | bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional | 22 | bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional |
diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index d1e59f22e..0cea79945 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" | 11 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" |
| 12 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | 12 | #include "shader_recompiler/frontend/ir/ir_emitter.h" |
| 13 | #include "shader_recompiler/frontend/ir/value.h" | 13 | #include "shader_recompiler/frontend/ir/value.h" |
| 14 | #include "shader_recompiler/host_translate_info.h" | ||
| 14 | #include "shader_recompiler/ir_opt/passes.h" | 15 | #include "shader_recompiler/ir_opt/passes.h" |
| 15 | 16 | ||
| 16 | namespace Shader::Optimization { | 17 | namespace Shader::Optimization { |
| @@ -408,7 +409,7 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageInfo& info) | |||
| 408 | } | 409 | } |
| 409 | 410 | ||
| 410 | /// Returns the offset in indices (not bytes) for an equivalent storage instruction | 411 | /// Returns the offset in indices (not bytes) for an equivalent storage instruction |
| 411 | IR::U32 StorageOffset(IR::Block& block, IR::Inst& inst, StorageBufferAddr buffer) { | 412 | IR::U32 StorageOffset(IR::Block& block, IR::Inst& inst, StorageBufferAddr buffer, u32 alignment) { |
| 412 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | 413 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; |
| 413 | IR::U32 offset; | 414 | IR::U32 offset; |
| 414 | if (const std::optional<LowAddrInfo> low_addr{TrackLowAddress(&inst)}) { | 415 | if (const std::optional<LowAddrInfo> low_addr{TrackLowAddress(&inst)}) { |
| @@ -421,7 +422,10 @@ IR::U32 StorageOffset(IR::Block& block, IR::Inst& inst, StorageBufferAddr buffer | |||
| 421 | } | 422 | } |
| 422 | // Subtract the least significant 32 bits from the guest offset. The result is the storage | 423 | // Subtract the least significant 32 bits from the guest offset. The result is the storage |
| 423 | // buffer offset in bytes. | 424 | // buffer offset in bytes. |
| 424 | const IR::U32 low_cbuf{ir.GetCbuf(ir.Imm32(buffer.index), ir.Imm32(buffer.offset))}; | 425 | IR::U32 low_cbuf{ir.GetCbuf(ir.Imm32(buffer.index), ir.Imm32(buffer.offset))}; |
| 426 | |||
| 427 | // Align the offset base to match the host alignment requirements | ||
| 428 | low_cbuf = ir.BitwiseAnd(low_cbuf, ir.Imm32(~(alignment - 1U))); | ||
| 425 | return ir.ISub(offset, low_cbuf); | 429 | return ir.ISub(offset, low_cbuf); |
| 426 | } | 430 | } |
| 427 | 431 | ||
| @@ -516,7 +520,7 @@ void Replace(IR::Block& block, IR::Inst& inst, const IR::U32& storage_index, | |||
| 516 | } | 520 | } |
| 517 | } // Anonymous namespace | 521 | } // Anonymous namespace |
| 518 | 522 | ||
| 519 | void GlobalMemoryToStorageBufferPass(IR::Program& program) { | 523 | void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateInfo& host_info) { |
| 520 | StorageInfo info; | 524 | StorageInfo info; |
| 521 | for (IR::Block* const block : program.post_order_blocks) { | 525 | for (IR::Block* const block : program.post_order_blocks) { |
| 522 | for (IR::Inst& inst : block->Instructions()) { | 526 | for (IR::Inst& inst : block->Instructions()) { |
| @@ -540,7 +544,8 @@ void GlobalMemoryToStorageBufferPass(IR::Program& program) { | |||
| 540 | const IR::U32 index{IR::Value{static_cast<u32>(info.set.index_of(it))}}; | 544 | const IR::U32 index{IR::Value{static_cast<u32>(info.set.index_of(it))}}; |
| 541 | IR::Block* const block{storage_inst.block}; | 545 | IR::Block* const block{storage_inst.block}; |
| 542 | IR::Inst* const inst{storage_inst.inst}; | 546 | IR::Inst* const inst{storage_inst.inst}; |
| 543 | const IR::U32 offset{StorageOffset(*block, *inst, storage_buffer)}; | 547 | const IR::U32 offset{ |
| 548 | StorageOffset(*block, *inst, storage_buffer, host_info.min_ssbo_alignment)}; | ||
| 544 | Replace(*block, *inst, index, offset); | 549 | Replace(*block, *inst, index, offset); |
| 545 | } | 550 | } |
| 546 | } | 551 | } |
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index d4d5285e5..1e637cb23 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h | |||
| @@ -16,7 +16,7 @@ void CollectShaderInfoPass(Environment& env, IR::Program& program); | |||
| 16 | void ConditionalBarrierPass(IR::Program& program); | 16 | void ConditionalBarrierPass(IR::Program& program); |
| 17 | void ConstantPropagationPass(Environment& env, IR::Program& program); | 17 | void ConstantPropagationPass(Environment& env, IR::Program& program); |
| 18 | void DeadCodeEliminationPass(IR::Program& program); | 18 | void DeadCodeEliminationPass(IR::Program& program); |
| 19 | void GlobalMemoryToStorageBufferPass(IR::Program& program); | 19 | void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateInfo& host_info); |
| 20 | void IdentityRemovalPass(IR::Program& program); | 20 | void IdentityRemovalPass(IR::Program& program); |
| 21 | void LowerFp64ToFp32(IR::Program& program); | 21 | void LowerFp64ToFp32(IR::Program& program); |
| 22 | void LowerFp16ToFp32(IR::Program& program); | 22 | void LowerFp16ToFp32(IR::Program& program); |
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index a9de9f4a9..66901a965 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h | |||
| @@ -85,6 +85,8 @@ struct Profile { | |||
| 85 | 85 | ||
| 86 | /// Maxwell and earlier nVidia architectures have broken robust support | 86 | /// Maxwell and earlier nVidia architectures have broken robust support |
| 87 | bool has_broken_robust{}; | 87 | bool has_broken_robust{}; |
| 88 | |||
| 89 | u64 min_ssbo_alignment{}; | ||
| 88 | }; | 90 | }; |
| 89 | 91 | ||
| 90 | } // namespace Shader | 92 | } // namespace Shader |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index b65b9f2a2..c22c7631c 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -15,6 +15,7 @@ add_library(video_core STATIC | |||
| 15 | buffer_cache/buffer_cache.cpp | 15 | buffer_cache/buffer_cache.cpp |
| 16 | buffer_cache/buffer_cache.h | 16 | buffer_cache/buffer_cache.h |
| 17 | buffer_cache/memory_tracker_base.h | 17 | buffer_cache/memory_tracker_base.h |
| 18 | buffer_cache/usage_tracker.h | ||
| 18 | buffer_cache/word_manager.h | 19 | buffer_cache/word_manager.h |
| 19 | cache_types.h | 20 | cache_types.h |
| 20 | cdma_pusher.cpp | 21 | cdma_pusher.cpp |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index f5b10411b..6d1fc3887 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -67,6 +67,7 @@ void BufferCache<P>::TickFrame() { | |||
| 67 | if (!channel_state) { | 67 | if (!channel_state) { |
| 68 | return; | 68 | return; |
| 69 | } | 69 | } |
| 70 | runtime.TickFrame(slot_buffers); | ||
| 70 | 71 | ||
| 71 | // Calculate hits and shots and move hit bits to the right | 72 | // Calculate hits and shots and move hit bits to the right |
| 72 | const u32 hits = std::reduce(channel_state->uniform_cache_hits.begin(), | 73 | const u32 hits = std::reduce(channel_state->uniform_cache_hits.begin(), |
| @@ -230,7 +231,10 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am | |||
| 230 | for (const IntervalType& add_interval : tmp_intervals) { | 231 | for (const IntervalType& add_interval : tmp_intervals) { |
| 231 | common_ranges.add(add_interval); | 232 | common_ranges.add(add_interval); |
| 232 | } | 233 | } |
| 233 | runtime.CopyBuffer(dest_buffer, src_buffer, copies); | 234 | const auto& copy = copies[0]; |
| 235 | src_buffer.MarkUsage(copy.src_offset, copy.size); | ||
| 236 | dest_buffer.MarkUsage(copy.dst_offset, copy.size); | ||
| 237 | runtime.CopyBuffer(dest_buffer, src_buffer, copies, true); | ||
| 234 | if (has_new_downloads) { | 238 | if (has_new_downloads) { |
| 235 | memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); | 239 | memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); |
| 236 | } | 240 | } |
| @@ -258,9 +262,10 @@ bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) { | |||
| 258 | common_ranges.subtract(subtract_interval); | 262 | common_ranges.subtract(subtract_interval); |
| 259 | 263 | ||
| 260 | const BufferId buffer = FindBuffer(*cpu_dst_address, static_cast<u32>(size)); | 264 | const BufferId buffer = FindBuffer(*cpu_dst_address, static_cast<u32>(size)); |
| 261 | auto& dest_buffer = slot_buffers[buffer]; | 265 | Buffer& dest_buffer = slot_buffers[buffer]; |
| 262 | const u32 offset = dest_buffer.Offset(*cpu_dst_address); | 266 | const u32 offset = dest_buffer.Offset(*cpu_dst_address); |
| 263 | runtime.ClearBuffer(dest_buffer, offset, size, value); | 267 | runtime.ClearBuffer(dest_buffer, offset, size, value); |
| 268 | dest_buffer.MarkUsage(offset, size); | ||
| 264 | return true; | 269 | return true; |
| 265 | } | 270 | } |
| 266 | 271 | ||
| @@ -603,6 +608,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() { | |||
| 603 | VAddr orig_cpu_addr = static_cast<VAddr>(second_copy.src_offset); | 608 | VAddr orig_cpu_addr = static_cast<VAddr>(second_copy.src_offset); |
| 604 | const IntervalType base_interval{orig_cpu_addr, orig_cpu_addr + copy.size}; | 609 | const IntervalType base_interval{orig_cpu_addr, orig_cpu_addr + copy.size}; |
| 605 | async_downloads += std::make_pair(base_interval, 1); | 610 | async_downloads += std::make_pair(base_interval, 1); |
| 611 | buffer.MarkUsage(copy.src_offset, copy.size); | ||
| 606 | runtime.CopyBuffer(download_staging.buffer, buffer, copies, false); | 612 | runtime.CopyBuffer(download_staging.buffer, buffer, copies, false); |
| 607 | normalized_copies.push_back(second_copy); | 613 | normalized_copies.push_back(second_copy); |
| 608 | } | 614 | } |
| @@ -621,8 +627,9 @@ void BufferCache<P>::CommitAsyncFlushesHigh() { | |||
| 621 | // Have in mind the staging buffer offset for the copy | 627 | // Have in mind the staging buffer offset for the copy |
| 622 | copy.dst_offset += download_staging.offset; | 628 | copy.dst_offset += download_staging.offset; |
| 623 | const std::array copies{copy}; | 629 | const std::array copies{copy}; |
| 624 | runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies, | 630 | Buffer& buffer = slot_buffers[buffer_id]; |
| 625 | false); | 631 | buffer.MarkUsage(copy.src_offset, copy.size); |
| 632 | runtime.CopyBuffer(download_staging.buffer, buffer, copies, false); | ||
| 626 | } | 633 | } |
| 627 | runtime.PostCopyBarrier(); | 634 | runtime.PostCopyBarrier(); |
| 628 | runtime.Finish(); | 635 | runtime.Finish(); |
| @@ -742,7 +749,7 @@ void BufferCache<P>::BindHostIndexBuffer() { | |||
| 742 | {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; | 749 | {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; |
| 743 | std::memcpy(upload_staging.mapped_span.data(), | 750 | std::memcpy(upload_staging.mapped_span.data(), |
| 744 | draw_state.inline_index_draw_indexes.data(), size); | 751 | draw_state.inline_index_draw_indexes.data(), size); |
| 745 | runtime.CopyBuffer(buffer, upload_staging.buffer, copies); | 752 | runtime.CopyBuffer(buffer, upload_staging.buffer, copies, true); |
| 746 | } else { | 753 | } else { |
| 747 | buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes); | 754 | buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes); |
| 748 | } | 755 | } |
| @@ -754,6 +761,7 @@ void BufferCache<P>::BindHostIndexBuffer() { | |||
| 754 | offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes(); | 761 | offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes(); |
| 755 | runtime.BindIndexBuffer(buffer, new_offset, size); | 762 | runtime.BindIndexBuffer(buffer, new_offset, size); |
| 756 | } else { | 763 | } else { |
| 764 | buffer.MarkUsage(offset, size); | ||
| 757 | runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, | 765 | runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, |
| 758 | draw_state.index_buffer.first, draw_state.index_buffer.count, | 766 | draw_state.index_buffer.first, draw_state.index_buffer.count, |
| 759 | buffer, offset, size); | 767 | buffer, offset, size); |
| @@ -790,6 +798,7 @@ void BufferCache<P>::BindHostVertexBuffers() { | |||
| 790 | 798 | ||
| 791 | const u32 stride = maxwell3d->regs.vertex_streams[index].stride; | 799 | const u32 stride = maxwell3d->regs.vertex_streams[index].stride; |
| 792 | const u32 offset = buffer.Offset(binding.cpu_addr); | 800 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 801 | buffer.MarkUsage(offset, binding.size); | ||
| 793 | 802 | ||
| 794 | host_bindings.buffers.push_back(&buffer); | 803 | host_bindings.buffers.push_back(&buffer); |
| 795 | host_bindings.offsets.push_back(offset); | 804 | host_bindings.offsets.push_back(offset); |
| @@ -895,6 +904,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 | |||
| 895 | if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { | 904 | if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { |
| 896 | channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size; | 905 | channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size; |
| 897 | } | 906 | } |
| 907 | buffer.MarkUsage(offset, size); | ||
| 898 | if constexpr (NEEDS_BIND_UNIFORM_INDEX) { | 908 | if constexpr (NEEDS_BIND_UNIFORM_INDEX) { |
| 899 | runtime.BindUniformBuffer(stage, binding_index, buffer, offset, size); | 909 | runtime.BindUniformBuffer(stage, binding_index, buffer, offset, size); |
| 900 | } else { | 910 | } else { |
| @@ -913,6 +923,7 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) { | |||
| 913 | SynchronizeBuffer(buffer, binding.cpu_addr, size); | 923 | SynchronizeBuffer(buffer, binding.cpu_addr, size); |
| 914 | 924 | ||
| 915 | const u32 offset = buffer.Offset(binding.cpu_addr); | 925 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 926 | buffer.MarkUsage(offset, size); | ||
| 916 | const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0; | 927 | const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0; |
| 917 | 928 | ||
| 918 | if (is_written) { | 929 | if (is_written) { |
| @@ -943,6 +954,7 @@ void BufferCache<P>::BindHostGraphicsTextureBuffers(size_t stage) { | |||
| 943 | 954 | ||
| 944 | const u32 offset = buffer.Offset(binding.cpu_addr); | 955 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 945 | const PixelFormat format = binding.format; | 956 | const PixelFormat format = binding.format; |
| 957 | buffer.MarkUsage(offset, size); | ||
| 946 | if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { | 958 | if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { |
| 947 | if (((channel_state->image_texture_buffers[stage] >> index) & 1) != 0) { | 959 | if (((channel_state->image_texture_buffers[stage] >> index) & 1) != 0) { |
| 948 | runtime.BindImageBuffer(buffer, offset, size, format); | 960 | runtime.BindImageBuffer(buffer, offset, size, format); |
| @@ -975,9 +987,10 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() { | |||
| 975 | MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size); | 987 | MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size); |
| 976 | 988 | ||
| 977 | const u32 offset = buffer.Offset(binding.cpu_addr); | 989 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 990 | buffer.MarkUsage(offset, size); | ||
| 978 | host_bindings.buffers.push_back(&buffer); | 991 | host_bindings.buffers.push_back(&buffer); |
| 979 | host_bindings.offsets.push_back(offset); | 992 | host_bindings.offsets.push_back(offset); |
| 980 | host_bindings.sizes.push_back(binding.size); | 993 | host_bindings.sizes.push_back(size); |
| 981 | } | 994 | } |
| 982 | if (host_bindings.buffers.size() > 0) { | 995 | if (host_bindings.buffers.size() > 0) { |
| 983 | runtime.BindTransformFeedbackBuffers(host_bindings); | 996 | runtime.BindTransformFeedbackBuffers(host_bindings); |
| @@ -1001,6 +1014,7 @@ void BufferCache<P>::BindHostComputeUniformBuffers() { | |||
| 1001 | SynchronizeBuffer(buffer, binding.cpu_addr, size); | 1014 | SynchronizeBuffer(buffer, binding.cpu_addr, size); |
| 1002 | 1015 | ||
| 1003 | const u32 offset = buffer.Offset(binding.cpu_addr); | 1016 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 1017 | buffer.MarkUsage(offset, size); | ||
| 1004 | if constexpr (NEEDS_BIND_UNIFORM_INDEX) { | 1018 | if constexpr (NEEDS_BIND_UNIFORM_INDEX) { |
| 1005 | runtime.BindComputeUniformBuffer(binding_index, buffer, offset, size); | 1019 | runtime.BindComputeUniformBuffer(binding_index, buffer, offset, size); |
| 1006 | ++binding_index; | 1020 | ++binding_index; |
| @@ -1021,6 +1035,7 @@ void BufferCache<P>::BindHostComputeStorageBuffers() { | |||
| 1021 | SynchronizeBuffer(buffer, binding.cpu_addr, size); | 1035 | SynchronizeBuffer(buffer, binding.cpu_addr, size); |
| 1022 | 1036 | ||
| 1023 | const u32 offset = buffer.Offset(binding.cpu_addr); | 1037 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 1038 | buffer.MarkUsage(offset, size); | ||
| 1024 | const bool is_written = | 1039 | const bool is_written = |
| 1025 | ((channel_state->written_compute_storage_buffers >> index) & 1) != 0; | 1040 | ((channel_state->written_compute_storage_buffers >> index) & 1) != 0; |
| 1026 | 1041 | ||
| @@ -1053,6 +1068,7 @@ void BufferCache<P>::BindHostComputeTextureBuffers() { | |||
| 1053 | 1068 | ||
| 1054 | const u32 offset = buffer.Offset(binding.cpu_addr); | 1069 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 1055 | const PixelFormat format = binding.format; | 1070 | const PixelFormat format = binding.format; |
| 1071 | buffer.MarkUsage(offset, size); | ||
| 1056 | if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { | 1072 | if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { |
| 1057 | if (((channel_state->image_compute_texture_buffers >> index) & 1) != 0) { | 1073 | if (((channel_state->image_compute_texture_buffers >> index) & 1) != 0) { |
| 1058 | runtime.BindImageBuffer(buffer, offset, size, format); | 1074 | runtime.BindImageBuffer(buffer, offset, size, format); |
| @@ -1172,10 +1188,11 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) { | |||
| 1172 | if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { | 1188 | if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { |
| 1173 | size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); | 1189 | size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); |
| 1174 | } | 1190 | } |
| 1191 | const BufferId buffer_id = FindBuffer(*cpu_addr, size); | ||
| 1175 | channel_state->vertex_buffers[index] = Binding{ | 1192 | channel_state->vertex_buffers[index] = Binding{ |
| 1176 | .cpu_addr = *cpu_addr, | 1193 | .cpu_addr = *cpu_addr, |
| 1177 | .size = size, | 1194 | .size = size, |
| 1178 | .buffer_id = FindBuffer(*cpu_addr, size), | 1195 | .buffer_id = buffer_id, |
| 1179 | }; | 1196 | }; |
| 1180 | } | 1197 | } |
| 1181 | 1198 | ||
| @@ -1401,7 +1418,8 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, | |||
| 1401 | .dst_offset = dst_base_offset, | 1418 | .dst_offset = dst_base_offset, |
| 1402 | .size = overlap.SizeBytes(), | 1419 | .size = overlap.SizeBytes(), |
| 1403 | }); | 1420 | }); |
| 1404 | runtime.CopyBuffer(new_buffer, overlap, copies); | 1421 | new_buffer.MarkUsage(copies[0].dst_offset, copies[0].size); |
| 1422 | runtime.CopyBuffer(new_buffer, overlap, copies, true); | ||
| 1405 | DeleteBuffer(overlap_id, true); | 1423 | DeleteBuffer(overlap_id, true); |
| 1406 | } | 1424 | } |
| 1407 | 1425 | ||
| @@ -1414,7 +1432,9 @@ BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) { | |||
| 1414 | const u32 size = static_cast<u32>(overlap.end - overlap.begin); | 1432 | const u32 size = static_cast<u32>(overlap.end - overlap.begin); |
| 1415 | const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size); | 1433 | const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size); |
| 1416 | auto& new_buffer = slot_buffers[new_buffer_id]; | 1434 | auto& new_buffer = slot_buffers[new_buffer_id]; |
| 1417 | runtime.ClearBuffer(new_buffer, 0, new_buffer.SizeBytes(), 0); | 1435 | const size_t size_bytes = new_buffer.SizeBytes(); |
| 1436 | runtime.ClearBuffer(new_buffer, 0, size_bytes, 0); | ||
| 1437 | new_buffer.MarkUsage(0, size_bytes); | ||
| 1418 | for (const BufferId overlap_id : overlap.ids) { | 1438 | for (const BufferId overlap_id : overlap.ids) { |
| 1419 | JoinOverlap(new_buffer_id, overlap_id, !overlap.has_stream_leap); | 1439 | JoinOverlap(new_buffer_id, overlap_id, !overlap.has_stream_leap); |
| 1420 | } | 1440 | } |
| @@ -1467,11 +1487,6 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept { | |||
| 1467 | 1487 | ||
| 1468 | template <class P> | 1488 | template <class P> |
| 1469 | bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { | 1489 | bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { |
| 1470 | return SynchronizeBufferImpl(buffer, cpu_addr, size); | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | template <class P> | ||
| 1474 | bool BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size) { | ||
| 1475 | boost::container::small_vector<BufferCopy, 4> copies; | 1490 | boost::container::small_vector<BufferCopy, 4> copies; |
| 1476 | u64 total_size_bytes = 0; | 1491 | u64 total_size_bytes = 0; |
| 1477 | u64 largest_copy = 0; | 1492 | u64 largest_copy = 0; |
| @@ -1494,51 +1509,6 @@ bool BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 s | |||
| 1494 | } | 1509 | } |
| 1495 | 1510 | ||
| 1496 | template <class P> | 1511 | template <class P> |
| 1497 | bool BufferCache<P>::SynchronizeBufferNoModified(Buffer& buffer, VAddr cpu_addr, u32 size) { | ||
| 1498 | boost::container::small_vector<BufferCopy, 4> copies; | ||
| 1499 | u64 total_size_bytes = 0; | ||
| 1500 | u64 largest_copy = 0; | ||
| 1501 | IntervalSet found_sets{}; | ||
| 1502 | auto make_copies = [&] { | ||
| 1503 | for (auto& interval : found_sets) { | ||
| 1504 | const std::size_t sub_size = interval.upper() - interval.lower(); | ||
| 1505 | const VAddr cpu_addr_ = interval.lower(); | ||
| 1506 | copies.push_back(BufferCopy{ | ||
| 1507 | .src_offset = total_size_bytes, | ||
| 1508 | .dst_offset = cpu_addr_ - buffer.CpuAddr(), | ||
| 1509 | .size = sub_size, | ||
| 1510 | }); | ||
| 1511 | total_size_bytes += sub_size; | ||
| 1512 | largest_copy = std::max<u64>(largest_copy, sub_size); | ||
| 1513 | } | ||
| 1514 | const std::span<BufferCopy> copies_span(copies.data(), copies.size()); | ||
| 1515 | UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); | ||
| 1516 | }; | ||
| 1517 | memory_tracker.ForEachUploadRange(cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) { | ||
| 1518 | const VAddr base_adr = cpu_addr_out; | ||
| 1519 | const VAddr end_adr = base_adr + range_size; | ||
| 1520 | const IntervalType add_interval{base_adr, end_adr}; | ||
| 1521 | found_sets.add(add_interval); | ||
| 1522 | }); | ||
| 1523 | if (found_sets.empty()) { | ||
| 1524 | return true; | ||
| 1525 | } | ||
| 1526 | const IntervalType search_interval{cpu_addr, cpu_addr + size}; | ||
| 1527 | auto it = common_ranges.lower_bound(search_interval); | ||
| 1528 | auto it_end = common_ranges.upper_bound(search_interval); | ||
| 1529 | if (it == common_ranges.end()) { | ||
| 1530 | make_copies(); | ||
| 1531 | return false; | ||
| 1532 | } | ||
| 1533 | while (it != it_end) { | ||
| 1534 | found_sets.subtract(*it); | ||
| 1535 | it++; | ||
| 1536 | } | ||
| 1537 | make_copies(); | ||
| 1538 | return false; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | template <class P> | ||
| 1542 | void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, | 1512 | void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, |
| 1543 | std::span<BufferCopy> copies) { | 1513 | std::span<BufferCopy> copies) { |
| 1544 | if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) { | 1514 | if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) { |
| @@ -1586,7 +1556,8 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer, | |||
| 1586 | // Apply the staging offset | 1556 | // Apply the staging offset |
| 1587 | copy.src_offset += upload_staging.offset; | 1557 | copy.src_offset += upload_staging.offset; |
| 1588 | } | 1558 | } |
| 1589 | runtime.CopyBuffer(buffer, upload_staging.buffer, copies); | 1559 | const bool can_reorder = runtime.CanReorderUpload(buffer, copies); |
| 1560 | runtime.CopyBuffer(buffer, upload_staging.buffer, copies, true, can_reorder); | ||
| 1590 | } | 1561 | } |
| 1591 | } | 1562 | } |
| 1592 | 1563 | ||
| @@ -1628,7 +1599,8 @@ void BufferCache<P>::InlineMemoryImplementation(VAddr dest_address, size_t copy_ | |||
| 1628 | }}; | 1599 | }}; |
| 1629 | u8* const src_pointer = upload_staging.mapped_span.data(); | 1600 | u8* const src_pointer = upload_staging.mapped_span.data(); |
| 1630 | std::memcpy(src_pointer, inlined_buffer.data(), copy_size); | 1601 | std::memcpy(src_pointer, inlined_buffer.data(), copy_size); |
| 1631 | runtime.CopyBuffer(buffer, upload_staging.buffer, copies); | 1602 | const bool can_reorder = runtime.CanReorderUpload(buffer, copies); |
| 1603 | runtime.CopyBuffer(buffer, upload_staging.buffer, copies, true, can_reorder); | ||
| 1632 | } else { | 1604 | } else { |
| 1633 | buffer.ImmediateUpload(buffer.Offset(dest_address), inlined_buffer.first(copy_size)); | 1605 | buffer.ImmediateUpload(buffer.Offset(dest_address), inlined_buffer.first(copy_size)); |
| 1634 | } | 1606 | } |
| @@ -1681,8 +1653,9 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si | |||
| 1681 | for (BufferCopy& copy : copies) { | 1653 | for (BufferCopy& copy : copies) { |
| 1682 | // Modify copies to have the staging offset in mind | 1654 | // Modify copies to have the staging offset in mind |
| 1683 | copy.dst_offset += download_staging.offset; | 1655 | copy.dst_offset += download_staging.offset; |
| 1656 | buffer.MarkUsage(copy.src_offset, copy.size); | ||
| 1684 | } | 1657 | } |
| 1685 | runtime.CopyBuffer(download_staging.buffer, buffer, copies_span); | 1658 | runtime.CopyBuffer(download_staging.buffer, buffer, copies_span, true); |
| 1686 | runtime.Finish(); | 1659 | runtime.Finish(); |
| 1687 | for (const BufferCopy& copy : copies) { | 1660 | for (const BufferCopy& copy : copies) { |
| 1688 | const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset; | 1661 | const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset; |
| @@ -1780,15 +1753,25 @@ Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index, | |||
| 1780 | const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr)); | 1753 | const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr)); |
| 1781 | return std::min(memory_layout_size, static_cast<u32>(8_MiB)); | 1754 | return std::min(memory_layout_size, static_cast<u32>(8_MiB)); |
| 1782 | }(); | 1755 | }(); |
| 1783 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); | 1756 | // Alignment only applies to the offset of the buffer |
| 1784 | if (!cpu_addr || size == 0) { | 1757 | const u32 alignment = runtime.GetStorageBufferAlignment(); |
| 1758 | const GPUVAddr aligned_gpu_addr = Common::AlignDown(gpu_addr, alignment); | ||
| 1759 | const u32 aligned_size = static_cast<u32>(gpu_addr - aligned_gpu_addr) + size; | ||
| 1760 | |||
| 1761 | const std::optional<VAddr> aligned_cpu_addr = gpu_memory->GpuToCpuAddress(aligned_gpu_addr); | ||
| 1762 | if (!aligned_cpu_addr || size == 0) { | ||
| 1785 | LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index); | 1763 | LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index); |
| 1786 | return NULL_BINDING; | 1764 | return NULL_BINDING; |
| 1787 | } | 1765 | } |
| 1788 | const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, YUZU_PAGESIZE); | 1766 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); |
| 1767 | ASSERT_MSG(cpu_addr, "Unaligned storage buffer address not found for cbuf index {}", | ||
| 1768 | cbuf_index); | ||
| 1769 | // The end address used for size calculation does not need to be aligned | ||
| 1770 | const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, Core::Memory::YUZU_PAGESIZE); | ||
| 1771 | |||
| 1789 | const Binding binding{ | 1772 | const Binding binding{ |
| 1790 | .cpu_addr = *cpu_addr, | 1773 | .cpu_addr = *aligned_cpu_addr, |
| 1791 | .size = is_written ? size : static_cast<u32>(cpu_end - *cpu_addr), | 1774 | .size = is_written ? aligned_size : static_cast<u32>(cpu_end - *aligned_cpu_addr), |
| 1792 | .buffer_id = BufferId{}, | 1775 | .buffer_id = BufferId{}, |
| 1793 | }; | 1776 | }; |
| 1794 | return binding; | 1777 | return binding; |
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index eed267361..d6d696d8c 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h | |||
| @@ -529,10 +529,6 @@ private: | |||
| 529 | 529 | ||
| 530 | bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size); | 530 | bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size); |
| 531 | 531 | ||
| 532 | bool SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size); | ||
| 533 | |||
| 534 | bool SynchronizeBufferNoModified(Buffer& buffer, VAddr cpu_addr, u32 size); | ||
| 535 | |||
| 536 | void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, | 532 | void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, |
| 537 | std::span<BufferCopy> copies); | 533 | std::span<BufferCopy> copies); |
| 538 | 534 | ||
diff --git a/src/video_core/buffer_cache/usage_tracker.h b/src/video_core/buffer_cache/usage_tracker.h new file mode 100644 index 000000000..ab05fe415 --- /dev/null +++ b/src/video_core/buffer_cache/usage_tracker.h | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/alignment.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace VideoCommon { | ||
| 10 | |||
| 11 | class UsageTracker { | ||
| 12 | static constexpr size_t BYTES_PER_BIT_SHIFT = 6; | ||
| 13 | static constexpr size_t PAGE_SHIFT = 6 + BYTES_PER_BIT_SHIFT; | ||
| 14 | static constexpr size_t PAGE_BYTES = 1 << PAGE_SHIFT; | ||
| 15 | |||
| 16 | public: | ||
| 17 | explicit UsageTracker(size_t size) { | ||
| 18 | const size_t num_pages = (size >> PAGE_SHIFT) + 1; | ||
| 19 | pages.resize(num_pages, 0ULL); | ||
| 20 | } | ||
| 21 | |||
| 22 | void Reset() noexcept { | ||
| 23 | std::ranges::fill(pages, 0ULL); | ||
| 24 | } | ||
| 25 | |||
| 26 | void Track(u64 offset, u64 size) noexcept { | ||
| 27 | const size_t page = offset >> PAGE_SHIFT; | ||
| 28 | const size_t page_end = (offset + size) >> PAGE_SHIFT; | ||
| 29 | TrackPage(page, offset, size); | ||
| 30 | if (page == page_end) { | ||
| 31 | return; | ||
| 32 | } | ||
| 33 | for (size_t i = page + 1; i < page_end; i++) { | ||
| 34 | pages[i] = ~u64{0}; | ||
| 35 | } | ||
| 36 | const size_t offset_end = offset + size; | ||
| 37 | const size_t offset_end_page_aligned = Common::AlignDown(offset_end, PAGE_BYTES); | ||
| 38 | TrackPage(page_end, offset_end_page_aligned, offset_end - offset_end_page_aligned); | ||
| 39 | } | ||
| 40 | |||
| 41 | [[nodiscard]] bool IsUsed(u64 offset, u64 size) const noexcept { | ||
| 42 | const size_t page = offset >> PAGE_SHIFT; | ||
| 43 | const size_t page_end = (offset + size) >> PAGE_SHIFT; | ||
| 44 | if (IsPageUsed(page, offset, size)) { | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | for (size_t i = page + 1; i < page_end; i++) { | ||
| 48 | if (pages[i] != 0) { | ||
| 49 | return true; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | const size_t offset_end = offset + size; | ||
| 53 | const size_t offset_end_page_aligned = Common::AlignDown(offset_end, PAGE_BYTES); | ||
| 54 | return IsPageUsed(page_end, offset_end_page_aligned, offset_end - offset_end_page_aligned); | ||
| 55 | } | ||
| 56 | |||
| 57 | private: | ||
| 58 | void TrackPage(u64 page, u64 offset, u64 size) noexcept { | ||
| 59 | const size_t offset_in_page = offset % PAGE_BYTES; | ||
| 60 | const size_t first_bit = offset_in_page >> BYTES_PER_BIT_SHIFT; | ||
| 61 | const size_t num_bits = std::min(size, PAGE_BYTES) >> BYTES_PER_BIT_SHIFT; | ||
| 62 | const size_t mask = ~u64{0} >> (64 - num_bits); | ||
| 63 | pages[page] |= (~u64{0} & mask) << first_bit; | ||
| 64 | } | ||
| 65 | |||
| 66 | bool IsPageUsed(u64 page, u64 offset, u64 size) const noexcept { | ||
| 67 | const size_t offset_in_page = offset % PAGE_BYTES; | ||
| 68 | const size_t first_bit = offset_in_page >> BYTES_PER_BIT_SHIFT; | ||
| 69 | const size_t num_bits = std::min(size, PAGE_BYTES) >> BYTES_PER_BIT_SHIFT; | ||
| 70 | const size_t mask = ~u64{0} >> (64 - num_bits); | ||
| 71 | const size_t mask2 = (~u64{0} & mask) << first_bit; | ||
| 72 | return (pages[page] & mask2) != 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | private: | ||
| 76 | std::vector<u64> pages; | ||
| 77 | }; | ||
| 78 | |||
| 79 | } // namespace VideoCommon | ||
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 38d553d3c..dfd696de6 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -178,13 +178,14 @@ void BufferCacheRuntime::CopyBuffer(GLuint dst_buffer, Buffer& src_buffer, | |||
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, GLuint src_buffer, | 180 | void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, GLuint src_buffer, |
| 181 | std::span<const VideoCommon::BufferCopy> copies, bool barrier) { | 181 | std::span<const VideoCommon::BufferCopy> copies, bool barrier, |
| 182 | bool) { | ||
| 182 | CopyBuffer(dst_buffer.Handle(), src_buffer, copies, barrier); | 183 | CopyBuffer(dst_buffer.Handle(), src_buffer, copies, barrier); |
| 183 | } | 184 | } |
| 184 | 185 | ||
| 185 | void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer, | 186 | void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer, |
| 186 | std::span<const VideoCommon::BufferCopy> copies) { | 187 | std::span<const VideoCommon::BufferCopy> copies, bool) { |
| 187 | CopyBuffer(dst_buffer.Handle(), src_buffer.Handle(), copies); | 188 | CopyBuffer(dst_buffer.Handle(), src_buffer.Handle(), copies, true); |
| 188 | } | 189 | } |
| 189 | 190 | ||
| 190 | void BufferCacheRuntime::PreCopyBarrier() { | 191 | void BufferCacheRuntime::PreCopyBarrier() { |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 41b746f3b..000f29a82 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h | |||
| @@ -30,6 +30,8 @@ public: | |||
| 30 | 30 | ||
| 31 | void MakeResident(GLenum access) noexcept; | 31 | void MakeResident(GLenum access) noexcept; |
| 32 | 32 | ||
| 33 | void MarkUsage(u64 offset, u64 size) {} | ||
| 34 | |||
| 33 | [[nodiscard]] GLuint View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format); | 35 | [[nodiscard]] GLuint View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format); |
| 34 | 36 | ||
| 35 | [[nodiscard]] GLuint64EXT HostGpuAddr() const noexcept { | 37 | [[nodiscard]] GLuint64EXT HostGpuAddr() const noexcept { |
| @@ -66,22 +68,29 @@ public: | |||
| 66 | 68 | ||
| 67 | [[nodiscard]] StagingBufferMap DownloadStagingBuffer(size_t size); | 69 | [[nodiscard]] StagingBufferMap DownloadStagingBuffer(size_t size); |
| 68 | 70 | ||
| 71 | bool CanReorderUpload(const Buffer&, std::span<const VideoCommon::BufferCopy>) { | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 69 | void CopyBuffer(GLuint dst_buffer, GLuint src_buffer, | 75 | void CopyBuffer(GLuint dst_buffer, GLuint src_buffer, |
| 70 | std::span<const VideoCommon::BufferCopy> copies, bool barrier = true); | 76 | std::span<const VideoCommon::BufferCopy> copies, bool barrier); |
| 71 | 77 | ||
| 72 | void CopyBuffer(GLuint dst_buffer, Buffer& src_buffer, | 78 | void CopyBuffer(GLuint dst_buffer, Buffer& src_buffer, |
| 73 | std::span<const VideoCommon::BufferCopy> copies, bool barrier = true); | 79 | std::span<const VideoCommon::BufferCopy> copies, bool barrier); |
| 74 | 80 | ||
| 75 | void CopyBuffer(Buffer& dst_buffer, GLuint src_buffer, | 81 | void CopyBuffer(Buffer& dst_buffer, GLuint src_buffer, |
| 76 | std::span<const VideoCommon::BufferCopy> copies, bool barrier = true); | 82 | std::span<const VideoCommon::BufferCopy> copies, bool barrier, |
| 83 | bool can_reorder_upload = false); | ||
| 77 | 84 | ||
| 78 | void CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer, | 85 | void CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer, |
| 79 | std::span<const VideoCommon::BufferCopy> copies); | 86 | std::span<const VideoCommon::BufferCopy> copies, bool); |
| 80 | 87 | ||
| 81 | void PreCopyBarrier(); | 88 | void PreCopyBarrier(); |
| 82 | void PostCopyBarrier(); | 89 | void PostCopyBarrier(); |
| 83 | void Finish(); | 90 | void Finish(); |
| 84 | 91 | ||
| 92 | void TickFrame(VideoCommon::SlotVector<Buffer>&) noexcept {} | ||
| 93 | |||
| 85 | void ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value); | 94 | void ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value); |
| 86 | 95 | ||
| 87 | void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size); | 96 | void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size); |
| @@ -182,6 +191,10 @@ public: | |||
| 182 | return device.CanReportMemoryUsage(); | 191 | return device.CanReportMemoryUsage(); |
| 183 | } | 192 | } |
| 184 | 193 | ||
| 194 | u32 GetStorageBufferAlignment() const { | ||
| 195 | return static_cast<u32>(device.GetShaderStorageBufferAlignment()); | ||
| 196 | } | ||
| 197 | |||
| 185 | private: | 198 | private: |
| 186 | static constexpr std::array PABO_LUT{ | 199 | static constexpr std::array PABO_LUT{ |
| 187 | GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV, GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV, | 200 | GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV, GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV, |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 2888e0238..26f2d0ea7 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -232,6 +232,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 232 | .has_gl_bool_ref_bug = device.HasBoolRefBug(), | 232 | .has_gl_bool_ref_bug = device.HasBoolRefBug(), |
| 233 | .ignore_nan_fp_comparisons = true, | 233 | .ignore_nan_fp_comparisons = true, |
| 234 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), | 234 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), |
| 235 | .min_ssbo_alignment = device.GetShaderStorageBufferAlignment(), | ||
| 235 | }, | 236 | }, |
| 236 | host_info{ | 237 | host_info{ |
| 237 | .support_float64 = true, | 238 | .support_float64 = true, |
| @@ -240,6 +241,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 240 | .needs_demote_reorder = device.IsAmd(), | 241 | .needs_demote_reorder = device.IsAmd(), |
| 241 | .support_snorm_render_buffer = false, | 242 | .support_snorm_render_buffer = false, |
| 242 | .support_viewport_index_layer = device.HasVertexViewportLayer(), | 243 | .support_viewport_index_layer = device.HasVertexViewportLayer(), |
| 244 | .min_ssbo_alignment = static_cast<u32>(device.GetShaderStorageBufferAlignment()), | ||
| 243 | .support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(), | 245 | .support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(), |
| 244 | .support_conditional_barrier = device.SupportsConditionalBarriers(), | 246 | .support_conditional_barrier = device.SupportsConditionalBarriers(), |
| 245 | } { | 247 | } { |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index d8148e89a..5958f52f7 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -79,13 +79,13 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo | |||
| 79 | } // Anonymous namespace | 79 | } // Anonymous namespace |
| 80 | 80 | ||
| 81 | Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) | 81 | Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) |
| 82 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params) {} | 82 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} {} |
| 83 | 83 | ||
| 84 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, | 84 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, |
| 85 | VAddr cpu_addr_, u64 size_bytes_) | 85 | VAddr cpu_addr_, u64 size_bytes_) |
| 86 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), | 86 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), |
| 87 | device{&runtime.device}, buffer{ | 87 | device{&runtime.device}, buffer{CreateBuffer(*device, runtime.memory_allocator, SizeBytes())}, |
| 88 | CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} { | 88 | tracker{SizeBytes()} { |
| 89 | if (runtime.device.HasDebuggingToolAttached()) { | 89 | if (runtime.device.HasDebuggingToolAttached()) { |
| 90 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); | 90 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); |
| 91 | } | 91 | } |
| @@ -355,12 +355,35 @@ bool BufferCacheRuntime::CanReportMemoryUsage() const { | |||
| 355 | return device.CanReportMemoryUsage(); | 355 | return device.CanReportMemoryUsage(); |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | u32 BufferCacheRuntime::GetStorageBufferAlignment() const { | ||
| 359 | return static_cast<u32>(device.GetStorageBufferAlignment()); | ||
| 360 | } | ||
| 361 | |||
| 362 | void BufferCacheRuntime::TickFrame(VideoCommon::SlotVector<Buffer>& slot_buffers) noexcept { | ||
| 363 | for (auto it = slot_buffers.begin(); it != slot_buffers.end(); it++) { | ||
| 364 | it->ResetUsageTracking(); | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 358 | void BufferCacheRuntime::Finish() { | 368 | void BufferCacheRuntime::Finish() { |
| 359 | scheduler.Finish(); | 369 | scheduler.Finish(); |
| 360 | } | 370 | } |
| 361 | 371 | ||
| 372 | bool BufferCacheRuntime::CanReorderUpload(const Buffer& buffer, | ||
| 373 | std::span<const VideoCommon::BufferCopy> copies) { | ||
| 374 | if (Settings::values.disable_buffer_reorder) { | ||
| 375 | return false; | ||
| 376 | } | ||
| 377 | const bool can_use_upload_cmdbuf = | ||
| 378 | std::ranges::all_of(copies, [&](const VideoCommon::BufferCopy& copy) { | ||
| 379 | return !buffer.IsRegionUsed(copy.dst_offset, copy.size); | ||
| 380 | }); | ||
| 381 | return can_use_upload_cmdbuf; | ||
| 382 | } | ||
| 383 | |||
| 362 | void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, | 384 | void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, |
| 363 | std::span<const VideoCommon::BufferCopy> copies, bool barrier) { | 385 | std::span<const VideoCommon::BufferCopy> copies, bool barrier, |
| 386 | bool can_reorder_upload) { | ||
| 364 | if (dst_buffer == VK_NULL_HANDLE || src_buffer == VK_NULL_HANDLE) { | 387 | if (dst_buffer == VK_NULL_HANDLE || src_buffer == VK_NULL_HANDLE) { |
| 365 | return; | 388 | return; |
| 366 | } | 389 | } |
| @@ -376,9 +399,18 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, | |||
| 376 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | 399 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 377 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | 400 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, |
| 378 | }; | 401 | }; |
| 402 | |||
| 379 | // Measuring a popular game, this number never exceeds the specified size once data is warmed up | 403 | // Measuring a popular game, this number never exceeds the specified size once data is warmed up |
| 380 | boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size()); | 404 | boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size()); |
| 381 | std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); | 405 | std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); |
| 406 | if (src_buffer == staging_pool.StreamBuf() && can_reorder_upload) { | ||
| 407 | scheduler.RecordWithUploadBuffer([src_buffer, dst_buffer, vk_copies]( | ||
| 408 | vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) { | ||
| 409 | upload_cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies); | ||
| 410 | }); | ||
| 411 | return; | ||
| 412 | } | ||
| 413 | |||
| 382 | scheduler.RequestOutsideRenderPassOperationContext(); | 414 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 383 | scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { | 415 | scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { |
| 384 | if (barrier) { | 416 | if (barrier) { |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 95446c732..0b3fbd6d0 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "video_core/buffer_cache/buffer_cache_base.h" | 6 | #include "video_core/buffer_cache/buffer_cache_base.h" |
| 7 | #include "video_core/buffer_cache/memory_tracker_base.h" | 7 | #include "video_core/buffer_cache/memory_tracker_base.h" |
| 8 | #include "video_core/buffer_cache/usage_tracker.h" | ||
| 8 | #include "video_core/engines/maxwell_3d.h" | 9 | #include "video_core/engines/maxwell_3d.h" |
| 9 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 10 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| 10 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 11 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| @@ -34,6 +35,18 @@ public: | |||
| 34 | return *buffer; | 35 | return *buffer; |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | [[nodiscard]] bool IsRegionUsed(u64 offset, u64 size) const noexcept { | ||
| 39 | return tracker.IsUsed(offset, size); | ||
| 40 | } | ||
| 41 | |||
| 42 | void MarkUsage(u64 offset, u64 size) noexcept { | ||
| 43 | tracker.Track(offset, size); | ||
| 44 | } | ||
| 45 | |||
| 46 | void ResetUsageTracking() noexcept { | ||
| 47 | tracker.Reset(); | ||
| 48 | } | ||
| 49 | |||
| 37 | operator VkBuffer() const noexcept { | 50 | operator VkBuffer() const noexcept { |
| 38 | return *buffer; | 51 | return *buffer; |
| 39 | } | 52 | } |
| @@ -49,6 +62,7 @@ private: | |||
| 49 | const Device* device{}; | 62 | const Device* device{}; |
| 50 | vk::Buffer buffer; | 63 | vk::Buffer buffer; |
| 51 | std::vector<BufferView> views; | 64 | std::vector<BufferView> views; |
| 65 | VideoCommon::UsageTracker tracker; | ||
| 52 | }; | 66 | }; |
| 53 | 67 | ||
| 54 | class QuadArrayIndexBuffer; | 68 | class QuadArrayIndexBuffer; |
| @@ -67,6 +81,8 @@ public: | |||
| 67 | ComputePassDescriptorQueue& compute_pass_descriptor_queue, | 81 | ComputePassDescriptorQueue& compute_pass_descriptor_queue, |
| 68 | DescriptorPool& descriptor_pool); | 82 | DescriptorPool& descriptor_pool); |
| 69 | 83 | ||
| 84 | void TickFrame(VideoCommon::SlotVector<Buffer>& slot_buffers) noexcept; | ||
| 85 | |||
| 70 | void Finish(); | 86 | void Finish(); |
| 71 | 87 | ||
| 72 | u64 GetDeviceLocalMemory() const; | 88 | u64 GetDeviceLocalMemory() const; |
| @@ -75,16 +91,21 @@ public: | |||
| 75 | 91 | ||
| 76 | bool CanReportMemoryUsage() const; | 92 | bool CanReportMemoryUsage() const; |
| 77 | 93 | ||
| 94 | u32 GetStorageBufferAlignment() const; | ||
| 95 | |||
| 78 | [[nodiscard]] StagingBufferRef UploadStagingBuffer(size_t size); | 96 | [[nodiscard]] StagingBufferRef UploadStagingBuffer(size_t size); |
| 79 | 97 | ||
| 80 | [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size, bool deferred = false); | 98 | [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size, bool deferred = false); |
| 81 | 99 | ||
| 100 | bool CanReorderUpload(const Buffer& buffer, std::span<const VideoCommon::BufferCopy> copies); | ||
| 101 | |||
| 82 | void FreeDeferredStagingBuffer(StagingBufferRef& ref); | 102 | void FreeDeferredStagingBuffer(StagingBufferRef& ref); |
| 83 | 103 | ||
| 84 | void PreCopyBarrier(); | 104 | void PreCopyBarrier(); |
| 85 | 105 | ||
| 86 | void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, | 106 | void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, |
| 87 | std::span<const VideoCommon::BufferCopy> copies, bool barrier = true); | 107 | std::span<const VideoCommon::BufferCopy> copies, bool barrier, |
| 108 | bool can_reorder_upload = false); | ||
| 88 | 109 | ||
| 89 | void PostCopyBarrier(); | 110 | void PostCopyBarrier(); |
| 90 | 111 | ||
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index 6b288b994..ac8b6e838 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp | |||
| @@ -100,12 +100,14 @@ void MasterSemaphore::Wait(u64 tick) { | |||
| 100 | Refresh(); | 100 | Refresh(); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | VkResult MasterSemaphore::SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | 103 | VkResult MasterSemaphore::SubmitQueue(vk::CommandBuffer& cmdbuf, vk::CommandBuffer& upload_cmdbuf, |
| 104 | VkSemaphore wait_semaphore, u64 host_tick) { | 104 | VkSemaphore signal_semaphore, VkSemaphore wait_semaphore, |
| 105 | u64 host_tick) { | ||
| 105 | if (semaphore) { | 106 | if (semaphore) { |
| 106 | return SubmitQueueTimeline(cmdbuf, signal_semaphore, wait_semaphore, host_tick); | 107 | return SubmitQueueTimeline(cmdbuf, upload_cmdbuf, signal_semaphore, wait_semaphore, |
| 108 | host_tick); | ||
| 107 | } else { | 109 | } else { |
| 108 | return SubmitQueueFence(cmdbuf, signal_semaphore, wait_semaphore, host_tick); | 110 | return SubmitQueueFence(cmdbuf, upload_cmdbuf, signal_semaphore, wait_semaphore, host_tick); |
| 109 | } | 111 | } |
| 110 | } | 112 | } |
| 111 | 113 | ||
| @@ -115,6 +117,7 @@ static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{ | |||
| 115 | }; | 117 | }; |
| 116 | 118 | ||
| 117 | VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, | 119 | VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, |
| 120 | vk::CommandBuffer& upload_cmdbuf, | ||
| 118 | VkSemaphore signal_semaphore, | 121 | VkSemaphore signal_semaphore, |
| 119 | VkSemaphore wait_semaphore, u64 host_tick) { | 122 | VkSemaphore wait_semaphore, u64 host_tick) { |
| 120 | const VkSemaphore timeline_semaphore = *semaphore; | 123 | const VkSemaphore timeline_semaphore = *semaphore; |
| @@ -123,6 +126,8 @@ VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, | |||
| 123 | const std::array signal_values{host_tick, u64(0)}; | 126 | const std::array signal_values{host_tick, u64(0)}; |
| 124 | const std::array signal_semaphores{timeline_semaphore, signal_semaphore}; | 127 | const std::array signal_semaphores{timeline_semaphore, signal_semaphore}; |
| 125 | 128 | ||
| 129 | const std::array cmdbuffers{*upload_cmdbuf, *cmdbuf}; | ||
| 130 | |||
| 126 | const u32 num_wait_semaphores = wait_semaphore ? 1 : 0; | 131 | const u32 num_wait_semaphores = wait_semaphore ? 1 : 0; |
| 127 | const VkTimelineSemaphoreSubmitInfo timeline_si{ | 132 | const VkTimelineSemaphoreSubmitInfo timeline_si{ |
| 128 | .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, | 133 | .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, |
| @@ -138,8 +143,8 @@ VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, | |||
| 138 | .waitSemaphoreCount = num_wait_semaphores, | 143 | .waitSemaphoreCount = num_wait_semaphores, |
| 139 | .pWaitSemaphores = &wait_semaphore, | 144 | .pWaitSemaphores = &wait_semaphore, |
| 140 | .pWaitDstStageMask = wait_stage_masks.data(), | 145 | .pWaitDstStageMask = wait_stage_masks.data(), |
| 141 | .commandBufferCount = 1, | 146 | .commandBufferCount = static_cast<u32>(cmdbuffers.size()), |
| 142 | .pCommandBuffers = cmdbuf.address(), | 147 | .pCommandBuffers = cmdbuffers.data(), |
| 143 | .signalSemaphoreCount = num_signal_semaphores, | 148 | .signalSemaphoreCount = num_signal_semaphores, |
| 144 | .pSignalSemaphores = signal_semaphores.data(), | 149 | .pSignalSemaphores = signal_semaphores.data(), |
| 145 | }; | 150 | }; |
| @@ -147,19 +152,23 @@ VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, | |||
| 147 | return device.GetGraphicsQueue().Submit(submit_info); | 152 | return device.GetGraphicsQueue().Submit(submit_info); |
| 148 | } | 153 | } |
| 149 | 154 | ||
| 150 | VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | 155 | VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, |
| 151 | VkSemaphore wait_semaphore, u64 host_tick) { | 156 | vk::CommandBuffer& upload_cmdbuf, |
| 157 | VkSemaphore signal_semaphore, VkSemaphore wait_semaphore, | ||
| 158 | u64 host_tick) { | ||
| 152 | const u32 num_signal_semaphores = signal_semaphore ? 1 : 0; | 159 | const u32 num_signal_semaphores = signal_semaphore ? 1 : 0; |
| 153 | const u32 num_wait_semaphores = wait_semaphore ? 1 : 0; | 160 | const u32 num_wait_semaphores = wait_semaphore ? 1 : 0; |
| 154 | 161 | ||
| 162 | const std::array cmdbuffers{*upload_cmdbuf, *cmdbuf}; | ||
| 163 | |||
| 155 | const VkSubmitInfo submit_info{ | 164 | const VkSubmitInfo submit_info{ |
| 156 | .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | 165 | .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, |
| 157 | .pNext = nullptr, | 166 | .pNext = nullptr, |
| 158 | .waitSemaphoreCount = num_wait_semaphores, | 167 | .waitSemaphoreCount = num_wait_semaphores, |
| 159 | .pWaitSemaphores = &wait_semaphore, | 168 | .pWaitSemaphores = &wait_semaphore, |
| 160 | .pWaitDstStageMask = wait_stage_masks.data(), | 169 | .pWaitDstStageMask = wait_stage_masks.data(), |
| 161 | .commandBufferCount = 1, | 170 | .commandBufferCount = static_cast<u32>(cmdbuffers.size()), |
| 162 | .pCommandBuffers = cmdbuf.address(), | 171 | .pCommandBuffers = cmdbuffers.data(), |
| 163 | .signalSemaphoreCount = num_signal_semaphores, | 172 | .signalSemaphoreCount = num_signal_semaphores, |
| 164 | .pSignalSemaphores = &signal_semaphore, | 173 | .pSignalSemaphores = &signal_semaphore, |
| 165 | }; | 174 | }; |
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 3f599d7bd..7dfb93ffb 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h | |||
| @@ -52,14 +52,16 @@ public: | |||
| 52 | void Wait(u64 tick); | 52 | void Wait(u64 tick); |
| 53 | 53 | ||
| 54 | /// Submits the device graphics queue, updating the tick as necessary | 54 | /// Submits the device graphics queue, updating the tick as necessary |
| 55 | VkResult SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | 55 | VkResult SubmitQueue(vk::CommandBuffer& cmdbuf, vk::CommandBuffer& upload_cmdbuf, |
| 56 | VkSemaphore wait_semaphore, u64 host_tick); | 56 | VkSemaphore signal_semaphore, VkSemaphore wait_semaphore, u64 host_tick); |
| 57 | 57 | ||
| 58 | private: | 58 | private: |
| 59 | VkResult SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | 59 | VkResult SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, vk::CommandBuffer& upload_cmdbuf, |
| 60 | VkSemaphore wait_semaphore, u64 host_tick); | 60 | VkSemaphore signal_semaphore, VkSemaphore wait_semaphore, |
| 61 | VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | 61 | u64 host_tick); |
| 62 | VkSemaphore wait_semaphore, u64 host_tick); | 62 | VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, vk::CommandBuffer& upload_cmdbuf, |
| 63 | VkSemaphore signal_semaphore, VkSemaphore wait_semaphore, | ||
| 64 | u64 host_tick); | ||
| 63 | 65 | ||
| 64 | void WaitThread(std::stop_token token); | 66 | void WaitThread(std::stop_token token); |
| 65 | 67 | ||
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 89b455bff..2a13b2a72 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -373,6 +373,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 373 | driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, | 373 | driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, |
| 374 | .has_broken_robust = | 374 | .has_broken_robust = |
| 375 | device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal, | 375 | device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal, |
| 376 | .min_ssbo_alignment = device.GetStorageBufferAlignment(), | ||
| 376 | }; | 377 | }; |
| 377 | 378 | ||
| 378 | host_info = Shader::HostTranslateInfo{ | 379 | host_info = Shader::HostTranslateInfo{ |
| @@ -383,6 +384,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 383 | driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE, | 384 | driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE, |
| 384 | .support_snorm_render_buffer = true, | 385 | .support_snorm_render_buffer = true, |
| 385 | .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), | 386 | .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), |
| 387 | .min_ssbo_alignment = static_cast<u32>(device.GetStorageBufferAlignment()), | ||
| 386 | .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), | 388 | .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), |
| 387 | .support_conditional_barrier = device.SupportsConditionalBarriers(), | 389 | .support_conditional_barrier = device.SupportsConditionalBarriers(), |
| 388 | }; | 390 | }; |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 3be7837f4..146923db4 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -22,11 +22,12 @@ namespace Vulkan { | |||
| 22 | 22 | ||
| 23 | MICROPROFILE_DECLARE(Vulkan_WaitForWorker); | 23 | MICROPROFILE_DECLARE(Vulkan_WaitForWorker); |
| 24 | 24 | ||
| 25 | void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) { | 25 | void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf, |
| 26 | vk::CommandBuffer upload_cmdbuf) { | ||
| 26 | auto command = first; | 27 | auto command = first; |
| 27 | while (command != nullptr) { | 28 | while (command != nullptr) { |
| 28 | auto next = command->GetNext(); | 29 | auto next = command->GetNext(); |
| 29 | command->Execute(cmdbuf); | 30 | command->Execute(cmdbuf, upload_cmdbuf); |
| 30 | command->~Command(); | 31 | command->~Command(); |
| 31 | command = next; | 32 | command = next; |
| 32 | } | 33 | } |
| @@ -180,7 +181,7 @@ void Scheduler::WorkerThread(std::stop_token stop_token) { | |||
| 180 | // Perform the work, tracking whether the chunk was a submission | 181 | // Perform the work, tracking whether the chunk was a submission |
| 181 | // before executing. | 182 | // before executing. |
| 182 | const bool has_submit = work->HasSubmit(); | 183 | const bool has_submit = work->HasSubmit(); |
| 183 | work->ExecuteAll(current_cmdbuf); | 184 | work->ExecuteAll(current_cmdbuf, current_upload_cmdbuf); |
| 184 | 185 | ||
| 185 | // If the chunk was a submission, reallocate the command buffer. | 186 | // If the chunk was a submission, reallocate the command buffer. |
| 186 | if (has_submit) { | 187 | if (has_submit) { |
| @@ -205,6 +206,13 @@ void Scheduler::AllocateWorkerCommandBuffer() { | |||
| 205 | .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, | 206 | .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, |
| 206 | .pInheritanceInfo = nullptr, | 207 | .pInheritanceInfo = nullptr, |
| 207 | }); | 208 | }); |
| 209 | current_upload_cmdbuf = vk::CommandBuffer(command_pool->Commit(), device.GetDispatchLoader()); | ||
| 210 | current_upload_cmdbuf.Begin({ | ||
| 211 | .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | ||
| 212 | .pNext = nullptr, | ||
| 213 | .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, | ||
| 214 | .pInheritanceInfo = nullptr, | ||
| 215 | }); | ||
| 208 | } | 216 | } |
| 209 | 217 | ||
| 210 | u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { | 218 | u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { |
| @@ -212,7 +220,17 @@ u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_se | |||
| 212 | InvalidateState(); | 220 | InvalidateState(); |
| 213 | 221 | ||
| 214 | const u64 signal_value = master_semaphore->NextTick(); | 222 | const u64 signal_value = master_semaphore->NextTick(); |
| 215 | Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) { | 223 | RecordWithUploadBuffer([signal_semaphore, wait_semaphore, signal_value, |
| 224 | this](vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf) { | ||
| 225 | static constexpr VkMemoryBarrier WRITE_BARRIER{ | ||
| 226 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 227 | .pNext = nullptr, | ||
| 228 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 229 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 230 | }; | ||
| 231 | upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 232 | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER); | ||
| 233 | upload_cmdbuf.End(); | ||
| 216 | cmdbuf.End(); | 234 | cmdbuf.End(); |
| 217 | 235 | ||
| 218 | if (on_submit) { | 236 | if (on_submit) { |
| @@ -221,7 +239,7 @@ u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_se | |||
| 221 | 239 | ||
| 222 | std::scoped_lock lock{submit_mutex}; | 240 | std::scoped_lock lock{submit_mutex}; |
| 223 | switch (const VkResult result = master_semaphore->SubmitQueue( | 241 | switch (const VkResult result = master_semaphore->SubmitQueue( |
| 224 | cmdbuf, signal_semaphore, wait_semaphore, signal_value)) { | 242 | cmdbuf, upload_cmdbuf, signal_semaphore, wait_semaphore, signal_value)) { |
| 225 | case VK_SUCCESS: | 243 | case VK_SUCCESS: |
| 226 | break; | 244 | break; |
| 227 | case VK_ERROR_DEVICE_LOST: | 245 | case VK_ERROR_DEVICE_LOST: |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index da03803aa..f8d8ca80a 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h | |||
| @@ -80,7 +80,8 @@ public: | |||
| 80 | 80 | ||
| 81 | /// Send work to a separate thread. | 81 | /// Send work to a separate thread. |
| 82 | template <typename T> | 82 | template <typename T> |
| 83 | void Record(T&& command) { | 83 | requires std::is_invocable_v<T, vk::CommandBuffer, vk::CommandBuffer> |
| 84 | void RecordWithUploadBuffer(T&& command) { | ||
| 84 | if (chunk->Record(command)) { | 85 | if (chunk->Record(command)) { |
| 85 | return; | 86 | return; |
| 86 | } | 87 | } |
| @@ -88,6 +89,15 @@ public: | |||
| 88 | (void)chunk->Record(command); | 89 | (void)chunk->Record(command); |
| 89 | } | 90 | } |
| 90 | 91 | ||
| 92 | template <typename T> | ||
| 93 | requires std::is_invocable_v<T, vk::CommandBuffer> | ||
| 94 | void Record(T&& c) { | ||
| 95 | this->RecordWithUploadBuffer( | ||
| 96 | [command = std::move(c)](vk::CommandBuffer cmdbuf, vk::CommandBuffer) { | ||
| 97 | command(cmdbuf); | ||
| 98 | }); | ||
| 99 | } | ||
| 100 | |||
| 91 | /// Returns the current command buffer tick. | 101 | /// Returns the current command buffer tick. |
| 92 | [[nodiscard]] u64 CurrentTick() const noexcept { | 102 | [[nodiscard]] u64 CurrentTick() const noexcept { |
| 93 | return master_semaphore->CurrentTick(); | 103 | return master_semaphore->CurrentTick(); |
| @@ -119,7 +129,7 @@ private: | |||
| 119 | public: | 129 | public: |
| 120 | virtual ~Command() = default; | 130 | virtual ~Command() = default; |
| 121 | 131 | ||
| 122 | virtual void Execute(vk::CommandBuffer cmdbuf) const = 0; | 132 | virtual void Execute(vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf) const = 0; |
| 123 | 133 | ||
| 124 | Command* GetNext() const { | 134 | Command* GetNext() const { |
| 125 | return next; | 135 | return next; |
| @@ -142,8 +152,8 @@ private: | |||
| 142 | TypedCommand(TypedCommand&&) = delete; | 152 | TypedCommand(TypedCommand&&) = delete; |
| 143 | TypedCommand& operator=(TypedCommand&&) = delete; | 153 | TypedCommand& operator=(TypedCommand&&) = delete; |
| 144 | 154 | ||
| 145 | void Execute(vk::CommandBuffer cmdbuf) const override { | 155 | void Execute(vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf) const override { |
| 146 | command(cmdbuf); | 156 | command(cmdbuf, upload_cmdbuf); |
| 147 | } | 157 | } |
| 148 | 158 | ||
| 149 | private: | 159 | private: |
| @@ -152,7 +162,7 @@ private: | |||
| 152 | 162 | ||
| 153 | class CommandChunk final { | 163 | class CommandChunk final { |
| 154 | public: | 164 | public: |
| 155 | void ExecuteAll(vk::CommandBuffer cmdbuf); | 165 | void ExecuteAll(vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf); |
| 156 | 166 | ||
| 157 | template <typename T> | 167 | template <typename T> |
| 158 | bool Record(T& command) { | 168 | bool Record(T& command) { |
| @@ -228,6 +238,7 @@ private: | |||
| 228 | VideoCommon::QueryCacheBase<QueryCacheParams>* query_cache = nullptr; | 238 | VideoCommon::QueryCacheBase<QueryCacheParams>* query_cache = nullptr; |
| 229 | 239 | ||
| 230 | vk::CommandBuffer current_cmdbuf; | 240 | vk::CommandBuffer current_cmdbuf; |
| 241 | vk::CommandBuffer current_upload_cmdbuf; | ||
| 231 | 242 | ||
| 232 | std::unique_ptr<CommandChunk> chunk; | 243 | std::unique_ptr<CommandChunk> chunk; |
| 233 | std::function<void()> on_submit; | 244 | std::function<void()> on_submit; |
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp index 5efd7d66e..70644ea82 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.cpp +++ b/src/video_core/renderer_vulkan/vk_smaa.cpp | |||
| @@ -672,7 +672,7 @@ void SMAA::UploadImages(Scheduler& scheduler) { | |||
| 672 | UploadImage(m_device, m_allocator, scheduler, m_static_images[Search], search_extent, | 672 | UploadImage(m_device, m_allocator, scheduler, m_static_images[Search], search_extent, |
| 673 | VK_FORMAT_R8_UNORM, ARRAY_TO_SPAN(searchTexBytes)); | 673 | VK_FORMAT_R8_UNORM, ARRAY_TO_SPAN(searchTexBytes)); |
| 674 | 674 | ||
| 675 | scheduler.Record([&](vk::CommandBuffer& cmdbuf) { | 675 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { |
| 676 | for (auto& images : m_dynamic_images) { | 676 | for (auto& images : m_dynamic_images) { |
| 677 | for (size_t i = 0; i < MaxDynamicImage; i++) { | 677 | for (size_t i = 0; i < MaxDynamicImage; i++) { |
| 678 | ClearColorImage(cmdbuf, *images.images[i]); | 678 | ClearColorImage(cmdbuf, *images.images[i]); |
| @@ -707,7 +707,7 @@ VkImageView SMAA::Draw(Scheduler& scheduler, size_t image_index, VkImage source_ | |||
| 707 | UpdateDescriptorSets(source_image_view, image_index); | 707 | UpdateDescriptorSets(source_image_view, image_index); |
| 708 | 708 | ||
| 709 | scheduler.RequestOutsideRenderPassOperationContext(); | 709 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 710 | scheduler.Record([=, this](vk::CommandBuffer& cmdbuf) { | 710 | scheduler.Record([=, this](vk::CommandBuffer cmdbuf) { |
| 711 | TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL); | 711 | TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL); |
| 712 | TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL); | 712 | TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL); |
| 713 | BeginRenderPass(cmdbuf, m_renderpasses[EdgeDetection], edge_detection_framebuffer, | 713 | BeginRenderPass(cmdbuf, m_renderpasses[EdgeDetection], edge_detection_framebuffer, |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index d3deb9072..f63a20327 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -36,6 +36,10 @@ public: | |||
| 36 | StagingBufferRef Request(size_t size, MemoryUsage usage, bool deferred = false); | 36 | StagingBufferRef Request(size_t size, MemoryUsage usage, bool deferred = false); |
| 37 | void FreeDeferred(StagingBufferRef& ref); | 37 | void FreeDeferred(StagingBufferRef& ref); |
| 38 | 38 | ||
| 39 | [[nodiscard]] VkBuffer StreamBuf() const noexcept { | ||
| 40 | return *stream_buffer; | ||
| 41 | } | ||
| 42 | |||
| 39 | void TickFrame(); | 43 | void TickFrame(); |
| 40 | 44 | ||
| 41 | private: | 45 | private: |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index de34f6d49..5dbec2e62 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -1785,8 +1785,22 @@ ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | |||
| 1785 | : VideoCommon::ImageViewBase{info, view_info, gpu_addr_}, | 1785 | : VideoCommon::ImageViewBase{info, view_info, gpu_addr_}, |
| 1786 | buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {} | 1786 | buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {} |
| 1787 | 1787 | ||
| 1788 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams& params) | 1788 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params) |
| 1789 | : VideoCommon::ImageViewBase{params} {} | 1789 | : VideoCommon::ImageViewBase{params}, device{&runtime.device} { |
| 1790 | if (device->HasNullDescriptor()) { | ||
| 1791 | return; | ||
| 1792 | } | ||
| 1793 | |||
| 1794 | // Handle fallback for devices without nullDescriptor | ||
| 1795 | ImageInfo info{}; | ||
| 1796 | info.format = PixelFormat::A8B8G8R8_UNORM; | ||
| 1797 | |||
| 1798 | null_image = MakeImage(*device, runtime.memory_allocator, info, {}); | ||
| 1799 | image_handle = *null_image; | ||
| 1800 | for (u32 i = 0; i < Shader::NUM_TEXTURE_TYPES; i++) { | ||
| 1801 | image_views[i] = MakeView(VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_ASPECT_COLOR_BIT); | ||
| 1802 | } | ||
| 1803 | } | ||
| 1790 | 1804 | ||
| 1791 | ImageView::~ImageView() = default; | 1805 | ImageView::~ImageView() = default; |
| 1792 | 1806 | ||
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 7a0807709..edf5d7635 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -267,6 +267,7 @@ private: | |||
| 267 | vk::ImageView depth_view; | 267 | vk::ImageView depth_view; |
| 268 | vk::ImageView stencil_view; | 268 | vk::ImageView stencil_view; |
| 269 | vk::ImageView color_view; | 269 | vk::ImageView color_view; |
| 270 | vk::Image null_image; | ||
| 270 | VkImage image_handle = VK_NULL_HANDLE; | 271 | VkImage image_handle = VK_NULL_HANDLE; |
| 271 | VkImageView render_target = VK_NULL_HANDLE; | 272 | VkImageView render_target = VK_NULL_HANDLE; |
| 272 | VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; | 273 | VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; |
diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h index 9df6a2903..3ffa2a661 100644 --- a/src/video_core/texture_cache/slot_vector.h +++ b/src/video_core/texture_cache/slot_vector.h | |||
| @@ -138,6 +138,10 @@ public: | |||
| 138 | return Iterator(this, SlotId{SlotId::INVALID_INDEX}); | 138 | return Iterator(this, SlotId{SlotId::INVALID_INDEX}); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | [[nodiscard]] size_t size() const noexcept { | ||
| 142 | return values_capacity - free_list.size(); | ||
| 143 | } | ||
| 144 | |||
| 141 | private: | 145 | private: |
| 142 | struct NonTrivialDummy { | 146 | struct NonTrivialDummy { |
| 143 | NonTrivialDummy() noexcept {} | 147 | NonTrivialDummy() noexcept {} |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 4ffd122fc..188ceeed7 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -899,7 +899,8 @@ bool Device::ShouldBoostClocks() const { | |||
| 899 | driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA || | 899 | driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA || |
| 900 | driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP; | 900 | driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP; |
| 901 | 901 | ||
| 902 | const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F; | 902 | const bool is_steam_deck = (vendor_id == 0x1002 && device_id == 0x163F) || |
| 903 | (vendor_id == 0x1002 && device_id == 0x1435); | ||
| 903 | 904 | ||
| 904 | const bool is_debugging = this->HasDebuggingToolAttached(); | 905 | const bool is_debugging = this->HasDebuggingToolAttached(); |
| 905 | 906 | ||
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 0487cd3b6..a0c70797f 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -1101,6 +1101,10 @@ public: | |||
| 1101 | return &handle; | 1101 | return &handle; |
| 1102 | } | 1102 | } |
| 1103 | 1103 | ||
| 1104 | VkCommandBuffer operator*() const noexcept { | ||
| 1105 | return handle; | ||
| 1106 | } | ||
| 1107 | |||
| 1104 | void Begin(const VkCommandBufferBeginInfo& begin_info) const { | 1108 | void Begin(const VkCommandBufferBeginInfo& begin_info) const { |
| 1105 | Check(dld->vkBeginCommandBuffer(handle, &begin_info)); | 1109 | Check(dld->vkBeginCommandBuffer(handle, &begin_info)); |
| 1106 | } | 1110 | } |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 181b2817c..f3ad2214b 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -38,8 +38,6 @@ add_executable(yuzu | |||
| 38 | compatdb.ui | 38 | compatdb.ui |
| 39 | compatibility_list.cpp | 39 | compatibility_list.cpp |
| 40 | compatibility_list.h | 40 | compatibility_list.h |
| 41 | configuration/config.cpp | ||
| 42 | configuration/config.h | ||
| 43 | configuration/configuration_shared.cpp | 41 | configuration/configuration_shared.cpp |
| 44 | configuration/configuration_shared.h | 42 | configuration/configuration_shared.h |
| 45 | configuration/configure.ui | 43 | configuration/configure.ui |
| @@ -147,6 +145,8 @@ add_executable(yuzu | |||
| 147 | configuration/shared_translation.h | 145 | configuration/shared_translation.h |
| 148 | configuration/shared_widget.cpp | 146 | configuration/shared_widget.cpp |
| 149 | configuration/shared_widget.h | 147 | configuration/shared_widget.h |
| 148 | configuration/qt_config.cpp | ||
| 149 | configuration/qt_config.h | ||
| 150 | debugger/console.cpp | 150 | debugger/console.cpp |
| 151 | debugger/console.h | 151 | debugger/console.h |
| 152 | debugger/controller.cpp | 152 | debugger/controller.cpp |
| @@ -377,7 +377,7 @@ endif() | |||
| 377 | 377 | ||
| 378 | create_target_directory_groups(yuzu) | 378 | create_target_directory_groups(yuzu) |
| 379 | 379 | ||
| 380 | target_link_libraries(yuzu PRIVATE common core input_common network video_core) | 380 | target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core) |
| 381 | target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets) | 381 | target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets) |
| 382 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 382 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) |
| 383 | 383 | ||
| @@ -386,7 +386,7 @@ if (NOT WIN32) | |||
| 386 | target_include_directories(yuzu PRIVATE ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS}) | 386 | target_include_directories(yuzu PRIVATE ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS}) |
| 387 | endif() | 387 | endif() |
| 388 | if (UNIX AND NOT APPLE) | 388 | if (UNIX AND NOT APPLE) |
| 389 | target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::DBus) | 389 | target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::DBus gamemode) |
| 390 | endif() | 390 | endif() |
| 391 | 391 | ||
| 392 | target_compile_definitions(yuzu PRIVATE | 392 | target_compile_definitions(yuzu PRIVATE |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 2afa72140..ed5750155 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | #include <QSize> | 30 | #include <QSize> |
| 31 | #include <QStringLiteral> | 31 | #include <QStringLiteral> |
| 32 | #include <QSurfaceFormat> | 32 | #include <QSurfaceFormat> |
| 33 | #include <QTimer> | ||
| 34 | #include <QWindow> | 33 | #include <QWindow> |
| 35 | #include <QtCore/qobjectdefs.h> | 34 | #include <QtCore/qobjectdefs.h> |
| 36 | 35 | ||
| @@ -66,6 +65,8 @@ class QObject; | |||
| 66 | class QPaintEngine; | 65 | class QPaintEngine; |
| 67 | class QSurface; | 66 | class QSurface; |
| 68 | 67 | ||
| 68 | constexpr int default_mouse_constrain_timeout = 10; | ||
| 69 | |||
| 69 | EmuThread::EmuThread(Core::System& system) : m_system{system} {} | 70 | EmuThread::EmuThread(Core::System& system) : m_system{system} {} |
| 70 | 71 | ||
| 71 | EmuThread::~EmuThread() = default; | 72 | EmuThread::~EmuThread() = default; |
| @@ -304,6 +305,9 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | |||
| 304 | Qt::QueuedConnection); | 305 | Qt::QueuedConnection); |
| 305 | connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection); | 306 | connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection); |
| 306 | connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged); | 307 | connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged); |
| 308 | |||
| 309 | mouse_constrain_timer.setInterval(default_mouse_constrain_timeout); | ||
| 310 | connect(&mouse_constrain_timer, &QTimer::timeout, this, &GRenderWindow::ConstrainMouse); | ||
| 307 | } | 311 | } |
| 308 | 312 | ||
| 309 | void GRenderWindow::ExecuteProgram(std::size_t program_index) { | 313 | void GRenderWindow::ExecuteProgram(std::size_t program_index) { |
| @@ -393,6 +397,22 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { | |||
| 393 | QWidget::closeEvent(event); | 397 | QWidget::closeEvent(event); |
| 394 | } | 398 | } |
| 395 | 399 | ||
| 400 | void GRenderWindow::leaveEvent(QEvent* event) { | ||
| 401 | if (Settings::values.mouse_panning) { | ||
| 402 | const QRect& rect = QWidget::geometry(); | ||
| 403 | QPoint position = QCursor::pos(); | ||
| 404 | |||
| 405 | qint32 x = qBound(rect.left(), position.x(), rect.right()); | ||
| 406 | qint32 y = qBound(rect.top(), position.y(), rect.bottom()); | ||
| 407 | // Only start the timer if the mouse has left the window bound. | ||
| 408 | // The leave event is also triggered when the window looses focus. | ||
| 409 | if (x != position.x() || y != position.y()) { | ||
| 410 | mouse_constrain_timer.start(); | ||
| 411 | } | ||
| 412 | event->accept(); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 396 | int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { | 416 | int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { |
| 397 | static constexpr std::array<std::pair<Qt::Key, Settings::NativeKeyboard::Keys>, 106> key_map = { | 417 | static constexpr std::array<std::pair<Qt::Key, Settings::NativeKeyboard::Keys>, 106> key_map = { |
| 398 | std::pair<Qt::Key, Settings::NativeKeyboard::Keys>{Qt::Key_A, Settings::NativeKeyboard::A}, | 418 | std::pair<Qt::Key, Settings::NativeKeyboard::Keys>{Qt::Key_A, Settings::NativeKeyboard::A}, |
| @@ -658,10 +678,19 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { | |||
| 658 | input_subsystem->GetMouse()->TouchMove(touch_x, touch_y); | 678 | input_subsystem->GetMouse()->TouchMove(touch_x, touch_y); |
| 659 | input_subsystem->GetMouse()->Move(pos.x(), pos.y(), center_x, center_y); | 679 | input_subsystem->GetMouse()->Move(pos.x(), pos.y(), center_x, center_y); |
| 660 | 680 | ||
| 681 | // Center mouse for mouse panning | ||
| 661 | if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { | 682 | if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { |
| 662 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); | 683 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); |
| 663 | } | 684 | } |
| 664 | 685 | ||
| 686 | // Constrain mouse for mouse emulation with mouse panning | ||
| 687 | if (Settings::values.mouse_panning && Settings::values.mouse_enabled) { | ||
| 688 | const auto [clamped_mouse_x, clamped_mouse_y] = ClipToTouchScreen(x, y); | ||
| 689 | QCursor::setPos(mapToGlobal( | ||
| 690 | QPoint{static_cast<int>(clamped_mouse_x), static_cast<int>(clamped_mouse_y)})); | ||
| 691 | } | ||
| 692 | |||
| 693 | mouse_constrain_timer.stop(); | ||
| 665 | emit MouseActivity(); | 694 | emit MouseActivity(); |
| 666 | } | 695 | } |
| 667 | 696 | ||
| @@ -675,6 +704,31 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { | |||
| 675 | input_subsystem->GetMouse()->ReleaseButton(button); | 704 | input_subsystem->GetMouse()->ReleaseButton(button); |
| 676 | } | 705 | } |
| 677 | 706 | ||
| 707 | void GRenderWindow::ConstrainMouse() { | ||
| 708 | if (emu_thread == nullptr || !Settings::values.mouse_panning) { | ||
| 709 | mouse_constrain_timer.stop(); | ||
| 710 | return; | ||
| 711 | } | ||
| 712 | if (!this->isActiveWindow()) { | ||
| 713 | mouse_constrain_timer.stop(); | ||
| 714 | return; | ||
| 715 | } | ||
| 716 | |||
| 717 | if (Settings::values.mouse_enabled) { | ||
| 718 | const auto pos = mapFromGlobal(QCursor::pos()); | ||
| 719 | const int new_pos_x = std::clamp(pos.x(), 0, width()); | ||
| 720 | const int new_pos_y = std::clamp(pos.y(), 0, height()); | ||
| 721 | |||
| 722 | QCursor::setPos(mapToGlobal(QPoint{new_pos_x, new_pos_y})); | ||
| 723 | return; | ||
| 724 | } | ||
| 725 | |||
| 726 | const int center_x = width() / 2; | ||
| 727 | const int center_y = height() / 2; | ||
| 728 | |||
| 729 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); | ||
| 730 | } | ||
| 731 | |||
| 678 | void GRenderWindow::wheelEvent(QWheelEvent* event) { | 732 | void GRenderWindow::wheelEvent(QWheelEvent* event) { |
| 679 | const int x = event->angleDelta().x(); | 733 | const int x = event->angleDelta().x(); |
| 680 | const int y = event->angleDelta().y(); | 734 | const int y = event->angleDelta().y(); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 87b23df12..60edd464c 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <QString> | 17 | #include <QString> |
| 18 | #include <QStringList> | 18 | #include <QStringList> |
| 19 | #include <QThread> | 19 | #include <QThread> |
| 20 | #include <QTimer> | ||
| 20 | #include <QWidget> | 21 | #include <QWidget> |
| 21 | #include <qglobal.h> | 22 | #include <qglobal.h> |
| 22 | #include <qnamespace.h> | 23 | #include <qnamespace.h> |
| @@ -38,7 +39,6 @@ class QMouseEvent; | |||
| 38 | class QObject; | 39 | class QObject; |
| 39 | class QResizeEvent; | 40 | class QResizeEvent; |
| 40 | class QShowEvent; | 41 | class QShowEvent; |
| 41 | class QTimer; | ||
| 42 | class QTouchEvent; | 42 | class QTouchEvent; |
| 43 | class QWheelEvent; | 43 | class QWheelEvent; |
| 44 | 44 | ||
| @@ -166,6 +166,7 @@ public: | |||
| 166 | std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; | 166 | std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; |
| 167 | 167 | ||
| 168 | void closeEvent(QCloseEvent* event) override; | 168 | void closeEvent(QCloseEvent* event) override; |
| 169 | void leaveEvent(QEvent* event) override; | ||
| 169 | 170 | ||
| 170 | void resizeEvent(QResizeEvent* event) override; | 171 | void resizeEvent(QResizeEvent* event) override; |
| 171 | 172 | ||
| @@ -229,6 +230,7 @@ private: | |||
| 229 | void TouchBeginEvent(const QTouchEvent* event); | 230 | void TouchBeginEvent(const QTouchEvent* event); |
| 230 | void TouchUpdateEvent(const QTouchEvent* event); | 231 | void TouchUpdateEvent(const QTouchEvent* event); |
| 231 | void TouchEndEvent(); | 232 | void TouchEndEvent(); |
| 233 | void ConstrainMouse(); | ||
| 232 | 234 | ||
| 233 | void RequestCameraCapture(); | 235 | void RequestCameraCapture(); |
| 234 | void OnCameraCapture(int requestId, const QImage& img); | 236 | void OnCameraCapture(int requestId, const QImage& img); |
| @@ -268,6 +270,8 @@ private: | |||
| 268 | std::unique_ptr<QTimer> camera_timer; | 270 | std::unique_ptr<QTimer> camera_timer; |
| 269 | #endif | 271 | #endif |
| 270 | 272 | ||
| 273 | QTimer mouse_constrain_timer; | ||
| 274 | |||
| 271 | Core::System& system; | 275 | Core::System& system; |
| 272 | 276 | ||
| 273 | protected: | 277 | protected: |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp deleted file mode 100644 index c0ae6468b..000000000 --- a/src/yuzu/configuration/config.cpp +++ /dev/null | |||
| @@ -1,1309 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <array> | ||
| 6 | #include <QKeySequence> | ||
| 7 | #include <QSettings> | ||
| 8 | #include "common/fs/fs.h" | ||
| 9 | #include "common/fs/path_util.h" | ||
| 10 | #include "common/settings.h" | ||
| 11 | #include "common/settings_common.h" | ||
| 12 | #include "common/settings_enums.h" | ||
| 13 | #include "core/core.h" | ||
| 14 | #include "core/hle/service/acc/profile_manager.h" | ||
| 15 | #include "core/hle/service/hid/controllers/npad.h" | ||
| 16 | #include "input_common/main.h" | ||
| 17 | #include "network/network.h" | ||
| 18 | #include "yuzu/configuration/config.h" | ||
| 19 | |||
| 20 | namespace FS = Common::FS; | ||
| 21 | |||
| 22 | Config::Config(const std::string& config_name, ConfigType config_type) | ||
| 23 | : type(config_type), global{config_type == ConfigType::GlobalConfig} { | ||
| 24 | Initialize(config_name); | ||
| 25 | } | ||
| 26 | |||
| 27 | Config::~Config() { | ||
| 28 | if (global) { | ||
| 29 | Save(); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { | ||
| 34 | Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F, | ||
| 35 | Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T, | ||
| 36 | Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, | ||
| 37 | Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0, | ||
| 38 | Qt::Key_Q, Qt::Key_E, | ||
| 39 | }; | ||
| 40 | |||
| 41 | const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = { | ||
| 42 | Qt::Key_7, | ||
| 43 | Qt::Key_8, | ||
| 44 | }; | ||
| 45 | |||
| 46 | const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ | ||
| 47 | { | ||
| 48 | Qt::Key_W, | ||
| 49 | Qt::Key_S, | ||
| 50 | Qt::Key_A, | ||
| 51 | Qt::Key_D, | ||
| 52 | }, | ||
| 53 | { | ||
| 54 | Qt::Key_I, | ||
| 55 | Qt::Key_K, | ||
| 56 | Qt::Key_J, | ||
| 57 | Qt::Key_L, | ||
| 58 | }, | ||
| 59 | }}; | ||
| 60 | |||
| 61 | const std::array<int, 2> Config::default_stick_mod = { | ||
| 62 | Qt::Key_Shift, | ||
| 63 | 0, | ||
| 64 | }; | ||
| 65 | |||
| 66 | const std::array<int, 2> Config::default_ringcon_analogs{{ | ||
| 67 | Qt::Key_A, | ||
| 68 | Qt::Key_D, | ||
| 69 | }}; | ||
| 70 | |||
| 71 | const std::map<Settings::AntiAliasing, QString> Config::anti_aliasing_texts_map = { | ||
| 72 | {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, | ||
| 73 | {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))}, | ||
| 74 | {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))}, | ||
| 75 | }; | ||
| 76 | |||
| 77 | const std::map<Settings::ScalingFilter, QString> Config::scaling_filter_texts_map = { | ||
| 78 | {Settings::ScalingFilter::NearestNeighbor, | ||
| 79 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))}, | ||
| 80 | {Settings::ScalingFilter::Bilinear, | ||
| 81 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))}, | ||
| 82 | {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, | ||
| 83 | {Settings::ScalingFilter::Gaussian, | ||
| 84 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, | ||
| 85 | {Settings::ScalingFilter::ScaleForce, | ||
| 86 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, | ||
| 87 | {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, | ||
| 88 | }; | ||
| 89 | |||
| 90 | const std::map<Settings::ConsoleMode, QString> Config::use_docked_mode_texts_map = { | ||
| 91 | {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, | ||
| 92 | {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, | ||
| 93 | }; | ||
| 94 | |||
| 95 | const std::map<Settings::GpuAccuracy, QString> Config::gpu_accuracy_texts_map = { | ||
| 96 | {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))}, | ||
| 97 | {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))}, | ||
| 98 | {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))}, | ||
| 99 | }; | ||
| 100 | |||
| 101 | const std::map<Settings::RendererBackend, QString> Config::renderer_backend_texts_map = { | ||
| 102 | {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))}, | ||
| 103 | {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))}, | ||
| 104 | {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))}, | ||
| 105 | }; | ||
| 106 | |||
| 107 | const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_map = { | ||
| 108 | {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, | ||
| 109 | {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, | ||
| 110 | {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, | ||
| 111 | }; | ||
| 112 | |||
| 113 | // This shouldn't have anything except static initializers (no functions). So | ||
| 114 | // QKeySequence(...).toString() is NOT ALLOWED HERE. | ||
| 115 | // This must be in alphabetical order according to action name as it must have the same order as | ||
| 116 | // UISetting::values.shortcuts, which is alphabetically ordered. | ||
| 117 | // clang-format off | ||
| 118 | const std::array<UISettings::Shortcut, 23> Config::default_hotkeys{{ | ||
| 119 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}}, | ||
| 120 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, | ||
| 121 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, | ||
| 122 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, | ||
| 123 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut, false}}, | ||
| 124 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut, false}}, | ||
| 125 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut, false}}, | ||
| 126 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut, false}}, | ||
| 127 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut, false}}, | ||
| 128 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut, false}}, | ||
| 129 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}}, | ||
| 130 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}}, | ||
| 131 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, | ||
| 132 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral("R+Plus+Minus"), Qt::WindowShortcut, false}}, | ||
| 133 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral("L+Plus+Minus"), Qt::WindowShortcut, false}}, | ||
| 134 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, | ||
| 135 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, | ||
| 136 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, | ||
| 137 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}}, | ||
| 138 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}}, | ||
| 139 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, | ||
| 140 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral(""), QStringLiteral(""), Qt::ApplicationShortcut, false}}, | ||
| 141 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}}, | ||
| 142 | }}; | ||
| 143 | // clang-format on | ||
| 144 | |||
| 145 | void Config::Initialize(const std::string& config_name) { | ||
| 146 | const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); | ||
| 147 | const auto config_file = fmt::format("{}.ini", config_name); | ||
| 148 | |||
| 149 | switch (type) { | ||
| 150 | case ConfigType::GlobalConfig: | ||
| 151 | qt_config_loc = FS::PathToUTF8String(fs_config_loc / config_file); | ||
| 152 | void(FS::CreateParentDir(qt_config_loc)); | ||
| 153 | qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), | ||
| 154 | QSettings::IniFormat); | ||
| 155 | Reload(); | ||
| 156 | break; | ||
| 157 | case ConfigType::PerGameConfig: | ||
| 158 | qt_config_loc = | ||
| 159 | FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); | ||
| 160 | void(FS::CreateParentDir(qt_config_loc)); | ||
| 161 | qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), | ||
| 162 | QSettings::IniFormat); | ||
| 163 | Reload(); | ||
| 164 | break; | ||
| 165 | case ConfigType::InputProfile: | ||
| 166 | qt_config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); | ||
| 167 | void(FS::CreateParentDir(qt_config_loc)); | ||
| 168 | qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), | ||
| 169 | QSettings::IniFormat); | ||
| 170 | break; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | bool Config::IsCustomConfig() { | ||
| 175 | return type == ConfigType::PerGameConfig; | ||
| 176 | } | ||
| 177 | |||
| 178 | void Config::ReadPlayerValue(std::size_t player_index) { | ||
| 179 | const QString player_prefix = [this, player_index] { | ||
| 180 | if (type == ConfigType::InputProfile) { | ||
| 181 | return QString{}; | ||
| 182 | } else { | ||
| 183 | return QStringLiteral("player_%1_").arg(player_index); | ||
| 184 | } | ||
| 185 | }(); | ||
| 186 | |||
| 187 | auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 188 | if (IsCustomConfig()) { | ||
| 189 | const auto profile_name = | ||
| 190 | qt_config->value(QStringLiteral("%1profile_name").arg(player_prefix), QString{}) | ||
| 191 | .toString() | ||
| 192 | .toStdString(); | ||
| 193 | if (profile_name.empty()) { | ||
| 194 | // Use the global input config | ||
| 195 | player = Settings::values.players.GetValue(true)[player_index]; | ||
| 196 | return; | ||
| 197 | } | ||
| 198 | player.profile_name = profile_name; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (player_prefix.isEmpty() && Settings::IsConfiguringGlobal()) { | ||
| 202 | const auto controller = static_cast<Settings::ControllerType>( | ||
| 203 | qt_config | ||
| 204 | ->value(QStringLiteral("%1type").arg(player_prefix), | ||
| 205 | static_cast<u8>(Settings::ControllerType::ProController)) | ||
| 206 | .toUInt()); | ||
| 207 | |||
| 208 | if (controller == Settings::ControllerType::LeftJoycon || | ||
| 209 | controller == Settings::ControllerType::RightJoycon) { | ||
| 210 | player.controller_type = controller; | ||
| 211 | } | ||
| 212 | } else { | ||
| 213 | player.connected = | ||
| 214 | ReadSetting(QStringLiteral("%1connected").arg(player_prefix), player_index == 0) | ||
| 215 | .toBool(); | ||
| 216 | |||
| 217 | player.controller_type = static_cast<Settings::ControllerType>( | ||
| 218 | qt_config | ||
| 219 | ->value(QStringLiteral("%1type").arg(player_prefix), | ||
| 220 | static_cast<u8>(Settings::ControllerType::ProController)) | ||
| 221 | .toUInt()); | ||
| 222 | |||
| 223 | player.vibration_enabled = | ||
| 224 | qt_config->value(QStringLiteral("%1vibration_enabled").arg(player_prefix), true) | ||
| 225 | .toBool(); | ||
| 226 | |||
| 227 | player.vibration_strength = | ||
| 228 | qt_config->value(QStringLiteral("%1vibration_strength").arg(player_prefix), 100) | ||
| 229 | .toInt(); | ||
| 230 | |||
| 231 | player.body_color_left = qt_config | ||
| 232 | ->value(QStringLiteral("%1body_color_left").arg(player_prefix), | ||
| 233 | Settings::JOYCON_BODY_NEON_BLUE) | ||
| 234 | .toUInt(); | ||
| 235 | player.body_color_right = | ||
| 236 | qt_config | ||
| 237 | ->value(QStringLiteral("%1body_color_right").arg(player_prefix), | ||
| 238 | Settings::JOYCON_BODY_NEON_RED) | ||
| 239 | .toUInt(); | ||
| 240 | player.button_color_left = | ||
| 241 | qt_config | ||
| 242 | ->value(QStringLiteral("%1button_color_left").arg(player_prefix), | ||
| 243 | Settings::JOYCON_BUTTONS_NEON_BLUE) | ||
| 244 | .toUInt(); | ||
| 245 | player.button_color_right = | ||
| 246 | qt_config | ||
| 247 | ->value(QStringLiteral("%1button_color_right").arg(player_prefix), | ||
| 248 | Settings::JOYCON_BUTTONS_NEON_RED) | ||
| 249 | .toUInt(); | ||
| 250 | } | ||
| 251 | |||
| 252 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 253 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 254 | auto& player_buttons = player.buttons[i]; | ||
| 255 | |||
| 256 | player_buttons = qt_config | ||
| 257 | ->value(QStringLiteral("%1").arg(player_prefix) + | ||
| 258 | QString::fromUtf8(Settings::NativeButton::mapping[i]), | ||
| 259 | QString::fromStdString(default_param)) | ||
| 260 | .toString() | ||
| 261 | .toStdString(); | ||
| 262 | if (player_buttons.empty()) { | ||
| 263 | player_buttons = default_param; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 268 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 269 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 270 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 271 | auto& player_analogs = player.analogs[i]; | ||
| 272 | |||
| 273 | player_analogs = qt_config | ||
| 274 | ->value(QStringLiteral("%1").arg(player_prefix) + | ||
| 275 | QString::fromUtf8(Settings::NativeAnalog::mapping[i]), | ||
| 276 | QString::fromStdString(default_param)) | ||
| 277 | .toString() | ||
| 278 | .toStdString(); | ||
| 279 | if (player_analogs.empty()) { | ||
| 280 | player_analogs = default_param; | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 285 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 286 | auto& player_motions = player.motions[i]; | ||
| 287 | |||
| 288 | player_motions = qt_config | ||
| 289 | ->value(QStringLiteral("%1").arg(player_prefix) + | ||
| 290 | QString::fromUtf8(Settings::NativeMotion::mapping[i]), | ||
| 291 | QString::fromStdString(default_param)) | ||
| 292 | .toString() | ||
| 293 | .toStdString(); | ||
| 294 | if (player_motions.empty()) { | ||
| 295 | player_motions = default_param; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | void Config::ReadDebugValues() { | ||
| 301 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 302 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 303 | auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; | ||
| 304 | |||
| 305 | debug_pad_buttons = qt_config | ||
| 306 | ->value(QStringLiteral("debug_pad_") + | ||
| 307 | QString::fromUtf8(Settings::NativeButton::mapping[i]), | ||
| 308 | QString::fromStdString(default_param)) | ||
| 309 | .toString() | ||
| 310 | .toStdString(); | ||
| 311 | if (debug_pad_buttons.empty()) { | ||
| 312 | debug_pad_buttons = default_param; | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 317 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 318 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 319 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 320 | auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; | ||
| 321 | |||
| 322 | debug_pad_analogs = qt_config | ||
| 323 | ->value(QStringLiteral("debug_pad_") + | ||
| 324 | QString::fromUtf8(Settings::NativeAnalog::mapping[i]), | ||
| 325 | QString::fromStdString(default_param)) | ||
| 326 | .toString() | ||
| 327 | .toStdString(); | ||
| 328 | if (debug_pad_analogs.empty()) { | ||
| 329 | debug_pad_analogs = default_param; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | void Config::ReadTouchscreenValues() { | ||
| 335 | Settings::values.touchscreen.enabled = | ||
| 336 | ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool(); | ||
| 337 | |||
| 338 | Settings::values.touchscreen.rotation_angle = | ||
| 339 | ReadSetting(QStringLiteral("touchscreen_angle"), 0).toUInt(); | ||
| 340 | Settings::values.touchscreen.diameter_x = | ||
| 341 | ReadSetting(QStringLiteral("touchscreen_diameter_x"), 15).toUInt(); | ||
| 342 | Settings::values.touchscreen.diameter_y = | ||
| 343 | ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt(); | ||
| 344 | } | ||
| 345 | |||
| 346 | void Config::ReadHidbusValues() { | ||
| 347 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 348 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||
| 349 | auto& ringcon_analogs = Settings::values.ringcon_analogs; | ||
| 350 | |||
| 351 | ringcon_analogs = | ||
| 352 | qt_config->value(QStringLiteral("ring_controller"), QString::fromStdString(default_param)) | ||
| 353 | .toString() | ||
| 354 | .toStdString(); | ||
| 355 | if (ringcon_analogs.empty()) { | ||
| 356 | ringcon_analogs = default_param; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | void Config::ReadAudioValues() { | ||
| 361 | qt_config->beginGroup(QStringLiteral("Audio")); | ||
| 362 | |||
| 363 | ReadCategory(Settings::Category::Audio); | ||
| 364 | ReadCategory(Settings::Category::UiAudio); | ||
| 365 | |||
| 366 | qt_config->endGroup(); | ||
| 367 | } | ||
| 368 | |||
| 369 | void Config::ReadControlValues() { | ||
| 370 | qt_config->beginGroup(QStringLiteral("Controls")); | ||
| 371 | |||
| 372 | ReadCategory(Settings::Category::Controls); | ||
| 373 | |||
| 374 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 375 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 376 | ReadPlayerValue(p); | ||
| 377 | } | ||
| 378 | |||
| 379 | // Disable docked mode if handheld is selected | ||
| 380 | const auto controller_type = Settings::values.players.GetValue()[0].controller_type; | ||
| 381 | if (controller_type == Settings::ControllerType::Handheld) { | ||
| 382 | Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig()); | ||
| 383 | Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); | ||
| 384 | } | ||
| 385 | |||
| 386 | if (IsCustomConfig()) { | ||
| 387 | qt_config->endGroup(); | ||
| 388 | return; | ||
| 389 | } | ||
| 390 | ReadDebugValues(); | ||
| 391 | ReadTouchscreenValues(); | ||
| 392 | ReadMotionTouchValues(); | ||
| 393 | ReadHidbusValues(); | ||
| 394 | |||
| 395 | qt_config->endGroup(); | ||
| 396 | } | ||
| 397 | |||
| 398 | void Config::ReadMotionTouchValues() { | ||
| 399 | int num_touch_from_button_maps = | ||
| 400 | qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); | ||
| 401 | |||
| 402 | if (num_touch_from_button_maps > 0) { | ||
| 403 | const auto append_touch_from_button_map = [this] { | ||
| 404 | Settings::TouchFromButtonMap map; | ||
| 405 | map.name = ReadSetting(QStringLiteral("name"), QStringLiteral("default")) | ||
| 406 | .toString() | ||
| 407 | .toStdString(); | ||
| 408 | const int num_touch_maps = qt_config->beginReadArray(QStringLiteral("entries")); | ||
| 409 | map.buttons.reserve(num_touch_maps); | ||
| 410 | for (int i = 0; i < num_touch_maps; i++) { | ||
| 411 | qt_config->setArrayIndex(i); | ||
| 412 | std::string touch_mapping = | ||
| 413 | ReadSetting(QStringLiteral("bind")).toString().toStdString(); | ||
| 414 | map.buttons.emplace_back(std::move(touch_mapping)); | ||
| 415 | } | ||
| 416 | qt_config->endArray(); // entries | ||
| 417 | Settings::values.touch_from_button_maps.emplace_back(std::move(map)); | ||
| 418 | }; | ||
| 419 | |||
| 420 | for (int i = 0; i < num_touch_from_button_maps; ++i) { | ||
| 421 | qt_config->setArrayIndex(i); | ||
| 422 | append_touch_from_button_map(); | ||
| 423 | } | ||
| 424 | } else { | ||
| 425 | Settings::values.touch_from_button_maps.emplace_back( | ||
| 426 | Settings::TouchFromButtonMap{"default", {}}); | ||
| 427 | num_touch_from_button_maps = 1; | ||
| 428 | } | ||
| 429 | qt_config->endArray(); | ||
| 430 | |||
| 431 | Settings::values.touch_from_button_map_index = std::clamp( | ||
| 432 | Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); | ||
| 433 | } | ||
| 434 | |||
| 435 | void Config::ReadCoreValues() { | ||
| 436 | qt_config->beginGroup(QStringLiteral("Core")); | ||
| 437 | |||
| 438 | ReadCategory(Settings::Category::Core); | ||
| 439 | |||
| 440 | qt_config->endGroup(); | ||
| 441 | } | ||
| 442 | |||
| 443 | void Config::ReadDataStorageValues() { | ||
| 444 | qt_config->beginGroup(QStringLiteral("Data Storage")); | ||
| 445 | |||
| 446 | FS::SetYuzuPath( | ||
| 447 | FS::YuzuPath::NANDDir, | ||
| 448 | qt_config | ||
| 449 | ->value(QStringLiteral("nand_directory"), | ||
| 450 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))) | ||
| 451 | .toString() | ||
| 452 | .toStdString()); | ||
| 453 | FS::SetYuzuPath( | ||
| 454 | FS::YuzuPath::SDMCDir, | ||
| 455 | qt_config | ||
| 456 | ->value(QStringLiteral("sdmc_directory"), | ||
| 457 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))) | ||
| 458 | .toString() | ||
| 459 | .toStdString()); | ||
| 460 | FS::SetYuzuPath( | ||
| 461 | FS::YuzuPath::LoadDir, | ||
| 462 | qt_config | ||
| 463 | ->value(QStringLiteral("load_directory"), | ||
| 464 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))) | ||
| 465 | .toString() | ||
| 466 | .toStdString()); | ||
| 467 | FS::SetYuzuPath( | ||
| 468 | FS::YuzuPath::DumpDir, | ||
| 469 | qt_config | ||
| 470 | ->value(QStringLiteral("dump_directory"), | ||
| 471 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))) | ||
| 472 | .toString() | ||
| 473 | .toStdString()); | ||
| 474 | FS::SetYuzuPath(FS::YuzuPath::TASDir, | ||
| 475 | qt_config | ||
| 476 | ->value(QStringLiteral("tas_directory"), | ||
| 477 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir))) | ||
| 478 | .toString() | ||
| 479 | .toStdString()); | ||
| 480 | |||
| 481 | ReadCategory(Settings::Category::DataStorage); | ||
| 482 | |||
| 483 | qt_config->endGroup(); | ||
| 484 | } | ||
| 485 | |||
| 486 | void Config::ReadDebuggingValues() { | ||
| 487 | qt_config->beginGroup(QStringLiteral("Debugging")); | ||
| 488 | |||
| 489 | // Intentionally not using the QT default setting as this is intended to be changed in the ini | ||
| 490 | Settings::values.record_frame_times = | ||
| 491 | qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); | ||
| 492 | |||
| 493 | ReadCategory(Settings::Category::Debugging); | ||
| 494 | ReadCategory(Settings::Category::DebuggingGraphics); | ||
| 495 | |||
| 496 | qt_config->endGroup(); | ||
| 497 | } | ||
| 498 | |||
| 499 | void Config::ReadServiceValues() { | ||
| 500 | qt_config->beginGroup(QStringLiteral("Services")); | ||
| 501 | |||
| 502 | ReadCategory(Settings::Category::Services); | ||
| 503 | |||
| 504 | qt_config->endGroup(); | ||
| 505 | } | ||
| 506 | |||
| 507 | void Config::ReadDisabledAddOnValues() { | ||
| 508 | const auto size = qt_config->beginReadArray(QStringLiteral("DisabledAddOns")); | ||
| 509 | |||
| 510 | for (int i = 0; i < size; ++i) { | ||
| 511 | qt_config->setArrayIndex(i); | ||
| 512 | const auto title_id = ReadSetting(QStringLiteral("title_id"), 0).toULongLong(); | ||
| 513 | std::vector<std::string> out; | ||
| 514 | const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled")); | ||
| 515 | for (int j = 0; j < d_size; ++j) { | ||
| 516 | qt_config->setArrayIndex(j); | ||
| 517 | out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString()); | ||
| 518 | } | ||
| 519 | qt_config->endArray(); | ||
| 520 | Settings::values.disabled_addons.insert_or_assign(title_id, out); | ||
| 521 | } | ||
| 522 | |||
| 523 | qt_config->endArray(); | ||
| 524 | } | ||
| 525 | |||
| 526 | void Config::ReadMiscellaneousValues() { | ||
| 527 | qt_config->beginGroup(QStringLiteral("Miscellaneous")); | ||
| 528 | |||
| 529 | ReadCategory(Settings::Category::Miscellaneous); | ||
| 530 | |||
| 531 | qt_config->endGroup(); | ||
| 532 | } | ||
| 533 | |||
| 534 | void Config::ReadPathValues() { | ||
| 535 | qt_config->beginGroup(QStringLiteral("Paths")); | ||
| 536 | |||
| 537 | UISettings::values.roms_path = ReadSetting(QStringLiteral("romsPath")).toString(); | ||
| 538 | UISettings::values.symbols_path = ReadSetting(QStringLiteral("symbolsPath")).toString(); | ||
| 539 | UISettings::values.game_dir_deprecated = | ||
| 540 | ReadSetting(QStringLiteral("gameListRootDir"), QStringLiteral(".")).toString(); | ||
| 541 | UISettings::values.game_dir_deprecated_deepscan = | ||
| 542 | ReadSetting(QStringLiteral("gameListDeepScan"), false).toBool(); | ||
| 543 | const int gamedirs_size = qt_config->beginReadArray(QStringLiteral("gamedirs")); | ||
| 544 | for (int i = 0; i < gamedirs_size; ++i) { | ||
| 545 | qt_config->setArrayIndex(i); | ||
| 546 | UISettings::GameDir game_dir; | ||
| 547 | game_dir.path = ReadSetting(QStringLiteral("path")).toString(); | ||
| 548 | game_dir.deep_scan = ReadSetting(QStringLiteral("deep_scan"), false).toBool(); | ||
| 549 | game_dir.expanded = ReadSetting(QStringLiteral("expanded"), true).toBool(); | ||
| 550 | UISettings::values.game_dirs.append(game_dir); | ||
| 551 | } | ||
| 552 | qt_config->endArray(); | ||
| 553 | // create NAND and SD card directories if empty, these are not removable through the UI, | ||
| 554 | // also carries over old game list settings if present | ||
| 555 | if (UISettings::values.game_dirs.isEmpty()) { | ||
| 556 | UISettings::GameDir game_dir; | ||
| 557 | game_dir.path = QStringLiteral("SDMC"); | ||
| 558 | game_dir.expanded = true; | ||
| 559 | UISettings::values.game_dirs.append(game_dir); | ||
| 560 | game_dir.path = QStringLiteral("UserNAND"); | ||
| 561 | UISettings::values.game_dirs.append(game_dir); | ||
| 562 | game_dir.path = QStringLiteral("SysNAND"); | ||
| 563 | UISettings::values.game_dirs.append(game_dir); | ||
| 564 | if (UISettings::values.game_dir_deprecated != QStringLiteral(".")) { | ||
| 565 | game_dir.path = UISettings::values.game_dir_deprecated; | ||
| 566 | game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan; | ||
| 567 | UISettings::values.game_dirs.append(game_dir); | ||
| 568 | } | ||
| 569 | } | ||
| 570 | UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList(); | ||
| 571 | UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString(); | ||
| 572 | |||
| 573 | qt_config->endGroup(); | ||
| 574 | } | ||
| 575 | |||
| 576 | void Config::ReadCpuValues() { | ||
| 577 | qt_config->beginGroup(QStringLiteral("Cpu")); | ||
| 578 | |||
| 579 | ReadCategory(Settings::Category::Cpu); | ||
| 580 | ReadCategory(Settings::Category::CpuDebug); | ||
| 581 | ReadCategory(Settings::Category::CpuUnsafe); | ||
| 582 | |||
| 583 | qt_config->endGroup(); | ||
| 584 | } | ||
| 585 | |||
| 586 | void Config::ReadRendererValues() { | ||
| 587 | qt_config->beginGroup(QStringLiteral("Renderer")); | ||
| 588 | |||
| 589 | ReadCategory(Settings::Category::Renderer); | ||
| 590 | ReadCategory(Settings::Category::RendererAdvanced); | ||
| 591 | ReadCategory(Settings::Category::RendererDebug); | ||
| 592 | |||
| 593 | qt_config->endGroup(); | ||
| 594 | } | ||
| 595 | |||
| 596 | void Config::ReadScreenshotValues() { | ||
| 597 | qt_config->beginGroup(QStringLiteral("Screenshots")); | ||
| 598 | |||
| 599 | ReadCategory(Settings::Category::Screenshots); | ||
| 600 | FS::SetYuzuPath( | ||
| 601 | FS::YuzuPath::ScreenshotsDir, | ||
| 602 | qt_config | ||
| 603 | ->value(QStringLiteral("screenshot_path"), | ||
| 604 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir))) | ||
| 605 | .toString() | ||
| 606 | .toStdString()); | ||
| 607 | |||
| 608 | qt_config->endGroup(); | ||
| 609 | } | ||
| 610 | |||
| 611 | void Config::ReadShortcutValues() { | ||
| 612 | qt_config->beginGroup(QStringLiteral("Shortcuts")); | ||
| 613 | |||
| 614 | for (const auto& [name, group, shortcut] : default_hotkeys) { | ||
| 615 | qt_config->beginGroup(group); | ||
| 616 | qt_config->beginGroup(name); | ||
| 617 | // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1 | ||
| 618 | // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open | ||
| 619 | // a file dialog in windowed mode | ||
| 620 | UISettings::values.shortcuts.push_back( | ||
| 621 | {name, | ||
| 622 | group, | ||
| 623 | {ReadSetting(QStringLiteral("KeySeq"), shortcut.keyseq).toString(), | ||
| 624 | ReadSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq) | ||
| 625 | .toString(), | ||
| 626 | shortcut.context, ReadSetting(QStringLiteral("Repeat"), shortcut.repeat).toBool()}}); | ||
| 627 | qt_config->endGroup(); | ||
| 628 | qt_config->endGroup(); | ||
| 629 | } | ||
| 630 | |||
| 631 | qt_config->endGroup(); | ||
| 632 | } | ||
| 633 | |||
| 634 | void Config::ReadSystemValues() { | ||
| 635 | qt_config->beginGroup(QStringLiteral("System")); | ||
| 636 | |||
| 637 | ReadCategory(Settings::Category::System); | ||
| 638 | ReadCategory(Settings::Category::SystemAudio); | ||
| 639 | |||
| 640 | qt_config->endGroup(); | ||
| 641 | } | ||
| 642 | |||
| 643 | void Config::ReadUIValues() { | ||
| 644 | qt_config->beginGroup(QStringLiteral("UI")); | ||
| 645 | |||
| 646 | UISettings::values.theme = | ||
| 647 | ReadSetting( | ||
| 648 | QStringLiteral("theme"), | ||
| 649 | QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)) | ||
| 650 | .toString(); | ||
| 651 | |||
| 652 | ReadUIGamelistValues(); | ||
| 653 | ReadUILayoutValues(); | ||
| 654 | ReadPathValues(); | ||
| 655 | ReadScreenshotValues(); | ||
| 656 | ReadShortcutValues(); | ||
| 657 | ReadMultiplayerValues(); | ||
| 658 | |||
| 659 | ReadCategory(Settings::Category::Ui); | ||
| 660 | ReadCategory(Settings::Category::UiGeneral); | ||
| 661 | |||
| 662 | qt_config->endGroup(); | ||
| 663 | } | ||
| 664 | |||
| 665 | void Config::ReadUIGamelistValues() { | ||
| 666 | qt_config->beginGroup(QStringLiteral("UIGameList")); | ||
| 667 | |||
| 668 | ReadCategory(Settings::Category::UiGameList); | ||
| 669 | |||
| 670 | const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); | ||
| 671 | for (int i = 0; i < favorites_size; i++) { | ||
| 672 | qt_config->setArrayIndex(i); | ||
| 673 | UISettings::values.favorited_ids.append( | ||
| 674 | ReadSetting(QStringLiteral("program_id")).toULongLong()); | ||
| 675 | } | ||
| 676 | qt_config->endArray(); | ||
| 677 | |||
| 678 | qt_config->endGroup(); | ||
| 679 | } | ||
| 680 | |||
| 681 | void Config::ReadUILayoutValues() { | ||
| 682 | qt_config->beginGroup(QStringLiteral("UILayout")); | ||
| 683 | |||
| 684 | UISettings::values.geometry = ReadSetting(QStringLiteral("geometry")).toByteArray(); | ||
| 685 | UISettings::values.state = ReadSetting(QStringLiteral("state")).toByteArray(); | ||
| 686 | UISettings::values.renderwindow_geometry = | ||
| 687 | ReadSetting(QStringLiteral("geometryRenderWindow")).toByteArray(); | ||
| 688 | UISettings::values.gamelist_header_state = | ||
| 689 | ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray(); | ||
| 690 | UISettings::values.microprofile_geometry = | ||
| 691 | ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray(); | ||
| 692 | |||
| 693 | ReadCategory(Settings::Category::UiLayout); | ||
| 694 | |||
| 695 | qt_config->endGroup(); | ||
| 696 | } | ||
| 697 | |||
| 698 | void Config::ReadWebServiceValues() { | ||
| 699 | qt_config->beginGroup(QStringLiteral("WebService")); | ||
| 700 | |||
| 701 | ReadCategory(Settings::Category::WebService); | ||
| 702 | |||
| 703 | qt_config->endGroup(); | ||
| 704 | } | ||
| 705 | |||
| 706 | void Config::ReadMultiplayerValues() { | ||
| 707 | qt_config->beginGroup(QStringLiteral("Multiplayer")); | ||
| 708 | |||
| 709 | ReadCategory(Settings::Category::Multiplayer); | ||
| 710 | |||
| 711 | // Read ban list back | ||
| 712 | int size = qt_config->beginReadArray(QStringLiteral("username_ban_list")); | ||
| 713 | UISettings::values.multiplayer_ban_list.first.resize(size); | ||
| 714 | for (int i = 0; i < size; ++i) { | ||
| 715 | qt_config->setArrayIndex(i); | ||
| 716 | UISettings::values.multiplayer_ban_list.first[i] = | ||
| 717 | ReadSetting(QStringLiteral("username")).toString().toStdString(); | ||
| 718 | } | ||
| 719 | qt_config->endArray(); | ||
| 720 | size = qt_config->beginReadArray(QStringLiteral("ip_ban_list")); | ||
| 721 | UISettings::values.multiplayer_ban_list.second.resize(size); | ||
| 722 | for (int i = 0; i < size; ++i) { | ||
| 723 | qt_config->setArrayIndex(i); | ||
| 724 | UISettings::values.multiplayer_ban_list.second[i] = | ||
| 725 | ReadSetting(QStringLiteral("ip")).toString().toStdString(); | ||
| 726 | } | ||
| 727 | qt_config->endArray(); | ||
| 728 | |||
| 729 | qt_config->endGroup(); | ||
| 730 | } | ||
| 731 | |||
| 732 | void Config::ReadNetworkValues() { | ||
| 733 | qt_config->beginGroup(QString::fromStdString("Services")); | ||
| 734 | |||
| 735 | ReadCategory(Settings::Category::Network); | ||
| 736 | |||
| 737 | qt_config->endGroup(); | ||
| 738 | } | ||
| 739 | |||
| 740 | void Config::ReadValues() { | ||
| 741 | if (global) { | ||
| 742 | ReadDataStorageValues(); | ||
| 743 | ReadDebuggingValues(); | ||
| 744 | ReadDisabledAddOnValues(); | ||
| 745 | ReadNetworkValues(); | ||
| 746 | ReadServiceValues(); | ||
| 747 | ReadUIValues(); | ||
| 748 | ReadWebServiceValues(); | ||
| 749 | ReadMiscellaneousValues(); | ||
| 750 | } | ||
| 751 | ReadControlValues(); | ||
| 752 | ReadCoreValues(); | ||
| 753 | ReadCpuValues(); | ||
| 754 | ReadRendererValues(); | ||
| 755 | ReadAudioValues(); | ||
| 756 | ReadSystemValues(); | ||
| 757 | } | ||
| 758 | |||
| 759 | void Config::SavePlayerValue(std::size_t player_index) { | ||
| 760 | const QString player_prefix = [this, player_index] { | ||
| 761 | if (type == ConfigType::InputProfile) { | ||
| 762 | return QString{}; | ||
| 763 | } else { | ||
| 764 | return QStringLiteral("player_%1_").arg(player_index); | ||
| 765 | } | ||
| 766 | }(); | ||
| 767 | |||
| 768 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 769 | if (IsCustomConfig()) { | ||
| 770 | if (player.profile_name.empty()) { | ||
| 771 | // No custom profile selected | ||
| 772 | return; | ||
| 773 | } | ||
| 774 | WriteSetting(QStringLiteral("%1profile_name").arg(player_prefix), | ||
| 775 | QString::fromStdString(player.profile_name), QString{}); | ||
| 776 | } | ||
| 777 | |||
| 778 | WriteSetting(QStringLiteral("%1type").arg(player_prefix), | ||
| 779 | static_cast<u8>(player.controller_type), | ||
| 780 | static_cast<u8>(Settings::ControllerType::ProController)); | ||
| 781 | |||
| 782 | if (!player_prefix.isEmpty() || !Settings::IsConfiguringGlobal()) { | ||
| 783 | WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected, | ||
| 784 | player_index == 0); | ||
| 785 | WriteSetting(QStringLiteral("%1vibration_enabled").arg(player_prefix), | ||
| 786 | player.vibration_enabled, true); | ||
| 787 | WriteSetting(QStringLiteral("%1vibration_strength").arg(player_prefix), | ||
| 788 | player.vibration_strength, 100); | ||
| 789 | WriteSetting(QStringLiteral("%1body_color_left").arg(player_prefix), player.body_color_left, | ||
| 790 | Settings::JOYCON_BODY_NEON_BLUE); | ||
| 791 | WriteSetting(QStringLiteral("%1body_color_right").arg(player_prefix), | ||
| 792 | player.body_color_right, Settings::JOYCON_BODY_NEON_RED); | ||
| 793 | WriteSetting(QStringLiteral("%1button_color_left").arg(player_prefix), | ||
| 794 | player.button_color_left, Settings::JOYCON_BUTTONS_NEON_BLUE); | ||
| 795 | WriteSetting(QStringLiteral("%1button_color_right").arg(player_prefix), | ||
| 796 | player.button_color_right, Settings::JOYCON_BUTTONS_NEON_RED); | ||
| 797 | } | ||
| 798 | |||
| 799 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 800 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 801 | WriteSetting(QStringLiteral("%1").arg(player_prefix) + | ||
| 802 | QString::fromStdString(Settings::NativeButton::mapping[i]), | ||
| 803 | QString::fromStdString(player.buttons[i]), | ||
| 804 | QString::fromStdString(default_param)); | ||
| 805 | } | ||
| 806 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 807 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 808 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 809 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 810 | WriteSetting(QStringLiteral("%1").arg(player_prefix) + | ||
| 811 | QString::fromStdString(Settings::NativeAnalog::mapping[i]), | ||
| 812 | QString::fromStdString(player.analogs[i]), | ||
| 813 | QString::fromStdString(default_param)); | ||
| 814 | } | ||
| 815 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 816 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 817 | WriteSetting(QStringLiteral("%1").arg(player_prefix) + | ||
| 818 | QString::fromStdString(Settings::NativeMotion::mapping[i]), | ||
| 819 | QString::fromStdString(player.motions[i]), | ||
| 820 | QString::fromStdString(default_param)); | ||
| 821 | } | ||
| 822 | } | ||
| 823 | |||
| 824 | void Config::SaveDebugValues() { | ||
| 825 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 826 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 827 | WriteSetting(QStringLiteral("debug_pad_") + | ||
| 828 | QString::fromStdString(Settings::NativeButton::mapping[i]), | ||
| 829 | QString::fromStdString(Settings::values.debug_pad_buttons[i]), | ||
| 830 | QString::fromStdString(default_param)); | ||
| 831 | } | ||
| 832 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 833 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 834 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 835 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 836 | WriteSetting(QStringLiteral("debug_pad_") + | ||
| 837 | QString::fromStdString(Settings::NativeAnalog::mapping[i]), | ||
| 838 | QString::fromStdString(Settings::values.debug_pad_analogs[i]), | ||
| 839 | QString::fromStdString(default_param)); | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 843 | void Config::SaveTouchscreenValues() { | ||
| 844 | const auto& touchscreen = Settings::values.touchscreen; | ||
| 845 | |||
| 846 | WriteSetting(QStringLiteral("touchscreen_enabled"), touchscreen.enabled, true); | ||
| 847 | |||
| 848 | WriteSetting(QStringLiteral("touchscreen_angle"), touchscreen.rotation_angle, 0); | ||
| 849 | WriteSetting(QStringLiteral("touchscreen_diameter_x"), touchscreen.diameter_x, 15); | ||
| 850 | WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); | ||
| 851 | } | ||
| 852 | |||
| 853 | void Config::SaveMotionTouchValues() { | ||
| 854 | qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); | ||
| 855 | for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { | ||
| 856 | qt_config->setArrayIndex(static_cast<int>(p)); | ||
| 857 | WriteSetting(QStringLiteral("name"), | ||
| 858 | QString::fromStdString(Settings::values.touch_from_button_maps[p].name), | ||
| 859 | QStringLiteral("default")); | ||
| 860 | qt_config->beginWriteArray(QStringLiteral("entries")); | ||
| 861 | for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); | ||
| 862 | ++q) { | ||
| 863 | qt_config->setArrayIndex(static_cast<int>(q)); | ||
| 864 | WriteSetting( | ||
| 865 | QStringLiteral("bind"), | ||
| 866 | QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q])); | ||
| 867 | } | ||
| 868 | qt_config->endArray(); | ||
| 869 | } | ||
| 870 | qt_config->endArray(); | ||
| 871 | } | ||
| 872 | |||
| 873 | void Config::SaveHidbusValues() { | ||
| 874 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 875 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||
| 876 | WriteSetting(QStringLiteral("ring_controller"), | ||
| 877 | QString::fromStdString(Settings::values.ringcon_analogs), | ||
| 878 | QString::fromStdString(default_param)); | ||
| 879 | } | ||
| 880 | |||
| 881 | void Config::SaveValues() { | ||
| 882 | if (global) { | ||
| 883 | SaveDataStorageValues(); | ||
| 884 | SaveDebuggingValues(); | ||
| 885 | SaveDisabledAddOnValues(); | ||
| 886 | SaveNetworkValues(); | ||
| 887 | SaveUIValues(); | ||
| 888 | SaveWebServiceValues(); | ||
| 889 | SaveMiscellaneousValues(); | ||
| 890 | } | ||
| 891 | SaveControlValues(); | ||
| 892 | SaveCoreValues(); | ||
| 893 | SaveCpuValues(); | ||
| 894 | SaveRendererValues(); | ||
| 895 | SaveAudioValues(); | ||
| 896 | SaveSystemValues(); | ||
| 897 | |||
| 898 | qt_config->sync(); | ||
| 899 | } | ||
| 900 | |||
| 901 | void Config::SaveAudioValues() { | ||
| 902 | qt_config->beginGroup(QStringLiteral("Audio")); | ||
| 903 | |||
| 904 | WriteCategory(Settings::Category::Audio); | ||
| 905 | WriteCategory(Settings::Category::UiAudio); | ||
| 906 | |||
| 907 | qt_config->endGroup(); | ||
| 908 | } | ||
| 909 | |||
| 910 | void Config::SaveControlValues() { | ||
| 911 | qt_config->beginGroup(QStringLiteral("Controls")); | ||
| 912 | |||
| 913 | WriteCategory(Settings::Category::Controls); | ||
| 914 | |||
| 915 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 916 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 917 | SavePlayerValue(p); | ||
| 918 | } | ||
| 919 | if (IsCustomConfig()) { | ||
| 920 | qt_config->endGroup(); | ||
| 921 | return; | ||
| 922 | } | ||
| 923 | SaveDebugValues(); | ||
| 924 | SaveTouchscreenValues(); | ||
| 925 | SaveMotionTouchValues(); | ||
| 926 | SaveHidbusValues(); | ||
| 927 | |||
| 928 | qt_config->endGroup(); | ||
| 929 | } | ||
| 930 | |||
| 931 | void Config::SaveCoreValues() { | ||
| 932 | qt_config->beginGroup(QStringLiteral("Core")); | ||
| 933 | |||
| 934 | WriteCategory(Settings::Category::Core); | ||
| 935 | |||
| 936 | qt_config->endGroup(); | ||
| 937 | } | ||
| 938 | |||
| 939 | void Config::SaveDataStorageValues() { | ||
| 940 | qt_config->beginGroup(QStringLiteral("Data Storage")); | ||
| 941 | |||
| 942 | WriteSetting(QStringLiteral("nand_directory"), | ||
| 943 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)), | ||
| 944 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | ||
| 945 | WriteSetting(QStringLiteral("sdmc_directory"), | ||
| 946 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)), | ||
| 947 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | ||
| 948 | WriteSetting(QStringLiteral("load_directory"), | ||
| 949 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)), | ||
| 950 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | ||
| 951 | WriteSetting(QStringLiteral("dump_directory"), | ||
| 952 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)), | ||
| 953 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | ||
| 954 | WriteSetting(QStringLiteral("tas_directory"), | ||
| 955 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)), | ||
| 956 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); | ||
| 957 | |||
| 958 | WriteCategory(Settings::Category::DataStorage); | ||
| 959 | |||
| 960 | qt_config->endGroup(); | ||
| 961 | } | ||
| 962 | |||
| 963 | void Config::SaveDebuggingValues() { | ||
| 964 | qt_config->beginGroup(QStringLiteral("Debugging")); | ||
| 965 | |||
| 966 | // Intentionally not using the QT default setting as this is intended to be changed in the ini | ||
| 967 | qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times); | ||
| 968 | |||
| 969 | WriteCategory(Settings::Category::Debugging); | ||
| 970 | WriteCategory(Settings::Category::DebuggingGraphics); | ||
| 971 | |||
| 972 | qt_config->endGroup(); | ||
| 973 | } | ||
| 974 | |||
| 975 | void Config::SaveNetworkValues() { | ||
| 976 | qt_config->beginGroup(QStringLiteral("Services")); | ||
| 977 | |||
| 978 | WriteCategory(Settings::Category::Network); | ||
| 979 | |||
| 980 | qt_config->endGroup(); | ||
| 981 | } | ||
| 982 | |||
| 983 | void Config::SaveDisabledAddOnValues() { | ||
| 984 | qt_config->beginWriteArray(QStringLiteral("DisabledAddOns")); | ||
| 985 | |||
| 986 | int i = 0; | ||
| 987 | for (const auto& elem : Settings::values.disabled_addons) { | ||
| 988 | qt_config->setArrayIndex(i); | ||
| 989 | WriteSetting(QStringLiteral("title_id"), QVariant::fromValue<u64>(elem.first), 0); | ||
| 990 | qt_config->beginWriteArray(QStringLiteral("disabled")); | ||
| 991 | for (std::size_t j = 0; j < elem.second.size(); ++j) { | ||
| 992 | qt_config->setArrayIndex(static_cast<int>(j)); | ||
| 993 | WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{}); | ||
| 994 | } | ||
| 995 | qt_config->endArray(); | ||
| 996 | ++i; | ||
| 997 | } | ||
| 998 | |||
| 999 | qt_config->endArray(); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | void Config::SaveMiscellaneousValues() { | ||
| 1003 | qt_config->beginGroup(QStringLiteral("Miscellaneous")); | ||
| 1004 | |||
| 1005 | WriteCategory(Settings::Category::Miscellaneous); | ||
| 1006 | |||
| 1007 | qt_config->endGroup(); | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | void Config::SavePathValues() { | ||
| 1011 | qt_config->beginGroup(QStringLiteral("Paths")); | ||
| 1012 | |||
| 1013 | WriteSetting(QStringLiteral("romsPath"), UISettings::values.roms_path); | ||
| 1014 | WriteSetting(QStringLiteral("symbolsPath"), UISettings::values.symbols_path); | ||
| 1015 | qt_config->beginWriteArray(QStringLiteral("gamedirs")); | ||
| 1016 | for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { | ||
| 1017 | qt_config->setArrayIndex(i); | ||
| 1018 | const auto& game_dir = UISettings::values.game_dirs[i]; | ||
| 1019 | WriteSetting(QStringLiteral("path"), game_dir.path); | ||
| 1020 | WriteSetting(QStringLiteral("deep_scan"), game_dir.deep_scan, false); | ||
| 1021 | WriteSetting(QStringLiteral("expanded"), game_dir.expanded, true); | ||
| 1022 | } | ||
| 1023 | qt_config->endArray(); | ||
| 1024 | WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files); | ||
| 1025 | WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{}); | ||
| 1026 | |||
| 1027 | qt_config->endGroup(); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | void Config::SaveCpuValues() { | ||
| 1031 | qt_config->beginGroup(QStringLiteral("Cpu")); | ||
| 1032 | |||
| 1033 | WriteCategory(Settings::Category::Cpu); | ||
| 1034 | WriteCategory(Settings::Category::CpuDebug); | ||
| 1035 | WriteCategory(Settings::Category::CpuUnsafe); | ||
| 1036 | |||
| 1037 | qt_config->endGroup(); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | void Config::SaveRendererValues() { | ||
| 1041 | qt_config->beginGroup(QStringLiteral("Renderer")); | ||
| 1042 | |||
| 1043 | WriteCategory(Settings::Category::Renderer); | ||
| 1044 | WriteCategory(Settings::Category::RendererAdvanced); | ||
| 1045 | WriteCategory(Settings::Category::RendererDebug); | ||
| 1046 | |||
| 1047 | qt_config->endGroup(); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | void Config::SaveScreenshotValues() { | ||
| 1051 | qt_config->beginGroup(QStringLiteral("Screenshots")); | ||
| 1052 | |||
| 1053 | WriteSetting(QStringLiteral("screenshot_path"), | ||
| 1054 | QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir))); | ||
| 1055 | WriteCategory(Settings::Category::Screenshots); | ||
| 1056 | |||
| 1057 | qt_config->endGroup(); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | void Config::SaveShortcutValues() { | ||
| 1061 | qt_config->beginGroup(QStringLiteral("Shortcuts")); | ||
| 1062 | |||
| 1063 | // Lengths of UISettings::values.shortcuts & default_hotkeys are same. | ||
| 1064 | // However, their ordering must also be the same. | ||
| 1065 | for (std::size_t i = 0; i < default_hotkeys.size(); i++) { | ||
| 1066 | const auto& [name, group, shortcut] = UISettings::values.shortcuts[i]; | ||
| 1067 | const auto& default_hotkey = default_hotkeys[i].shortcut; | ||
| 1068 | |||
| 1069 | qt_config->beginGroup(group); | ||
| 1070 | qt_config->beginGroup(name); | ||
| 1071 | WriteSetting(QStringLiteral("KeySeq"), shortcut.keyseq, default_hotkey.keyseq); | ||
| 1072 | WriteSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq, | ||
| 1073 | default_hotkey.controller_keyseq); | ||
| 1074 | WriteSetting(QStringLiteral("Context"), shortcut.context, default_hotkey.context); | ||
| 1075 | WriteSetting(QStringLiteral("Repeat"), shortcut.repeat, default_hotkey.repeat); | ||
| 1076 | qt_config->endGroup(); | ||
| 1077 | qt_config->endGroup(); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | qt_config->endGroup(); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | void Config::SaveSystemValues() { | ||
| 1084 | qt_config->beginGroup(QStringLiteral("System")); | ||
| 1085 | |||
| 1086 | WriteCategory(Settings::Category::System); | ||
| 1087 | WriteCategory(Settings::Category::SystemAudio); | ||
| 1088 | |||
| 1089 | qt_config->endGroup(); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | void Config::SaveUIValues() { | ||
| 1093 | qt_config->beginGroup(QStringLiteral("UI")); | ||
| 1094 | |||
| 1095 | WriteCategory(Settings::Category::Ui); | ||
| 1096 | WriteCategory(Settings::Category::UiGeneral); | ||
| 1097 | |||
| 1098 | WriteSetting(QStringLiteral("theme"), UISettings::values.theme, | ||
| 1099 | QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)); | ||
| 1100 | |||
| 1101 | SaveUIGamelistValues(); | ||
| 1102 | SaveUILayoutValues(); | ||
| 1103 | SavePathValues(); | ||
| 1104 | SaveScreenshotValues(); | ||
| 1105 | SaveShortcutValues(); | ||
| 1106 | SaveMultiplayerValues(); | ||
| 1107 | |||
| 1108 | qt_config->endGroup(); | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | void Config::SaveUIGamelistValues() { | ||
| 1112 | qt_config->beginGroup(QStringLiteral("UIGameList")); | ||
| 1113 | |||
| 1114 | WriteCategory(Settings::Category::UiGameList); | ||
| 1115 | |||
| 1116 | qt_config->beginWriteArray(QStringLiteral("favorites")); | ||
| 1117 | for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { | ||
| 1118 | qt_config->setArrayIndex(i); | ||
| 1119 | WriteSetting(QStringLiteral("program_id"), | ||
| 1120 | QVariant::fromValue(UISettings::values.favorited_ids[i])); | ||
| 1121 | } | ||
| 1122 | qt_config->endArray(); | ||
| 1123 | |||
| 1124 | qt_config->endGroup(); | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | void Config::SaveUILayoutValues() { | ||
| 1128 | qt_config->beginGroup(QStringLiteral("UILayout")); | ||
| 1129 | |||
| 1130 | WriteSetting(QStringLiteral("geometry"), UISettings::values.geometry); | ||
| 1131 | WriteSetting(QStringLiteral("state"), UISettings::values.state); | ||
| 1132 | WriteSetting(QStringLiteral("geometryRenderWindow"), UISettings::values.renderwindow_geometry); | ||
| 1133 | WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state); | ||
| 1134 | WriteSetting(QStringLiteral("microProfileDialogGeometry"), | ||
| 1135 | UISettings::values.microprofile_geometry); | ||
| 1136 | |||
| 1137 | WriteCategory(Settings::Category::UiLayout); | ||
| 1138 | |||
| 1139 | qt_config->endGroup(); | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | void Config::SaveWebServiceValues() { | ||
| 1143 | qt_config->beginGroup(QStringLiteral("WebService")); | ||
| 1144 | |||
| 1145 | WriteCategory(Settings::Category::WebService); | ||
| 1146 | |||
| 1147 | qt_config->endGroup(); | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | void Config::SaveMultiplayerValues() { | ||
| 1151 | qt_config->beginGroup(QStringLiteral("Multiplayer")); | ||
| 1152 | |||
| 1153 | WriteCategory(Settings::Category::Multiplayer); | ||
| 1154 | |||
| 1155 | // Write ban list | ||
| 1156 | qt_config->beginWriteArray(QStringLiteral("username_ban_list")); | ||
| 1157 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { | ||
| 1158 | qt_config->setArrayIndex(static_cast<int>(i)); | ||
| 1159 | WriteSetting(QStringLiteral("username"), | ||
| 1160 | QString::fromStdString(UISettings::values.multiplayer_ban_list.first[i])); | ||
| 1161 | } | ||
| 1162 | qt_config->endArray(); | ||
| 1163 | qt_config->beginWriteArray(QStringLiteral("ip_ban_list")); | ||
| 1164 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { | ||
| 1165 | qt_config->setArrayIndex(static_cast<int>(i)); | ||
| 1166 | WriteSetting(QStringLiteral("ip"), | ||
| 1167 | QString::fromStdString(UISettings::values.multiplayer_ban_list.second[i])); | ||
| 1168 | } | ||
| 1169 | qt_config->endArray(); | ||
| 1170 | |||
| 1171 | qt_config->endGroup(); | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | QVariant Config::ReadSetting(const QString& name) const { | ||
| 1175 | return qt_config->value(name); | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | QVariant Config::ReadSetting(const QString& name, const QVariant& default_value) const { | ||
| 1179 | QVariant result; | ||
| 1180 | if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { | ||
| 1181 | result = default_value; | ||
| 1182 | } else { | ||
| 1183 | result = qt_config->value(name, default_value); | ||
| 1184 | } | ||
| 1185 | return result; | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | void Config::WriteSetting(const QString& name, const QVariant& value) { | ||
| 1189 | qt_config->setValue(name, value); | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | void Config::WriteSetting(const QString& name, const QVariant& value, | ||
| 1193 | const QVariant& default_value) { | ||
| 1194 | qt_config->setValue(name + QStringLiteral("/default"), value == default_value); | ||
| 1195 | qt_config->setValue(name, value); | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | void Config::WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value, | ||
| 1199 | bool use_global) { | ||
| 1200 | if (!global) { | ||
| 1201 | qt_config->setValue(name + QStringLiteral("/use_global"), use_global); | ||
| 1202 | } | ||
| 1203 | if (global || !use_global) { | ||
| 1204 | qt_config->setValue(name + QStringLiteral("/default"), value == default_value); | ||
| 1205 | qt_config->setValue(name, value); | ||
| 1206 | } | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | void Config::Reload() { | ||
| 1210 | ReadValues(); | ||
| 1211 | // To apply default value changes | ||
| 1212 | SaveValues(); | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | void Config::Save() { | ||
| 1216 | SaveValues(); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | void Config::ReadControlPlayerValue(std::size_t player_index) { | ||
| 1220 | qt_config->beginGroup(QStringLiteral("Controls")); | ||
| 1221 | ReadPlayerValue(player_index); | ||
| 1222 | qt_config->endGroup(); | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | void Config::SaveControlPlayerValue(std::size_t player_index) { | ||
| 1226 | qt_config->beginGroup(QStringLiteral("Controls")); | ||
| 1227 | SavePlayerValue(player_index); | ||
| 1228 | qt_config->endGroup(); | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | void Config::ClearControlPlayerValues() { | ||
| 1232 | qt_config->beginGroup(QStringLiteral("Controls")); | ||
| 1233 | // If key is an empty string, all keys in the current group() are removed. | ||
| 1234 | qt_config->remove(QString{}); | ||
| 1235 | qt_config->endGroup(); | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | const std::string& Config::GetConfigFilePath() const { | ||
| 1239 | return qt_config_loc; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | static auto FindRelevantList(Settings::Category category) { | ||
| 1243 | auto& map = Settings::values.linkage.by_category; | ||
| 1244 | if (map.contains(category)) { | ||
| 1245 | return Settings::values.linkage.by_category[category]; | ||
| 1246 | } | ||
| 1247 | return UISettings::values.linkage.by_category[category]; | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | void Config::ReadCategory(Settings::Category category) { | ||
| 1251 | const auto& settings = FindRelevantList(category); | ||
| 1252 | std::for_each(settings.begin(), settings.end(), | ||
| 1253 | [&](const auto& setting) { ReadSettingGeneric(setting); }); | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | void Config::WriteCategory(Settings::Category category) { | ||
| 1257 | const auto& settings = FindRelevantList(category); | ||
| 1258 | std::for_each(settings.begin(), settings.end(), | ||
| 1259 | [&](const auto& setting) { WriteSettingGeneric(setting); }); | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) { | ||
| 1263 | if (!setting->Save() || (!setting->Switchable() && !global)) { | ||
| 1264 | return; | ||
| 1265 | } | ||
| 1266 | const QString name = QString::fromStdString(setting->GetLabel()); | ||
| 1267 | const auto default_value = | ||
| 1268 | QVariant::fromValue<QString>(QString::fromStdString(setting->DefaultToString())); | ||
| 1269 | |||
| 1270 | bool use_global = true; | ||
| 1271 | if (setting->Switchable() && !global) { | ||
| 1272 | use_global = qt_config->value(name + QStringLiteral("/use_global"), true).value<bool>(); | ||
| 1273 | setting->SetGlobal(use_global); | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | if (global || !use_global) { | ||
| 1277 | const bool is_default = | ||
| 1278 | qt_config->value(name + QStringLiteral("/default"), true).value<bool>(); | ||
| 1279 | if (!is_default) { | ||
| 1280 | setting->LoadString( | ||
| 1281 | qt_config->value(name, default_value).value<QString>().toStdString()); | ||
| 1282 | } else { | ||
| 1283 | // Empty string resets the Setting to default | ||
| 1284 | setting->LoadString(""); | ||
| 1285 | } | ||
| 1286 | } | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const { | ||
| 1290 | if (!setting->Save()) { | ||
| 1291 | return; | ||
| 1292 | } | ||
| 1293 | const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString())); | ||
| 1294 | const QVariant default_value = | ||
| 1295 | QVariant::fromValue(QString::fromStdString(setting->DefaultToString())); | ||
| 1296 | const QString label = QString::fromStdString(setting->GetLabel()); | ||
| 1297 | if (setting->Switchable()) { | ||
| 1298 | if (!global) { | ||
| 1299 | qt_config->setValue(label + QStringLiteral("/use_global"), setting->UsingGlobal()); | ||
| 1300 | } | ||
| 1301 | if (global || !setting->UsingGlobal()) { | ||
| 1302 | qt_config->setValue(label + QStringLiteral("/default"), value == default_value); | ||
| 1303 | qt_config->setValue(label, value); | ||
| 1304 | } | ||
| 1305 | } else if (global) { | ||
| 1306 | qt_config->setValue(label + QStringLiteral("/default"), value == default_value); | ||
| 1307 | qt_config->setValue(label, value); | ||
| 1308 | } | ||
| 1309 | } | ||
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h deleted file mode 100644 index 1589ba057..000000000 --- a/src/yuzu/configuration/config.h +++ /dev/null | |||
| @@ -1,179 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include <QMetaType> | ||
| 10 | #include <QVariant> | ||
| 11 | #include "common/settings.h" | ||
| 12 | #include "common/settings_enums.h" | ||
| 13 | #include "yuzu/uisettings.h" | ||
| 14 | |||
| 15 | class QSettings; | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 20 | |||
| 21 | class Config { | ||
| 22 | public: | ||
| 23 | enum class ConfigType { | ||
| 24 | GlobalConfig, | ||
| 25 | PerGameConfig, | ||
| 26 | InputProfile, | ||
| 27 | }; | ||
| 28 | |||
| 29 | explicit Config(const std::string& config_name = "qt-config", | ||
| 30 | ConfigType config_type = ConfigType::GlobalConfig); | ||
| 31 | ~Config(); | ||
| 32 | |||
| 33 | void Reload(); | ||
| 34 | void Save(); | ||
| 35 | |||
| 36 | void ReadControlPlayerValue(std::size_t player_index); | ||
| 37 | void SaveControlPlayerValue(std::size_t player_index); | ||
| 38 | void ClearControlPlayerValues(); | ||
| 39 | |||
| 40 | const std::string& GetConfigFilePath() const; | ||
| 41 | |||
| 42 | static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; | ||
| 43 | static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; | ||
| 44 | static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; | ||
| 45 | static const std::array<int, 2> default_stick_mod; | ||
| 46 | static const std::array<int, 2> default_ringcon_analogs; | ||
| 47 | static const std::array<int, Settings::NativeMouseButton::NumMouseButtons> | ||
| 48 | default_mouse_buttons; | ||
| 49 | static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; | ||
| 50 | static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; | ||
| 51 | static const std::array<UISettings::Shortcut, 23> default_hotkeys; | ||
| 52 | |||
| 53 | static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map; | ||
| 54 | static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map; | ||
| 55 | static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map; | ||
| 56 | static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map; | ||
| 57 | static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map; | ||
| 58 | static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map; | ||
| 59 | |||
| 60 | static constexpr UISettings::Theme default_theme{ | ||
| 61 | #ifdef _WIN32 | ||
| 62 | UISettings::Theme::DarkColorful | ||
| 63 | #else | ||
| 64 | UISettings::Theme::DefaultColorful | ||
| 65 | #endif | ||
| 66 | }; | ||
| 67 | |||
| 68 | private: | ||
| 69 | void Initialize(const std::string& config_name); | ||
| 70 | bool IsCustomConfig(); | ||
| 71 | |||
| 72 | void ReadValues(); | ||
| 73 | void ReadPlayerValue(std::size_t player_index); | ||
| 74 | void ReadDebugValues(); | ||
| 75 | void ReadKeyboardValues(); | ||
| 76 | void ReadMouseValues(); | ||
| 77 | void ReadTouchscreenValues(); | ||
| 78 | void ReadMotionTouchValues(); | ||
| 79 | void ReadHidbusValues(); | ||
| 80 | void ReadIrCameraValues(); | ||
| 81 | |||
| 82 | // Read functions bases off the respective config section names. | ||
| 83 | void ReadAudioValues(); | ||
| 84 | void ReadControlValues(); | ||
| 85 | void ReadCoreValues(); | ||
| 86 | void ReadDataStorageValues(); | ||
| 87 | void ReadDebuggingValues(); | ||
| 88 | void ReadServiceValues(); | ||
| 89 | void ReadDisabledAddOnValues(); | ||
| 90 | void ReadMiscellaneousValues(); | ||
| 91 | void ReadPathValues(); | ||
| 92 | void ReadCpuValues(); | ||
| 93 | void ReadRendererValues(); | ||
| 94 | void ReadScreenshotValues(); | ||
| 95 | void ReadShortcutValues(); | ||
| 96 | void ReadSystemValues(); | ||
| 97 | void ReadUIValues(); | ||
| 98 | void ReadUIGamelistValues(); | ||
| 99 | void ReadUILayoutValues(); | ||
| 100 | void ReadWebServiceValues(); | ||
| 101 | void ReadMultiplayerValues(); | ||
| 102 | void ReadNetworkValues(); | ||
| 103 | |||
| 104 | void SaveValues(); | ||
| 105 | void SavePlayerValue(std::size_t player_index); | ||
| 106 | void SaveDebugValues(); | ||
| 107 | void SaveMouseValues(); | ||
| 108 | void SaveTouchscreenValues(); | ||
| 109 | void SaveMotionTouchValues(); | ||
| 110 | void SaveHidbusValues(); | ||
| 111 | void SaveIrCameraValues(); | ||
| 112 | |||
| 113 | // Save functions based off the respective config section names. | ||
| 114 | void SaveAudioValues(); | ||
| 115 | void SaveControlValues(); | ||
| 116 | void SaveCoreValues(); | ||
| 117 | void SaveDataStorageValues(); | ||
| 118 | void SaveDebuggingValues(); | ||
| 119 | void SaveNetworkValues(); | ||
| 120 | void SaveDisabledAddOnValues(); | ||
| 121 | void SaveMiscellaneousValues(); | ||
| 122 | void SavePathValues(); | ||
| 123 | void SaveCpuValues(); | ||
| 124 | void SaveRendererValues(); | ||
| 125 | void SaveScreenshotValues(); | ||
| 126 | void SaveShortcutValues(); | ||
| 127 | void SaveSystemValues(); | ||
| 128 | void SaveUIValues(); | ||
| 129 | void SaveUIGamelistValues(); | ||
| 130 | void SaveUILayoutValues(); | ||
| 131 | void SaveWebServiceValues(); | ||
| 132 | void SaveMultiplayerValues(); | ||
| 133 | |||
| 134 | /** | ||
| 135 | * Reads a setting from the qt_config. | ||
| 136 | * | ||
| 137 | * @param name The setting's identifier | ||
| 138 | * @param default_value The value to use when the setting is not already present in the config | ||
| 139 | */ | ||
| 140 | QVariant ReadSetting(const QString& name) const; | ||
| 141 | QVariant ReadSetting(const QString& name, const QVariant& default_value) const; | ||
| 142 | |||
| 143 | /** | ||
| 144 | * Writes a setting to the qt_config. | ||
| 145 | * | ||
| 146 | * @param name The setting's idetentifier | ||
| 147 | * @param value Value of the setting | ||
| 148 | * @param default_value Default of the setting if not present in qt_config | ||
| 149 | * @param use_global Specifies if the custom or global config should be in use, for custom | ||
| 150 | * configs | ||
| 151 | */ | ||
| 152 | void WriteSetting(const QString& name, const QVariant& value); | ||
| 153 | void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); | ||
| 154 | void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value, | ||
| 155 | bool use_global); | ||
| 156 | |||
| 157 | void ReadCategory(Settings::Category category); | ||
| 158 | void WriteCategory(Settings::Category category); | ||
| 159 | void ReadSettingGeneric(Settings::BasicSetting* const setting); | ||
| 160 | void WriteSettingGeneric(Settings::BasicSetting* const setting) const; | ||
| 161 | |||
| 162 | const ConfigType type; | ||
| 163 | std::unique_ptr<QSettings> qt_config; | ||
| 164 | std::string qt_config_loc; | ||
| 165 | const bool global; | ||
| 166 | }; | ||
| 167 | |||
| 168 | // These metatype declarations cannot be in common/settings.h because core is devoid of QT | ||
| 169 | Q_DECLARE_METATYPE(Settings::CpuAccuracy); | ||
| 170 | Q_DECLARE_METATYPE(Settings::GpuAccuracy); | ||
| 171 | Q_DECLARE_METATYPE(Settings::FullscreenMode); | ||
| 172 | Q_DECLARE_METATYPE(Settings::NvdecEmulation); | ||
| 173 | Q_DECLARE_METATYPE(Settings::ResolutionSetup); | ||
| 174 | Q_DECLARE_METATYPE(Settings::ScalingFilter); | ||
| 175 | Q_DECLARE_METATYPE(Settings::AntiAliasing); | ||
| 176 | Q_DECLARE_METATYPE(Settings::RendererBackend); | ||
| 177 | Q_DECLARE_METATYPE(Settings::ShaderBackend); | ||
| 178 | Q_DECLARE_METATYPE(Settings::AstcRecompression); | ||
| 179 | Q_DECLARE_METATYPE(Settings::AstcDecodeMode); | ||
diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp index d95e96696..3368f53f3 100644 --- a/src/yuzu/configuration/configure_camera.cpp +++ b/src/yuzu/configuration/configure_camera.cpp | |||
| @@ -10,10 +10,10 @@ | |||
| 10 | #include <QStandardItemModel> | 10 | #include <QStandardItemModel> |
| 11 | #include <QTimer> | 11 | #include <QTimer> |
| 12 | 12 | ||
| 13 | #include "common/settings.h" | ||
| 13 | #include "input_common/drivers/camera.h" | 14 | #include "input_common/drivers/camera.h" |
| 14 | #include "input_common/main.h" | 15 | #include "input_common/main.h" |
| 15 | #include "ui_configure_camera.h" | 16 | #include "ui_configure_camera.h" |
| 16 | #include "yuzu/configuration/config.h" | ||
| 17 | #include "yuzu/configuration/configure_camera.h" | 17 | #include "yuzu/configuration/configure_camera.h" |
| 18 | 18 | ||
| 19 | ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) | 19 | ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) |
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index ef421c754..1010038b7 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -51,6 +51,8 @@ void ConfigureDebug::SetConfiguration() { | |||
| 51 | ui->enable_all_controllers->setChecked(Settings::values.enable_all_controllers.GetValue()); | 51 | ui->enable_all_controllers->setChecked(Settings::values.enable_all_controllers.GetValue()); |
| 52 | ui->enable_renderdoc_hotkey->setEnabled(runtime_lock); | 52 | ui->enable_renderdoc_hotkey->setEnabled(runtime_lock); |
| 53 | ui->enable_renderdoc_hotkey->setChecked(Settings::values.enable_renderdoc_hotkey.GetValue()); | 53 | ui->enable_renderdoc_hotkey->setChecked(Settings::values.enable_renderdoc_hotkey.GetValue()); |
| 54 | ui->disable_buffer_reorder->setEnabled(runtime_lock); | ||
| 55 | ui->disable_buffer_reorder->setChecked(Settings::values.disable_buffer_reorder.GetValue()); | ||
| 54 | ui->enable_graphics_debugging->setEnabled(runtime_lock); | 56 | ui->enable_graphics_debugging->setEnabled(runtime_lock); |
| 55 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); | 57 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); |
| 56 | ui->enable_shader_feedback->setEnabled(runtime_lock); | 58 | ui->enable_shader_feedback->setEnabled(runtime_lock); |
| @@ -96,6 +98,7 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 96 | Settings::values.enable_all_controllers = ui->enable_all_controllers->isChecked(); | 98 | Settings::values.enable_all_controllers = ui->enable_all_controllers->isChecked(); |
| 97 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); | 99 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); |
| 98 | Settings::values.enable_renderdoc_hotkey = ui->enable_renderdoc_hotkey->isChecked(); | 100 | Settings::values.enable_renderdoc_hotkey = ui->enable_renderdoc_hotkey->isChecked(); |
| 101 | Settings::values.disable_buffer_reorder = ui->disable_buffer_reorder->isChecked(); | ||
| 99 | Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked(); | 102 | Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked(); |
| 100 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); | 103 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); |
| 101 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); | 104 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 76fe98924..22b51f39c 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -271,19 +271,6 @@ | |||
| 271 | </widget> | 271 | </widget> |
| 272 | </item> | 272 | </item> |
| 273 | <item row="8" column="0"> | 273 | <item row="8" column="0"> |
| 274 | <widget class="QCheckBox" name="disable_macro_hle"> | ||
| 275 | <property name="enabled"> | ||
| 276 | <bool>true</bool> | ||
| 277 | </property> | ||
| 278 | <property name="toolTip"> | ||
| 279 | <string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string> | ||
| 280 | </property> | ||
| 281 | <property name="text"> | ||
| 282 | <string>Disable Macro HLE</string> | ||
| 283 | </property> | ||
| 284 | </widget> | ||
| 285 | </item> | ||
| 286 | <item row="7" column="0"> | ||
| 287 | <widget class="QCheckBox" name="dump_macros"> | 274 | <widget class="QCheckBox" name="dump_macros"> |
| 288 | <property name="enabled"> | 275 | <property name="enabled"> |
| 289 | <bool>true</bool> | 276 | <bool>true</bool> |
| @@ -306,17 +293,27 @@ | |||
| 306 | </property> | 293 | </property> |
| 307 | </widget> | 294 | </widget> |
| 308 | </item> | 295 | </item> |
| 309 | <item row="2" column="0"> | 296 | <item row="6" column="0"> |
| 310 | <widget class="QCheckBox" name="enable_shader_feedback"> | 297 | <widget class="QCheckBox" name="dump_shaders"> |
| 298 | <property name="enabled"> | ||
| 299 | <bool>true</bool> | ||
| 300 | </property> | ||
| 311 | <property name="toolTip"> | 301 | <property name="toolTip"> |
| 312 | <string>When checked, yuzu will log statistics about the compiled pipeline cache</string> | 302 | <string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string> |
| 313 | </property> | 303 | </property> |
| 314 | <property name="text"> | 304 | <property name="text"> |
| 315 | <string>Enable Shader Feedback</string> | 305 | <string>Dump Game Shaders</string> |
| 316 | </property> | 306 | </property> |
| 317 | </widget> | 307 | </widget> |
| 318 | </item> | 308 | </item> |
| 319 | <item row="6" column="0"> | 309 | <item row="1" column="0"> |
| 310 | <widget class="QCheckBox" name="enable_renderdoc_hotkey"> | ||
| 311 | <property name="text"> | ||
| 312 | <string>Enable Renderdoc Hotkey</string> | ||
| 313 | </property> | ||
| 314 | </widget> | ||
| 315 | </item> | ||
| 316 | <item row="7" column="0"> | ||
| 320 | <widget class="QCheckBox" name="disable_macro_jit"> | 317 | <widget class="QCheckBox" name="disable_macro_jit"> |
| 321 | <property name="enabled"> | 318 | <property name="enabled"> |
| 322 | <bool>true</bool> | 319 | <bool>true</bool> |
| @@ -330,20 +327,17 @@ | |||
| 330 | </widget> | 327 | </widget> |
| 331 | </item> | 328 | </item> |
| 332 | <item row="9" column="0"> | 329 | <item row="9" column="0"> |
| 333 | <spacer name="verticalSpacer_5"> | 330 | <widget class="QCheckBox" name="disable_macro_hle"> |
| 334 | <property name="orientation"> | 331 | <property name="enabled"> |
| 335 | <enum>Qt::Vertical</enum> | 332 | <bool>true</bool> |
| 336 | </property> | 333 | </property> |
| 337 | <property name="sizeType"> | 334 | <property name="toolTip"> |
| 338 | <enum>QSizePolicy::Preferred</enum> | 335 | <string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string> |
| 339 | </property> | 336 | </property> |
| 340 | <property name="sizeHint" stdset="0"> | 337 | <property name="text"> |
| 341 | <size> | 338 | <string>Disable Macro HLE</string> |
| 342 | <width>20</width> | ||
| 343 | <height>0</height> | ||
| 344 | </size> | ||
| 345 | </property> | 339 | </property> |
| 346 | </spacer> | 340 | </widget> |
| 347 | </item> | 341 | </item> |
| 348 | <item row="0" column="0"> | 342 | <item row="0" column="0"> |
| 349 | <widget class="QCheckBox" name="enable_graphics_debugging"> | 343 | <widget class="QCheckBox" name="enable_graphics_debugging"> |
| @@ -358,23 +352,39 @@ | |||
| 358 | </property> | 352 | </property> |
| 359 | </widget> | 353 | </widget> |
| 360 | </item> | 354 | </item> |
| 361 | <item row="5" column="0"> | 355 | <item row="10" column="0"> |
| 362 | <widget class="QCheckBox" name="dump_shaders"> | 356 | <spacer name="verticalSpacer_5"> |
| 363 | <property name="enabled"> | 357 | <property name="orientation"> |
| 364 | <bool>true</bool> | 358 | <enum>Qt::Vertical</enum> |
| 359 | </property> | ||
| 360 | <property name="sizeType"> | ||
| 361 | <enum>QSizePolicy::Preferred</enum> | ||
| 365 | </property> | 362 | </property> |
| 363 | <property name="sizeHint" stdset="0"> | ||
| 364 | <size> | ||
| 365 | <width>20</width> | ||
| 366 | <height>0</height> | ||
| 367 | </size> | ||
| 368 | </property> | ||
| 369 | </spacer> | ||
| 370 | </item> | ||
| 371 | <item row="2" column="0"> | ||
| 372 | <widget class="QCheckBox" name="enable_shader_feedback"> | ||
| 366 | <property name="toolTip"> | 373 | <property name="toolTip"> |
| 367 | <string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string> | 374 | <string>When checked, yuzu will log statistics about the compiled pipeline cache</string> |
| 368 | </property> | 375 | </property> |
| 369 | <property name="text"> | 376 | <property name="text"> |
| 370 | <string>Dump Game Shaders</string> | 377 | <string>Enable Shader Feedback</string> |
| 371 | </property> | 378 | </property> |
| 372 | </widget> | 379 | </widget> |
| 373 | </item> | 380 | </item> |
| 374 | <item row="1" column="0"> | 381 | <item row="5" column="0"> |
| 375 | <widget class="QCheckBox" name="enable_renderdoc_hotkey"> | 382 | <widget class="QCheckBox" name="disable_buffer_reorder"> |
| 383 | <property name="toolTip"> | ||
| 384 | <string><html><head/><body><p>When checked, disables reording of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.</p></body></html></string> | ||
| 385 | </property> | ||
| 376 | <property name="text"> | 386 | <property name="text"> |
| 377 | <string>Enable Renderdoc Hotkey</string> | 387 | <string>Disable Buffer Reorder</string> |
| 378 | </property> | 388 | </property> |
| 379 | </widget> | 389 | </widget> |
| 380 | </item> | 390 | </item> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 0ad95cc02..aab54a1cc 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "ui_configure.h" | 9 | #include "ui_configure.h" |
| 10 | #include "vk_device_info.h" | 10 | #include "vk_device_info.h" |
| 11 | #include "yuzu/configuration/config.h" | ||
| 12 | #include "yuzu/configuration/configure_audio.h" | 11 | #include "yuzu/configuration/configure_audio.h" |
| 13 | #include "yuzu/configuration/configure_cpu.h" | 12 | #include "yuzu/configuration/configure_cpu.h" |
| 14 | #include "yuzu/configuration/configure_debug_tab.h" | 13 | #include "yuzu/configuration/configure_debug_tab.h" |
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index c727fadd1..701b895e7 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp | |||
| @@ -36,12 +36,29 @@ ConfigureGeneral::~ConfigureGeneral() = default; | |||
| 36 | void ConfigureGeneral::SetConfiguration() {} | 36 | void ConfigureGeneral::SetConfiguration() {} |
| 37 | 37 | ||
| 38 | void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) { | 38 | void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) { |
| 39 | QLayout& layout = *ui->general_widget->layout(); | 39 | QLayout& general_layout = *ui->general_widget->layout(); |
| 40 | QLayout& linux_layout = *ui->linux_widget->layout(); | ||
| 40 | 41 | ||
| 41 | std::map<u32, QWidget*> hold{}; | 42 | std::map<u32, QWidget*> general_hold{}; |
| 43 | std::map<u32, QWidget*> linux_hold{}; | ||
| 42 | 44 | ||
| 43 | for (const auto setting : | 45 | std::vector<Settings::BasicSetting*> settings; |
| 44 | UISettings::values.linkage.by_category[Settings::Category::UiGeneral]) { | 46 | |
| 47 | auto push = [&settings](auto& list) { | ||
| 48 | for (auto setting : list) { | ||
| 49 | settings.push_back(setting); | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | |||
| 53 | push(UISettings::values.linkage.by_category[Settings::Category::UiGeneral]); | ||
| 54 | push(Settings::values.linkage.by_category[Settings::Category::Linux]); | ||
| 55 | |||
| 56 | // Only show Linux group on Unix | ||
| 57 | #ifndef __unix__ | ||
| 58 | ui->LinuxGroupBox->setVisible(false); | ||
| 59 | #endif | ||
| 60 | |||
| 61 | for (const auto setting : settings) { | ||
| 45 | auto* widget = builder.BuildWidget(setting, apply_funcs); | 62 | auto* widget = builder.BuildWidget(setting, apply_funcs); |
| 46 | 63 | ||
| 47 | if (widget == nullptr) { | 64 | if (widget == nullptr) { |
| @@ -52,11 +69,23 @@ void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) { | |||
| 52 | continue; | 69 | continue; |
| 53 | } | 70 | } |
| 54 | 71 | ||
| 55 | hold.emplace(setting->Id(), widget); | 72 | switch (setting->GetCategory()) { |
| 73 | case Settings::Category::UiGeneral: | ||
| 74 | general_hold.emplace(setting->Id(), widget); | ||
| 75 | break; | ||
| 76 | case Settings::Category::Linux: | ||
| 77 | linux_hold.emplace(setting->Id(), widget); | ||
| 78 | break; | ||
| 79 | default: | ||
| 80 | widget->deleteLater(); | ||
| 81 | } | ||
| 56 | } | 82 | } |
| 57 | 83 | ||
| 58 | for (const auto& [id, widget] : hold) { | 84 | for (const auto& [id, widget] : general_hold) { |
| 59 | layout.addWidget(widget); | 85 | general_layout.addWidget(widget); |
| 86 | } | ||
| 87 | for (const auto& [id, widget] : linux_hold) { | ||
| 88 | linux_layout.addWidget(widget); | ||
| 60 | } | 89 | } |
| 61 | } | 90 | } |
| 62 | 91 | ||
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index a10e7d3a5..ef20891a3 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui | |||
| @@ -47,6 +47,33 @@ | |||
| 47 | </widget> | 47 | </widget> |
| 48 | </item> | 48 | </item> |
| 49 | <item> | 49 | <item> |
| 50 | <widget class="QGroupBox" name="LinuxGroupBox"> | ||
| 51 | <property name="title"> | ||
| 52 | <string>Linux</string> | ||
| 53 | </property> | ||
| 54 | <layout class="QVBoxLayout" name="LinuxVerticalLayout_1"> | ||
| 55 | <item> | ||
| 56 | <widget class="QWidget" name="linux_widget" native="true"> | ||
| 57 | <layout class="QVBoxLayout" name="LinuxVerticalLayout_2"> | ||
| 58 | <property name="leftMargin"> | ||
| 59 | <number>0</number> | ||
| 60 | </property> | ||
| 61 | <property name="topMargin"> | ||
| 62 | <number>0</number> | ||
| 63 | </property> | ||
| 64 | <property name="rightMargin"> | ||
| 65 | <number>0</number> | ||
| 66 | </property> | ||
| 67 | <property name="bottomMargin"> | ||
| 68 | <number>0</number> | ||
| 69 | </property> | ||
| 70 | </layout> | ||
| 71 | </widget> | ||
| 72 | </item> | ||
| 73 | </layout> | ||
| 74 | </widget> | ||
| 75 | </item> | ||
| 76 | <item> | ||
| 50 | <spacer name="verticalSpacer"> | 77 | <spacer name="verticalSpacer"> |
| 51 | <property name="orientation"> | 78 | <property name="orientation"> |
| 52 | <enum>Qt::Vertical</enum> | 79 | <enum>Qt::Vertical</enum> |
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 68e21cd84..76fc33e49 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp | |||
| @@ -9,10 +9,11 @@ | |||
| 9 | #include "core/hid/emulated_controller.h" | 9 | #include "core/hid/emulated_controller.h" |
| 10 | #include "core/hid/hid_core.h" | 10 | #include "core/hid/hid_core.h" |
| 11 | 11 | ||
| 12 | #include "frontend_common/config.h" | ||
| 12 | #include "ui_configure_hotkeys.h" | 13 | #include "ui_configure_hotkeys.h" |
| 13 | #include "yuzu/configuration/config.h" | ||
| 14 | #include "yuzu/configuration/configure_hotkeys.h" | 14 | #include "yuzu/configuration/configure_hotkeys.h" |
| 15 | #include "yuzu/hotkeys.h" | 15 | #include "yuzu/hotkeys.h" |
| 16 | #include "yuzu/uisettings.h" | ||
| 16 | #include "yuzu/util/sequence_dialog/sequence_dialog.h" | 17 | #include "yuzu/util/sequence_dialog/sequence_dialog.h" |
| 17 | 18 | ||
| 18 | constexpr int name_column = 0; | 19 | constexpr int name_column = 0; |
| @@ -62,18 +63,21 @@ ConfigureHotkeys::~ConfigureHotkeys() = default; | |||
| 62 | 63 | ||
| 63 | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { | 64 | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { |
| 64 | for (const auto& group : registry.hotkey_groups) { | 65 | for (const auto& group : registry.hotkey_groups) { |
| 66 | QString parent_item_data = QString::fromStdString(group.first); | ||
| 65 | auto* parent_item = | 67 | auto* parent_item = |
| 66 | new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(group.first))); | 68 | new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(parent_item_data))); |
| 67 | parent_item->setEditable(false); | 69 | parent_item->setEditable(false); |
| 68 | parent_item->setData(group.first); | 70 | parent_item->setData(parent_item_data); |
| 69 | for (const auto& hotkey : group.second) { | 71 | for (const auto& hotkey : group.second) { |
| 70 | auto* action = | 72 | QString hotkey_action_data = QString::fromStdString(hotkey.first); |
| 71 | new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(hotkey.first))); | 73 | auto* action = new QStandardItem( |
| 74 | QCoreApplication::translate("Hotkeys", qPrintable(hotkey_action_data))); | ||
| 72 | auto* keyseq = | 75 | auto* keyseq = |
| 73 | new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); | 76 | new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); |
| 74 | auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); | 77 | auto* controller_keyseq = |
| 78 | new QStandardItem(QString::fromStdString(hotkey.second.controller_keyseq)); | ||
| 75 | action->setEditable(false); | 79 | action->setEditable(false); |
| 76 | action->setData(hotkey.first); | 80 | action->setData(hotkey_action_data); |
| 77 | keyseq->setEditable(false); | 81 | keyseq->setEditable(false); |
| 78 | controller_keyseq->setEditable(false); | 82 | controller_keyseq->setEditable(false); |
| 79 | parent_item->appendRow({action, keyseq, controller_keyseq}); | 83 | parent_item->appendRow({action, keyseq, controller_keyseq}); |
| @@ -301,13 +305,13 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { | |||
| 301 | const QStandardItem* controller_keyseq = | 305 | const QStandardItem* controller_keyseq = |
| 302 | parent->child(key_column_id, controller_column); | 306 | parent->child(key_column_id, controller_column); |
| 303 | for (auto& [group, sub_actions] : registry.hotkey_groups) { | 307 | for (auto& [group, sub_actions] : registry.hotkey_groups) { |
| 304 | if (group != parent->data()) | 308 | if (group != parent->data().toString().toStdString()) |
| 305 | continue; | 309 | continue; |
| 306 | for (auto& [action_name, hotkey] : sub_actions) { | 310 | for (auto& [action_name, hotkey] : sub_actions) { |
| 307 | if (action_name != action->data()) | 311 | if (action_name != action->data().toString().toStdString()) |
| 308 | continue; | 312 | continue; |
| 309 | hotkey.keyseq = QKeySequence(keyseq->text()); | 313 | hotkey.keyseq = QKeySequence(keyseq->text()); |
| 310 | hotkey.controller_keyseq = controller_keyseq->text(); | 314 | hotkey.controller_keyseq = controller_keyseq->text().toStdString(); |
| 311 | } | 315 | } |
| 312 | } | 316 | } |
| 313 | } | 317 | } |
| @@ -319,7 +323,7 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { | |||
| 319 | void ConfigureHotkeys::RestoreDefaults() { | 323 | void ConfigureHotkeys::RestoreDefaults() { |
| 320 | for (int r = 0; r < model->rowCount(); ++r) { | 324 | for (int r = 0; r < model->rowCount(); ++r) { |
| 321 | const QStandardItem* parent = model->item(r, 0); | 325 | const QStandardItem* parent = model->item(r, 0); |
| 322 | const int hotkey_size = static_cast<int>(Config::default_hotkeys.size()); | 326 | const int hotkey_size = static_cast<int>(UISettings::default_hotkeys.size()); |
| 323 | 327 | ||
| 324 | if (hotkey_size != parent->rowCount()) { | 328 | if (hotkey_size != parent->rowCount()) { |
| 325 | QMessageBox::warning(this, tr("Invalid hotkey settings"), | 329 | QMessageBox::warning(this, tr("Invalid hotkey settings"), |
| @@ -330,10 +334,11 @@ void ConfigureHotkeys::RestoreDefaults() { | |||
| 330 | for (int r2 = 0; r2 < parent->rowCount(); ++r2) { | 334 | for (int r2 = 0; r2 < parent->rowCount(); ++r2) { |
| 331 | model->item(r, 0) | 335 | model->item(r, 0) |
| 332 | ->child(r2, hotkey_column) | 336 | ->child(r2, hotkey_column) |
| 333 | ->setText(Config::default_hotkeys[r2].shortcut.keyseq); | 337 | ->setText(QString::fromStdString(UISettings::default_hotkeys[r2].shortcut.keyseq)); |
| 334 | model->item(r, 0) | 338 | model->item(r, 0) |
| 335 | ->child(r2, controller_column) | 339 | ->child(r2, controller_column) |
| 336 | ->setText(Config::default_hotkeys[r2].shortcut.controller_keyseq); | 340 | ->setText(QString::fromStdString( |
| 341 | UISettings::default_hotkeys[r2].shortcut.controller_keyseq)); | ||
| 337 | } | 342 | } |
| 338 | } | 343 | } |
| 339 | } | 344 | } |
| @@ -379,7 +384,7 @@ void ConfigureHotkeys::PopupContextMenu(const QPoint& menu_location) { | |||
| 379 | 384 | ||
| 380 | void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { | 385 | void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { |
| 381 | const QString& default_key_sequence = | 386 | const QString& default_key_sequence = |
| 382 | Config::default_hotkeys[index.row()].shortcut.controller_keyseq; | 387 | QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.controller_keyseq); |
| 383 | const auto [key_sequence_used, used_action] = IsUsedControllerKey(default_key_sequence); | 388 | const auto [key_sequence_used, used_action] = IsUsedControllerKey(default_key_sequence); |
| 384 | 389 | ||
| 385 | if (key_sequence_used && default_key_sequence != model->data(index).toString()) { | 390 | if (key_sequence_used && default_key_sequence != model->data(index).toString()) { |
| @@ -393,7 +398,8 @@ void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { | |||
| 393 | 398 | ||
| 394 | void ConfigureHotkeys::RestoreHotkey(QModelIndex index) { | 399 | void ConfigureHotkeys::RestoreHotkey(QModelIndex index) { |
| 395 | const QKeySequence& default_key_sequence = QKeySequence::fromString( | 400 | const QKeySequence& default_key_sequence = QKeySequence::fromString( |
| 396 | Config::default_hotkeys[index.row()].shortcut.keyseq, QKeySequence::NativeText); | 401 | QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.keyseq), |
| 402 | QKeySequence::NativeText); | ||
| 397 | const auto [key_sequence_used, used_action] = IsUsedKey(default_key_sequence); | 403 | const auto [key_sequence_used, used_action] = IsUsedKey(default_key_sequence); |
| 398 | 404 | ||
| 399 | if (key_sequence_used && default_key_sequence != QKeySequence(model->data(index).toString())) { | 405 | if (key_sequence_used && default_key_sequence != QKeySequence(model->data(index).toString())) { |
diff --git a/src/yuzu/configuration/configure_input_per_game.cpp b/src/yuzu/configuration/configure_input_per_game.cpp index 78e65d468..8d9f65a05 100644 --- a/src/yuzu/configuration/configure_input_per_game.cpp +++ b/src/yuzu/configuration/configure_input_per_game.cpp | |||
| @@ -5,12 +5,12 @@ | |||
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/hid/emulated_controller.h" | 6 | #include "core/hid/emulated_controller.h" |
| 7 | #include "core/hid/hid_core.h" | 7 | #include "core/hid/hid_core.h" |
| 8 | #include "frontend_common/config.h" | ||
| 8 | #include "ui_configure_input_per_game.h" | 9 | #include "ui_configure_input_per_game.h" |
| 9 | #include "yuzu/configuration/config.h" | ||
| 10 | #include "yuzu/configuration/configure_input_per_game.h" | 10 | #include "yuzu/configuration/configure_input_per_game.h" |
| 11 | #include "yuzu/configuration/input_profiles.h" | 11 | #include "yuzu/configuration/input_profiles.h" |
| 12 | 12 | ||
| 13 | ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, Config* config_, | 13 | ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, QtConfig* config_, |
| 14 | QWidget* parent) | 14 | QWidget* parent) |
| 15 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPerGame>()), | 15 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPerGame>()), |
| 16 | profiles(std::make_unique<InputProfiles>()), system{system_}, config{config_} { | 16 | profiles(std::make_unique<InputProfiles>()), system{system_}, config{config_} { |
| @@ -110,6 +110,6 @@ void ConfigureInputPerGame::SaveConfiguration() { | |||
| 110 | // Clear all controls from the config in case the user reverted back to globals | 110 | // Clear all controls from the config in case the user reverted back to globals |
| 111 | config->ClearControlPlayerValues(); | 111 | config->ClearControlPlayerValues(); |
| 112 | for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) { | 112 | for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) { |
| 113 | config->SaveControlPlayerValue(index); | 113 | config->SaveQtControlPlayerValues(index); |
| 114 | } | 114 | } |
| 115 | } | 115 | } |
diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 660faf574..4420e856c 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "ui_configure_input_per_game.h" | 10 | #include "ui_configure_input_per_game.h" |
| 11 | #include "yuzu/configuration/input_profiles.h" | 11 | #include "yuzu/configuration/input_profiles.h" |
| 12 | #include "yuzu/configuration/qt_config.h" | ||
| 12 | 13 | ||
| 13 | class QComboBox; | 14 | class QComboBox; |
| 14 | 15 | ||
| @@ -22,7 +23,7 @@ class ConfigureInputPerGame : public QWidget { | |||
| 22 | Q_OBJECT | 23 | Q_OBJECT |
| 23 | 24 | ||
| 24 | public: | 25 | public: |
| 25 | explicit ConfigureInputPerGame(Core::System& system_, Config* config_, | 26 | explicit ConfigureInputPerGame(Core::System& system_, QtConfig* config_, |
| 26 | QWidget* parent = nullptr); | 27 | QWidget* parent = nullptr); |
| 27 | 28 | ||
| 28 | /// Load and Save configurations to settings file. | 29 | /// Load and Save configurations to settings file. |
| @@ -41,5 +42,5 @@ private: | |||
| 41 | std::array<QComboBox*, 8> profile_comboboxes; | 42 | std::array<QComboBox*, 8> profile_comboboxes; |
| 42 | 43 | ||
| 43 | Core::System& system; | 44 | Core::System& system; |
| 44 | Config* config; | 45 | QtConfig* config; |
| 45 | }; | 46 | }; |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 9259e2a5d..0f7b3714e 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -12,15 +12,16 @@ | |||
| 12 | #include <QTimer> | 12 | #include <QTimer> |
| 13 | #include "common/assert.h" | 13 | #include "common/assert.h" |
| 14 | #include "common/param_package.h" | 14 | #include "common/param_package.h" |
| 15 | #include "configuration/qt_config.h" | ||
| 15 | #include "core/hid/emulated_controller.h" | 16 | #include "core/hid/emulated_controller.h" |
| 16 | #include "core/hid/hid_core.h" | 17 | #include "core/hid/hid_core.h" |
| 17 | #include "core/hid/hid_types.h" | 18 | #include "core/hid/hid_types.h" |
| 19 | #include "frontend_common/config.h" | ||
| 18 | #include "input_common/drivers/keyboard.h" | 20 | #include "input_common/drivers/keyboard.h" |
| 19 | #include "input_common/drivers/mouse.h" | 21 | #include "input_common/drivers/mouse.h" |
| 20 | #include "input_common/main.h" | 22 | #include "input_common/main.h" |
| 21 | #include "ui_configure_input_player.h" | 23 | #include "ui_configure_input_player.h" |
| 22 | #include "yuzu/bootmanager.h" | 24 | #include "yuzu/bootmanager.h" |
| 23 | #include "yuzu/configuration/config.h" | ||
| 24 | #include "yuzu/configuration/configure_input_player.h" | 25 | #include "yuzu/configuration/configure_input_player.h" |
| 25 | #include "yuzu/configuration/configure_input_player_widget.h" | 26 | #include "yuzu/configuration/configure_input_player_widget.h" |
| 26 | #include "yuzu/configuration/configure_mouse_panning.h" | 27 | #include "yuzu/configuration/configure_mouse_panning.h" |
| @@ -1397,25 +1398,25 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | |||
| 1397 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { | 1398 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { |
| 1398 | emulated_controller->SetButtonParam( | 1399 | emulated_controller->SetButtonParam( |
| 1399 | button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( | 1400 | button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( |
| 1400 | Config::default_buttons[button_id])}); | 1401 | QtConfig::default_buttons[button_id])}); |
| 1401 | } | 1402 | } |
| 1402 | for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { | 1403 | for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { |
| 1403 | Common::ParamPackage analog_param{}; | 1404 | Common::ParamPackage analog_param{}; |
| 1404 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { | 1405 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { |
| 1405 | Common::ParamPackage params{InputCommon::GenerateKeyboardParam( | 1406 | Common::ParamPackage params{InputCommon::GenerateKeyboardParam( |
| 1406 | Config::default_analogs[analog_id][sub_button_id])}; | 1407 | QtConfig::default_analogs[analog_id][sub_button_id])}; |
| 1407 | SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]); | 1408 | SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]); |
| 1408 | } | 1409 | } |
| 1409 | 1410 | ||
| 1410 | analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( | 1411 | analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( |
| 1411 | Config::default_stick_mod[analog_id])); | 1412 | QtConfig::default_stick_mod[analog_id])); |
| 1412 | emulated_controller->SetStickParam(analog_id, analog_param); | 1413 | emulated_controller->SetStickParam(analog_id, analog_param); |
| 1413 | } | 1414 | } |
| 1414 | 1415 | ||
| 1415 | for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { | 1416 | for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { |
| 1416 | emulated_controller->SetMotionParam( | 1417 | emulated_controller->SetMotionParam( |
| 1417 | motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( | 1418 | motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( |
| 1418 | Config::default_motions[motion_id])}); | 1419 | QtConfig::default_motions[motion_id])}); |
| 1419 | } | 1420 | } |
| 1420 | 1421 | ||
| 1421 | // If mouse is selected we want to override with mappings from the driver | 1422 | // If mouse is selected we want to override with mappings from the driver |
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index b91d6ad4a..b274a3321 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp | |||
| @@ -25,8 +25,8 @@ | |||
| 25 | #include "core/file_sys/patch_manager.h" | 25 | #include "core/file_sys/patch_manager.h" |
| 26 | #include "core/file_sys/xts_archive.h" | 26 | #include "core/file_sys/xts_archive.h" |
| 27 | #include "core/loader/loader.h" | 27 | #include "core/loader/loader.h" |
| 28 | #include "frontend_common/config.h" | ||
| 28 | #include "ui_configure_per_game.h" | 29 | #include "ui_configure_per_game.h" |
| 29 | #include "yuzu/configuration/config.h" | ||
| 30 | #include "yuzu/configuration/configuration_shared.h" | 30 | #include "yuzu/configuration/configuration_shared.h" |
| 31 | #include "yuzu/configuration/configure_audio.h" | 31 | #include "yuzu/configuration/configure_audio.h" |
| 32 | #include "yuzu/configuration/configure_cpu.h" | 32 | #include "yuzu/configuration/configure_cpu.h" |
| @@ -50,8 +50,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st | |||
| 50 | const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); | 50 | const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); |
| 51 | const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) | 51 | const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) |
| 52 | : fmt::format("{:016X}", title_id); | 52 | : fmt::format("{:016X}", title_id); |
| 53 | game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig); | 53 | game_config = std::make_unique<QtConfig>(config_file_name, Config::ConfigType::PerGameConfig); |
| 54 | |||
| 55 | addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this); | 54 | addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this); |
| 56 | audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this); | 55 | audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this); |
| 57 | cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this); | 56 | cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this); |
| @@ -108,7 +107,7 @@ void ConfigurePerGame::ApplyConfiguration() { | |||
| 108 | system.ApplySettings(); | 107 | system.ApplySettings(); |
| 109 | Settings::LogSettings(); | 108 | Settings::LogSettings(); |
| 110 | 109 | ||
| 111 | game_config->Save(); | 110 | game_config->SaveAllValues(); |
| 112 | } | 111 | } |
| 113 | 112 | ||
| 114 | void ConfigurePerGame::changeEvent(QEvent* event) { | 113 | void ConfigurePerGame::changeEvent(QEvent* event) { |
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index cc2513001..c8ee46c04 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h | |||
| @@ -12,9 +12,10 @@ | |||
| 12 | 12 | ||
| 13 | #include "configuration/shared_widget.h" | 13 | #include "configuration/shared_widget.h" |
| 14 | #include "core/file_sys/vfs_types.h" | 14 | #include "core/file_sys/vfs_types.h" |
| 15 | #include "frontend_common/config.h" | ||
| 15 | #include "vk_device_info.h" | 16 | #include "vk_device_info.h" |
| 16 | #include "yuzu/configuration/config.h" | ||
| 17 | #include "yuzu/configuration/configuration_shared.h" | 17 | #include "yuzu/configuration/configuration_shared.h" |
| 18 | #include "yuzu/configuration/qt_config.h" | ||
| 18 | #include "yuzu/configuration/shared_translation.h" | 19 | #include "yuzu/configuration/shared_translation.h" |
| 19 | 20 | ||
| 20 | namespace Core { | 21 | namespace Core { |
| @@ -72,7 +73,7 @@ private: | |||
| 72 | 73 | ||
| 73 | QGraphicsScene* scene; | 74 | QGraphicsScene* scene; |
| 74 | 75 | ||
| 75 | std::unique_ptr<Config> game_config; | 76 | std::unique_ptr<QtConfig> game_config; |
| 76 | 77 | ||
| 77 | Core::System& system; | 78 | Core::System& system; |
| 78 | std::unique_ptr<ConfigurationShared::Builder> builder; | 79 | std::unique_ptr<ConfigurationShared::Builder> builder; |
diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 674a75a62..140a7fe5d 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp | |||
| @@ -19,7 +19,6 @@ | |||
| 19 | #include "core/file_sys/xts_archive.h" | 19 | #include "core/file_sys/xts_archive.h" |
| 20 | #include "core/loader/loader.h" | 20 | #include "core/loader/loader.h" |
| 21 | #include "ui_configure_per_game_addons.h" | 21 | #include "ui_configure_per_game_addons.h" |
| 22 | #include "yuzu/configuration/config.h" | ||
| 23 | #include "yuzu/configuration/configure_input.h" | 22 | #include "yuzu/configuration/configure_input.h" |
| 24 | #include "yuzu/configuration/configure_per_game_addons.h" | 23 | #include "yuzu/configuration/configure_per_game_addons.h" |
| 25 | #include "yuzu/uisettings.h" | 24 | #include "yuzu/uisettings.h" |
diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index f83705544..9572ff43c 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <QTimer> | 8 | #include <QTimer> |
| 9 | #include <fmt/format.h> | 9 | #include <fmt/format.h> |
| 10 | 10 | ||
| 11 | #include "configuration/qt_config.h" | ||
| 11 | #include "core/hid/emulated_controller.h" | 12 | #include "core/hid/emulated_controller.h" |
| 12 | #include "core/hid/hid_core.h" | 13 | #include "core/hid/hid_core.h" |
| 13 | #include "input_common/drivers/keyboard.h" | 14 | #include "input_common/drivers/keyboard.h" |
| @@ -15,7 +16,6 @@ | |||
| 15 | #include "input_common/main.h" | 16 | #include "input_common/main.h" |
| 16 | #include "ui_configure_ringcon.h" | 17 | #include "ui_configure_ringcon.h" |
| 17 | #include "yuzu/bootmanager.h" | 18 | #include "yuzu/bootmanager.h" |
| 18 | #include "yuzu/configuration/config.h" | ||
| 19 | #include "yuzu/configuration/configure_ringcon.h" | 19 | #include "yuzu/configuration/configure_ringcon.h" |
| 20 | 20 | ||
| 21 | const std::array<std::string, ConfigureRingController::ANALOG_SUB_BUTTONS_NUM> | 21 | const std::array<std::string, ConfigureRingController::ANALOG_SUB_BUTTONS_NUM> |
| @@ -270,7 +270,7 @@ void ConfigureRingController::LoadConfiguration() { | |||
| 270 | 270 | ||
| 271 | void ConfigureRingController::RestoreDefaults() { | 271 | void ConfigureRingController::RestoreDefaults() { |
| 272 | const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys( | 272 | const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys( |
| 273 | 0, 0, Config::default_ringcon_analogs[0], Config::default_ringcon_analogs[1], 0, 0.05f); | 273 | 0, 0, QtConfig::default_ringcon_analogs[0], QtConfig::default_ringcon_analogs[1], 0, 0.05f); |
| 274 | emulated_controller->SetRingParam(Common::ParamPackage(default_ring_string)); | 274 | emulated_controller->SetRingParam(Common::ParamPackage(default_ring_string)); |
| 275 | UpdateUI(); | 275 | UpdateUI(); |
| 276 | } | 276 | } |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 0c8e5c8b4..7cbf43775 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -16,7 +16,6 @@ | |||
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/hle/service/time/time_manager.h" | 17 | #include "core/hle/service/time/time_manager.h" |
| 18 | #include "ui_configure_system.h" | 18 | #include "ui_configure_system.h" |
| 19 | #include "yuzu/configuration/config.h" | ||
| 20 | #include "yuzu/configuration/configuration_shared.h" | 19 | #include "yuzu/configuration/configuration_shared.h" |
| 21 | #include "yuzu/configuration/configure_system.h" | 20 | #include "yuzu/configuration/configure_system.h" |
| 22 | #include "yuzu/configuration/shared_widget.h" | 21 | #include "yuzu/configuration/shared_widget.h" |
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 2a735836e..04b771129 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui | |||
| @@ -57,7 +57,7 @@ | |||
| 57 | </widget> | 57 | </widget> |
| 58 | </item> | 58 | </item> |
| 59 | <item> | 59 | <item> |
| 60 | <widget class="QGroupBox" name="groupBox"> | 60 | <widget class="QGroupBox" name="coreGroup"> |
| 61 | <property name="title"> | 61 | <property name="title"> |
| 62 | <string>Core</string> | 62 | <string>Core</string> |
| 63 | </property> | 63 | </property> |
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.cpp b/src/yuzu/configuration/configure_touchscreen_advanced.cpp index 5a03e48df..94df6d9d3 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.cpp +++ b/src/yuzu/configuration/configure_touchscreen_advanced.cpp | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | #include "common/settings.h" | ||
| 5 | #include "ui_configure_touchscreen_advanced.h" | 6 | #include "ui_configure_touchscreen_advanced.h" |
| 6 | #include "yuzu/configuration/config.h" | ||
| 7 | #include "yuzu/configuration/configure_touchscreen_advanced.h" | 7 | #include "yuzu/configuration/configure_touchscreen_advanced.h" |
| 8 | 8 | ||
| 9 | ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent) | 9 | ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent) |
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 82f3b6e78..dd43f0a0e 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp | |||
| @@ -164,7 +164,7 @@ ConfigureUi::~ConfigureUi() = default; | |||
| 164 | 164 | ||
| 165 | void ConfigureUi::ApplyConfiguration() { | 165 | void ConfigureUi::ApplyConfiguration() { |
| 166 | UISettings::values.theme = | 166 | UISettings::values.theme = |
| 167 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); | 167 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString().toStdString(); |
| 168 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); | 168 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); |
| 169 | UISettings::values.show_compat = ui->show_compat->isChecked(); | 169 | UISettings::values.show_compat = ui->show_compat->isChecked(); |
| 170 | UISettings::values.show_size = ui->show_size->isChecked(); | 170 | UISettings::values.show_size = ui->show_size->isChecked(); |
| @@ -191,9 +191,10 @@ void ConfigureUi::RequestGameListUpdate() { | |||
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | void ConfigureUi::SetConfiguration() { | 193 | void ConfigureUi::SetConfiguration() { |
| 194 | ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); | 194 | ui->theme_combobox->setCurrentIndex( |
| 195 | ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme))); | ||
| 195 | ui->language_combobox->setCurrentIndex( | 196 | ui->language_combobox->setCurrentIndex( |
| 196 | ui->language_combobox->findData(UISettings::values.language)); | 197 | ui->language_combobox->findData(QString::fromStdString(UISettings::values.language))); |
| 197 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); | 198 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); |
| 198 | ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); | 199 | ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); |
| 199 | ui->show_size->setChecked(UISettings::values.show_size.GetValue()); | 200 | ui->show_size->setChecked(UISettings::values.show_size.GetValue()); |
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp index 41ef4250a..716efbccd 100644 --- a/src/yuzu/configuration/input_profiles.cpp +++ b/src/yuzu/configuration/input_profiles.cpp | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/fs/fs.h" | 6 | #include "common/fs/fs.h" |
| 7 | #include "common/fs/path_util.h" | 7 | #include "common/fs/path_util.h" |
| 8 | #include "yuzu/configuration/config.h" | 8 | #include "frontend_common/config.h" |
| 9 | #include "yuzu/configuration/input_profiles.h" | 9 | #include "yuzu/configuration/input_profiles.h" |
| 10 | 10 | ||
| 11 | namespace FS = Common::FS; | 11 | namespace FS = Common::FS; |
| @@ -44,7 +44,7 @@ InputProfiles::InputProfiles() { | |||
| 44 | if (IsINI(filename) && IsProfileNameValid(name_without_ext)) { | 44 | if (IsINI(filename) && IsProfileNameValid(name_without_ext)) { |
| 45 | map_profiles.insert_or_assign( | 45 | map_profiles.insert_or_assign( |
| 46 | name_without_ext, | 46 | name_without_ext, |
| 47 | std::make_unique<Config>(name_without_ext, Config::ConfigType::InputProfile)); | 47 | std::make_unique<QtConfig>(name_without_ext, Config::ConfigType::InputProfile)); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | return true; | 50 | return true; |
| @@ -85,7 +85,7 @@ bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t p | |||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | map_profiles.insert_or_assign( | 87 | map_profiles.insert_or_assign( |
| 88 | profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile)); | 88 | profile_name, std::make_unique<QtConfig>(profile_name, Config::ConfigType::InputProfile)); |
| 89 | 89 | ||
| 90 | return SaveProfile(profile_name, player_index); | 90 | return SaveProfile(profile_name, player_index); |
| 91 | } | 91 | } |
| @@ -113,7 +113,7 @@ bool InputProfiles::LoadProfile(const std::string& profile_name, std::size_t pla | |||
| 113 | return false; | 113 | return false; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | map_profiles[profile_name]->ReadControlPlayerValue(player_index); | 116 | map_profiles[profile_name]->ReadQtControlPlayerValues(player_index); |
| 117 | return true; | 117 | return true; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| @@ -122,7 +122,7 @@ bool InputProfiles::SaveProfile(const std::string& profile_name, std::size_t pla | |||
| 122 | return false; | 122 | return false; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | map_profiles[profile_name]->SaveControlPlayerValue(player_index); | 125 | map_profiles[profile_name]->SaveQtControlPlayerValues(player_index); |
| 126 | return true; | 126 | return true; |
| 127 | } | 127 | } |
| 128 | 128 | ||
diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 2bf3e4250..023ec74a6 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <unordered_map> | 7 | #include <unordered_map> |
| 8 | 8 | ||
| 9 | #include "configuration/qt_config.h" | ||
| 10 | |||
| 9 | namespace Core { | 11 | namespace Core { |
| 10 | class System; | 12 | class System; |
| 11 | } | 13 | } |
| @@ -30,5 +32,5 @@ public: | |||
| 30 | private: | 32 | private: |
| 31 | bool ProfileExistsInMap(const std::string& profile_name) const; | 33 | bool ProfileExistsInMap(const std::string& profile_name) const; |
| 32 | 34 | ||
| 33 | std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles; | 35 | std::unordered_map<std::string, std::unique_ptr<QtConfig>> map_profiles; |
| 34 | }; | 36 | }; |
diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp new file mode 100644 index 000000000..5a8e69aa9 --- /dev/null +++ b/src/yuzu/configuration/qt_config.cpp | |||
| @@ -0,0 +1,549 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "input_common/main.h" | ||
| 5 | #include "qt_config.h" | ||
| 6 | #include "uisettings.h" | ||
| 7 | |||
| 8 | const std::array<int, Settings::NativeButton::NumButtons> QtConfig::default_buttons = { | ||
| 9 | Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F, | ||
| 10 | Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T, | ||
| 11 | Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, | ||
| 12 | Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0, | ||
| 13 | Qt::Key_Q, Qt::Key_E, | ||
| 14 | }; | ||
| 15 | |||
| 16 | const std::array<int, Settings::NativeMotion::NumMotions> QtConfig::default_motions = { | ||
| 17 | Qt::Key_7, | ||
| 18 | Qt::Key_8, | ||
| 19 | }; | ||
| 20 | |||
| 21 | const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{ | ||
| 22 | { | ||
| 23 | Qt::Key_W, | ||
| 24 | Qt::Key_S, | ||
| 25 | Qt::Key_A, | ||
| 26 | Qt::Key_D, | ||
| 27 | }, | ||
| 28 | { | ||
| 29 | Qt::Key_I, | ||
| 30 | Qt::Key_K, | ||
| 31 | Qt::Key_J, | ||
| 32 | Qt::Key_L, | ||
| 33 | }, | ||
| 34 | }}; | ||
| 35 | |||
| 36 | const std::array<int, 2> QtConfig::default_stick_mod = { | ||
| 37 | Qt::Key_Shift, | ||
| 38 | 0, | ||
| 39 | }; | ||
| 40 | |||
| 41 | const std::array<int, 2> QtConfig::default_ringcon_analogs{{ | ||
| 42 | Qt::Key_A, | ||
| 43 | Qt::Key_D, | ||
| 44 | }}; | ||
| 45 | |||
| 46 | QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type) | ||
| 47 | : Config(config_type) { | ||
| 48 | Initialize(config_name); | ||
| 49 | if (config_type != ConfigType::InputProfile) { | ||
| 50 | ReadQtValues(); | ||
| 51 | SaveQtValues(); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | QtConfig::~QtConfig() { | ||
| 56 | if (global) { | ||
| 57 | QtConfig::SaveAllValues(); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | void QtConfig::ReloadAllValues() { | ||
| 62 | Reload(); | ||
| 63 | ReadQtValues(); | ||
| 64 | SaveQtValues(); | ||
| 65 | } | ||
| 66 | |||
| 67 | void QtConfig::SaveAllValues() { | ||
| 68 | Save(); | ||
| 69 | SaveQtValues(); | ||
| 70 | } | ||
| 71 | |||
| 72 | void QtConfig::ReadQtValues() { | ||
| 73 | if (global) { | ||
| 74 | ReadUIValues(); | ||
| 75 | } | ||
| 76 | ReadQtControlValues(); | ||
| 77 | } | ||
| 78 | |||
| 79 | void QtConfig::ReadQtPlayerValues(const std::size_t player_index) { | ||
| 80 | std::string player_prefix; | ||
| 81 | if (type != ConfigType::InputProfile) { | ||
| 82 | player_prefix.append("player_").append(ToString(player_index)).append("_"); | ||
| 83 | } | ||
| 84 | |||
| 85 | auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 86 | if (IsCustomConfig()) { | ||
| 87 | const auto profile_name = | ||
| 88 | ReadStringSetting(std::string(player_prefix).append("profile_name")); | ||
| 89 | if (profile_name.empty()) { | ||
| 90 | // Use the global input config | ||
| 91 | player = Settings::values.players.GetValue(true)[player_index]; | ||
| 92 | return; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 97 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 98 | auto& player_buttons = player.buttons[i]; | ||
| 99 | |||
| 100 | player_buttons = ReadStringSetting( | ||
| 101 | std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); | ||
| 102 | if (player_buttons.empty()) { | ||
| 103 | player_buttons = default_param; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 108 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 109 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 110 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 111 | auto& player_analogs = player.analogs[i]; | ||
| 112 | |||
| 113 | player_analogs = ReadStringSetting( | ||
| 114 | std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); | ||
| 115 | if (player_analogs.empty()) { | ||
| 116 | player_analogs = default_param; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 121 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 122 | auto& player_motions = player.motions[i]; | ||
| 123 | |||
| 124 | player_motions = ReadStringSetting( | ||
| 125 | std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); | ||
| 126 | if (player_motions.empty()) { | ||
| 127 | player_motions = default_param; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | void QtConfig::ReadHidbusValues() { | ||
| 133 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 134 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||
| 135 | auto& ringcon_analogs = Settings::values.ringcon_analogs; | ||
| 136 | |||
| 137 | ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); | ||
| 138 | if (ringcon_analogs.empty()) { | ||
| 139 | ringcon_analogs = default_param; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | void QtConfig::ReadDebugControlValues() { | ||
| 144 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 145 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 146 | auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; | ||
| 147 | |||
| 148 | debug_pad_buttons = ReadStringSetting( | ||
| 149 | std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param); | ||
| 150 | if (debug_pad_buttons.empty()) { | ||
| 151 | debug_pad_buttons = default_param; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 156 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 157 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 158 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 159 | auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; | ||
| 160 | |||
| 161 | debug_pad_analogs = ReadStringSetting( | ||
| 162 | std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param); | ||
| 163 | if (debug_pad_analogs.empty()) { | ||
| 164 | debug_pad_analogs = default_param; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | void QtConfig::ReadQtControlValues() { | ||
| 170 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 171 | |||
| 172 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 173 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 174 | ReadQtPlayerValues(p); | ||
| 175 | } | ||
| 176 | if (IsCustomConfig()) { | ||
| 177 | EndGroup(); | ||
| 178 | return; | ||
| 179 | } | ||
| 180 | ReadDebugControlValues(); | ||
| 181 | ReadHidbusValues(); | ||
| 182 | |||
| 183 | EndGroup(); | ||
| 184 | } | ||
| 185 | |||
| 186 | void QtConfig::ReadPathValues() { | ||
| 187 | BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); | ||
| 188 | |||
| 189 | UISettings::values.roms_path = ReadStringSetting(std::string("romsPath")); | ||
| 190 | UISettings::values.symbols_path = ReadStringSetting(std::string("symbolsPath")); | ||
| 191 | UISettings::values.game_dir_deprecated = | ||
| 192 | ReadStringSetting(std::string("gameListRootDir"), std::string(".")); | ||
| 193 | UISettings::values.game_dir_deprecated_deepscan = | ||
| 194 | ReadBooleanSetting(std::string("gameListDeepScan"), std::make_optional(false)); | ||
| 195 | |||
| 196 | const int gamedirs_size = BeginArray(std::string("gamedirs")); | ||
| 197 | for (int i = 0; i < gamedirs_size; ++i) { | ||
| 198 | SetArrayIndex(i); | ||
| 199 | UISettings::GameDir game_dir; | ||
| 200 | game_dir.path = ReadStringSetting(std::string("path")); | ||
| 201 | game_dir.deep_scan = | ||
| 202 | ReadBooleanSetting(std::string("deep_scan"), std::make_optional(false)); | ||
| 203 | game_dir.expanded = ReadBooleanSetting(std::string("expanded"), std::make_optional(true)); | ||
| 204 | UISettings::values.game_dirs.append(game_dir); | ||
| 205 | } | ||
| 206 | EndArray(); | ||
| 207 | |||
| 208 | // Create NAND and SD card directories if empty, these are not removable through the UI, | ||
| 209 | // also carries over old game list settings if present | ||
| 210 | if (UISettings::values.game_dirs.empty()) { | ||
| 211 | UISettings::GameDir game_dir; | ||
| 212 | game_dir.path = std::string("SDMC"); | ||
| 213 | game_dir.expanded = true; | ||
| 214 | UISettings::values.game_dirs.append(game_dir); | ||
| 215 | game_dir.path = std::string("UserNAND"); | ||
| 216 | UISettings::values.game_dirs.append(game_dir); | ||
| 217 | game_dir.path = std::string("SysNAND"); | ||
| 218 | UISettings::values.game_dirs.append(game_dir); | ||
| 219 | if (UISettings::values.game_dir_deprecated != std::string(".")) { | ||
| 220 | game_dir.path = UISettings::values.game_dir_deprecated; | ||
| 221 | game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan; | ||
| 222 | UISettings::values.game_dirs.append(game_dir); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | UISettings::values.recent_files = | ||
| 226 | QString::fromStdString(ReadStringSetting(std::string("recentFiles"))) | ||
| 227 | .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); | ||
| 228 | UISettings::values.language = ReadStringSetting(std::string("language"), std::string("")); | ||
| 229 | |||
| 230 | EndGroup(); | ||
| 231 | } | ||
| 232 | |||
| 233 | void QtConfig::ReadShortcutValues() { | ||
| 234 | BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); | ||
| 235 | |||
| 236 | for (const auto& [name, group, shortcut] : UISettings::default_hotkeys) { | ||
| 237 | BeginGroup(group); | ||
| 238 | BeginGroup(name); | ||
| 239 | |||
| 240 | // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1 | ||
| 241 | // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open | ||
| 242 | // a file dialog in windowed mode | ||
| 243 | UISettings::values.shortcuts.push_back( | ||
| 244 | {name, | ||
| 245 | group, | ||
| 246 | {ReadStringSetting(std::string("KeySeq"), shortcut.keyseq), | ||
| 247 | ReadStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq), | ||
| 248 | shortcut.context, | ||
| 249 | ReadBooleanSetting(std::string("Repeat"), std::optional(shortcut.repeat))}}); | ||
| 250 | |||
| 251 | EndGroup(); // name | ||
| 252 | EndGroup(); // group | ||
| 253 | } | ||
| 254 | |||
| 255 | EndGroup(); | ||
| 256 | } | ||
| 257 | |||
| 258 | void QtConfig::ReadUIValues() { | ||
| 259 | BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); | ||
| 260 | |||
| 261 | UISettings::values.theme = ReadStringSetting( | ||
| 262 | std::string("theme"), | ||
| 263 | std::string(UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second)); | ||
| 264 | |||
| 265 | ReadUIGamelistValues(); | ||
| 266 | ReadUILayoutValues(); | ||
| 267 | ReadPathValues(); | ||
| 268 | ReadScreenshotValues(); | ||
| 269 | ReadShortcutValues(); | ||
| 270 | ReadMultiplayerValues(); | ||
| 271 | |||
| 272 | ReadCategory(Settings::Category::Ui); | ||
| 273 | ReadCategory(Settings::Category::UiGeneral); | ||
| 274 | |||
| 275 | EndGroup(); | ||
| 276 | } | ||
| 277 | |||
| 278 | void QtConfig::ReadUIGamelistValues() { | ||
| 279 | BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); | ||
| 280 | |||
| 281 | ReadCategory(Settings::Category::UiGameList); | ||
| 282 | |||
| 283 | const int favorites_size = BeginArray("favorites"); | ||
| 284 | for (int i = 0; i < favorites_size; i++) { | ||
| 285 | SetArrayIndex(i); | ||
| 286 | UISettings::values.favorited_ids.append( | ||
| 287 | ReadUnsignedIntegerSetting(std::string("program_id"))); | ||
| 288 | } | ||
| 289 | EndArray(); | ||
| 290 | |||
| 291 | EndGroup(); | ||
| 292 | } | ||
| 293 | |||
| 294 | void QtConfig::ReadUILayoutValues() { | ||
| 295 | BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); | ||
| 296 | |||
| 297 | ReadCategory(Settings::Category::UiLayout); | ||
| 298 | |||
| 299 | EndGroup(); | ||
| 300 | } | ||
| 301 | |||
| 302 | void QtConfig::ReadMultiplayerValues() { | ||
| 303 | BeginGroup(Settings::TranslateCategory(Settings::Category::Multiplayer)); | ||
| 304 | |||
| 305 | ReadCategory(Settings::Category::Multiplayer); | ||
| 306 | |||
| 307 | // Read ban list back | ||
| 308 | int size = BeginArray(std::string("username_ban_list")); | ||
| 309 | UISettings::values.multiplayer_ban_list.first.resize(size); | ||
| 310 | for (int i = 0; i < size; ++i) { | ||
| 311 | SetArrayIndex(i); | ||
| 312 | UISettings::values.multiplayer_ban_list.first[i] = | ||
| 313 | ReadStringSetting(std::string("username"), std::string("")); | ||
| 314 | } | ||
| 315 | EndArray(); | ||
| 316 | |||
| 317 | size = BeginArray(std::string("ip_ban_list")); | ||
| 318 | UISettings::values.multiplayer_ban_list.second.resize(size); | ||
| 319 | for (int i = 0; i < size; ++i) { | ||
| 320 | UISettings::values.multiplayer_ban_list.second[i] = | ||
| 321 | ReadStringSetting("username", std::string("")); | ||
| 322 | } | ||
| 323 | EndArray(); | ||
| 324 | |||
| 325 | EndGroup(); | ||
| 326 | } | ||
| 327 | |||
| 328 | void QtConfig::SaveQtValues() { | ||
| 329 | if (global) { | ||
| 330 | SaveUIValues(); | ||
| 331 | } | ||
| 332 | SaveQtControlValues(); | ||
| 333 | |||
| 334 | WriteToIni(); | ||
| 335 | } | ||
| 336 | |||
| 337 | void QtConfig::SaveQtPlayerValues(const std::size_t player_index) { | ||
| 338 | std::string player_prefix; | ||
| 339 | if (type != ConfigType::InputProfile) { | ||
| 340 | player_prefix = std::string("player_").append(ToString(player_index)).append("_"); | ||
| 341 | } | ||
| 342 | |||
| 343 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 344 | if (IsCustomConfig() && player.profile_name.empty()) { | ||
| 345 | // No custom profile selected | ||
| 346 | return; | ||
| 347 | } | ||
| 348 | |||
| 349 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 350 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 351 | WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | ||
| 352 | player.buttons[i], std::make_optional(default_param)); | ||
| 353 | } | ||
| 354 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 355 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 356 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 357 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 358 | WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | ||
| 359 | player.analogs[i], std::make_optional(default_param)); | ||
| 360 | } | ||
| 361 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 362 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 363 | WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | ||
| 364 | player.motions[i], std::make_optional(default_param)); | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | void QtConfig::SaveDebugControlValues() { | ||
| 369 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 370 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 371 | WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | ||
| 372 | Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); | ||
| 373 | } | ||
| 374 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 375 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 376 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 377 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 378 | WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | ||
| 379 | Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | void QtConfig::SaveHidbusValues() { | ||
| 384 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 385 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||
| 386 | WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | ||
| 387 | std::make_optional(default_param)); | ||
| 388 | } | ||
| 389 | |||
| 390 | void QtConfig::SaveQtControlValues() { | ||
| 391 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 392 | |||
| 393 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 394 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 395 | SaveQtPlayerValues(p); | ||
| 396 | } | ||
| 397 | if (IsCustomConfig()) { | ||
| 398 | EndGroup(); | ||
| 399 | return; | ||
| 400 | } | ||
| 401 | SaveDebugControlValues(); | ||
| 402 | SaveHidbusValues(); | ||
| 403 | |||
| 404 | EndGroup(); | ||
| 405 | } | ||
| 406 | |||
| 407 | void QtConfig::SavePathValues() { | ||
| 408 | BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); | ||
| 409 | |||
| 410 | WriteSetting(std::string("romsPath"), UISettings::values.roms_path); | ||
| 411 | WriteSetting(std::string("symbolsPath"), UISettings::values.symbols_path); | ||
| 412 | BeginArray(std::string("gamedirs")); | ||
| 413 | for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { | ||
| 414 | SetArrayIndex(i); | ||
| 415 | const auto& game_dir = UISettings::values.game_dirs[i]; | ||
| 416 | WriteSetting(std::string("path"), game_dir.path); | ||
| 417 | WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); | ||
| 418 | WriteSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); | ||
| 419 | } | ||
| 420 | EndArray(); | ||
| 421 | |||
| 422 | WriteSetting(std::string("recentFiles"), | ||
| 423 | UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); | ||
| 424 | WriteSetting(std::string("language"), UISettings::values.language); | ||
| 425 | |||
| 426 | EndGroup(); | ||
| 427 | } | ||
| 428 | |||
| 429 | void QtConfig::SaveShortcutValues() { | ||
| 430 | BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); | ||
| 431 | |||
| 432 | // Lengths of UISettings::values.shortcuts & default_hotkeys are same. | ||
| 433 | // However, their ordering must also be the same. | ||
| 434 | for (std::size_t i = 0; i < UISettings::default_hotkeys.size(); i++) { | ||
| 435 | const auto& [name, group, shortcut] = UISettings::values.shortcuts[i]; | ||
| 436 | const auto& default_hotkey = UISettings::default_hotkeys[i].shortcut; | ||
| 437 | |||
| 438 | BeginGroup(group); | ||
| 439 | BeginGroup(name); | ||
| 440 | |||
| 441 | WriteSetting(std::string("KeySeq"), shortcut.keyseq, | ||
| 442 | std::make_optional(default_hotkey.keyseq)); | ||
| 443 | WriteSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, | ||
| 444 | std::make_optional(default_hotkey.controller_keyseq)); | ||
| 445 | WriteSetting(std::string("Context"), shortcut.context, | ||
| 446 | std::make_optional(default_hotkey.context)); | ||
| 447 | WriteSetting(std::string("Repeat"), shortcut.repeat, | ||
| 448 | std::make_optional(default_hotkey.repeat)); | ||
| 449 | |||
| 450 | EndGroup(); // name | ||
| 451 | EndGroup(); // group | ||
| 452 | } | ||
| 453 | |||
| 454 | EndGroup(); | ||
| 455 | } | ||
| 456 | |||
| 457 | void QtConfig::SaveUIValues() { | ||
| 458 | BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); | ||
| 459 | |||
| 460 | WriteCategory(Settings::Category::Ui); | ||
| 461 | WriteCategory(Settings::Category::UiGeneral); | ||
| 462 | |||
| 463 | WriteSetting(std::string("theme"), UISettings::values.theme, | ||
| 464 | std::make_optional(std::string( | ||
| 465 | UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second))); | ||
| 466 | |||
| 467 | SaveUIGamelistValues(); | ||
| 468 | SaveUILayoutValues(); | ||
| 469 | SavePathValues(); | ||
| 470 | SaveScreenshotValues(); | ||
| 471 | SaveShortcutValues(); | ||
| 472 | SaveMultiplayerValues(); | ||
| 473 | |||
| 474 | EndGroup(); | ||
| 475 | } | ||
| 476 | |||
| 477 | void QtConfig::SaveUIGamelistValues() { | ||
| 478 | BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); | ||
| 479 | |||
| 480 | WriteCategory(Settings::Category::UiGameList); | ||
| 481 | |||
| 482 | BeginArray(std::string("favorites")); | ||
| 483 | for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { | ||
| 484 | SetArrayIndex(i); | ||
| 485 | WriteSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); | ||
| 486 | } | ||
| 487 | EndArray(); // favorites | ||
| 488 | |||
| 489 | EndGroup(); | ||
| 490 | } | ||
| 491 | |||
| 492 | void QtConfig::SaveUILayoutValues() { | ||
| 493 | BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout)); | ||
| 494 | |||
| 495 | WriteCategory(Settings::Category::UiLayout); | ||
| 496 | |||
| 497 | EndGroup(); | ||
| 498 | } | ||
| 499 | |||
| 500 | void QtConfig::SaveMultiplayerValues() { | ||
| 501 | BeginGroup(std::string("Multiplayer")); | ||
| 502 | |||
| 503 | WriteCategory(Settings::Category::Multiplayer); | ||
| 504 | |||
| 505 | // Write ban list | ||
| 506 | BeginArray(std::string("username_ban_list")); | ||
| 507 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { | ||
| 508 | SetArrayIndex(static_cast<int>(i)); | ||
| 509 | WriteSetting(std::string("username"), UISettings::values.multiplayer_ban_list.first[i]); | ||
| 510 | } | ||
| 511 | EndArray(); // username_ban_list | ||
| 512 | |||
| 513 | BeginArray(std::string("ip_ban_list")); | ||
| 514 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { | ||
| 515 | SetArrayIndex(static_cast<int>(i)); | ||
| 516 | WriteSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); | ||
| 517 | } | ||
| 518 | EndArray(); // ip_ban_list | ||
| 519 | |||
| 520 | EndGroup(); | ||
| 521 | } | ||
| 522 | |||
| 523 | std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) { | ||
| 524 | auto& map = Settings::values.linkage.by_category; | ||
| 525 | if (map.contains(category)) { | ||
| 526 | return Settings::values.linkage.by_category[category]; | ||
| 527 | } | ||
| 528 | return UISettings::values.linkage.by_category[category]; | ||
| 529 | } | ||
| 530 | |||
| 531 | void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) { | ||
| 532 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 533 | |||
| 534 | ReadPlayerValues(player_index); | ||
| 535 | ReadQtPlayerValues(player_index); | ||
| 536 | |||
| 537 | EndGroup(); | ||
| 538 | } | ||
| 539 | |||
| 540 | void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) { | ||
| 541 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 542 | |||
| 543 | SavePlayerValues(player_index); | ||
| 544 | SaveQtPlayerValues(player_index); | ||
| 545 | |||
| 546 | EndGroup(); | ||
| 547 | |||
| 548 | WriteToIni(); | ||
| 549 | } | ||
diff --git a/src/yuzu/configuration/qt_config.h b/src/yuzu/configuration/qt_config.h new file mode 100644 index 000000000..dc2dceb4d --- /dev/null +++ b/src/yuzu/configuration/qt_config.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <QMetaType> | ||
| 7 | |||
| 8 | #include "frontend_common/config.h" | ||
| 9 | |||
| 10 | class QtConfig final : public Config { | ||
| 11 | public: | ||
| 12 | explicit QtConfig(const std::string& config_name = "qt-config", | ||
| 13 | ConfigType config_type = ConfigType::GlobalConfig); | ||
| 14 | ~QtConfig() override; | ||
| 15 | |||
| 16 | void ReloadAllValues() override; | ||
| 17 | void SaveAllValues() override; | ||
| 18 | |||
| 19 | void ReadQtControlPlayerValues(std::size_t player_index); | ||
| 20 | void SaveQtControlPlayerValues(std::size_t player_index); | ||
| 21 | |||
| 22 | protected: | ||
| 23 | void ReadQtValues(); | ||
| 24 | void ReadQtPlayerValues(std::size_t player_index); | ||
| 25 | void ReadQtControlValues(); | ||
| 26 | void ReadHidbusValues() override; | ||
| 27 | void ReadDebugControlValues() override; | ||
| 28 | void ReadPathValues() override; | ||
| 29 | void ReadShortcutValues() override; | ||
| 30 | void ReadUIValues() override; | ||
| 31 | void ReadUIGamelistValues() override; | ||
| 32 | void ReadUILayoutValues() override; | ||
| 33 | void ReadMultiplayerValues() override; | ||
| 34 | |||
| 35 | void SaveQtValues(); | ||
| 36 | void SaveQtPlayerValues(std::size_t player_index); | ||
| 37 | void SaveQtControlValues(); | ||
| 38 | void SaveHidbusValues() override; | ||
| 39 | void SaveDebugControlValues() override; | ||
| 40 | void SavePathValues() override; | ||
| 41 | void SaveShortcutValues() override; | ||
| 42 | void SaveUIValues() override; | ||
| 43 | void SaveUIGamelistValues() override; | ||
| 44 | void SaveUILayoutValues() override; | ||
| 45 | void SaveMultiplayerValues() override; | ||
| 46 | |||
| 47 | std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; | ||
| 48 | |||
| 49 | public: | ||
| 50 | static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; | ||
| 51 | static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; | ||
| 52 | static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; | ||
| 53 | static const std::array<int, 2> default_stick_mod; | ||
| 54 | static const std::array<int, 2> default_ringcon_analogs; | ||
| 55 | }; | ||
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index a7b5def32..ee0ca4aa7 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp | |||
| @@ -176,6 +176,9 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { | |||
| 176 | INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), | 176 | INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), |
| 177 | QStringLiteral()); | 177 | QStringLiteral()); |
| 178 | 178 | ||
| 179 | // Linux | ||
| 180 | INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QStringLiteral()); | ||
| 181 | |||
| 179 | // Ui Debugging | 182 | // Ui Debugging |
| 180 | 183 | ||
| 181 | // Ui Multiplayer | 184 | // Ui Multiplayer |
diff --git a/src/yuzu/configuration/shared_translation.h b/src/yuzu/configuration/shared_translation.h index 99a0e808c..d5fc3b8de 100644 --- a/src/yuzu/configuration/shared_translation.h +++ b/src/yuzu/configuration/shared_translation.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | #include <QString> | 11 | #include <QString> |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/settings.h" | ||
| 13 | 14 | ||
| 14 | class QWidget; | 15 | class QWidget; |
| 15 | 16 | ||
| @@ -22,4 +23,46 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent); | |||
| 22 | 23 | ||
| 23 | std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent); | 24 | std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent); |
| 24 | 25 | ||
| 26 | static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map = { | ||
| 27 | {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, | ||
| 28 | {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))}, | ||
| 29 | {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))}, | ||
| 30 | }; | ||
| 31 | |||
| 32 | static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map = { | ||
| 33 | {Settings::ScalingFilter::NearestNeighbor, | ||
| 34 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))}, | ||
| 35 | {Settings::ScalingFilter::Bilinear, | ||
| 36 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))}, | ||
| 37 | {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, | ||
| 38 | {Settings::ScalingFilter::Gaussian, | ||
| 39 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, | ||
| 40 | {Settings::ScalingFilter::ScaleForce, | ||
| 41 | QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, | ||
| 42 | {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, | ||
| 43 | }; | ||
| 44 | |||
| 45 | static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = { | ||
| 46 | {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, | ||
| 47 | {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, | ||
| 48 | }; | ||
| 49 | |||
| 50 | static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = { | ||
| 51 | {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))}, | ||
| 52 | {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))}, | ||
| 53 | {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))}, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map = { | ||
| 57 | {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))}, | ||
| 58 | {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))}, | ||
| 59 | {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))}, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map = { | ||
| 63 | {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, | ||
| 64 | {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, | ||
| 65 | {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, | ||
| 66 | }; | ||
| 67 | |||
| 25 | } // namespace ConfigurationShared | 68 | } // namespace ConfigurationShared |
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 7049c57b6..6d227ef8d 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -36,10 +36,8 @@ constexpr std::array<std::array<Qt::GlobalColor, 2>, 10> WaitTreeColors{{ | |||
| 36 | 36 | ||
| 37 | bool IsDarkTheme() { | 37 | bool IsDarkTheme() { |
| 38 | const auto& theme = UISettings::values.theme; | 38 | const auto& theme = UISettings::values.theme; |
| 39 | return theme == QStringLiteral("qdarkstyle") || | 39 | return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || |
| 40 | theme == QStringLiteral("qdarkstyle_midnight_blue") || | 40 | theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); |
| 41 | theme == QStringLiteral("colorful_dark") || | ||
| 42 | theme == QStringLiteral("colorful_midnight_blue"); | ||
| 43 | } | 41 | } |
| 44 | 42 | ||
| 45 | } // namespace | 43 | } // namespace |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index f294dc23d..59b317135 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -278,7 +278,7 @@ void GameList::OnUpdateThemedIcons() { | |||
| 278 | case GameListItemType::CustomDir: { | 278 | case GameListItemType::CustomDir: { |
| 279 | const UISettings::GameDir& game_dir = | 279 | const UISettings::GameDir& game_dir = |
| 280 | UISettings::values.game_dirs[child->data(GameListDir::GameDirRole).toInt()]; | 280 | UISettings::values.game_dirs[child->data(GameListDir::GameDirRole).toInt()]; |
| 281 | const QString icon_name = QFileInfo::exists(game_dir.path) | 281 | const QString icon_name = QFileInfo::exists(QString::fromStdString(game_dir.path)) |
| 282 | ? QStringLiteral("folder") | 282 | ? QStringLiteral("folder") |
| 283 | : QStringLiteral("bad_folder"); | 283 | : QStringLiteral("bad_folder"); |
| 284 | child->setData( | 284 | child->setData( |
| @@ -727,7 +727,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | |||
| 727 | }); | 727 | }); |
| 728 | 728 | ||
| 729 | connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { | 729 | connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { |
| 730 | emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); | 730 | emit OpenDirectory( |
| 731 | QString::fromStdString(UISettings::values.game_dirs[game_dir_index].path)); | ||
| 731 | }); | 732 | }); |
| 732 | } | 733 | } |
| 733 | 734 | ||
| @@ -869,7 +870,7 @@ const QStringList GameList::supported_file_extensions = { | |||
| 869 | QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; | 870 | QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; |
| 870 | 871 | ||
| 871 | void GameList::RefreshGameDirectory() { | 872 | void GameList::RefreshGameDirectory() { |
| 872 | if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { | 873 | if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { |
| 873 | LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); | 874 | LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); |
| 874 | PopulateAsync(UISettings::values.game_dirs); | 875 | PopulateAsync(UISettings::values.game_dirs); |
| 875 | } | 876 | } |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 86a0c41d9..c330b574f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -286,13 +286,13 @@ public: | |||
| 286 | setData(QObject::tr("System Titles"), Qt::DisplayRole); | 286 | setData(QObject::tr("System Titles"), Qt::DisplayRole); |
| 287 | break; | 287 | break; |
| 288 | case GameListItemType::CustomDir: { | 288 | case GameListItemType::CustomDir: { |
| 289 | const QString icon_name = QFileInfo::exists(game_dir->path) | 289 | const QString path = QString::fromStdString(game_dir->path); |
| 290 | ? QStringLiteral("folder") | 290 | const QString icon_name = |
| 291 | : QStringLiteral("bad_folder"); | 291 | QFileInfo::exists(path) ? QStringLiteral("folder") : QStringLiteral("bad_folder"); |
| 292 | setData(QIcon::fromTheme(icon_name).pixmap(icon_size).scaled( | 292 | setData(QIcon::fromTheme(icon_name).pixmap(icon_size).scaled( |
| 293 | icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | 293 | icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), |
| 294 | Qt::DecorationRole); | 294 | Qt::DecorationRole); |
| 295 | setData(game_dir->path, Qt::DisplayRole); | 295 | setData(path, Qt::DisplayRole); |
| 296 | break; | 296 | break; |
| 297 | } | 297 | } |
| 298 | default: | 298 | default: |
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 307eac02d..dc006832e 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp | |||
| @@ -456,26 +456,26 @@ void GameListWorker::run() { | |||
| 456 | break; | 456 | break; |
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | if (game_dir.path == QStringLiteral("SDMC")) { | 459 | if (game_dir.path == std::string("SDMC")) { |
| 460 | auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir); | 460 | auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir); |
| 461 | DirEntryReady(game_list_dir); | 461 | DirEntryReady(game_list_dir); |
| 462 | AddTitlesToGameList(game_list_dir); | 462 | AddTitlesToGameList(game_list_dir); |
| 463 | } else if (game_dir.path == QStringLiteral("UserNAND")) { | 463 | } else if (game_dir.path == std::string("UserNAND")) { |
| 464 | auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir); | 464 | auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir); |
| 465 | DirEntryReady(game_list_dir); | 465 | DirEntryReady(game_list_dir); |
| 466 | AddTitlesToGameList(game_list_dir); | 466 | AddTitlesToGameList(game_list_dir); |
| 467 | } else if (game_dir.path == QStringLiteral("SysNAND")) { | 467 | } else if (game_dir.path == std::string("SysNAND")) { |
| 468 | auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir); | 468 | auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir); |
| 469 | DirEntryReady(game_list_dir); | 469 | DirEntryReady(game_list_dir); |
| 470 | AddTitlesToGameList(game_list_dir); | 470 | AddTitlesToGameList(game_list_dir); |
| 471 | } else { | 471 | } else { |
| 472 | watch_list.append(game_dir.path); | 472 | watch_list.append(QString::fromStdString(game_dir.path)); |
| 473 | auto* const game_list_dir = new GameListDir(game_dir); | 473 | auto* const game_list_dir = new GameListDir(game_dir); |
| 474 | DirEntryReady(game_list_dir); | 474 | DirEntryReady(game_list_dir); |
| 475 | ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), | 475 | ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path, game_dir.deep_scan, |
| 476 | game_dir.deep_scan, game_list_dir); | 476 | game_list_dir); |
| 477 | ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), | 477 | ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path, game_dir.deep_scan, |
| 478 | game_dir.deep_scan, game_list_dir); | 478 | game_list_dir); |
| 479 | } | 479 | } |
| 480 | } | 480 | } |
| 481 | 481 | ||
diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 6530186c1..eebfbf155 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp | |||
| @@ -19,7 +19,7 @@ void HotkeyRegistry::SaveHotkeys() { | |||
| 19 | for (const auto& hotkey : group.second) { | 19 | for (const auto& hotkey : group.second) { |
| 20 | UISettings::values.shortcuts.push_back( | 20 | UISettings::values.shortcuts.push_back( |
| 21 | {hotkey.first, group.first, | 21 | {hotkey.first, group.first, |
| 22 | UISettings::ContextualShortcut({hotkey.second.keyseq.toString(), | 22 | UISettings::ContextualShortcut({hotkey.second.keyseq.toString().toStdString(), |
| 23 | hotkey.second.controller_keyseq, | 23 | hotkey.second.controller_keyseq, |
| 24 | hotkey.second.context, hotkey.second.repeat})}); | 24 | hotkey.second.context, hotkey.second.repeat})}); |
| 25 | } | 25 | } |
| @@ -31,12 +31,12 @@ void HotkeyRegistry::LoadHotkeys() { | |||
| 31 | // beginGroup() | 31 | // beginGroup() |
| 32 | for (auto shortcut : UISettings::values.shortcuts) { | 32 | for (auto shortcut : UISettings::values.shortcuts) { |
| 33 | Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name]; | 33 | Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name]; |
| 34 | if (!shortcut.shortcut.keyseq.isEmpty()) { | 34 | if (!shortcut.shortcut.keyseq.empty()) { |
| 35 | hk.keyseq = | 35 | hk.keyseq = QKeySequence::fromString(QString::fromStdString(shortcut.shortcut.keyseq), |
| 36 | QKeySequence::fromString(shortcut.shortcut.keyseq, QKeySequence::NativeText); | 36 | QKeySequence::NativeText); |
| 37 | hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.context); | 37 | hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.context); |
| 38 | } | 38 | } |
| 39 | if (!shortcut.shortcut.controller_keyseq.isEmpty()) { | 39 | if (!shortcut.shortcut.controller_keyseq.empty()) { |
| 40 | hk.controller_keyseq = shortcut.shortcut.controller_keyseq; | 40 | hk.controller_keyseq = shortcut.shortcut.controller_keyseq; |
| 41 | } | 41 | } |
| 42 | if (hk.shortcut) { | 42 | if (hk.shortcut) { |
| @@ -51,7 +51,8 @@ void HotkeyRegistry::LoadHotkeys() { | |||
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { | 54 | QShortcut* HotkeyRegistry::GetHotkey(const std::string& group, const std::string& action, |
| 55 | QWidget* widget) { | ||
| 55 | Hotkey& hk = hotkey_groups[group][action]; | 56 | Hotkey& hk = hotkey_groups[group][action]; |
| 56 | 57 | ||
| 57 | if (!hk.shortcut) { | 58 | if (!hk.shortcut) { |
| @@ -62,7 +63,8 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action | |||
| 62 | return hk.shortcut; | 63 | return hk.shortcut; |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, const QString& action, | 66 | ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const std::string& group, |
| 67 | const std::string& action, | ||
| 66 | Core::HID::EmulatedController* controller) { | 68 | Core::HID::EmulatedController* controller) { |
| 67 | Hotkey& hk = hotkey_groups[group][action]; | 69 | Hotkey& hk = hotkey_groups[group][action]; |
| 68 | 70 | ||
| @@ -74,12 +76,12 @@ ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, co | |||
| 74 | return hk.controller_shortcut; | 76 | return hk.controller_shortcut; |
| 75 | } | 77 | } |
| 76 | 78 | ||
| 77 | QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) { | 79 | QKeySequence HotkeyRegistry::GetKeySequence(const std::string& group, const std::string& action) { |
| 78 | return hotkey_groups[group][action].keyseq; | 80 | return hotkey_groups[group][action].keyseq; |
| 79 | } | 81 | } |
| 80 | 82 | ||
| 81 | Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group, | 83 | Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const std::string& group, |
| 82 | const QString& action) { | 84 | const std::string& action) { |
| 83 | return hotkey_groups[group][action].context; | 85 | return hotkey_groups[group][action].context; |
| 84 | } | 86 | } |
| 85 | 87 | ||
| @@ -101,10 +103,10 @@ void ControllerShortcut::SetKey(const ControllerButtonSequence& buttons) { | |||
| 101 | button_sequence = buttons; | 103 | button_sequence = buttons; |
| 102 | } | 104 | } |
| 103 | 105 | ||
| 104 | void ControllerShortcut::SetKey(const QString& buttons_shortcut) { | 106 | void ControllerShortcut::SetKey(const std::string& buttons_shortcut) { |
| 105 | ControllerButtonSequence sequence{}; | 107 | ControllerButtonSequence sequence{}; |
| 106 | name = buttons_shortcut.toStdString(); | 108 | name = buttons_shortcut; |
| 107 | std::istringstream command_line(buttons_shortcut.toStdString()); | 109 | std::istringstream command_line(buttons_shortcut); |
| 108 | std::string line; | 110 | std::string line; |
| 109 | while (std::getline(command_line, line, '+')) { | 111 | while (std::getline(command_line, line, '+')) { |
| 110 | if (line.empty()) { | 112 | if (line.empty()) { |
diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h index 56eee8d82..e11332d2e 100644 --- a/src/yuzu/hotkeys.h +++ b/src/yuzu/hotkeys.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | ~ControllerShortcut(); | 33 | ~ControllerShortcut(); |
| 34 | 34 | ||
| 35 | void SetKey(const ControllerButtonSequence& buttons); | 35 | void SetKey(const ControllerButtonSequence& buttons); |
| 36 | void SetKey(const QString& buttons_shortcut); | 36 | void SetKey(const std::string& buttons_shortcut); |
| 37 | 37 | ||
| 38 | ControllerButtonSequence ButtonSequence() const; | 38 | ControllerButtonSequence ButtonSequence() const; |
| 39 | 39 | ||
| @@ -88,8 +88,8 @@ public: | |||
| 88 | * will be the same. Thus, you shouldn't rely on the caller really being the | 88 | * will be the same. Thus, you shouldn't rely on the caller really being the |
| 89 | * QShortcut's parent. | 89 | * QShortcut's parent. |
| 90 | */ | 90 | */ |
| 91 | QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); | 91 | QShortcut* GetHotkey(const std::string& group, const std::string& action, QWidget* widget); |
| 92 | ControllerShortcut* GetControllerHotkey(const QString& group, const QString& action, | 92 | ControllerShortcut* GetControllerHotkey(const std::string& group, const std::string& action, |
| 93 | Core::HID::EmulatedController* controller); | 93 | Core::HID::EmulatedController* controller); |
| 94 | 94 | ||
| 95 | /** | 95 | /** |
| @@ -98,7 +98,7 @@ public: | |||
| 98 | * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). | 98 | * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). |
| 99 | * @param action Name of the action (e.g. "Start Emulation", "Load Image"). | 99 | * @param action Name of the action (e.g. "Start Emulation", "Load Image"). |
| 100 | */ | 100 | */ |
| 101 | QKeySequence GetKeySequence(const QString& group, const QString& action); | 101 | QKeySequence GetKeySequence(const std::string& group, const std::string& action); |
| 102 | 102 | ||
| 103 | /** | 103 | /** |
| 104 | * Returns a Qt::ShortcutContext object who can be connected to other | 104 | * Returns a Qt::ShortcutContext object who can be connected to other |
| @@ -108,20 +108,20 @@ public: | |||
| 108 | * "Debugger"). | 108 | * "Debugger"). |
| 109 | * @param action Name of the action (e.g. "Start Emulation", "Load Image"). | 109 | * @param action Name of the action (e.g. "Start Emulation", "Load Image"). |
| 110 | */ | 110 | */ |
| 111 | Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action); | 111 | Qt::ShortcutContext GetShortcutContext(const std::string& group, const std::string& action); |
| 112 | 112 | ||
| 113 | private: | 113 | private: |
| 114 | struct Hotkey { | 114 | struct Hotkey { |
| 115 | QKeySequence keyseq; | 115 | QKeySequence keyseq; |
| 116 | QString controller_keyseq; | 116 | std::string controller_keyseq; |
| 117 | QShortcut* shortcut = nullptr; | 117 | QShortcut* shortcut = nullptr; |
| 118 | ControllerShortcut* controller_shortcut = nullptr; | 118 | ControllerShortcut* controller_shortcut = nullptr; |
| 119 | Qt::ShortcutContext context = Qt::WindowShortcut; | 119 | Qt::ShortcutContext context = Qt::WindowShortcut; |
| 120 | bool repeat; | 120 | bool repeat; |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | using HotkeyMap = std::map<QString, Hotkey>; | 123 | using HotkeyMap = std::map<std::string, Hotkey>; |
| 124 | using HotkeyGroupMap = std::map<QString, HotkeyMap>; | 124 | using HotkeyGroupMap = std::map<std::string, HotkeyMap>; |
| 125 | 125 | ||
| 126 | HotkeyGroupMap hotkey_groups; | 126 | HotkeyGroupMap hotkey_groups; |
| 127 | }; | 127 | }; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f22db233b..10c788290 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #ifdef __unix__ | 17 | #ifdef __unix__ |
| 18 | #include <csignal> | 18 | #include <csignal> |
| 19 | #include <sys/socket.h> | 19 | #include <sys/socket.h> |
| 20 | #include "common/linux/gamemode.h" | ||
| 20 | #endif | 21 | #endif |
| 21 | 22 | ||
| 22 | #include <boost/container/flat_set.hpp> | 23 | #include <boost/container/flat_set.hpp> |
| @@ -47,6 +48,7 @@ | |||
| 47 | #include "core/hle/service/am/applet_ae.h" | 48 | #include "core/hle/service/am/applet_ae.h" |
| 48 | #include "core/hle/service/am/applet_oe.h" | 49 | #include "core/hle/service/am/applet_oe.h" |
| 49 | #include "core/hle/service/am/applets/applets.h" | 50 | #include "core/hle/service/am/applets/applets.h" |
| 51 | #include "core/hle/service/set/set_sys.h" | ||
| 50 | #include "yuzu/multiplayer/state.h" | 52 | #include "yuzu/multiplayer/state.h" |
| 51 | #include "yuzu/util/controller_navigation.h" | 53 | #include "yuzu/util/controller_navigation.h" |
| 52 | 54 | ||
| @@ -128,6 +130,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 128 | #include "core/loader/loader.h" | 130 | #include "core/loader/loader.h" |
| 129 | #include "core/perf_stats.h" | 131 | #include "core/perf_stats.h" |
| 130 | #include "core/telemetry_session.h" | 132 | #include "core/telemetry_session.h" |
| 133 | #include "frontend_common/config.h" | ||
| 131 | #include "input_common/drivers/tas_input.h" | 134 | #include "input_common/drivers/tas_input.h" |
| 132 | #include "input_common/drivers/virtual_amiibo.h" | 135 | #include "input_common/drivers/virtual_amiibo.h" |
| 133 | #include "input_common/main.h" | 136 | #include "input_common/main.h" |
| @@ -140,9 +143,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 140 | #include "yuzu/bootmanager.h" | 143 | #include "yuzu/bootmanager.h" |
| 141 | #include "yuzu/compatdb.h" | 144 | #include "yuzu/compatdb.h" |
| 142 | #include "yuzu/compatibility_list.h" | 145 | #include "yuzu/compatibility_list.h" |
| 143 | #include "yuzu/configuration/config.h" | ||
| 144 | #include "yuzu/configuration/configure_dialog.h" | 146 | #include "yuzu/configuration/configure_dialog.h" |
| 145 | #include "yuzu/configuration/configure_input_per_game.h" | 147 | #include "yuzu/configuration/configure_input_per_game.h" |
| 148 | #include "yuzu/configuration/qt_config.h" | ||
| 146 | #include "yuzu/debugger/console.h" | 149 | #include "yuzu/debugger/console.h" |
| 147 | #include "yuzu/debugger/controller.h" | 150 | #include "yuzu/debugger/controller.h" |
| 148 | #include "yuzu/debugger/profiler.h" | 151 | #include "yuzu/debugger/profiler.h" |
| @@ -185,7 +188,6 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | |||
| 185 | #endif | 188 | #endif |
| 186 | 189 | ||
| 187 | constexpr int default_mouse_hide_timeout = 2500; | 190 | constexpr int default_mouse_hide_timeout = 2500; |
| 188 | constexpr int default_mouse_center_timeout = 10; | ||
| 189 | constexpr int default_input_update_timeout = 1; | 191 | constexpr int default_input_update_timeout = 1; |
| 190 | 192 | ||
| 191 | constexpr size_t CopyBufferSize = 1_MiB; | 193 | constexpr size_t CopyBufferSize = 1_MiB; |
| @@ -311,13 +313,14 @@ bool GMainWindow::CheckDarkMode() { | |||
| 311 | #endif // __unix__ | 313 | #endif // __unix__ |
| 312 | } | 314 | } |
| 313 | 315 | ||
| 314 | GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan) | 316 | GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan) |
| 315 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, | 317 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, |
| 316 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)}, | 318 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)}, |
| 317 | vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, | 319 | vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, |
| 318 | provider{std::make_unique<FileSys::ManualContentProvider>()} { | 320 | provider{std::make_unique<FileSys::ManualContentProvider>()} { |
| 319 | #ifdef __unix__ | 321 | #ifdef __unix__ |
| 320 | SetupSigInterrupts(); | 322 | SetupSigInterrupts(); |
| 323 | SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue()); | ||
| 321 | #endif | 324 | #endif |
| 322 | system->Initialize(); | 325 | system->Initialize(); |
| 323 | 326 | ||
| @@ -435,9 +438,6 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 435 | connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); | 438 | connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); |
| 436 | connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor); | 439 | connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor); |
| 437 | 440 | ||
| 438 | mouse_center_timer.setInterval(default_mouse_center_timeout); | ||
| 439 | connect(&mouse_center_timer, &QTimer::timeout, this, &GMainWindow::CenterMouseCursor); | ||
| 440 | |||
| 441 | update_input_timer.setInterval(default_input_update_timeout); | 441 | update_input_timer.setInterval(default_input_update_timeout); |
| 442 | connect(&update_input_timer, &QTimer::timeout, this, &GMainWindow::UpdateInputDrivers); | 442 | connect(&update_input_timer, &QTimer::timeout, this, &GMainWindow::UpdateInputDrivers); |
| 443 | update_input_timer.start(); | 443 | update_input_timer.start(); |
| @@ -676,7 +676,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers( | |||
| 676 | // Don't forget to apply settings. | 676 | // Don't forget to apply settings. |
| 677 | system->HIDCore().DisableAllControllerConfiguration(); | 677 | system->HIDCore().DisableAllControllerConfiguration(); |
| 678 | system->ApplySettings(); | 678 | system->ApplySettings(); |
| 679 | config->Save(); | 679 | config->SaveAllValues(); |
| 680 | 680 | ||
| 681 | UpdateStatusButtons(); | 681 | UpdateStatusButtons(); |
| 682 | 682 | ||
| @@ -1047,7 +1047,12 @@ void GMainWindow::InitializeWidgets() { | |||
| 1047 | statusBar()->addPermanentWidget(label); | 1047 | statusBar()->addPermanentWidget(label); |
| 1048 | } | 1048 | } |
| 1049 | 1049 | ||
| 1050 | // TODO (flTobi): Add the widget when multiplayer is fully implemented | 1050 | firmware_label = new QLabel(); |
| 1051 | firmware_label->setObjectName(QStringLiteral("FirmwareLabel")); | ||
| 1052 | firmware_label->setVisible(false); | ||
| 1053 | firmware_label->setFocusPolicy(Qt::NoFocus); | ||
| 1054 | statusBar()->addPermanentWidget(firmware_label); | ||
| 1055 | |||
| 1051 | statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); | 1056 | statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); |
| 1052 | statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); | 1057 | statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); |
| 1053 | 1058 | ||
| @@ -1129,7 +1134,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 1129 | connect(aa_status_button, &QPushButton::customContextMenuRequested, | 1134 | connect(aa_status_button, &QPushButton::customContextMenuRequested, |
| 1130 | [this](const QPoint& menu_location) { | 1135 | [this](const QPoint& menu_location) { |
| 1131 | QMenu context_menu; | 1136 | QMenu context_menu; |
| 1132 | for (auto const& aa_text_pair : Config::anti_aliasing_texts_map) { | 1137 | for (auto const& aa_text_pair : ConfigurationShared::anti_aliasing_texts_map) { |
| 1133 | context_menu.addAction(aa_text_pair.second, [this, aa_text_pair] { | 1138 | context_menu.addAction(aa_text_pair.second, [this, aa_text_pair] { |
| 1134 | Settings::values.anti_aliasing.SetValue(aa_text_pair.first); | 1139 | Settings::values.anti_aliasing.SetValue(aa_text_pair.first); |
| 1135 | UpdateAAText(); | 1140 | UpdateAAText(); |
| @@ -1153,7 +1158,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 1153 | connect(filter_status_button, &QPushButton::customContextMenuRequested, | 1158 | connect(filter_status_button, &QPushButton::customContextMenuRequested, |
| 1154 | [this](const QPoint& menu_location) { | 1159 | [this](const QPoint& menu_location) { |
| 1155 | QMenu context_menu; | 1160 | QMenu context_menu; |
| 1156 | for (auto const& filter_text_pair : Config::scaling_filter_texts_map) { | 1161 | for (auto const& filter_text_pair : ConfigurationShared::scaling_filter_texts_map) { |
| 1157 | context_menu.addAction(filter_text_pair.second, [this, filter_text_pair] { | 1162 | context_menu.addAction(filter_text_pair.second, [this, filter_text_pair] { |
| 1158 | Settings::values.scaling_filter.SetValue(filter_text_pair.first); | 1163 | Settings::values.scaling_filter.SetValue(filter_text_pair.first); |
| 1159 | UpdateFilterText(); | 1164 | UpdateFilterText(); |
| @@ -1176,7 +1181,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 1176 | [this](const QPoint& menu_location) { | 1181 | [this](const QPoint& menu_location) { |
| 1177 | QMenu context_menu; | 1182 | QMenu context_menu; |
| 1178 | 1183 | ||
| 1179 | for (auto const& pair : Config::use_docked_mode_texts_map) { | 1184 | for (auto const& pair : ConfigurationShared::use_docked_mode_texts_map) { |
| 1180 | context_menu.addAction(pair.second, [this, &pair] { | 1185 | context_menu.addAction(pair.second, [this, &pair] { |
| 1181 | if (pair.first != Settings::values.use_docked_mode.GetValue()) { | 1186 | if (pair.first != Settings::values.use_docked_mode.GetValue()) { |
| 1182 | OnToggleDockedMode(); | 1187 | OnToggleDockedMode(); |
| @@ -1200,7 +1205,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 1200 | [this](const QPoint& menu_location) { | 1205 | [this](const QPoint& menu_location) { |
| 1201 | QMenu context_menu; | 1206 | QMenu context_menu; |
| 1202 | 1207 | ||
| 1203 | for (auto const& gpu_accuracy_pair : Config::gpu_accuracy_texts_map) { | 1208 | for (auto const& gpu_accuracy_pair : ConfigurationShared::gpu_accuracy_texts_map) { |
| 1204 | if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) { | 1209 | if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) { |
| 1205 | continue; | 1210 | continue; |
| 1206 | } | 1211 | } |
| @@ -1229,7 +1234,8 @@ void GMainWindow::InitializeWidgets() { | |||
| 1229 | [this](const QPoint& menu_location) { | 1234 | [this](const QPoint& menu_location) { |
| 1230 | QMenu context_menu; | 1235 | QMenu context_menu; |
| 1231 | 1236 | ||
| 1232 | for (auto const& renderer_backend_pair : Config::renderer_backend_texts_map) { | 1237 | for (auto const& renderer_backend_pair : |
| 1238 | ConfigurationShared::renderer_backend_texts_map) { | ||
| 1233 | if (renderer_backend_pair.first == Settings::RendererBackend::Null) { | 1239 | if (renderer_backend_pair.first == Settings::RendererBackend::Null) { |
| 1234 | continue; | 1240 | continue; |
| 1235 | } | 1241 | } |
| @@ -1294,16 +1300,17 @@ void GMainWindow::InitializeRecentFileMenuActions() { | |||
| 1294 | 1300 | ||
| 1295 | void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name, | 1301 | void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name, |
| 1296 | const bool tas_allowed) { | 1302 | const bool tas_allowed) { |
| 1297 | static const QString main_window = QStringLiteral("Main Window"); | 1303 | static const auto main_window = std::string("Main Window"); |
| 1298 | action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name)); | 1304 | action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name.toStdString())); |
| 1299 | action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name)); | 1305 | action->setShortcutContext( |
| 1306 | hotkey_registry.GetShortcutContext(main_window, action_name.toStdString())); | ||
| 1300 | action->setAutoRepeat(false); | 1307 | action->setAutoRepeat(false); |
| 1301 | 1308 | ||
| 1302 | this->addAction(action); | 1309 | this->addAction(action); |
| 1303 | 1310 | ||
| 1304 | auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | 1311 | auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); |
| 1305 | const auto* controller_hotkey = | 1312 | const auto* controller_hotkey = |
| 1306 | hotkey_registry.GetControllerHotkey(main_window, action_name, controller); | 1313 | hotkey_registry.GetControllerHotkey(main_window, action_name.toStdString(), controller); |
| 1307 | connect( | 1314 | connect( |
| 1308 | controller_hotkey, &ControllerShortcut::Activated, this, | 1315 | controller_hotkey, &ControllerShortcut::Activated, this, |
| 1309 | [action, tas_allowed, this] { | 1316 | [action, tas_allowed, this] { |
| @@ -1335,10 +1342,11 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1335 | 1342 | ||
| 1336 | static const QString main_window = QStringLiteral("Main Window"); | 1343 | static const QString main_window = QStringLiteral("Main Window"); |
| 1337 | const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) { | 1344 | const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) { |
| 1338 | const auto* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this); | 1345 | const auto* hotkey = |
| 1346 | hotkey_registry.GetHotkey(main_window.toStdString(), action_name.toStdString(), this); | ||
| 1339 | auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | 1347 | auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); |
| 1340 | const auto* controller_hotkey = | 1348 | const auto* controller_hotkey = hotkey_registry.GetControllerHotkey( |
| 1341 | hotkey_registry.GetControllerHotkey(main_window, action_name, controller); | 1349 | main_window.toStdString(), action_name.toStdString(), controller); |
| 1342 | connect(hotkey, &QShortcut::activated, this, function); | 1350 | connect(hotkey, &QShortcut::activated, this, function); |
| 1343 | connect(controller_hotkey, &ControllerShortcut::Activated, this, function, | 1351 | connect(controller_hotkey, &ControllerShortcut::Activated, this, function, |
| 1344 | Qt::QueuedConnection); | 1352 | Qt::QueuedConnection); |
| @@ -1366,14 +1374,6 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1366 | } | 1374 | } |
| 1367 | }); | 1375 | }); |
| 1368 | connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { | 1376 | connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { |
| 1369 | if (Settings::values.mouse_enabled) { | ||
| 1370 | Settings::values.mouse_panning = false; | ||
| 1371 | QMessageBox::warning( | ||
| 1372 | this, tr("Emulated mouse is enabled"), | ||
| 1373 | tr("Real mouse input and mouse panning are incompatible. Please disable the " | ||
| 1374 | "emulated mouse in input advanced settings to allow mouse panning.")); | ||
| 1375 | return; | ||
| 1376 | } | ||
| 1377 | Settings::values.mouse_panning = !Settings::values.mouse_panning; | 1377 | Settings::values.mouse_panning = !Settings::values.mouse_panning; |
| 1378 | if (Settings::values.mouse_panning) { | 1378 | if (Settings::values.mouse_panning) { |
| 1379 | render_window->installEventFilter(render_window); | 1379 | render_window->installEventFilter(render_window); |
| @@ -1918,7 +1918,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1918 | // Save configurations | 1918 | // Save configurations |
| 1919 | UpdateUISettings(); | 1919 | UpdateUISettings(); |
| 1920 | game_list->SaveInterfaceLayout(); | 1920 | game_list->SaveInterfaceLayout(); |
| 1921 | config->Save(); | 1921 | config->SaveAllValues(); |
| 1922 | 1922 | ||
| 1923 | u64 title_id{0}; | 1923 | u64 title_id{0}; |
| 1924 | 1924 | ||
| @@ -1936,7 +1936,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1936 | const auto config_file_name = title_id == 0 | 1936 | const auto config_file_name = title_id == 0 |
| 1937 | ? Common::FS::PathToUTF8String(file_path.filename()) | 1937 | ? Common::FS::PathToUTF8String(file_path.filename()) |
| 1938 | : fmt::format("{:016X}", title_id); | 1938 | : fmt::format("{:016X}", title_id); |
| 1939 | Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); | 1939 | QtConfig per_game_config(config_file_name, Config::ConfigType::PerGameConfig); |
| 1940 | system->HIDCore().ReloadInputDevices(); | 1940 | system->HIDCore().ReloadInputDevices(); |
| 1941 | system->ApplySettings(); | 1941 | system->ApplySettings(); |
| 1942 | } | 1942 | } |
| @@ -2122,6 +2122,10 @@ void GMainWindow::OnEmulationStopped() { | |||
| 2122 | 2122 | ||
| 2123 | discord_rpc->Update(); | 2123 | discord_rpc->Update(); |
| 2124 | 2124 | ||
| 2125 | #ifdef __unix__ | ||
| 2126 | Common::Linux::StopGamemode(); | ||
| 2127 | #endif | ||
| 2128 | |||
| 2125 | // The emulation is stopped, so closing the window or not does not matter anymore | 2129 | // The emulation is stopped, so closing the window or not does not matter anymore |
| 2126 | disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); | 2130 | disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); |
| 2127 | 2131 | ||
| @@ -2161,6 +2165,10 @@ void GMainWindow::OnEmulationStopped() { | |||
| 2161 | emu_frametime_label->setVisible(false); | 2165 | emu_frametime_label->setVisible(false); |
| 2162 | renderer_status_button->setEnabled(!UISettings::values.has_broken_vulkan); | 2166 | renderer_status_button->setEnabled(!UISettings::values.has_broken_vulkan); |
| 2163 | 2167 | ||
| 2168 | if (!firmware_label->text().isEmpty()) { | ||
| 2169 | firmware_label->setVisible(true); | ||
| 2170 | } | ||
| 2171 | |||
| 2164 | current_game_path.clear(); | 2172 | current_game_path.clear(); |
| 2165 | 2173 | ||
| 2166 | // When closing the game, destroy the GLWindow to clear the context after the game is closed | 2174 | // When closing the game, destroy the GLWindow to clear the context after the game is closed |
| @@ -3135,7 +3143,7 @@ void GMainWindow::OnGameListAddDirectory() { | |||
| 3135 | return; | 3143 | return; |
| 3136 | } | 3144 | } |
| 3137 | 3145 | ||
| 3138 | UISettings::GameDir game_dir{dir_path, false, true}; | 3146 | UISettings::GameDir game_dir{dir_path.toStdString(), false, true}; |
| 3139 | if (!UISettings::values.game_dirs.contains(game_dir)) { | 3147 | if (!UISettings::values.game_dirs.contains(game_dir)) { |
| 3140 | UISettings::values.game_dirs.append(game_dir); | 3148 | UISettings::values.game_dirs.append(game_dir); |
| 3141 | game_list->PopulateAsync(UISettings::values.game_dirs); | 3149 | game_list->PopulateAsync(UISettings::values.game_dirs); |
| @@ -3181,14 +3189,14 @@ void GMainWindow::OnMenuLoadFile() { | |||
| 3181 | "%1 is an identifier for the Switch executable file extensions.") | 3189 | "%1 is an identifier for the Switch executable file extensions.") |
| 3182 | .arg(extensions); | 3190 | .arg(extensions); |
| 3183 | const QString filename = QFileDialog::getOpenFileName( | 3191 | const QString filename = QFileDialog::getOpenFileName( |
| 3184 | this, tr("Load File"), UISettings::values.roms_path, file_filter); | 3192 | this, tr("Load File"), QString::fromStdString(UISettings::values.roms_path), file_filter); |
| 3185 | is_load_file_select_active = false; | 3193 | is_load_file_select_active = false; |
| 3186 | 3194 | ||
| 3187 | if (filename.isEmpty()) { | 3195 | if (filename.isEmpty()) { |
| 3188 | return; | 3196 | return; |
| 3189 | } | 3197 | } |
| 3190 | 3198 | ||
| 3191 | UISettings::values.roms_path = QFileInfo(filename).path(); | 3199 | UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); |
| 3192 | BootGame(filename); | 3200 | BootGame(filename); |
| 3193 | } | 3201 | } |
| 3194 | 3202 | ||
| @@ -3221,7 +3229,8 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 3221 | "Image (*.xci)"); | 3229 | "Image (*.xci)"); |
| 3222 | 3230 | ||
| 3223 | QStringList filenames = QFileDialog::getOpenFileNames( | 3231 | QStringList filenames = QFileDialog::getOpenFileNames( |
| 3224 | this, tr("Install Files"), UISettings::values.roms_path, file_filter); | 3232 | this, tr("Install Files"), QString::fromStdString(UISettings::values.roms_path), |
| 3233 | file_filter); | ||
| 3225 | 3234 | ||
| 3226 | if (filenames.isEmpty()) { | 3235 | if (filenames.isEmpty()) { |
| 3227 | return; | 3236 | return; |
| @@ -3239,7 +3248,7 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 3239 | } | 3248 | } |
| 3240 | 3249 | ||
| 3241 | // Save folder location of the first selected file | 3250 | // Save folder location of the first selected file |
| 3242 | UISettings::values.roms_path = QFileInfo(filenames[0]).path(); | 3251 | UISettings::values.roms_path = QFileInfo(filenames[0]).path().toStdString(); |
| 3243 | 3252 | ||
| 3244 | int remaining = filenames.size(); | 3253 | int remaining = filenames.size(); |
| 3245 | 3254 | ||
| @@ -3499,6 +3508,10 @@ void GMainWindow::OnStartGame() { | |||
| 3499 | play_time_manager->Start(); | 3508 | play_time_manager->Start(); |
| 3500 | 3509 | ||
| 3501 | discord_rpc->Update(); | 3510 | discord_rpc->Update(); |
| 3511 | |||
| 3512 | #ifdef __unix__ | ||
| 3513 | Common::Linux::StartGamemode(); | ||
| 3514 | #endif | ||
| 3502 | } | 3515 | } |
| 3503 | 3516 | ||
| 3504 | void GMainWindow::OnRestartGame() { | 3517 | void GMainWindow::OnRestartGame() { |
| @@ -3519,6 +3532,10 @@ void GMainWindow::OnPauseGame() { | |||
| 3519 | play_time_manager->Stop(); | 3532 | play_time_manager->Stop(); |
| 3520 | UpdateMenuState(); | 3533 | UpdateMenuState(); |
| 3521 | AllowOSSleep(); | 3534 | AllowOSSleep(); |
| 3535 | |||
| 3536 | #ifdef __unix__ | ||
| 3537 | Common::Linux::StopGamemode(); | ||
| 3538 | #endif | ||
| 3522 | } | 3539 | } |
| 3523 | 3540 | ||
| 3524 | void GMainWindow::OnPauseContinueGame() { | 3541 | void GMainWindow::OnPauseContinueGame() { |
| @@ -3584,7 +3601,7 @@ void GMainWindow::OnExit() { | |||
| 3584 | 3601 | ||
| 3585 | void GMainWindow::OnSaveConfig() { | 3602 | void GMainWindow::OnSaveConfig() { |
| 3586 | system->ApplySettings(); | 3603 | system->ApplySettings(); |
| 3587 | config->Save(); | 3604 | config->SaveAllValues(); |
| 3588 | } | 3605 | } |
| 3589 | 3606 | ||
| 3590 | void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { | 3607 | void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { |
| @@ -3800,6 +3817,9 @@ void GMainWindow::OnConfigure() { | |||
| 3800 | const auto old_theme = UISettings::values.theme; | 3817 | const auto old_theme = UISettings::values.theme; |
| 3801 | const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue(); | 3818 | const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue(); |
| 3802 | const auto old_language_index = Settings::values.language_index.GetValue(); | 3819 | const auto old_language_index = Settings::values.language_index.GetValue(); |
| 3820 | #ifdef __unix__ | ||
| 3821 | const bool old_gamemode = Settings::values.enable_gamemode.GetValue(); | ||
| 3822 | #endif | ||
| 3803 | 3823 | ||
| 3804 | Settings::SetConfiguringGlobal(true); | 3824 | Settings::SetConfiguringGlobal(true); |
| 3805 | ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), | 3825 | ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), |
| @@ -3840,7 +3860,7 @@ void GMainWindow::OnConfigure() { | |||
| 3840 | 3860 | ||
| 3841 | Settings::values.disabled_addons.clear(); | 3861 | Settings::values.disabled_addons.clear(); |
| 3842 | 3862 | ||
| 3843 | config = std::make_unique<Config>(); | 3863 | config = std::make_unique<QtConfig>(); |
| 3844 | UISettings::values.reset_to_defaults = false; | 3864 | UISettings::values.reset_to_defaults = false; |
| 3845 | 3865 | ||
| 3846 | UISettings::values.game_dirs = std::move(old_game_dirs); | 3866 | UISettings::values.game_dirs = std::move(old_game_dirs); |
| @@ -3861,6 +3881,11 @@ void GMainWindow::OnConfigure() { | |||
| 3861 | if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) { | 3881 | if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) { |
| 3862 | SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); | 3882 | SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); |
| 3863 | } | 3883 | } |
| 3884 | #ifdef __unix__ | ||
| 3885 | if (Settings::values.enable_gamemode.GetValue() != old_gamemode) { | ||
| 3886 | SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue()); | ||
| 3887 | } | ||
| 3888 | #endif | ||
| 3864 | 3889 | ||
| 3865 | if (!multiplayer_state->IsHostingPublicRoom()) { | 3890 | if (!multiplayer_state->IsHostingPublicRoom()) { |
| 3866 | multiplayer_state->UpdateCredentials(); | 3891 | multiplayer_state->UpdateCredentials(); |
| @@ -3875,7 +3900,7 @@ void GMainWindow::OnConfigure() { | |||
| 3875 | 3900 | ||
| 3876 | UISettings::values.configuration_applied = false; | 3901 | UISettings::values.configuration_applied = false; |
| 3877 | 3902 | ||
| 3878 | config->Save(); | 3903 | config->SaveAllValues(); |
| 3879 | 3904 | ||
| 3880 | if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { | 3905 | if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { |
| 3881 | render_window->installEventFilter(render_window); | 3906 | render_window->installEventFilter(render_window); |
| @@ -4091,7 +4116,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file | |||
| 4091 | UISettings::values.configuration_applied = false; | 4116 | UISettings::values.configuration_applied = false; |
| 4092 | 4117 | ||
| 4093 | if (!is_powered_on) { | 4118 | if (!is_powered_on) { |
| 4094 | config->Save(); | 4119 | config->SaveAllValues(); |
| 4095 | } | 4120 | } |
| 4096 | } | 4121 | } |
| 4097 | 4122 | ||
| @@ -4324,7 +4349,7 @@ void GMainWindow::OnAlbum() { | |||
| 4324 | system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); | 4349 | system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); |
| 4325 | 4350 | ||
| 4326 | const auto filename = QString::fromStdString(album_nca->GetFullPath()); | 4351 | const auto filename = QString::fromStdString(album_nca->GetFullPath()); |
| 4327 | UISettings::values.roms_path = QFileInfo(filename).path(); | 4352 | UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); |
| 4328 | BootGame(filename, AlbumId); | 4353 | BootGame(filename, AlbumId); |
| 4329 | } | 4354 | } |
| 4330 | 4355 | ||
| @@ -4348,7 +4373,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { | |||
| 4348 | system->GetAppletManager().SetCabinetMode(mode); | 4373 | system->GetAppletManager().SetCabinetMode(mode); |
| 4349 | 4374 | ||
| 4350 | const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); | 4375 | const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); |
| 4351 | UISettings::values.roms_path = QFileInfo(filename).path(); | 4376 | UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); |
| 4352 | BootGame(filename, CabinetId); | 4377 | BootGame(filename, CabinetId); |
| 4353 | } | 4378 | } |
| 4354 | 4379 | ||
| @@ -4371,7 +4396,7 @@ void GMainWindow::OnMiiEdit() { | |||
| 4371 | system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); | 4396 | system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); |
| 4372 | 4397 | ||
| 4373 | const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); | 4398 | const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); |
| 4374 | UISettings::values.roms_path = QFileInfo(filename).path(); | 4399 | UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); |
| 4375 | BootGame(filename, MiiEditId); | 4400 | BootGame(filename, MiiEditId); |
| 4376 | } | 4401 | } |
| 4377 | 4402 | ||
| @@ -4396,7 +4421,7 @@ void GMainWindow::OnOpenControllerMenu() { | |||
| 4396 | system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); | 4421 | system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); |
| 4397 | 4422 | ||
| 4398 | const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); | 4423 | const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); |
| 4399 | UISettings::values.roms_path = QFileInfo(filename).path(); | 4424 | UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); |
| 4400 | BootGame(filename, ControllerAppletId); | 4425 | BootGame(filename, ControllerAppletId); |
| 4401 | } | 4426 | } |
| 4402 | 4427 | ||
| @@ -4586,11 +4611,13 @@ void GMainWindow::UpdateStatusBar() { | |||
| 4586 | emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); | 4611 | emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); |
| 4587 | game_fps_label->setVisible(true); | 4612 | game_fps_label->setVisible(true); |
| 4588 | emu_frametime_label->setVisible(true); | 4613 | emu_frametime_label->setVisible(true); |
| 4614 | firmware_label->setVisible(false); | ||
| 4589 | } | 4615 | } |
| 4590 | 4616 | ||
| 4591 | void GMainWindow::UpdateGPUAccuracyButton() { | 4617 | void GMainWindow::UpdateGPUAccuracyButton() { |
| 4592 | const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue(); | 4618 | const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue(); |
| 4593 | const auto gpu_accuracy_text = Config::gpu_accuracy_texts_map.find(gpu_accuracy)->second; | 4619 | const auto gpu_accuracy_text = |
| 4620 | ConfigurationShared::gpu_accuracy_texts_map.find(gpu_accuracy)->second; | ||
| 4594 | gpu_accuracy_button->setText(gpu_accuracy_text.toUpper()); | 4621 | gpu_accuracy_button->setText(gpu_accuracy_text.toUpper()); |
| 4595 | gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal); | 4622 | gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal); |
| 4596 | } | 4623 | } |
| @@ -4599,31 +4626,32 @@ void GMainWindow::UpdateDockedButton() { | |||
| 4599 | const auto console_mode = Settings::values.use_docked_mode.GetValue(); | 4626 | const auto console_mode = Settings::values.use_docked_mode.GetValue(); |
| 4600 | dock_status_button->setChecked(Settings::IsDockedMode()); | 4627 | dock_status_button->setChecked(Settings::IsDockedMode()); |
| 4601 | dock_status_button->setText( | 4628 | dock_status_button->setText( |
| 4602 | Config::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); | 4629 | ConfigurationShared::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); |
| 4603 | } | 4630 | } |
| 4604 | 4631 | ||
| 4605 | void GMainWindow::UpdateAPIText() { | 4632 | void GMainWindow::UpdateAPIText() { |
| 4606 | const auto api = Settings::values.renderer_backend.GetValue(); | 4633 | const auto api = Settings::values.renderer_backend.GetValue(); |
| 4607 | const auto renderer_status_text = Config::renderer_backend_texts_map.find(api)->second; | 4634 | const auto renderer_status_text = |
| 4635 | ConfigurationShared::renderer_backend_texts_map.find(api)->second; | ||
| 4608 | renderer_status_button->setText( | 4636 | renderer_status_button->setText( |
| 4609 | api == Settings::RendererBackend::OpenGL | 4637 | api == Settings::RendererBackend::OpenGL |
| 4610 | ? tr("%1 %2").arg( | 4638 | ? tr("%1 %2").arg(renderer_status_text.toUpper(), |
| 4611 | renderer_status_text.toUpper(), | 4639 | ConfigurationShared::shader_backend_texts_map |
| 4612 | Config::shader_backend_texts_map.find(Settings::values.shader_backend.GetValue()) | 4640 | .find(Settings::values.shader_backend.GetValue()) |
| 4613 | ->second) | 4641 | ->second) |
| 4614 | : renderer_status_text.toUpper()); | 4642 | : renderer_status_text.toUpper()); |
| 4615 | } | 4643 | } |
| 4616 | 4644 | ||
| 4617 | void GMainWindow::UpdateFilterText() { | 4645 | void GMainWindow::UpdateFilterText() { |
| 4618 | const auto filter = Settings::values.scaling_filter.GetValue(); | 4646 | const auto filter = Settings::values.scaling_filter.GetValue(); |
| 4619 | const auto filter_text = Config::scaling_filter_texts_map.find(filter)->second; | 4647 | const auto filter_text = ConfigurationShared::scaling_filter_texts_map.find(filter)->second; |
| 4620 | filter_status_button->setText(filter == Settings::ScalingFilter::Fsr ? tr("FSR") | 4648 | filter_status_button->setText(filter == Settings::ScalingFilter::Fsr ? tr("FSR") |
| 4621 | : filter_text.toUpper()); | 4649 | : filter_text.toUpper()); |
| 4622 | } | 4650 | } |
| 4623 | 4651 | ||
| 4624 | void GMainWindow::UpdateAAText() { | 4652 | void GMainWindow::UpdateAAText() { |
| 4625 | const auto aa_mode = Settings::values.anti_aliasing.GetValue(); | 4653 | const auto aa_mode = Settings::values.anti_aliasing.GetValue(); |
| 4626 | const auto aa_text = Config::anti_aliasing_texts_map.find(aa_mode)->second; | 4654 | const auto aa_text = ConfigurationShared::anti_aliasing_texts_map.find(aa_mode)->second; |
| 4627 | aa_status_button->setText(aa_mode == Settings::AntiAliasing::None | 4655 | aa_status_button->setText(aa_mode == Settings::AntiAliasing::None |
| 4628 | ? QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "NO AA")) | 4656 | ? QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "NO AA")) |
| 4629 | : aa_text.toUpper()); | 4657 | : aa_text.toUpper()); |
| @@ -4693,26 +4721,10 @@ void GMainWindow::ShowMouseCursor() { | |||
| 4693 | } | 4721 | } |
| 4694 | } | 4722 | } |
| 4695 | 4723 | ||
| 4696 | void GMainWindow::CenterMouseCursor() { | ||
| 4697 | if (emu_thread == nullptr || !Settings::values.mouse_panning) { | ||
| 4698 | mouse_center_timer.stop(); | ||
| 4699 | return; | ||
| 4700 | } | ||
| 4701 | if (!this->isActiveWindow()) { | ||
| 4702 | mouse_center_timer.stop(); | ||
| 4703 | return; | ||
| 4704 | } | ||
| 4705 | const int center_x = render_window->width() / 2; | ||
| 4706 | const int center_y = render_window->height() / 2; | ||
| 4707 | |||
| 4708 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); | ||
| 4709 | } | ||
| 4710 | |||
| 4711 | void GMainWindow::OnMouseActivity() { | 4724 | void GMainWindow::OnMouseActivity() { |
| 4712 | if (!Settings::values.mouse_panning) { | 4725 | if (!Settings::values.mouse_panning) { |
| 4713 | ShowMouseCursor(); | 4726 | ShowMouseCursor(); |
| 4714 | } | 4727 | } |
| 4715 | mouse_center_timer.stop(); | ||
| 4716 | } | 4728 | } |
| 4717 | 4729 | ||
| 4718 | void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | 4730 | void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { |
| @@ -4803,6 +4815,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | |||
| 4803 | "games.")); | 4815 | "games.")); |
| 4804 | } | 4816 | } |
| 4805 | 4817 | ||
| 4818 | SetFirmwareVersion(); | ||
| 4819 | |||
| 4806 | if (behavior == ReinitializeKeyBehavior::Warning) { | 4820 | if (behavior == ReinitializeKeyBehavior::Warning) { |
| 4807 | game_list->PopulateAsync(UISettings::values.game_dirs); | 4821 | game_list->PopulateAsync(UISettings::values.game_dirs); |
| 4808 | } | 4822 | } |
| @@ -4830,7 +4844,7 @@ bool GMainWindow::CheckSystemArchiveDecryption() { | |||
| 4830 | } | 4844 | } |
| 4831 | 4845 | ||
| 4832 | bool GMainWindow::CheckFirmwarePresence() { | 4846 | bool GMainWindow::CheckFirmwarePresence() { |
| 4833 | constexpr u64 MiiEditId = 0x0100000000001009ull; | 4847 | constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); |
| 4834 | 4848 | ||
| 4835 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); | 4849 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); |
| 4836 | if (!bis_system) { | 4850 | if (!bis_system) { |
| @@ -4845,6 +4859,28 @@ bool GMainWindow::CheckFirmwarePresence() { | |||
| 4845 | return true; | 4859 | return true; |
| 4846 | } | 4860 | } |
| 4847 | 4861 | ||
| 4862 | void GMainWindow::SetFirmwareVersion() { | ||
| 4863 | Service::Set::FirmwareVersionFormat firmware_data{}; | ||
| 4864 | const auto result = Service::Set::GetFirmwareVersionImpl( | ||
| 4865 | firmware_data, *system, Service::Set::GetFirmwareVersionType::Version2); | ||
| 4866 | |||
| 4867 | if (result.IsError() || !CheckFirmwarePresence()) { | ||
| 4868 | LOG_INFO(Frontend, "Installed firmware: No firmware available"); | ||
| 4869 | firmware_label->setVisible(false); | ||
| 4870 | return; | ||
| 4871 | } | ||
| 4872 | |||
| 4873 | firmware_label->setVisible(true); | ||
| 4874 | |||
| 4875 | const std::string display_version(firmware_data.display_version.data()); | ||
| 4876 | const std::string display_title(firmware_data.display_title.data()); | ||
| 4877 | |||
| 4878 | LOG_INFO(Frontend, "Installed firmware: {}", display_title); | ||
| 4879 | |||
| 4880 | firmware_label->setText(QString::fromStdString(display_version)); | ||
| 4881 | firmware_label->setToolTip(QString::fromStdString(display_title)); | ||
| 4882 | } | ||
| 4883 | |||
| 4848 | bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id, | 4884 | bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id, |
| 4849 | u64* selected_title_id, u8* selected_content_record_type) { | 4885 | u64* selected_title_id, u8* selected_content_record_type) { |
| 4850 | using ContentInfo = std::tuple<u64, FileSys::TitleType, FileSys::ContentRecordType>; | 4886 | using ContentInfo = std::tuple<u64, FileSys::TitleType, FileSys::ContentRecordType>; |
| @@ -4926,6 +4962,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { | |||
| 4926 | 4962 | ||
| 4927 | UpdateUISettings(); | 4963 | UpdateUISettings(); |
| 4928 | game_list->SaveInterfaceLayout(); | 4964 | game_list->SaveInterfaceLayout(); |
| 4965 | UISettings::SaveWindowState(); | ||
| 4929 | hotkey_registry.SaveHotkeys(); | 4966 | hotkey_registry.SaveHotkeys(); |
| 4930 | 4967 | ||
| 4931 | // Unload controllers early | 4968 | // Unload controllers early |
| @@ -4988,22 +5025,6 @@ void GMainWindow::dragMoveEvent(QDragMoveEvent* event) { | |||
| 4988 | AcceptDropEvent(event); | 5025 | AcceptDropEvent(event); |
| 4989 | } | 5026 | } |
| 4990 | 5027 | ||
| 4991 | void GMainWindow::leaveEvent(QEvent* event) { | ||
| 4992 | if (Settings::values.mouse_panning) { | ||
| 4993 | const QRect& rect = geometry(); | ||
| 4994 | QPoint position = QCursor::pos(); | ||
| 4995 | |||
| 4996 | qint32 x = qBound(rect.left(), position.x(), rect.right()); | ||
| 4997 | qint32 y = qBound(rect.top(), position.y(), rect.bottom()); | ||
| 4998 | // Only start the timer if the mouse has left the window bound. | ||
| 4999 | // The leave event is also triggered when the window looses focus. | ||
| 5000 | if (x != position.x() || y != position.y()) { | ||
| 5001 | mouse_center_timer.start(); | ||
| 5002 | } | ||
| 5003 | event->accept(); | ||
| 5004 | } | ||
| 5005 | } | ||
| 5006 | |||
| 5007 | bool GMainWindow::ConfirmChangeGame() { | 5028 | bool GMainWindow::ConfirmChangeGame() { |
| 5008 | if (emu_thread == nullptr) | 5029 | if (emu_thread == nullptr) |
| 5009 | return true; | 5030 | return true; |
| @@ -5080,9 +5101,9 @@ static void AdjustLinkColor() { | |||
| 5080 | } | 5101 | } |
| 5081 | 5102 | ||
| 5082 | void GMainWindow::UpdateUITheme() { | 5103 | void GMainWindow::UpdateUITheme() { |
| 5083 | const QString default_theme = | 5104 | const QString default_theme = QString::fromUtf8( |
| 5084 | QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second); | 5105 | UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second); |
| 5085 | QString current_theme = UISettings::values.theme; | 5106 | QString current_theme = QString::fromStdString(UISettings::values.theme); |
| 5086 | 5107 | ||
| 5087 | if (current_theme.isEmpty()) { | 5108 | if (current_theme.isEmpty()) { |
| 5088 | current_theme = default_theme; | 5109 | current_theme = default_theme; |
| @@ -5110,7 +5131,7 @@ void GMainWindow::UpdateUITheme() { | |||
| 5110 | QFile f(theme_uri); | 5131 | QFile f(theme_uri); |
| 5111 | if (!f.open(QFile::ReadOnly | QFile::Text)) { | 5132 | if (!f.open(QFile::ReadOnly | QFile::Text)) { |
| 5112 | LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme", | 5133 | LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme", |
| 5113 | UISettings::values.theme.toStdString()); | 5134 | UISettings::values.theme); |
| 5114 | current_theme = default_theme; | 5135 | current_theme = default_theme; |
| 5115 | } | 5136 | } |
| 5116 | } | 5137 | } |
| @@ -5123,7 +5144,7 @@ void GMainWindow::UpdateUITheme() { | |||
| 5123 | setStyleSheet(ts.readAll()); | 5144 | setStyleSheet(ts.readAll()); |
| 5124 | } else { | 5145 | } else { |
| 5125 | LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found", | 5146 | LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found", |
| 5126 | UISettings::values.theme.toStdString()); | 5147 | UISettings::values.theme); |
| 5127 | qApp->setStyleSheet({}); | 5148 | qApp->setStyleSheet({}); |
| 5128 | setStyleSheet({}); | 5149 | setStyleSheet({}); |
| 5129 | } | 5150 | } |
| @@ -5132,27 +5153,28 @@ void GMainWindow::UpdateUITheme() { | |||
| 5132 | void GMainWindow::LoadTranslation() { | 5153 | void GMainWindow::LoadTranslation() { |
| 5133 | bool loaded; | 5154 | bool loaded; |
| 5134 | 5155 | ||
| 5135 | if (UISettings::values.language.isEmpty()) { | 5156 | if (UISettings::values.language.empty()) { |
| 5136 | // If the selected language is empty, use system locale | 5157 | // If the selected language is empty, use system locale |
| 5137 | loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/")); | 5158 | loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/")); |
| 5138 | } else { | 5159 | } else { |
| 5139 | // Otherwise load from the specified file | 5160 | // Otherwise load from the specified file |
| 5140 | loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/")); | 5161 | loaded = translator.load(QString::fromStdString(UISettings::values.language), |
| 5162 | QStringLiteral(":/languages/")); | ||
| 5141 | } | 5163 | } |
| 5142 | 5164 | ||
| 5143 | if (loaded) { | 5165 | if (loaded) { |
| 5144 | qApp->installTranslator(&translator); | 5166 | qApp->installTranslator(&translator); |
| 5145 | } else { | 5167 | } else { |
| 5146 | UISettings::values.language = QStringLiteral("en"); | 5168 | UISettings::values.language = std::string("en"); |
| 5147 | } | 5169 | } |
| 5148 | } | 5170 | } |
| 5149 | 5171 | ||
| 5150 | void GMainWindow::OnLanguageChanged(const QString& locale) { | 5172 | void GMainWindow::OnLanguageChanged(const QString& locale) { |
| 5151 | if (UISettings::values.language != QStringLiteral("en")) { | 5173 | if (UISettings::values.language != std::string("en")) { |
| 5152 | qApp->removeTranslator(&translator); | 5174 | qApp->removeTranslator(&translator); |
| 5153 | } | 5175 | } |
| 5154 | 5176 | ||
| 5155 | UISettings::values.language = locale; | 5177 | UISettings::values.language = locale.toStdString(); |
| 5156 | LoadTranslation(); | 5178 | LoadTranslation(); |
| 5157 | ui->retranslateUi(this); | 5179 | ui->retranslateUi(this); |
| 5158 | multiplayer_state->retranslateUi(); | 5180 | multiplayer_state->retranslateUi(); |
| @@ -5172,13 +5194,21 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { | |||
| 5172 | discord_rpc->Update(); | 5194 | discord_rpc->Update(); |
| 5173 | } | 5195 | } |
| 5174 | 5196 | ||
| 5197 | #ifdef __unix__ | ||
| 5198 | void GMainWindow::SetGamemodeEnabled(bool state) { | ||
| 5199 | if (emulation_running) { | ||
| 5200 | Common::Linux::SetGamemodeState(state); | ||
| 5201 | } | ||
| 5202 | } | ||
| 5203 | #endif | ||
| 5204 | |||
| 5175 | void GMainWindow::changeEvent(QEvent* event) { | 5205 | void GMainWindow::changeEvent(QEvent* event) { |
| 5176 | #ifdef __unix__ | 5206 | #ifdef __unix__ |
| 5177 | // PaletteChange event appears to only reach so far into the GUI, explicitly asking to | 5207 | // PaletteChange event appears to only reach so far into the GUI, explicitly asking to |
| 5178 | // UpdateUITheme is a decent work around | 5208 | // UpdateUITheme is a decent work around |
| 5179 | if (event->type() == QEvent::PaletteChange) { | 5209 | if (event->type() == QEvent::PaletteChange) { |
| 5180 | const QPalette test_palette(qApp->palette()); | 5210 | const QPalette test_palette(qApp->palette()); |
| 5181 | const QString current_theme = UISettings::values.theme; | 5211 | const QString current_theme = QString::fromStdString(UISettings::values.theme); |
| 5182 | // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too | 5212 | // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too |
| 5183 | static QColor last_window_color; | 5213 | static QColor last_window_color; |
| 5184 | const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); | 5214 | const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); |
| @@ -5272,7 +5302,8 @@ static void SetHighDPIAttributes() { | |||
| 5272 | } | 5302 | } |
| 5273 | 5303 | ||
| 5274 | int main(int argc, char* argv[]) { | 5304 | int main(int argc, char* argv[]) { |
| 5275 | std::unique_ptr<Config> config = std::make_unique<Config>(); | 5305 | std::unique_ptr<QtConfig> config = std::make_unique<QtConfig>(); |
| 5306 | UISettings::RestoreWindowState(config); | ||
| 5276 | bool has_broken_vulkan = false; | 5307 | bool has_broken_vulkan = false; |
| 5277 | bool is_child = false; | 5308 | bool is_child = false; |
| 5278 | if (CheckEnvVars(&is_child)) { | 5309 | if (CheckEnvVars(&is_child)) { |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 49ee1e1d2..530e445f9 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | #include "common/announce_multiplayer_room.h" | 16 | #include "common/announce_multiplayer_room.h" |
| 17 | #include "common/common_types.h" | 17 | #include "common/common_types.h" |
| 18 | #include "configuration/qt_config.h" | ||
| 18 | #include "input_common/drivers/tas_input.h" | 19 | #include "input_common/drivers/tas_input.h" |
| 19 | #include "yuzu/compatibility_list.h" | 20 | #include "yuzu/compatibility_list.h" |
| 20 | #include "yuzu/hotkeys.h" | 21 | #include "yuzu/hotkeys.h" |
| @@ -26,7 +27,7 @@ | |||
| 26 | #include <QtDBus/QtDBus> | 27 | #include <QtDBus/QtDBus> |
| 27 | #endif | 28 | #endif |
| 28 | 29 | ||
| 29 | class Config; | 30 | class QtConfig; |
| 30 | class ClickableLabel; | 31 | class ClickableLabel; |
| 31 | class EmuThread; | 32 | class EmuThread; |
| 32 | class GameList; | 33 | class GameList; |
| @@ -185,7 +186,7 @@ class GMainWindow : public QMainWindow { | |||
| 185 | public: | 186 | public: |
| 186 | void filterBarSetChecked(bool state); | 187 | void filterBarSetChecked(bool state); |
| 187 | void UpdateUITheme(); | 188 | void UpdateUITheme(); |
| 188 | explicit GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan); | 189 | explicit GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan); |
| 189 | ~GMainWindow() override; | 190 | ~GMainWindow() override; |
| 190 | 191 | ||
| 191 | bool DropAction(QDropEvent* event); | 192 | bool DropAction(QDropEvent* event); |
| @@ -339,6 +340,7 @@ private: | |||
| 339 | void SetupSigInterrupts(); | 340 | void SetupSigInterrupts(); |
| 340 | static void HandleSigInterrupt(int); | 341 | static void HandleSigInterrupt(int); |
| 341 | void OnSigInterruptNotifierActivated(); | 342 | void OnSigInterruptNotifierActivated(); |
| 343 | void SetGamemodeEnabled(bool state); | ||
| 342 | #endif | 344 | #endif |
| 343 | 345 | ||
| 344 | private slots: | 346 | private slots: |
| @@ -450,13 +452,13 @@ private: | |||
| 450 | void UpdateInputDrivers(); | 452 | void UpdateInputDrivers(); |
| 451 | void HideMouseCursor(); | 453 | void HideMouseCursor(); |
| 452 | void ShowMouseCursor(); | 454 | void ShowMouseCursor(); |
| 453 | void CenterMouseCursor(); | ||
| 454 | void OpenURL(const QUrl& url); | 455 | void OpenURL(const QUrl& url); |
| 455 | void LoadTranslation(); | 456 | void LoadTranslation(); |
| 456 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); | 457 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); |
| 457 | bool CheckDarkMode(); | 458 | bool CheckDarkMode(); |
| 458 | bool CheckSystemArchiveDecryption(); | 459 | bool CheckSystemArchiveDecryption(); |
| 459 | bool CheckFirmwarePresence(); | 460 | bool CheckFirmwarePresence(); |
| 461 | void SetFirmwareVersion(); | ||
| 460 | void ConfigureFilesystemProvider(const std::string& filepath); | 462 | void ConfigureFilesystemProvider(const std::string& filepath); |
| 461 | /** | 463 | /** |
| 462 | * Open (or not) the right confirm dialog based on current setting and game exit lock | 464 | * Open (or not) the right confirm dialog based on current setting and game exit lock |
| @@ -511,6 +513,7 @@ private: | |||
| 511 | QLabel* game_fps_label = nullptr; | 513 | QLabel* game_fps_label = nullptr; |
| 512 | QLabel* emu_frametime_label = nullptr; | 514 | QLabel* emu_frametime_label = nullptr; |
| 513 | QLabel* tas_label = nullptr; | 515 | QLabel* tas_label = nullptr; |
| 516 | QLabel* firmware_label = nullptr; | ||
| 514 | QPushButton* gpu_accuracy_button = nullptr; | 517 | QPushButton* gpu_accuracy_button = nullptr; |
| 515 | QPushButton* renderer_status_button = nullptr; | 518 | QPushButton* renderer_status_button = nullptr; |
| 516 | QPushButton* dock_status_button = nullptr; | 519 | QPushButton* dock_status_button = nullptr; |
| @@ -521,7 +524,7 @@ private: | |||
| 521 | QSlider* volume_slider = nullptr; | 524 | QSlider* volume_slider = nullptr; |
| 522 | QTimer status_bar_update_timer; | 525 | QTimer status_bar_update_timer; |
| 523 | 526 | ||
| 524 | std::unique_ptr<Config> config; | 527 | std::unique_ptr<QtConfig> config; |
| 525 | 528 | ||
| 526 | // Whether emulation is currently running in yuzu. | 529 | // Whether emulation is currently running in yuzu. |
| 527 | bool emulation_running = false; | 530 | bool emulation_running = false; |
| @@ -532,7 +535,6 @@ private: | |||
| 532 | bool auto_paused = false; | 535 | bool auto_paused = false; |
| 533 | bool auto_muted = false; | 536 | bool auto_muted = false; |
| 534 | QTimer mouse_hide_timer; | 537 | QTimer mouse_hide_timer; |
| 535 | QTimer mouse_center_timer; | ||
| 536 | QTimer update_input_timer; | 538 | QTimer update_input_timer; |
| 537 | 539 | ||
| 538 | QString startup_icon_theme; | 540 | QString startup_icon_theme; |
| @@ -589,5 +591,4 @@ protected: | |||
| 589 | void dropEvent(QDropEvent* event) override; | 591 | void dropEvent(QDropEvent* event) override; |
| 590 | void dragEnterEvent(QDragEnterEvent* event) override; | 592 | void dragEnterEvent(QDragEnterEvent* event) override; |
| 591 | void dragMoveEvent(QDragMoveEvent* event) override; | 593 | void dragMoveEvent(QDragMoveEvent* event) override; |
| 592 | void leaveEvent(QEvent* event) override; | ||
| 593 | }; | 594 | }; |
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index 1c833767b..7bb7e95af 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project | 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <QSettings> | ||
| 5 | #include "common/fs/fs.h" | ||
| 6 | #include "common/fs/path_util.h" | ||
| 4 | #include "yuzu/uisettings.h" | 7 | #include "yuzu/uisettings.h" |
| 5 | 8 | ||
| 6 | #ifndef CANNOT_EXPLICITLY_INSTANTIATE | 9 | #ifndef CANNOT_EXPLICITLY_INSTANTIATE |
| @@ -15,6 +18,8 @@ template class Setting<unsigned long long>; | |||
| 15 | } // namespace Settings | 18 | } // namespace Settings |
| 16 | #endif | 19 | #endif |
| 17 | 20 | ||
| 21 | namespace FS = Common::FS; | ||
| 22 | |||
| 18 | namespace UISettings { | 23 | namespace UISettings { |
| 19 | 24 | ||
| 20 | const Themes themes{{ | 25 | const Themes themes{{ |
| @@ -28,10 +33,8 @@ const Themes themes{{ | |||
| 28 | 33 | ||
| 29 | bool IsDarkTheme() { | 34 | bool IsDarkTheme() { |
| 30 | const auto& theme = UISettings::values.theme; | 35 | const auto& theme = UISettings::values.theme; |
| 31 | return theme == QStringLiteral("qdarkstyle") || | 36 | return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || |
| 32 | theme == QStringLiteral("qdarkstyle_midnight_blue") || | 37 | theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); |
| 33 | theme == QStringLiteral("colorful_dark") || | ||
| 34 | theme == QStringLiteral("colorful_midnight_blue"); | ||
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | Values values = {}; | 40 | Values values = {}; |
| @@ -52,4 +55,58 @@ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) { | |||
| 52 | return height * 16 / 9; | 55 | return height * 16 / 9; |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 58 | void SaveWindowState() { | ||
| 59 | const auto window_state_config_loc = | ||
| 60 | FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini"); | ||
| 61 | |||
| 62 | void(FS::CreateParentDir(window_state_config_loc)); | ||
| 63 | QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); | ||
| 64 | |||
| 65 | config.setValue(QStringLiteral("geometry"), values.geometry); | ||
| 66 | config.setValue(QStringLiteral("state"), values.state); | ||
| 67 | config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry); | ||
| 68 | config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state); | ||
| 69 | config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry); | ||
| 70 | |||
| 71 | config.sync(); | ||
| 72 | } | ||
| 73 | |||
| 74 | void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig) { | ||
| 75 | const auto window_state_config_loc = | ||
| 76 | FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini"); | ||
| 77 | |||
| 78 | // Migrate window state from old location | ||
| 79 | if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) { | ||
| 80 | const auto config_loc = | ||
| 81 | FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "qt-config.ini"); | ||
| 82 | QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat); | ||
| 83 | |||
| 84 | config.beginGroup(QStringLiteral("UI")); | ||
| 85 | config.beginGroup(QStringLiteral("UILayout")); | ||
| 86 | values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); | ||
| 87 | values.state = config.value(QStringLiteral("state")).toByteArray(); | ||
| 88 | values.renderwindow_geometry = | ||
| 89 | config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); | ||
| 90 | values.gamelist_header_state = | ||
| 91 | config.value(QStringLiteral("gameListHeaderState")).toByteArray(); | ||
| 92 | values.microprofile_geometry = | ||
| 93 | config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); | ||
| 94 | config.endGroup(); | ||
| 95 | config.endGroup(); | ||
| 96 | return; | ||
| 97 | } | ||
| 98 | |||
| 99 | void(FS::CreateParentDir(window_state_config_loc)); | ||
| 100 | const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); | ||
| 101 | |||
| 102 | values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); | ||
| 103 | values.state = config.value(QStringLiteral("state")).toByteArray(); | ||
| 104 | values.renderwindow_geometry = | ||
| 105 | config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); | ||
| 106 | values.gamelist_header_state = | ||
| 107 | config.value(QStringLiteral("gameListHeaderState")).toByteArray(); | ||
| 108 | values.microprofile_geometry = | ||
| 109 | config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); | ||
| 110 | } | ||
| 111 | |||
| 55 | } // namespace UISettings | 112 | } // namespace UISettings |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 3485a6347..549a39e1b 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "common/settings.h" | 15 | #include "common/settings.h" |
| 16 | #include "common/settings_enums.h" | 16 | #include "common/settings_enums.h" |
| 17 | #include "configuration/qt_config.h" | ||
| 17 | 18 | ||
| 18 | using Settings::Category; | 19 | using Settings::Category; |
| 19 | using Settings::ConfirmStop; | 20 | using Settings::ConfirmStop; |
| @@ -37,15 +38,15 @@ namespace UISettings { | |||
| 37 | bool IsDarkTheme(); | 38 | bool IsDarkTheme(); |
| 38 | 39 | ||
| 39 | struct ContextualShortcut { | 40 | struct ContextualShortcut { |
| 40 | QString keyseq; | 41 | std::string keyseq; |
| 41 | QString controller_keyseq; | 42 | std::string controller_keyseq; |
| 42 | int context; | 43 | int context; |
| 43 | bool repeat; | 44 | bool repeat; |
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | struct Shortcut { | 47 | struct Shortcut { |
| 47 | QString name; | 48 | std::string name; |
| 48 | QString group; | 49 | std::string group; |
| 49 | ContextualShortcut shortcut; | 50 | ContextualShortcut shortcut; |
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| @@ -58,11 +59,19 @@ enum class Theme { | |||
| 58 | MidnightBlueColorful, | 59 | MidnightBlueColorful, |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 62 | static constexpr Theme default_theme{ | ||
| 63 | #ifdef _WIN32 | ||
| 64 | Theme::DarkColorful | ||
| 65 | #else | ||
| 66 | Theme::DefaultColorful | ||
| 67 | #endif | ||
| 68 | }; | ||
| 69 | |||
| 61 | using Themes = std::array<std::pair<const char*, const char*>, 6>; | 70 | using Themes = std::array<std::pair<const char*, const char*>, 6>; |
| 62 | extern const Themes themes; | 71 | extern const Themes themes; |
| 63 | 72 | ||
| 64 | struct GameDir { | 73 | struct GameDir { |
| 65 | QString path; | 74 | std::string path; |
| 66 | bool deep_scan = false; | 75 | bool deep_scan = false; |
| 67 | bool expanded = false; | 76 | bool expanded = false; |
| 68 | bool operator==(const GameDir& rhs) const { | 77 | bool operator==(const GameDir& rhs) const { |
| @@ -144,15 +153,15 @@ struct Values { | |||
| 144 | Category::Screenshots}; | 153 | Category::Screenshots}; |
| 145 | Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; | 154 | Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; |
| 146 | 155 | ||
| 147 | QString roms_path; | 156 | std::string roms_path; |
| 148 | QString symbols_path; | 157 | std::string symbols_path; |
| 149 | QString game_dir_deprecated; | 158 | std::string game_dir_deprecated; |
| 150 | bool game_dir_deprecated_deepscan; | 159 | bool game_dir_deprecated_deepscan; |
| 151 | QVector<UISettings::GameDir> game_dirs; | 160 | QVector<GameDir> game_dirs; |
| 152 | QStringList recent_files; | 161 | QStringList recent_files; |
| 153 | QString language; | 162 | std::string language; |
| 154 | 163 | ||
| 155 | QString theme; | 164 | std::string theme; |
| 156 | 165 | ||
| 157 | // Shortcut name <Shortcut, context> | 166 | // Shortcut name <Shortcut, context> |
| 158 | std::vector<Shortcut> shortcuts; | 167 | std::vector<Shortcut> shortcuts; |
| @@ -206,6 +215,54 @@ extern Values values; | |||
| 206 | 215 | ||
| 207 | u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); | 216 | u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); |
| 208 | 217 | ||
| 218 | void SaveWindowState(); | ||
| 219 | void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig); | ||
| 220 | |||
| 221 | // This shouldn't have anything except static initializers (no functions). So | ||
| 222 | // QKeySequence(...).toString() is NOT ALLOWED HERE. | ||
| 223 | // This must be in alphabetical order according to action name as it must have the same order as | ||
| 224 | // UISetting::values.shortcuts, which is alphabetically ordered. | ||
| 225 | // clang-format off | ||
| 226 | const std::array<Shortcut, 23> default_hotkeys{{ | ||
| 227 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, | ||
| 228 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, | ||
| 229 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, | ||
| 230 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, | ||
| 231 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}}, | ||
| 232 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}}, | ||
| 233 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}}, | ||
| 234 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}}, | ||
| 235 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}}, | ||
| 236 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}}, | ||
| 237 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, | ||
| 238 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, | ||
| 239 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, | ||
| 240 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, | ||
| 241 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, | ||
| 242 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, | ||
| 243 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}}, | ||
| 244 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}}, | ||
| 245 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}}, | ||
| 246 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}}, | ||
| 247 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}}, | ||
| 248 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, | ||
| 249 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, | ||
| 250 | }}; | ||
| 251 | // clang-format on | ||
| 252 | |||
| 209 | } // namespace UISettings | 253 | } // namespace UISettings |
| 210 | 254 | ||
| 211 | Q_DECLARE_METATYPE(UISettings::GameDir*); | 255 | Q_DECLARE_METATYPE(UISettings::GameDir*); |
| 256 | |||
| 257 | // These metatype declarations cannot be in common/settings.h because core is devoid of QT | ||
| 258 | Q_DECLARE_METATYPE(Settings::CpuAccuracy); | ||
| 259 | Q_DECLARE_METATYPE(Settings::GpuAccuracy); | ||
| 260 | Q_DECLARE_METATYPE(Settings::FullscreenMode); | ||
| 261 | Q_DECLARE_METATYPE(Settings::NvdecEmulation); | ||
| 262 | Q_DECLARE_METATYPE(Settings::ResolutionSetup); | ||
| 263 | Q_DECLARE_METATYPE(Settings::ScalingFilter); | ||
| 264 | Q_DECLARE_METATYPE(Settings::AntiAliasing); | ||
| 265 | Q_DECLARE_METATYPE(Settings::RendererBackend); | ||
| 266 | Q_DECLARE_METATYPE(Settings::ShaderBackend); | ||
| 267 | Q_DECLARE_METATYPE(Settings::AstcRecompression); | ||
| 268 | Q_DECLARE_METATYPE(Settings::AstcDecodeMode); | ||
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 46eddf423..fbeba8813 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt | |||
| @@ -13,9 +13,6 @@ function(create_resource file output filename) | |||
| 13 | endfunction() | 13 | endfunction() |
| 14 | 14 | ||
| 15 | add_executable(yuzu-cmd | 15 | add_executable(yuzu-cmd |
| 16 | config.cpp | ||
| 17 | config.h | ||
| 18 | default_ini.h | ||
| 19 | emu_window/emu_window_sdl2.cpp | 16 | emu_window/emu_window_sdl2.cpp |
| 20 | emu_window/emu_window_sdl2.h | 17 | emu_window/emu_window_sdl2.h |
| 21 | emu_window/emu_window_sdl2_gl.cpp | 18 | emu_window/emu_window_sdl2_gl.cpp |
| @@ -25,14 +22,16 @@ add_executable(yuzu-cmd | |||
| 25 | emu_window/emu_window_sdl2_vk.cpp | 22 | emu_window/emu_window_sdl2_vk.cpp |
| 26 | emu_window/emu_window_sdl2_vk.h | 23 | emu_window/emu_window_sdl2_vk.h |
| 27 | precompiled_headers.h | 24 | precompiled_headers.h |
| 25 | sdl_config.cpp | ||
| 26 | sdl_config.h | ||
| 28 | yuzu.cpp | 27 | yuzu.cpp |
| 29 | yuzu.rc | 28 | yuzu.rc |
| 30 | ) | 29 | ) |
| 31 | 30 | ||
| 32 | create_target_directory_groups(yuzu-cmd) | 31 | create_target_directory_groups(yuzu-cmd) |
| 33 | 32 | ||
| 34 | target_link_libraries(yuzu-cmd PRIVATE common core input_common) | 33 | target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common) |
| 35 | target_link_libraries(yuzu-cmd PRIVATE inih::INIReader glad) | 34 | target_link_libraries(yuzu-cmd PRIVATE glad) |
| 36 | if (MSVC) | 35 | if (MSVC) |
| 37 | target_link_libraries(yuzu-cmd PRIVATE getopt) | 36 | target_link_libraries(yuzu-cmd PRIVATE getopt) |
| 38 | endif() | 37 | endif() |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp deleted file mode 100644 index 0d25ff400..000000000 --- a/src/yuzu_cmd/config.cpp +++ /dev/null | |||
| @@ -1,279 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <memory> | ||
| 5 | #include <optional> | ||
| 6 | #include <sstream> | ||
| 7 | #include <INIReader.h> | ||
| 8 | #include <SDL.h> | ||
| 9 | #include "common/fs/file.h" | ||
| 10 | #include "common/fs/fs.h" | ||
| 11 | #include "common/fs/path_util.h" | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/settings.h" | ||
| 14 | #include "core/hle/service/acc/profile_manager.h" | ||
| 15 | #include "input_common/main.h" | ||
| 16 | #include "yuzu_cmd/config.h" | ||
| 17 | #include "yuzu_cmd/default_ini.h" | ||
| 18 | |||
| 19 | namespace FS = Common::FS; | ||
| 20 | |||
| 21 | const std::filesystem::path default_config_path = | ||
| 22 | FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini"; | ||
| 23 | |||
| 24 | Config::Config(std::optional<std::filesystem::path> config_path) | ||
| 25 | : sdl2_config_loc{config_path.value_or(default_config_path)}, | ||
| 26 | sdl2_config{std::make_unique<INIReader>(FS::PathToUTF8String(sdl2_config_loc))} { | ||
| 27 | Reload(); | ||
| 28 | } | ||
| 29 | |||
| 30 | Config::~Config() = default; | ||
| 31 | |||
| 32 | bool Config::LoadINI(const std::string& default_contents, bool retry) { | ||
| 33 | const auto config_loc_str = FS::PathToUTF8String(sdl2_config_loc); | ||
| 34 | if (sdl2_config->ParseError() < 0) { | ||
| 35 | if (retry) { | ||
| 36 | LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", | ||
| 37 | config_loc_str); | ||
| 38 | |||
| 39 | void(FS::CreateParentDir(sdl2_config_loc)); | ||
| 40 | void(FS::WriteStringToFile(sdl2_config_loc, FS::FileType::TextFile, default_contents)); | ||
| 41 | |||
| 42 | sdl2_config = std::make_unique<INIReader>(config_loc_str); | ||
| 43 | |||
| 44 | return LoadINI(default_contents, false); | ||
| 45 | } | ||
| 46 | LOG_ERROR(Config, "Failed."); | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | LOG_INFO(Config, "Successfully loaded {}", config_loc_str); | ||
| 50 | return true; | ||
| 51 | } | ||
| 52 | |||
| 53 | static const std::array<int, Settings::NativeButton::NumButtons> default_buttons = { | ||
| 54 | SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, | ||
| 55 | SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, | ||
| 56 | SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, | ||
| 57 | }; | ||
| 58 | |||
| 59 | static const std::array<int, Settings::NativeMotion::NumMotions> default_motions = { | ||
| 60 | SDL_SCANCODE_7, | ||
| 61 | SDL_SCANCODE_8, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs{{ | ||
| 65 | { | ||
| 66 | SDL_SCANCODE_UP, | ||
| 67 | SDL_SCANCODE_DOWN, | ||
| 68 | SDL_SCANCODE_LEFT, | ||
| 69 | SDL_SCANCODE_RIGHT, | ||
| 70 | SDL_SCANCODE_D, | ||
| 71 | }, | ||
| 72 | { | ||
| 73 | SDL_SCANCODE_I, | ||
| 74 | SDL_SCANCODE_K, | ||
| 75 | SDL_SCANCODE_J, | ||
| 76 | SDL_SCANCODE_L, | ||
| 77 | SDL_SCANCODE_D, | ||
| 78 | }, | ||
| 79 | }}; | ||
| 80 | |||
| 81 | template <> | ||
| 82 | void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) { | ||
| 83 | std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); | ||
| 84 | if (setting_value.empty()) { | ||
| 85 | setting_value = setting.GetDefault(); | ||
| 86 | } | ||
| 87 | setting = std::move(setting_value); | ||
| 88 | } | ||
| 89 | |||
| 90 | template <> | ||
| 91 | void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) { | ||
| 92 | setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); | ||
| 93 | } | ||
| 94 | |||
| 95 | template <typename Type, bool ranged> | ||
| 96 | void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) { | ||
| 97 | setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(), | ||
| 98 | static_cast<long>(setting.GetDefault()))); | ||
| 99 | } | ||
| 100 | |||
| 101 | void Config::ReadCategory(Settings::Category category) { | ||
| 102 | for (const auto setting : Settings::values.linkage.by_category[category]) { | ||
| 103 | const char* category_name = [&]() { | ||
| 104 | if (category == Settings::Category::Controls) { | ||
| 105 | // For compatibility with older configs | ||
| 106 | return "ControlsGeneral"; | ||
| 107 | } else { | ||
| 108 | return Settings::TranslateCategory(category); | ||
| 109 | } | ||
| 110 | }(); | ||
| 111 | std::string setting_value = | ||
| 112 | sdl2_config->Get(category_name, setting->GetLabel(), setting->DefaultToString()); | ||
| 113 | setting->LoadString(setting_value); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | void Config::ReadValues() { | ||
| 118 | // Controls | ||
| 119 | ReadCategory(Settings::Category::Controls); | ||
| 120 | |||
| 121 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 122 | auto& player = Settings::values.players.GetValue()[p]; | ||
| 123 | |||
| 124 | const auto group = fmt::format("ControlsP{}", p); | ||
| 125 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 126 | std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 127 | player.buttons[i] = | ||
| 128 | sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param); | ||
| 129 | if (player.buttons[i].empty()) { | ||
| 130 | player.buttons[i] = default_param; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 135 | std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 136 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 137 | default_analogs[i][3], default_analogs[i][4], 0.5f); | ||
| 138 | player.analogs[i] = | ||
| 139 | sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param); | ||
| 140 | if (player.analogs[i].empty()) { | ||
| 141 | player.analogs[i] = default_param; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 146 | const std::string default_param = | ||
| 147 | InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 148 | auto& player_motions = player.motions[i]; | ||
| 149 | |||
| 150 | player_motions = | ||
| 151 | sdl2_config->Get(group, Settings::NativeMotion::mapping[i], default_param); | ||
| 152 | if (player_motions.empty()) { | ||
| 153 | player_motions = default_param; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | player.connected = sdl2_config->GetBoolean(group, "connected", false); | ||
| 158 | } | ||
| 159 | |||
| 160 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 161 | std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 162 | Settings::values.debug_pad_buttons[i] = sdl2_config->Get( | ||
| 163 | "ControlsGeneral", std::string("debug_pad_") + Settings::NativeButton::mapping[i], | ||
| 164 | default_param); | ||
| 165 | if (Settings::values.debug_pad_buttons[i].empty()) | ||
| 166 | Settings::values.debug_pad_buttons[i] = default_param; | ||
| 167 | } | ||
| 168 | |||
| 169 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 170 | std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 171 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 172 | default_analogs[i][3], default_analogs[i][4], 0.5f); | ||
| 173 | Settings::values.debug_pad_analogs[i] = sdl2_config->Get( | ||
| 174 | "ControlsGeneral", std::string("debug_pad_") + Settings::NativeAnalog::mapping[i], | ||
| 175 | default_param); | ||
| 176 | if (Settings::values.debug_pad_analogs[i].empty()) | ||
| 177 | Settings::values.debug_pad_analogs[i] = default_param; | ||
| 178 | } | ||
| 179 | |||
| 180 | Settings::values.touchscreen.enabled = | ||
| 181 | sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true); | ||
| 182 | Settings::values.touchscreen.rotation_angle = | ||
| 183 | sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0); | ||
| 184 | Settings::values.touchscreen.diameter_x = | ||
| 185 | sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); | ||
| 186 | Settings::values.touchscreen.diameter_y = | ||
| 187 | sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); | ||
| 188 | |||
| 189 | int num_touch_from_button_maps = | ||
| 190 | sdl2_config->GetInteger("ControlsGeneral", "touch_from_button_map", 0); | ||
| 191 | if (num_touch_from_button_maps > 0) { | ||
| 192 | for (int i = 0; i < num_touch_from_button_maps; ++i) { | ||
| 193 | Settings::TouchFromButtonMap map; | ||
| 194 | map.name = sdl2_config->Get("ControlsGeneral", | ||
| 195 | std::string("touch_from_button_maps_") + std::to_string(i) + | ||
| 196 | std::string("_name"), | ||
| 197 | "default"); | ||
| 198 | const int num_touch_maps = sdl2_config->GetInteger( | ||
| 199 | "ControlsGeneral", | ||
| 200 | std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"), | ||
| 201 | 0); | ||
| 202 | map.buttons.reserve(num_touch_maps); | ||
| 203 | |||
| 204 | for (int j = 0; j < num_touch_maps; ++j) { | ||
| 205 | std::string touch_mapping = | ||
| 206 | sdl2_config->Get("ControlsGeneral", | ||
| 207 | std::string("touch_from_button_maps_") + std::to_string(i) + | ||
| 208 | std::string("_bind_") + std::to_string(j), | ||
| 209 | ""); | ||
| 210 | map.buttons.emplace_back(std::move(touch_mapping)); | ||
| 211 | } | ||
| 212 | |||
| 213 | Settings::values.touch_from_button_maps.emplace_back(std::move(map)); | ||
| 214 | } | ||
| 215 | } else { | ||
| 216 | Settings::values.touch_from_button_maps.emplace_back( | ||
| 217 | Settings::TouchFromButtonMap{"default", {}}); | ||
| 218 | num_touch_from_button_maps = 1; | ||
| 219 | } | ||
| 220 | Settings::values.touch_from_button_map_index = std::clamp( | ||
| 221 | Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); | ||
| 222 | |||
| 223 | ReadCategory(Settings::Category::Audio); | ||
| 224 | ReadCategory(Settings::Category::Core); | ||
| 225 | ReadCategory(Settings::Category::Cpu); | ||
| 226 | ReadCategory(Settings::Category::CpuDebug); | ||
| 227 | ReadCategory(Settings::Category::CpuUnsafe); | ||
| 228 | ReadCategory(Settings::Category::Renderer); | ||
| 229 | ReadCategory(Settings::Category::RendererAdvanced); | ||
| 230 | ReadCategory(Settings::Category::RendererDebug); | ||
| 231 | ReadCategory(Settings::Category::System); | ||
| 232 | ReadCategory(Settings::Category::SystemAudio); | ||
| 233 | ReadCategory(Settings::Category::DataStorage); | ||
| 234 | ReadCategory(Settings::Category::Debugging); | ||
| 235 | ReadCategory(Settings::Category::DebuggingGraphics); | ||
| 236 | ReadCategory(Settings::Category::Miscellaneous); | ||
| 237 | ReadCategory(Settings::Category::Network); | ||
| 238 | ReadCategory(Settings::Category::WebService); | ||
| 239 | |||
| 240 | // Data Storage | ||
| 241 | FS::SetYuzuPath(FS::YuzuPath::NANDDir, | ||
| 242 | sdl2_config->Get("Data Storage", "nand_directory", | ||
| 243 | FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | ||
| 244 | FS::SetYuzuPath(FS::YuzuPath::SDMCDir, | ||
| 245 | sdl2_config->Get("Data Storage", "sdmc_directory", | ||
| 246 | FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | ||
| 247 | FS::SetYuzuPath(FS::YuzuPath::LoadDir, | ||
| 248 | sdl2_config->Get("Data Storage", "load_directory", | ||
| 249 | FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | ||
| 250 | FS::SetYuzuPath(FS::YuzuPath::DumpDir, | ||
| 251 | sdl2_config->Get("Data Storage", "dump_directory", | ||
| 252 | FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | ||
| 253 | |||
| 254 | // Debugging | ||
| 255 | Settings::values.record_frame_times = | ||
| 256 | sdl2_config->GetBoolean("Debugging", "record_frame_times", false); | ||
| 257 | |||
| 258 | const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); | ||
| 259 | std::stringstream ss(title_list); | ||
| 260 | std::string line; | ||
| 261 | while (std::getline(ss, line, '|')) { | ||
| 262 | const auto title_id = std::strtoul(line.c_str(), nullptr, 16); | ||
| 263 | const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, ""); | ||
| 264 | |||
| 265 | std::stringstream inner_ss(disabled_list); | ||
| 266 | std::string inner_line; | ||
| 267 | std::vector<std::string> out; | ||
| 268 | while (std::getline(inner_ss, inner_line, '|')) { | ||
| 269 | out.push_back(inner_line); | ||
| 270 | } | ||
| 271 | |||
| 272 | Settings::values.disabled_addons.insert_or_assign(title_id, out); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | void Config::Reload() { | ||
| 277 | LoadINI(DefaultINI::sdl2_config_file); | ||
| 278 | ReadValues(); | ||
| 279 | } | ||
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h deleted file mode 100644 index 512591a39..000000000 --- a/src/yuzu_cmd/config.h +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <filesystem> | ||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | #include <string> | ||
| 10 | |||
| 11 | #include "common/settings.h" | ||
| 12 | |||
| 13 | class INIReader; | ||
| 14 | |||
| 15 | class Config { | ||
| 16 | std::filesystem::path sdl2_config_loc; | ||
| 17 | std::unique_ptr<INIReader> sdl2_config; | ||
| 18 | |||
| 19 | bool LoadINI(const std::string& default_contents = "", bool retry = true); | ||
| 20 | void ReadValues(); | ||
| 21 | |||
| 22 | public: | ||
| 23 | explicit Config(std::optional<std::filesystem::path> config_path); | ||
| 24 | ~Config(); | ||
| 25 | |||
| 26 | void Reload(); | ||
| 27 | |||
| 28 | private: | ||
| 29 | /** | ||
| 30 | * Applies a value read from the sdl2_config to a Setting. | ||
| 31 | * | ||
| 32 | * @param group The name of the INI group | ||
| 33 | * @param setting The yuzu setting to modify | ||
| 34 | */ | ||
| 35 | template <typename Type, bool ranged> | ||
| 36 | void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting); | ||
| 37 | void ReadCategory(Settings::Category category); | ||
| 38 | }; | ||
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h deleted file mode 100644 index 119e22183..000000000 --- a/src/yuzu_cmd/default_ini.h +++ /dev/null | |||
| @@ -1,553 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | namespace DefaultINI { | ||
| 7 | |||
| 8 | const char* sdl2_config_file = | ||
| 9 | R"( | ||
| 10 | [ControlsP0] | ||
| 11 | # The input devices and parameters for each Switch native input | ||
| 12 | # The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ... | ||
| 13 | # It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." | ||
| 14 | # Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values | ||
| 15 | |||
| 16 | # Indicates if this player should be connected at boot | ||
| 17 | # 0 (default): Disabled, 1: Enabled | ||
| 18 | connected= | ||
| 19 | |||
| 20 | # for button input, the following devices are available: | ||
| 21 | # - "keyboard" (default) for keyboard input. Required parameters: | ||
| 22 | # - "code": the code of the key to bind | ||
| 23 | # - "sdl" for joystick input using SDL. Required parameters: | ||
| 24 | # - "guid": SDL identification GUID of the joystick | ||
| 25 | # - "port": the index of the joystick to bind | ||
| 26 | # - "button"(optional): the index of the button to bind | ||
| 27 | # - "hat"(optional): the index of the hat to bind as direction buttons | ||
| 28 | # - "axis"(optional): the index of the axis to bind | ||
| 29 | # - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" | ||
| 30 | # - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is | ||
| 31 | # triggered if the axis value crosses | ||
| 32 | # - "direction"(only used for axis): "+" means the button is triggered when the axis value | ||
| 33 | # is greater than the threshold; "-" means the button is triggered when the axis value | ||
| 34 | # is smaller than the threshold | ||
| 35 | button_a= | ||
| 36 | button_b= | ||
| 37 | button_x= | ||
| 38 | button_y= | ||
| 39 | button_lstick= | ||
| 40 | button_rstick= | ||
| 41 | button_l= | ||
| 42 | button_r= | ||
| 43 | button_zl= | ||
| 44 | button_zr= | ||
| 45 | button_plus= | ||
| 46 | button_minus= | ||
| 47 | button_dleft= | ||
| 48 | button_dup= | ||
| 49 | button_dright= | ||
| 50 | button_ddown= | ||
| 51 | button_lstick_left= | ||
| 52 | button_lstick_up= | ||
| 53 | button_lstick_right= | ||
| 54 | button_lstick_down= | ||
| 55 | button_sl= | ||
| 56 | button_sr= | ||
| 57 | button_home= | ||
| 58 | button_screenshot= | ||
| 59 | |||
| 60 | # for analog input, the following devices are available: | ||
| 61 | # - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: | ||
| 62 | # - "up", "down", "left", "right": sub-devices for each direction. | ||
| 63 | # Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" | ||
| 64 | # - "modifier": sub-devices as a modifier. | ||
| 65 | # - "modifier_scale": a float number representing the applied modifier scale to the analog input. | ||
| 66 | # Must be in range of 0.0-1.0. Defaults to 0.5 | ||
| 67 | # - "sdl" for joystick input using SDL. Required parameters: | ||
| 68 | # - "guid": SDL identification GUID of the joystick | ||
| 69 | # - "port": the index of the joystick to bind | ||
| 70 | # - "axis_x": the index of the axis to bind as x-axis (default to 0) | ||
| 71 | # - "axis_y": the index of the axis to bind as y-axis (default to 1) | ||
| 72 | lstick= | ||
| 73 | rstick= | ||
| 74 | |||
| 75 | # for motion input, the following devices are available: | ||
| 76 | # - "keyboard" (default) for emulating random motion input from buttons. Required parameters: | ||
| 77 | # - "code": the code of the key to bind | ||
| 78 | # - "sdl" for motion input using SDL. Required parameters: | ||
| 79 | # - "guid": SDL identification GUID of the joystick | ||
| 80 | # - "port": the index of the joystick to bind | ||
| 81 | # - "motion": the index of the motion sensor to bind | ||
| 82 | # - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters: | ||
| 83 | # - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001" | ||
| 84 | # - "port": the port of the cemu hook server | ||
| 85 | # - "pad": the index of the joystick | ||
| 86 | # - "motion": the index of the motion sensor of the joystick to bind | ||
| 87 | motionleft= | ||
| 88 | motionright= | ||
| 89 | |||
| 90 | [ControlsGeneral] | ||
| 91 | # To use the debug_pad, prepend `debug_pad_` before each button setting above. | ||
| 92 | # i.e. debug_pad_button_a= | ||
| 93 | |||
| 94 | # Enable debug pad inputs to the guest | ||
| 95 | # 0 (default): Disabled, 1: Enabled | ||
| 96 | debug_pad_enabled = | ||
| 97 | |||
| 98 | # Enable sdl raw input. Allows to configure up to 8 xinput controllers. | ||
| 99 | # 0 (default): Disabled, 1: Enabled | ||
| 100 | enable_raw_input = | ||
| 101 | |||
| 102 | # Enable yuzu joycon driver instead of SDL drive. | ||
| 103 | # 0: Disabled, 1 (default): Enabled | ||
| 104 | enable_joycon_driver = | ||
| 105 | |||
| 106 | # Emulates an analog input from buttons. Allowing to dial any angle. | ||
| 107 | # 0 (default): Disabled, 1: Enabled | ||
| 108 | emulate_analog_keyboard = | ||
| 109 | |||
| 110 | # Whether to enable or disable vibration | ||
| 111 | # 0: Disabled, 1 (default): Enabled | ||
| 112 | vibration_enabled= | ||
| 113 | |||
| 114 | # Whether to enable or disable accurate vibrations | ||
| 115 | # 0 (default): Disabled, 1: Enabled | ||
| 116 | enable_accurate_vibrations= | ||
| 117 | |||
| 118 | # Enables controller motion inputs | ||
| 119 | # 0: Disabled, 1 (default): Enabled | ||
| 120 | motion_enabled = | ||
| 121 | |||
| 122 | # Defines the udp device's touch screen coordinate system for cemuhookudp devices | ||
| 123 | # - "min_x", "min_y", "max_x", "max_y" | ||
| 124 | touch_device= | ||
| 125 | |||
| 126 | # for mapping buttons to touch inputs. | ||
| 127 | #touch_from_button_map=1 | ||
| 128 | #touch_from_button_maps_0_name=default | ||
| 129 | #touch_from_button_maps_0_count=2 | ||
| 130 | #touch_from_button_maps_0_bind_0=foo | ||
| 131 | #touch_from_button_maps_0_bind_1=bar | ||
| 132 | # etc. | ||
| 133 | |||
| 134 | # List of Cemuhook UDP servers, delimited by ','. | ||
| 135 | # Default: 127.0.0.1:26760 | ||
| 136 | # Example: 127.0.0.1:26760,123.4.5.67:26761 | ||
| 137 | udp_input_servers = | ||
| 138 | |||
| 139 | # Enable controlling an axis via a mouse input. | ||
| 140 | # 0 (default): Off, 1: On | ||
| 141 | mouse_panning = | ||
| 142 | |||
| 143 | # Set mouse panning horizontal sensitivity. | ||
| 144 | # Default: 50.0 | ||
| 145 | mouse_panning_x_sensitivity = | ||
| 146 | |||
| 147 | # Set mouse panning vertical sensitivity. | ||
| 148 | # Default: 50.0 | ||
| 149 | mouse_panning_y_sensitivity = | ||
| 150 | |||
| 151 | # Set mouse panning deadzone horizontal counterweight. | ||
| 152 | # Default: 0.0 | ||
| 153 | mouse_panning_deadzone_x_counterweight = | ||
| 154 | |||
| 155 | # Set mouse panning deadzone vertical counterweight. | ||
| 156 | # Default: 0.0 | ||
| 157 | mouse_panning_deadzone_y_counterweight = | ||
| 158 | |||
| 159 | # Set mouse panning stick decay strength. | ||
| 160 | # Default: 22.0 | ||
| 161 | mouse_panning_decay_strength = | ||
| 162 | |||
| 163 | # Set mouse panning stick minimum decay. | ||
| 164 | # Default: 5.0 | ||
| 165 | mouse_panning_minimum_decay = | ||
| 166 | |||
| 167 | # Emulate an analog control stick from keyboard inputs. | ||
| 168 | # 0 (default): Disabled, 1: Enabled | ||
| 169 | emulate_analog_keyboard = | ||
| 170 | |||
| 171 | # Enable mouse inputs to the guest | ||
| 172 | # 0 (default): Disabled, 1: Enabled | ||
| 173 | mouse_enabled = | ||
| 174 | |||
| 175 | # Enable keyboard inputs to the guest | ||
| 176 | # 0 (default): Disabled, 1: Enabled | ||
| 177 | keyboard_enabled = | ||
| 178 | |||
| 179 | )" | ||
| 180 | R"( | ||
| 181 | [Core] | ||
| 182 | # Whether to use multi-core for CPU emulation | ||
| 183 | # 0: Disabled, 1 (default): Enabled | ||
| 184 | use_multi_core = | ||
| 185 | |||
| 186 | # Enable unsafe extended guest system memory layout (8GB DRAM) | ||
| 187 | # 0 (default): Disabled, 1: Enabled | ||
| 188 | use_unsafe_extended_memory_layout = | ||
| 189 | |||
| 190 | [Cpu] | ||
| 191 | # Adjusts various optimizations. | ||
| 192 | # Auto-select mode enables choice unsafe optimizations. | ||
| 193 | # Accurate enables only safe optimizations. | ||
| 194 | # Unsafe allows any unsafe optimizations. | ||
| 195 | # 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations | ||
| 196 | cpu_accuracy = | ||
| 197 | |||
| 198 | # Allow disabling safe optimizations. | ||
| 199 | # 0 (default): Disabled, 1: Enabled | ||
| 200 | cpu_debug_mode = | ||
| 201 | |||
| 202 | # Enable inline page tables optimization (faster guest memory access) | ||
| 203 | # 0: Disabled, 1 (default): Enabled | ||
| 204 | cpuopt_page_tables = | ||
| 205 | |||
| 206 | # Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) | ||
| 207 | # 0: Disabled, 1 (default): Enabled | ||
| 208 | cpuopt_block_linking = | ||
| 209 | |||
| 210 | # Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) | ||
| 211 | # 0: Disabled, 1 (default): Enabled | ||
| 212 | cpuopt_return_stack_buffer = | ||
| 213 | |||
| 214 | # Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) | ||
| 215 | # 0: Disabled, 1 (default): Enabled | ||
| 216 | cpuopt_fast_dispatcher = | ||
| 217 | |||
| 218 | # Enable context elimination CPU Optimization (reduce host memory use for guest context) | ||
| 219 | # 0: Disabled, 1 (default): Enabled | ||
| 220 | cpuopt_context_elimination = | ||
| 221 | |||
| 222 | # Enable constant propagation CPU optimization (basic IR optimization) | ||
| 223 | # 0: Disabled, 1 (default): Enabled | ||
| 224 | cpuopt_const_prop = | ||
| 225 | |||
| 226 | # Enable miscellaneous CPU optimizations (basic IR optimization) | ||
| 227 | # 0: Disabled, 1 (default): Enabled | ||
| 228 | cpuopt_misc_ir = | ||
| 229 | |||
| 230 | # Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) | ||
| 231 | # 0: Disabled, 1 (default): Enabled | ||
| 232 | cpuopt_reduce_misalign_checks = | ||
| 233 | |||
| 234 | # Enable Host MMU Emulation (faster guest memory access) | ||
| 235 | # 0: Disabled, 1 (default): Enabled | ||
| 236 | cpuopt_fastmem = | ||
| 237 | |||
| 238 | # Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access) | ||
| 239 | # 0: Disabled, 1 (default): Enabled | ||
| 240 | cpuopt_fastmem_exclusives = | ||
| 241 | |||
| 242 | # Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access) | ||
| 243 | # 0: Disabled, 1 (default): Enabled | ||
| 244 | cpuopt_recompile_exclusives = | ||
| 245 | |||
| 246 | # Enable optimization to ignore invalid memory accesses (faster guest memory access) | ||
| 247 | # 0: Disabled, 1 (default): Enabled | ||
| 248 | cpuopt_ignore_memory_aborts = | ||
| 249 | |||
| 250 | # Enable unfuse FMA (improve performance on CPUs without FMA) | ||
| 251 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 252 | # 0: Disabled, 1 (default): Enabled | ||
| 253 | cpuopt_unsafe_unfuse_fma = | ||
| 254 | |||
| 255 | # Enable faster FRSQRTE and FRECPE | ||
| 256 | # Only enabled if cpu_accuracy is set to Unsafe. | ||
| 257 | # 0: Disabled, 1 (default): Enabled | ||
| 258 | cpuopt_unsafe_reduce_fp_error = | ||
| 259 | |||
| 260 | # Enable faster ASIMD instructions (32 bits only) | ||
| 261 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 262 | # 0: Disabled, 1 (default): Enabled | ||
| 263 | cpuopt_unsafe_ignore_standard_fpcr = | ||
| 264 | |||
| 265 | # Enable inaccurate NaN handling | ||
| 266 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 267 | # 0: Disabled, 1 (default): Enabled | ||
| 268 | cpuopt_unsafe_inaccurate_nan = | ||
| 269 | |||
| 270 | # Disable address space checks (64 bits only) | ||
| 271 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 272 | # 0: Disabled, 1 (default): Enabled | ||
| 273 | cpuopt_unsafe_fastmem_check = | ||
| 274 | |||
| 275 | # Enable faster exclusive instructions | ||
| 276 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 277 | # 0: Disabled, 1 (default): Enabled | ||
| 278 | cpuopt_unsafe_ignore_global_monitor = | ||
| 279 | |||
| 280 | )" | ||
| 281 | R"( | ||
| 282 | [Renderer] | ||
| 283 | # Which backend API to use. | ||
| 284 | # 0: OpenGL, 1 (default): Vulkan | ||
| 285 | backend = | ||
| 286 | |||
| 287 | # Whether to enable asynchronous presentation (Vulkan only) | ||
| 288 | # 0 (default): Off, 1: On | ||
| 289 | async_presentation = | ||
| 290 | |||
| 291 | # Enable graphics API debugging mode. | ||
| 292 | # 0 (default): Disabled, 1: Enabled | ||
| 293 | debug = | ||
| 294 | |||
| 295 | # Enable shader feedback. | ||
| 296 | # 0 (default): Disabled, 1: Enabled | ||
| 297 | renderer_shader_feedback = | ||
| 298 | |||
| 299 | # Enable Nsight Aftermath crash dumps | ||
| 300 | # 0 (default): Disabled, 1: Enabled | ||
| 301 | nsight_aftermath = | ||
| 302 | |||
| 303 | # Disable shader loop safety checks, executing the shader without loop logic changes | ||
| 304 | # 0 (default): Disabled, 1: Enabled | ||
| 305 | disable_shader_loop_safety_checks = | ||
| 306 | |||
| 307 | # Which Vulkan physical device to use (defaults to 0) | ||
| 308 | vulkan_device = | ||
| 309 | |||
| 310 | # 0: 0.5x (360p/540p) [EXPERIMENTAL] | ||
| 311 | # 1: 0.75x (540p/810p) [EXPERIMENTAL] | ||
| 312 | # 2 (default): 1x (720p/1080p) | ||
| 313 | # 3: 1.5x (1080p/1620p) [EXPERIMENTAL] | ||
| 314 | # 4: 2x (1440p/2160p) | ||
| 315 | # 5: 3x (2160p/3240p) | ||
| 316 | # 6: 4x (2880p/4320p) | ||
| 317 | # 7: 5x (3600p/5400p) | ||
| 318 | # 8: 6x (4320p/6480p) | ||
| 319 | # 9: 7x (5040p/7560p) | ||
| 320 | # 10: 8x (5760/8640p) | ||
| 321 | resolution_setup = | ||
| 322 | |||
| 323 | # Pixel filter to use when up- or down-sampling rendered frames. | ||
| 324 | # 0: Nearest Neighbor | ||
| 325 | # 1 (default): Bilinear | ||
| 326 | # 2: Bicubic | ||
| 327 | # 3: Gaussian | ||
| 328 | # 4: ScaleForce | ||
| 329 | # 5: AMD FidelityFX™️ Super Resolution | ||
| 330 | scaling_filter = | ||
| 331 | |||
| 332 | # Anti-Aliasing (AA) | ||
| 333 | # 0 (default): None, 1: FXAA, 2: SMAA | ||
| 334 | anti_aliasing = | ||
| 335 | |||
| 336 | # Whether to use fullscreen or borderless window mode | ||
| 337 | # 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen | ||
| 338 | fullscreen_mode = | ||
| 339 | |||
| 340 | # Aspect ratio | ||
| 341 | # 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window | ||
| 342 | aspect_ratio = | ||
| 343 | |||
| 344 | # Anisotropic filtering | ||
| 345 | # 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x | ||
| 346 | max_anisotropy = | ||
| 347 | |||
| 348 | # Whether to enable VSync or not. | ||
| 349 | # OpenGL: Values other than 0 enable VSync | ||
| 350 | # Vulkan: FIFO is selected if the requested mode is not supported by the driver. | ||
| 351 | # FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. | ||
| 352 | # FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. | ||
| 353 | # Mailbox can have lower latency than FIFO and does not tear but may drop frames. | ||
| 354 | # Immediate (no synchronization) just presents whatever is available and can exhibit tearing. | ||
| 355 | # 0: Immediate (Off), 1: Mailbox, 2 (Default): FIFO (On), 3: FIFO Relaxed | ||
| 356 | use_vsync = | ||
| 357 | |||
| 358 | # Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is | ||
| 359 | # not available and GLASM is selected, GLSL will be used. | ||
| 360 | # 0: GLSL, 1 (default): GLASM, 2: SPIR-V | ||
| 361 | shader_backend = | ||
| 362 | |||
| 363 | # Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. | ||
| 364 | # 0: Off, 1 (default): On | ||
| 365 | use_reactive_flushing = | ||
| 366 | |||
| 367 | # Whether to allow asynchronous shader building. | ||
| 368 | # 0 (default): Off, 1: On | ||
| 369 | use_asynchronous_shaders = | ||
| 370 | |||
| 371 | # NVDEC emulation. | ||
| 372 | # 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding | ||
| 373 | nvdec_emulation = | ||
| 374 | |||
| 375 | # Accelerate ASTC texture decoding. | ||
| 376 | # 0: Off, 1 (default): On | ||
| 377 | accelerate_astc = | ||
| 378 | |||
| 379 | # Decode ASTC textures asynchronously. | ||
| 380 | # 0 (default): Off, 1: On | ||
| 381 | async_astc = | ||
| 382 | |||
| 383 | # Recompress ASTC textures to a different format. | ||
| 384 | # 0 (default): Uncompressed, 1: BC1 (Low quality), 2: BC3: (Medium quality) | ||
| 385 | async_astc = | ||
| 386 | |||
| 387 | # Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value | ||
| 388 | # 0: Off, 1: On (default) | ||
| 389 | use_speed_limit = | ||
| 390 | |||
| 391 | # Limits the speed of the game to run no faster than this value as a percentage of target speed | ||
| 392 | # 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) | ||
| 393 | speed_limit = | ||
| 394 | |||
| 395 | # Whether to use disk based shader cache | ||
| 396 | # 0: Off, 1 (default): On | ||
| 397 | use_disk_shader_cache = | ||
| 398 | |||
| 399 | # Which gpu accuracy level to use | ||
| 400 | # 0: Normal, 1 (default): High, 2: Extreme (Very slow) | ||
| 401 | gpu_accuracy = | ||
| 402 | |||
| 403 | # Whether to use asynchronous GPU emulation | ||
| 404 | # 0 : Off (slow), 1 (default): On (fast) | ||
| 405 | use_asynchronous_gpu_emulation = | ||
| 406 | |||
| 407 | # Inform the guest that GPU operations completed more quickly than they did. | ||
| 408 | # 0: Off, 1 (default): On | ||
| 409 | use_fast_gpu_time = | ||
| 410 | |||
| 411 | # Whether to use garbage collection or not for GPU caches. | ||
| 412 | # 0 (default): Off, 1: On | ||
| 413 | use_caches_gc = | ||
| 414 | |||
| 415 | # The clear color for the renderer. What shows up on the sides of the bottom screen. | ||
| 416 | # Must be in range of 0-255. Defaults to 0 for all. | ||
| 417 | bg_red = | ||
| 418 | bg_blue = | ||
| 419 | bg_green = | ||
| 420 | |||
| 421 | )" | ||
| 422 | R"( | ||
| 423 | [Audio] | ||
| 424 | # Which audio output engine to use. | ||
| 425 | # auto (default): Auto-select | ||
| 426 | # cubeb: Cubeb audio engine (if available) | ||
| 427 | # sdl2: SDL2 audio engine (if available) | ||
| 428 | # null: No audio output | ||
| 429 | output_engine = | ||
| 430 | |||
| 431 | # Which audio device to use. | ||
| 432 | # auto (default): Auto-select | ||
| 433 | output_device = | ||
| 434 | |||
| 435 | # Output volume. | ||
| 436 | # 100 (default): 100%, 0; mute | ||
| 437 | volume = | ||
| 438 | |||
| 439 | [Data Storage] | ||
| 440 | # Whether to create a virtual SD card. | ||
| 441 | # 1 (default): Yes, 0: No | ||
| 442 | use_virtual_sd = | ||
| 443 | |||
| 444 | # Whether or not to enable gamecard emulation | ||
| 445 | # 1: Yes, 0 (default): No | ||
| 446 | gamecard_inserted = | ||
| 447 | |||
| 448 | # Whether or not the gamecard should be emulated as the current game | ||
| 449 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 450 | # 1: Yes, 0 (default): No | ||
| 451 | gamecard_current_game = | ||
| 452 | |||
| 453 | # Path to an XCI file to use as the gamecard | ||
| 454 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 455 | # If 'gamecard_current_game' is 1 this setting is irrelevant | ||
| 456 | gamecard_path = | ||
| 457 | |||
| 458 | [System] | ||
| 459 | # Whether the system is docked | ||
| 460 | # 1 (default): Yes, 0: No | ||
| 461 | use_docked_mode = | ||
| 462 | |||
| 463 | # Sets the seed for the RNG generator built into the switch | ||
| 464 | # rng_seed will be ignored and randomly generated if rng_seed_enabled is false | ||
| 465 | rng_seed_enabled = | ||
| 466 | rng_seed = | ||
| 467 | |||
| 468 | # Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service | ||
| 469 | # This will auto-increment, with the time set being the time the game is started | ||
| 470 | # This override will only occur if custom_rtc_enabled is true, otherwise the current time is used | ||
| 471 | custom_rtc_enabled = | ||
| 472 | custom_rtc = | ||
| 473 | |||
| 474 | # Sets the systems language index | ||
| 475 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, | ||
| 476 | # 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, | ||
| 477 | # 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese | ||
| 478 | language_index = | ||
| 479 | |||
| 480 | # The system region that yuzu will use during emulation | ||
| 481 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | ||
| 482 | region_index = | ||
| 483 | |||
| 484 | # The system time zone that yuzu will use during emulation | ||
| 485 | # 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone | ||
| 486 | time_zone_index = | ||
| 487 | |||
| 488 | # Sets the sound output mode. | ||
| 489 | # 0: Mono, 1 (default): Stereo, 2: Surround | ||
| 490 | sound_index = | ||
| 491 | |||
| 492 | [Miscellaneous] | ||
| 493 | # A filter which removes logs below a certain logging level. | ||
| 494 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | ||
| 495 | log_filter = *:Trace | ||
| 496 | |||
| 497 | # Use developer keys | ||
| 498 | # 0 (default): Disabled, 1: Enabled | ||
| 499 | use_dev_keys = | ||
| 500 | |||
| 501 | [Debugging] | ||
| 502 | # Record frame time data, can be found in the log directory. Boolean value | ||
| 503 | record_frame_times = | ||
| 504 | # Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them | ||
| 505 | dump_exefs=false | ||
| 506 | # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them | ||
| 507 | dump_nso=false | ||
| 508 | # Determines whether or not yuzu will save the filesystem access log. | ||
| 509 | enable_fs_access_log=false | ||
| 510 | # Enables verbose reporting services | ||
| 511 | reporting_services = | ||
| 512 | # Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode | ||
| 513 | # false: Retail/Normal Mode (default), true: Kiosk Mode | ||
| 514 | quest_flag = | ||
| 515 | # Determines whether debug asserts should be enabled, which will throw an exception on asserts. | ||
| 516 | # false: Disabled (default), true: Enabled | ||
| 517 | use_debug_asserts = | ||
| 518 | # Determines whether unimplemented HLE service calls should be automatically stubbed. | ||
| 519 | # false: Disabled (default), true: Enabled | ||
| 520 | use_auto_stub = | ||
| 521 | # Enables/Disables the macro JIT compiler | ||
| 522 | disable_macro_jit=false | ||
| 523 | # Determines whether to enable the GDB stub and wait for the debugger to attach before running. | ||
| 524 | # false: Disabled (default), true: Enabled | ||
| 525 | use_gdbstub=false | ||
| 526 | # The port to use for the GDB server, if it is enabled. | ||
| 527 | gdbstub_port=6543 | ||
| 528 | |||
| 529 | [WebService] | ||
| 530 | # Whether or not to enable telemetry | ||
| 531 | # 0: No, 1 (default): Yes | ||
| 532 | enable_telemetry = | ||
| 533 | # URL for Web API | ||
| 534 | web_api_url = https://api.yuzu-emu.org | ||
| 535 | # Username and token for yuzu Web Service | ||
| 536 | # See https://profile.yuzu-emu.org/ for more info | ||
| 537 | yuzu_username = | ||
| 538 | yuzu_token = | ||
| 539 | |||
| 540 | [Network] | ||
| 541 | # Name of the network interface device to use with yuzu LAN play. | ||
| 542 | # e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo' | ||
| 543 | # e.g. On Windows: 'Ethernet', 'Wi-Fi' | ||
| 544 | network_interface = | ||
| 545 | |||
| 546 | [AddOns] | ||
| 547 | # Used to disable add-ons | ||
| 548 | # List of title IDs of games that will have add-ons disabled (separated by '|'): | ||
| 549 | title_ids = | ||
| 550 | # For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') | ||
| 551 | # e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey | ||
| 552 | )"; | ||
| 553 | } // namespace DefaultINI | ||
diff --git a/src/yuzu_cmd/sdl_config.cpp b/src/yuzu_cmd/sdl_config.cpp new file mode 100644 index 000000000..39fd8050c --- /dev/null +++ b/src/yuzu_cmd/sdl_config.cpp | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | // SDL will break our main function in yuzu-cmd if we don't define this before adding SDL.h | ||
| 5 | #define SDL_MAIN_HANDLED | ||
| 6 | #include <SDL.h> | ||
| 7 | |||
| 8 | #include "input_common/main.h" | ||
| 9 | #include "sdl_config.h" | ||
| 10 | |||
| 11 | const std::array<int, Settings::NativeButton::NumButtons> SdlConfig::default_buttons = { | ||
| 12 | SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, | ||
| 13 | SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, | ||
| 14 | SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, | ||
| 15 | }; | ||
| 16 | |||
| 17 | const std::array<int, Settings::NativeMotion::NumMotions> SdlConfig::default_motions = { | ||
| 18 | SDL_SCANCODE_7, | ||
| 19 | SDL_SCANCODE_8, | ||
| 20 | }; | ||
| 21 | |||
| 22 | const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{ | ||
| 23 | { | ||
| 24 | { | ||
| 25 | SDL_SCANCODE_UP, | ||
| 26 | SDL_SCANCODE_DOWN, | ||
| 27 | SDL_SCANCODE_LEFT, | ||
| 28 | SDL_SCANCODE_RIGHT, | ||
| 29 | }, | ||
| 30 | { | ||
| 31 | SDL_SCANCODE_I, | ||
| 32 | SDL_SCANCODE_K, | ||
| 33 | SDL_SCANCODE_J, | ||
| 34 | SDL_SCANCODE_L, | ||
| 35 | }, | ||
| 36 | }}; | ||
| 37 | |||
| 38 | const std::array<int, 2> SdlConfig::default_stick_mod = { | ||
| 39 | SDL_SCANCODE_D, | ||
| 40 | 0, | ||
| 41 | }; | ||
| 42 | |||
| 43 | const std::array<int, 2> SdlConfig::default_ringcon_analogs{{ | ||
| 44 | 0, | ||
| 45 | 0, | ||
| 46 | }}; | ||
| 47 | |||
| 48 | SdlConfig::SdlConfig(const std::optional<std::string> config_path) { | ||
| 49 | Initialize(config_path); | ||
| 50 | ReadSdlValues(); | ||
| 51 | SaveSdlValues(); | ||
| 52 | } | ||
| 53 | |||
| 54 | SdlConfig::~SdlConfig() { | ||
| 55 | if (global) { | ||
| 56 | SdlConfig::SaveAllValues(); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | void SdlConfig::ReloadAllValues() { | ||
| 61 | Reload(); | ||
| 62 | ReadSdlValues(); | ||
| 63 | SaveSdlValues(); | ||
| 64 | } | ||
| 65 | |||
| 66 | void SdlConfig::SaveAllValues() { | ||
| 67 | Save(); | ||
| 68 | SaveSdlValues(); | ||
| 69 | } | ||
| 70 | |||
| 71 | void SdlConfig::ReadSdlValues() { | ||
| 72 | ReadSdlControlValues(); | ||
| 73 | } | ||
| 74 | |||
| 75 | void SdlConfig::ReadSdlControlValues() { | ||
| 76 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 77 | |||
| 78 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 79 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 80 | ReadSdlPlayerValues(p); | ||
| 81 | } | ||
| 82 | if (IsCustomConfig()) { | ||
| 83 | EndGroup(); | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | ReadDebugControlValues(); | ||
| 87 | ReadHidbusValues(); | ||
| 88 | |||
| 89 | EndGroup(); | ||
| 90 | } | ||
| 91 | |||
| 92 | void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) { | ||
| 93 | std::string player_prefix; | ||
| 94 | if (type != ConfigType::InputProfile) { | ||
| 95 | player_prefix.append("player_").append(ToString(player_index)).append("_"); | ||
| 96 | } | ||
| 97 | |||
| 98 | auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 99 | if (IsCustomConfig()) { | ||
| 100 | const auto profile_name = | ||
| 101 | ReadStringSetting(std::string(player_prefix).append("profile_name")); | ||
| 102 | if (profile_name.empty()) { | ||
| 103 | // Use the global input config | ||
| 104 | player = Settings::values.players.GetValue(true)[player_index]; | ||
| 105 | return; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 110 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 111 | auto& player_buttons = player.buttons[i]; | ||
| 112 | |||
| 113 | player_buttons = ReadStringSetting( | ||
| 114 | std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); | ||
| 115 | if (player_buttons.empty()) { | ||
| 116 | player_buttons = default_param; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 121 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 122 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 123 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 124 | auto& player_analogs = player.analogs[i]; | ||
| 125 | |||
| 126 | player_analogs = ReadStringSetting( | ||
| 127 | std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); | ||
| 128 | if (player_analogs.empty()) { | ||
| 129 | player_analogs = default_param; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 134 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 135 | auto& player_motions = player.motions[i]; | ||
| 136 | |||
| 137 | player_motions = ReadStringSetting( | ||
| 138 | std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); | ||
| 139 | if (player_motions.empty()) { | ||
| 140 | player_motions = default_param; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | void SdlConfig::ReadDebugControlValues() { | ||
| 146 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 147 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 148 | auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; | ||
| 149 | debug_pad_buttons = ReadStringSetting( | ||
| 150 | std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param); | ||
| 151 | if (debug_pad_buttons.empty()) { | ||
| 152 | debug_pad_buttons = default_param; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 156 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 157 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 158 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 159 | auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; | ||
| 160 | debug_pad_analogs = ReadStringSetting( | ||
| 161 | std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param); | ||
| 162 | if (debug_pad_analogs.empty()) { | ||
| 163 | debug_pad_analogs = default_param; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | void SdlConfig::ReadHidbusValues() { | ||
| 169 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 170 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||
| 171 | auto& ringcon_analogs = Settings::values.ringcon_analogs; | ||
| 172 | |||
| 173 | ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); | ||
| 174 | if (ringcon_analogs.empty()) { | ||
| 175 | ringcon_analogs = default_param; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | void SdlConfig::SaveSdlValues() { | ||
| 180 | SaveSdlControlValues(); | ||
| 181 | |||
| 182 | WriteToIni(); | ||
| 183 | } | ||
| 184 | |||
| 185 | void SdlConfig::SaveSdlControlValues() { | ||
| 186 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 187 | |||
| 188 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 189 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 190 | SaveSdlPlayerValues(p); | ||
| 191 | } | ||
| 192 | if (IsCustomConfig()) { | ||
| 193 | EndGroup(); | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | SaveDebugControlValues(); | ||
| 197 | SaveHidbusValues(); | ||
| 198 | |||
| 199 | EndGroup(); | ||
| 200 | } | ||
| 201 | |||
| 202 | void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) { | ||
| 203 | std::string player_prefix; | ||
| 204 | if (type != ConfigType::InputProfile) { | ||
| 205 | player_prefix = std::string("player_").append(ToString(player_index)).append("_"); | ||
| 206 | } | ||
| 207 | |||
| 208 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 209 | if (IsCustomConfig() && player.profile_name.empty()) { | ||
| 210 | // No custom profile selected | ||
| 211 | return; | ||
| 212 | } | ||
| 213 | |||
| 214 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 215 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 216 | WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | ||
| 217 | player.buttons[i], std::make_optional(default_param)); | ||
| 218 | } | ||
| 219 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 220 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 221 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 222 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 223 | WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | ||
| 224 | player.analogs[i], std::make_optional(default_param)); | ||
| 225 | } | ||
| 226 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 227 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 228 | WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | ||
| 229 | player.motions[i], std::make_optional(default_param)); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | void SdlConfig::SaveDebugControlValues() { | ||
| 234 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 235 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||
| 236 | WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | ||
| 237 | Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); | ||
| 238 | } | ||
| 239 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 240 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 241 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||
| 242 | default_analogs[i][3], default_stick_mod[i], 0.5f); | ||
| 243 | WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | ||
| 244 | Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | void SdlConfig::SaveHidbusValues() { | ||
| 249 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||
| 250 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||
| 251 | WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | ||
| 252 | std::make_optional(default_param)); | ||
| 253 | } | ||
| 254 | |||
| 255 | std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) { | ||
| 256 | return Settings::values.linkage.by_category[category]; | ||
| 257 | } | ||
diff --git a/src/yuzu_cmd/sdl_config.h b/src/yuzu_cmd/sdl_config.h new file mode 100644 index 000000000..1fd1c692d --- /dev/null +++ b/src/yuzu_cmd/sdl_config.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "frontend_common/config.h" | ||
| 7 | |||
| 8 | class SdlConfig final : public Config { | ||
| 9 | public: | ||
| 10 | explicit SdlConfig(std::optional<std::string> config_path); | ||
| 11 | ~SdlConfig() override; | ||
| 12 | |||
| 13 | void ReloadAllValues() override; | ||
| 14 | void SaveAllValues() override; | ||
| 15 | |||
| 16 | protected: | ||
| 17 | void ReadSdlValues(); | ||
| 18 | void ReadSdlPlayerValues(std::size_t player_index); | ||
| 19 | void ReadSdlControlValues(); | ||
| 20 | void ReadHidbusValues() override; | ||
| 21 | void ReadDebugControlValues() override; | ||
| 22 | void ReadPathValues() override {} | ||
| 23 | void ReadShortcutValues() override {} | ||
| 24 | void ReadUIValues() override {} | ||
| 25 | void ReadUIGamelistValues() override {} | ||
| 26 | void ReadUILayoutValues() override {} | ||
| 27 | void ReadMultiplayerValues() override {} | ||
| 28 | |||
| 29 | void SaveSdlValues(); | ||
| 30 | void SaveSdlPlayerValues(std::size_t player_index); | ||
| 31 | void SaveSdlControlValues(); | ||
| 32 | void SaveHidbusValues() override; | ||
| 33 | void SaveDebugControlValues() override; | ||
| 34 | void SavePathValues() override {} | ||
| 35 | void SaveShortcutValues() override {} | ||
| 36 | void SaveUIValues() override {} | ||
| 37 | void SaveUIGamelistValues() override {} | ||
| 38 | void SaveUILayoutValues() override {} | ||
| 39 | void SaveMultiplayerValues() override {} | ||
| 40 | |||
| 41 | std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; | ||
| 42 | |||
| 43 | public: | ||
| 44 | static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; | ||
| 45 | static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; | ||
| 46 | static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; | ||
| 47 | static const std::array<int, 2> default_stick_mod; | ||
| 48 | static const std::array<int, 2> default_ringcon_analogs; | ||
| 49 | }; | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 087cfaa26..a81635fa4 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -29,10 +29,11 @@ | |||
| 29 | #include "core/hle/service/filesystem/filesystem.h" | 29 | #include "core/hle/service/filesystem/filesystem.h" |
| 30 | #include "core/loader/loader.h" | 30 | #include "core/loader/loader.h" |
| 31 | #include "core/telemetry_session.h" | 31 | #include "core/telemetry_session.h" |
| 32 | #include "frontend_common/config.h" | ||
| 32 | #include "input_common/main.h" | 33 | #include "input_common/main.h" |
| 33 | #include "network/network.h" | 34 | #include "network/network.h" |
| 35 | #include "sdl_config.h" | ||
| 34 | #include "video_core/renderer_base.h" | 36 | #include "video_core/renderer_base.h" |
| 35 | #include "yuzu_cmd/config.h" | ||
| 36 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 37 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 37 | #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" | 38 | #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" |
| 38 | #include "yuzu_cmd/emu_window/emu_window_sdl2_null.h" | 39 | #include "yuzu_cmd/emu_window/emu_window_sdl2_null.h" |
| @@ -62,6 +63,10 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | |||
| 62 | } | 63 | } |
| 63 | #endif | 64 | #endif |
| 64 | 65 | ||
| 66 | #ifdef __unix__ | ||
| 67 | #include "common/linux/gamemode.h" | ||
| 68 | #endif | ||
| 69 | |||
| 65 | static void PrintHelp(const char* argv0) { | 70 | static void PrintHelp(const char* argv0) { |
| 66 | std::cout << "Usage: " << argv0 | 71 | std::cout << "Usage: " << argv0 |
| 67 | << " [options] <filename>\n" | 72 | << " [options] <filename>\n" |
| @@ -300,7 +305,7 @@ int main(int argc, char** argv) { | |||
| 300 | } | 305 | } |
| 301 | } | 306 | } |
| 302 | 307 | ||
| 303 | Config config{config_path}; | 308 | SdlConfig config{config_path}; |
| 304 | 309 | ||
| 305 | // apply the log_filter setting | 310 | // apply the log_filter setting |
| 306 | // the logger was initialized before and doesn't pick up the filter on its own | 311 | // the logger was initialized before and doesn't pick up the filter on its own |
| @@ -424,6 +429,10 @@ int main(int argc, char** argv) { | |||
| 424 | exit(0); | 429 | exit(0); |
| 425 | }); | 430 | }); |
| 426 | 431 | ||
| 432 | #ifdef __unix__ | ||
| 433 | Common::Linux::StartGamemode(); | ||
| 434 | #endif | ||
| 435 | |||
| 427 | void(system.Run()); | 436 | void(system.Run()); |
| 428 | if (system.DebuggerEnabled()) { | 437 | if (system.DebuggerEnabled()) { |
| 429 | system.InitializeDebugger(); | 438 | system.InitializeDebugger(); |
| @@ -435,6 +444,10 @@ int main(int argc, char** argv) { | |||
| 435 | void(system.Pause()); | 444 | void(system.Pause()); |
| 436 | system.ShutdownMainProcess(); | 445 | system.ShutdownMainProcess(); |
| 437 | 446 | ||
| 447 | #ifdef __unix__ | ||
| 448 | Common::Linux::StopGamemode(); | ||
| 449 | #endif | ||
| 450 | |||
| 438 | detached_tasks.WaitForAllTasks(); | 451 | detached_tasks.WaitForAllTasks(); |
| 439 | return 0; | 452 | return 0; |
| 440 | } | 453 | } |