settings.cpp (86228B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "settings.h" 5 #include "achievements.h" 6 #include "controller.h" 7 #include "host.h" 8 #include "system.h" 9 10 #include "util/gpu_device.h" 11 #include "util/imgui_manager.h" 12 #include "util/input_manager.h" 13 #include "util/media_capture.h" 14 15 #include "common/assert.h" 16 #include "common/file_system.h" 17 #include "common/log.h" 18 #include "common/path.h" 19 #include "common/string_util.h" 20 21 #include <algorithm> 22 #include <array> 23 #include <cctype> 24 #include <numeric> 25 26 Log_SetChannel(Settings); 27 28 Settings g_settings; 29 30 const char* SettingInfo::StringDefaultValue() const 31 { 32 return default_value ? default_value : ""; 33 } 34 35 bool SettingInfo::BooleanDefaultValue() const 36 { 37 return default_value ? StringUtil::FromChars<bool>(default_value).value_or(false) : false; 38 } 39 40 s32 SettingInfo::IntegerDefaultValue() const 41 { 42 return default_value ? StringUtil::FromChars<s32>(default_value).value_or(0) : 0; 43 } 44 45 s32 SettingInfo::IntegerMinValue() const 46 { 47 static constexpr s32 fallback_value = std::numeric_limits<s32>::min(); 48 return min_value ? StringUtil::FromChars<s32>(min_value).value_or(fallback_value) : fallback_value; 49 } 50 51 s32 SettingInfo::IntegerMaxValue() const 52 { 53 static constexpr s32 fallback_value = std::numeric_limits<s32>::max(); 54 return max_value ? StringUtil::FromChars<s32>(max_value).value_or(fallback_value) : fallback_value; 55 } 56 57 s32 SettingInfo::IntegerStepValue() const 58 { 59 static constexpr s32 fallback_value = 1; 60 return step_value ? StringUtil::FromChars<s32>(step_value).value_or(fallback_value) : fallback_value; 61 } 62 63 float SettingInfo::FloatDefaultValue() const 64 { 65 return default_value ? StringUtil::FromChars<float>(default_value).value_or(0.0f) : 0.0f; 66 } 67 68 float SettingInfo::FloatMinValue() const 69 { 70 static constexpr float fallback_value = std::numeric_limits<float>::min(); 71 return min_value ? StringUtil::FromChars<float>(min_value).value_or(fallback_value) : fallback_value; 72 } 73 74 float SettingInfo::FloatMaxValue() const 75 { 76 static constexpr float fallback_value = std::numeric_limits<float>::max(); 77 return max_value ? StringUtil::FromChars<float>(max_value).value_or(fallback_value) : fallback_value; 78 } 79 80 float SettingInfo::FloatStepValue() const 81 { 82 static constexpr float fallback_value = 0.1f; 83 return step_value ? StringUtil::FromChars<float>(step_value).value_or(fallback_value) : fallback_value; 84 } 85 86 #if defined(_WIN32) 87 const MediaCaptureBackend Settings::DEFAULT_MEDIA_CAPTURE_BACKEND = MediaCaptureBackend::MediaFoundation; 88 #elif !defined(__ANDROID__) 89 const MediaCaptureBackend Settings::DEFAULT_MEDIA_CAPTURE_BACKEND = MediaCaptureBackend::FFmpeg; 90 #endif 91 92 Settings::Settings() 93 { 94 controller_types[0] = DEFAULT_CONTROLLER_1_TYPE; 95 memory_card_types[0] = DEFAULT_MEMORY_CARD_1_TYPE; 96 for (u32 i = 1; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) 97 { 98 controller_types[i] = DEFAULT_CONTROLLER_2_TYPE; 99 memory_card_types[i] = DEFAULT_MEMORY_CARD_2_TYPE; 100 } 101 } 102 103 bool Settings::HasAnyPerGameMemoryCards() const 104 { 105 return std::any_of(memory_card_types.begin(), memory_card_types.end(), [](MemoryCardType t) { 106 return (t == MemoryCardType::PerGame || t == MemoryCardType::PerGameTitle); 107 }); 108 } 109 110 void Settings::CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator) 111 { 112 const u32 percent_gcd = std::gcd(percent, 100); 113 *numerator = percent / percent_gcd; 114 *denominator = 100u / percent_gcd; 115 } 116 117 u32 Settings::CPUOverclockFractionToPercent(u32 numerator, u32 denominator) 118 { 119 return (numerator * 100u) / denominator; 120 } 121 122 void Settings::SetCPUOverclockPercent(u32 percent) 123 { 124 CPUOverclockPercentToFraction(percent, &cpu_overclock_numerator, &cpu_overclock_denominator); 125 } 126 127 u32 Settings::GetCPUOverclockPercent() const 128 { 129 return CPUOverclockFractionToPercent(cpu_overclock_numerator, cpu_overclock_denominator); 130 } 131 132 void Settings::UpdateOverclockActive() 133 { 134 cpu_overclock_active = (cpu_overclock_enable && (cpu_overclock_numerator != 1 || cpu_overclock_denominator != 1)); 135 } 136 137 void Settings::Load(SettingsInterface& si, SettingsInterface& controller_si) 138 { 139 region = 140 ParseConsoleRegionName( 141 si.GetStringValue("Console", "Region", Settings::GetConsoleRegionName(Settings::DEFAULT_CONSOLE_REGION)).c_str()) 142 .value_or(DEFAULT_CONSOLE_REGION); 143 enable_8mb_ram = si.GetBoolValue("Console", "Enable8MBRAM", false); 144 145 emulation_speed = si.GetFloatValue("Main", "EmulationSpeed", 1.0f); 146 fast_forward_speed = si.GetFloatValue("Main", "FastForwardSpeed", 0.0f); 147 turbo_speed = si.GetFloatValue("Main", "TurboSpeed", 0.0f); 148 sync_to_host_refresh_rate = si.GetBoolValue("Main", "SyncToHostRefreshRate", false); 149 increase_timer_resolution = si.GetBoolValue("Main", "IncreaseTimerResolution", true); 150 inhibit_screensaver = si.GetBoolValue("Main", "InhibitScreensaver", true); 151 start_paused = si.GetBoolValue("Main", "StartPaused", false); 152 start_fullscreen = si.GetBoolValue("Main", "StartFullscreen", false); 153 pause_on_focus_loss = si.GetBoolValue("Main", "PauseOnFocusLoss", false); 154 pause_on_controller_disconnection = si.GetBoolValue("Main", "PauseOnControllerDisconnection", false); 155 save_state_on_exit = si.GetBoolValue("Main", "SaveStateOnExit", true); 156 create_save_state_backups = si.GetBoolValue("Main", "CreateSaveStateBackups", DEFAULT_SAVE_STATE_BACKUPS); 157 confim_power_off = si.GetBoolValue("Main", "ConfirmPowerOff", true); 158 load_devices_from_save_states = si.GetBoolValue("Main", "LoadDevicesFromSaveStates", false); 159 apply_compatibility_settings = si.GetBoolValue("Main", "ApplyCompatibilitySettings", true); 160 apply_game_settings = si.GetBoolValue("Main", "ApplyGameSettings", true); 161 enable_cheats = si.GetBoolValue("Console", "EnableCheats", false); 162 disable_all_enhancements = si.GetBoolValue("Main", "DisableAllEnhancements", false); 163 enable_discord_presence = si.GetBoolValue("Main", "EnableDiscordPresence", false); 164 rewind_enable = si.GetBoolValue("Main", "RewindEnable", false); 165 rewind_save_frequency = si.GetFloatValue("Main", "RewindFrequency", 10.0f); 166 rewind_save_slots = static_cast<u32>(si.GetIntValue("Main", "RewindSaveSlots", 10)); 167 runahead_frames = static_cast<u32>(si.GetIntValue("Main", "RunaheadFrameCount", 0)); 168 169 pine_enable = si.GetBoolValue("PINE", "Enabled", false); 170 pine_slot = static_cast<u16>( 171 std::min<u32>(si.GetUIntValue("PINE", "Slot", DEFAULT_PINE_SLOT), std::numeric_limits<u16>::max())); 172 173 cpu_execution_mode = 174 ParseCPUExecutionMode( 175 si.GetStringValue("CPU", "ExecutionMode", GetCPUExecutionModeName(DEFAULT_CPU_EXECUTION_MODE)).c_str()) 176 .value_or(DEFAULT_CPU_EXECUTION_MODE); 177 cpu_overclock_numerator = std::max(si.GetIntValue("CPU", "OverclockNumerator", 1), 1); 178 cpu_overclock_denominator = std::max(si.GetIntValue("CPU", "OverclockDenominator", 1), 1); 179 cpu_overclock_enable = si.GetBoolValue("CPU", "OverclockEnable", false); 180 UpdateOverclockActive(); 181 cpu_recompiler_memory_exceptions = si.GetBoolValue("CPU", "RecompilerMemoryExceptions", false); 182 cpu_recompiler_block_linking = si.GetBoolValue("CPU", "RecompilerBlockLinking", true); 183 cpu_recompiler_icache = si.GetBoolValue("CPU", "RecompilerICache", false); 184 cpu_fastmem_mode = ParseCPUFastmemMode( 185 si.GetStringValue("CPU", "FastmemMode", GetCPUFastmemModeName(DEFAULT_CPU_FASTMEM_MODE)).c_str()) 186 .value_or(DEFAULT_CPU_FASTMEM_MODE); 187 188 gpu_renderer = ParseRendererName(si.GetStringValue("GPU", "Renderer", GetRendererName(DEFAULT_GPU_RENDERER)).c_str()) 189 .value_or(DEFAULT_GPU_RENDERER); 190 gpu_adapter = si.GetStringValue("GPU", "Adapter", ""); 191 gpu_resolution_scale = static_cast<u8>(si.GetIntValue("GPU", "ResolutionScale", 1)); 192 gpu_multisamples = static_cast<u8>(si.GetIntValue("GPU", "Multisamples", 1)); 193 gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false); 194 gpu_disable_shader_cache = si.GetBoolValue("GPU", "DisableShaderCache", false); 195 gpu_disable_dual_source_blend = si.GetBoolValue("GPU", "DisableDualSourceBlend", false); 196 gpu_disable_framebuffer_fetch = si.GetBoolValue("GPU", "DisableFramebufferFetch", false); 197 gpu_disable_texture_buffers = si.GetBoolValue("GPU", "DisableTextureBuffers", false); 198 gpu_disable_texture_copy_to_self = si.GetBoolValue("GPU", "DisableTextureCopyToSelf", false); 199 gpu_disable_memory_import = si.GetBoolValue("GPU", "DisableMemoryImport", false); 200 gpu_disable_raster_order_views = si.GetBoolValue("GPU", "DisableRasterOrderViews", false); 201 gpu_per_sample_shading = si.GetBoolValue("GPU", "PerSampleShading", false); 202 gpu_use_thread = si.GetBoolValue("GPU", "UseThread", true); 203 gpu_use_software_renderer_for_readbacks = si.GetBoolValue("GPU", "UseSoftwareRendererForReadbacks", false); 204 gpu_threaded_presentation = si.GetBoolValue("GPU", "ThreadedPresentation", DEFAULT_THREADED_PRESENTATION); 205 gpu_true_color = si.GetBoolValue("GPU", "TrueColor", true); 206 gpu_debanding = si.GetBoolValue("GPU", "Debanding", false); 207 gpu_scaled_dithering = si.GetBoolValue("GPU", "ScaledDithering", true); 208 gpu_force_round_texcoords = si.GetBoolValue("GPU", "ForceRoundTextureCoordinates", false); 209 gpu_accurate_blending = si.GetBoolValue("GPU", "AccurateBlending", false); 210 gpu_texture_filter = 211 ParseTextureFilterName( 212 si.GetStringValue("GPU", "TextureFilter", GetTextureFilterName(DEFAULT_GPU_TEXTURE_FILTER)).c_str()) 213 .value_or(DEFAULT_GPU_TEXTURE_FILTER); 214 gpu_sprite_texture_filter = 215 ParseTextureFilterName( 216 si.GetStringValue("GPU", "SpriteTextureFilter", GetTextureFilterName(gpu_texture_filter)).c_str()) 217 .value_or(gpu_texture_filter); 218 gpu_line_detect_mode = 219 ParseLineDetectModeName( 220 si.GetStringValue("GPU", "LineDetectMode", GetLineDetectModeName(DEFAULT_GPU_LINE_DETECT_MODE)).c_str()) 221 .value_or(DEFAULT_GPU_LINE_DETECT_MODE); 222 gpu_downsample_mode = 223 ParseDownsampleModeName( 224 si.GetStringValue("GPU", "DownsampleMode", GetDownsampleModeName(DEFAULT_GPU_DOWNSAMPLE_MODE)).c_str()) 225 .value_or(DEFAULT_GPU_DOWNSAMPLE_MODE); 226 gpu_downsample_scale = static_cast<u8>(si.GetUIntValue("GPU", "DownsampleScale", 1)); 227 gpu_wireframe_mode = 228 ParseGPUWireframeMode( 229 si.GetStringValue("GPU", "WireframeMode", GetGPUWireframeModeName(DEFAULT_GPU_WIREFRAME_MODE)).c_str()) 230 .value_or(DEFAULT_GPU_WIREFRAME_MODE); 231 gpu_disable_interlacing = si.GetBoolValue("GPU", "DisableInterlacing", true); 232 gpu_force_ntsc_timings = si.GetBoolValue("GPU", "ForceNTSCTimings", false); 233 gpu_widescreen_hack = si.GetBoolValue("GPU", "WidescreenHack", false); 234 display_24bit_chroma_smoothing = si.GetBoolValue("GPU", "ChromaSmoothing24Bit", false); 235 gpu_pgxp_enable = si.GetBoolValue("GPU", "PGXPEnable", false); 236 gpu_pgxp_culling = si.GetBoolValue("GPU", "PGXPCulling", true); 237 gpu_pgxp_texture_correction = si.GetBoolValue("GPU", "PGXPTextureCorrection", true); 238 gpu_pgxp_color_correction = si.GetBoolValue("GPU", "PGXPColorCorrection", false); 239 gpu_pgxp_vertex_cache = si.GetBoolValue("GPU", "PGXPVertexCache", false); 240 gpu_pgxp_cpu = si.GetBoolValue("GPU", "PGXPCPU", false); 241 gpu_pgxp_preserve_proj_fp = si.GetBoolValue("GPU", "PGXPPreserveProjFP", false); 242 gpu_pgxp_tolerance = si.GetFloatValue("GPU", "PGXPTolerance", -1.0f); 243 gpu_pgxp_depth_buffer = si.GetBoolValue("GPU", "PGXPDepthBuffer", false); 244 gpu_pgxp_disable_2d = si.GetBoolValue("GPU", "PGXPDisableOn2DPolygons", false); 245 SetPGXPDepthClearThreshold(si.GetFloatValue("GPU", "PGXPDepthClearThreshold", DEFAULT_GPU_PGXP_DEPTH_THRESHOLD)); 246 247 display_deinterlacing_mode = 248 ParseDisplayDeinterlacingMode(si.GetStringValue("Display", "DeinterlacingMode", 249 GetDisplayDeinterlacingModeName(DEFAULT_DISPLAY_DEINTERLACING_MODE)) 250 .c_str()) 251 .value_or(DEFAULT_DISPLAY_DEINTERLACING_MODE); 252 display_crop_mode = 253 ParseDisplayCropMode( 254 si.GetStringValue("Display", "CropMode", GetDisplayCropModeName(DEFAULT_DISPLAY_CROP_MODE)).c_str()) 255 .value_or(DEFAULT_DISPLAY_CROP_MODE); 256 display_aspect_ratio = 257 ParseDisplayAspectRatio( 258 si.GetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(DEFAULT_DISPLAY_ASPECT_RATIO)).c_str()) 259 .value_or(DEFAULT_DISPLAY_ASPECT_RATIO); 260 display_aspect_ratio_custom_numerator = static_cast<u16>( 261 std::clamp<int>(si.GetIntValue("Display", "CustomAspectRatioNumerator", 4), 1, std::numeric_limits<u16>::max())); 262 display_aspect_ratio_custom_denominator = static_cast<u16>( 263 std::clamp<int>(si.GetIntValue("Display", "CustomAspectRatioDenominator", 3), 1, std::numeric_limits<u16>::max())); 264 display_alignment = 265 ParseDisplayAlignment( 266 si.GetStringValue("Display", "Alignment", GetDisplayAlignmentName(DEFAULT_DISPLAY_ALIGNMENT)).c_str()) 267 .value_or(DEFAULT_DISPLAY_ALIGNMENT); 268 display_rotation = 269 ParseDisplayRotation( 270 si.GetStringValue("Display", "Rotation", GetDisplayRotationName(DEFAULT_DISPLAY_ROTATION)).c_str()) 271 .value_or(DEFAULT_DISPLAY_ROTATION); 272 display_scaling = 273 ParseDisplayScaling(si.GetStringValue("Display", "Scaling", GetDisplayScalingName(DEFAULT_DISPLAY_SCALING)).c_str()) 274 .value_or(DEFAULT_DISPLAY_SCALING); 275 display_exclusive_fullscreen_control = 276 ParseDisplayExclusiveFullscreenControl( 277 si.GetStringValue("Display", "ExclusiveFullscreenControl", 278 GetDisplayExclusiveFullscreenControlName(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL)) 279 .c_str()) 280 .value_or(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL); 281 display_screenshot_mode = 282 ParseDisplayScreenshotMode( 283 si.GetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(DEFAULT_DISPLAY_SCREENSHOT_MODE)) 284 .c_str()) 285 .value_or(DEFAULT_DISPLAY_SCREENSHOT_MODE); 286 display_screenshot_format = 287 ParseDisplayScreenshotFormat(si.GetStringValue("Display", "ScreenshotFormat", 288 GetDisplayScreenshotFormatName(DEFAULT_DISPLAY_SCREENSHOT_FORMAT)) 289 .c_str()) 290 .value_or(DEFAULT_DISPLAY_SCREENSHOT_FORMAT); 291 display_screenshot_quality = static_cast<u8>( 292 std::clamp<u32>(si.GetUIntValue("Display", "ScreenshotQuality", DEFAULT_DISPLAY_SCREENSHOT_QUALITY), 1, 100)); 293 display_optimal_frame_pacing = si.GetBoolValue("Display", "OptimalFramePacing", false); 294 display_pre_frame_sleep = si.GetBoolValue("Display", "PreFrameSleep", false); 295 display_pre_frame_sleep_buffer = 296 si.GetFloatValue("Display", "PreFrameSleepBuffer", DEFAULT_DISPLAY_PRE_FRAME_SLEEP_BUFFER); 297 display_skip_presenting_duplicate_frames = si.GetBoolValue("Display", "SkipPresentingDuplicateFrames", false); 298 display_vsync = si.GetBoolValue("Display", "VSync", false); 299 display_disable_mailbox_presentation = si.GetBoolValue("Display", "DisableMailboxPresentation", false); 300 display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false); 301 display_active_start_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveStartOffset", 0)); 302 display_active_end_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveEndOffset", 0)); 303 display_line_start_offset = static_cast<s8>(si.GetIntValue("Display", "LineStartOffset", 0)); 304 display_line_end_offset = static_cast<s8>(si.GetIntValue("Display", "LineEndOffset", 0)); 305 display_show_osd_messages = si.GetBoolValue("Display", "ShowOSDMessages", true); 306 display_show_fps = si.GetBoolValue("Display", "ShowFPS", false); 307 display_show_speed = si.GetBoolValue("Display", "ShowSpeed", false); 308 display_show_gpu_stats = si.GetBoolValue("Display", "ShowGPUStatistics", false); 309 display_show_resolution = si.GetBoolValue("Display", "ShowResolution", false); 310 display_show_latency_stats = si.GetBoolValue("Display", "ShowLatencyStatistics", false); 311 display_show_cpu_usage = si.GetBoolValue("Display", "ShowCPU", false); 312 display_show_gpu_usage = si.GetBoolValue("Display", "ShowGPU", false); 313 display_show_frame_times = si.GetBoolValue("Display", "ShowFrameTimes", false); 314 display_show_status_indicators = si.GetBoolValue("Display", "ShowStatusIndicators", true); 315 display_show_inputs = si.GetBoolValue("Display", "ShowInputs", false); 316 display_show_enhancements = si.GetBoolValue("Display", "ShowEnhancements", false); 317 display_stretch_vertically = si.GetBoolValue("Display", "StretchVertically", false); 318 display_osd_scale = si.GetFloatValue("Display", "OSDScale", DEFAULT_OSD_SCALE); 319 320 save_state_compression = ParseSaveStateCompressionModeName( 321 si.GetStringValue("Main", "SaveStateCompression", 322 GetSaveStateCompressionModeName(DEFAULT_SAVE_STATE_COMPRESSION_MODE)) 323 .c_str()) 324 .value_or(DEFAULT_SAVE_STATE_COMPRESSION_MODE); 325 326 cdrom_readahead_sectors = 327 static_cast<u8>(si.GetIntValue("CDROM", "ReadaheadSectors", DEFAULT_CDROM_READAHEAD_SECTORS)); 328 cdrom_mechacon_version = 329 ParseCDROMMechVersionName( 330 si.GetStringValue("CDROM", "MechaconVersion", GetCDROMMechVersionName(DEFAULT_CDROM_MECHACON_VERSION)).c_str()) 331 .value_or(DEFAULT_CDROM_MECHACON_VERSION); 332 cdrom_region_check = si.GetBoolValue("CDROM", "RegionCheck", false); 333 cdrom_load_image_to_ram = si.GetBoolValue("CDROM", "LoadImageToRAM", false); 334 cdrom_load_image_patches = si.GetBoolValue("CDROM", "LoadImagePatches", false); 335 cdrom_mute_cd_audio = si.GetBoolValue("CDROM", "MuteCDAudio", false); 336 cdrom_read_speedup = si.GetIntValue("CDROM", "ReadSpeedup", 1); 337 cdrom_seek_speedup = si.GetIntValue("CDROM", "SeekSpeedup", 1); 338 339 audio_backend = 340 AudioStream::ParseBackendName( 341 si.GetStringValue("Audio", "Backend", AudioStream::GetBackendName(AudioStream::DEFAULT_BACKEND)).c_str()) 342 .value_or(AudioStream::DEFAULT_BACKEND); 343 audio_driver = si.GetStringValue("Audio", "Driver"); 344 audio_output_device = si.GetStringValue("Audio", "OutputDevice"); 345 audio_stream_parameters.Load(si, "Audio"); 346 audio_output_volume = si.GetUIntValue("Audio", "OutputVolume", 100); 347 audio_fast_forward_volume = si.GetUIntValue("Audio", "FastForwardVolume", 100); 348 349 audio_output_muted = si.GetBoolValue("Audio", "OutputMuted", false); 350 351 use_old_mdec_routines = si.GetBoolValue("Hacks", "UseOldMDECRoutines", false); 352 export_shared_memory = si.GetBoolValue("Hacks", "ExportSharedMemory", false); 353 pcdrv_enable = si.GetBoolValue("PCDrv", "Enabled", false); 354 pcdrv_enable_writes = si.GetBoolValue("PCDrv", "EnableWrites", false); 355 pcdrv_root = si.GetStringValue("PCDrv", "Root"); 356 357 dma_max_slice_ticks = si.GetIntValue("Hacks", "DMAMaxSliceTicks", DEFAULT_DMA_MAX_SLICE_TICKS); 358 dma_halt_ticks = si.GetIntValue("Hacks", "DMAHaltTicks", DEFAULT_DMA_HALT_TICKS); 359 gpu_fifo_size = static_cast<u32>(si.GetIntValue("Hacks", "GPUFIFOSize", DEFAULT_GPU_FIFO_SIZE)); 360 gpu_max_run_ahead = si.GetIntValue("Hacks", "GPUMaxRunAhead", DEFAULT_GPU_MAX_RUN_AHEAD); 361 362 bios_tty_logging = si.GetBoolValue("BIOS", "TTYLogging", false); 363 bios_patch_fast_boot = si.GetBoolValue("BIOS", "PatchFastBoot", DEFAULT_FAST_BOOT_VALUE); 364 365 multitap_mode = 366 ParseMultitapModeName( 367 controller_si.GetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(DEFAULT_MULTITAP_MODE)) 368 .c_str()) 369 .value_or(DEFAULT_MULTITAP_MODE); 370 371 const std::array<bool, 2> mtap_enabled = {{IsPort1MultitapEnabled(), IsPort2MultitapEnabled()}}; 372 for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) 373 { 374 // Ignore types when multitap not enabled 375 const auto [port, slot] = Controller::ConvertPadToPortAndSlot(i); 376 if (Controller::PadIsMultitapSlot(slot) && !mtap_enabled[port]) 377 { 378 controller_types[i] = ControllerType::None; 379 continue; 380 } 381 382 const ControllerType default_type = (i == 0) ? DEFAULT_CONTROLLER_1_TYPE : DEFAULT_CONTROLLER_2_TYPE; 383 const Controller::ControllerInfo* cinfo = Controller::GetControllerInfo(controller_si.GetTinyStringValue( 384 Controller::GetSettingsSection(i).c_str(), "Type", Controller::GetControllerInfo(default_type)->name)); 385 controller_types[i] = cinfo ? cinfo->type : default_type; 386 } 387 388 memory_card_types[0] = 389 ParseMemoryCardTypeName( 390 si.GetStringValue("MemoryCards", "Card1Type", GetMemoryCardTypeName(DEFAULT_MEMORY_CARD_1_TYPE)).c_str()) 391 .value_or(DEFAULT_MEMORY_CARD_1_TYPE); 392 memory_card_types[1] = 393 ParseMemoryCardTypeName( 394 si.GetStringValue("MemoryCards", "Card2Type", GetMemoryCardTypeName(DEFAULT_MEMORY_CARD_2_TYPE)).c_str()) 395 .value_or(DEFAULT_MEMORY_CARD_2_TYPE); 396 memory_card_paths[0] = si.GetStringValue("MemoryCards", "Card1Path", ""); 397 memory_card_paths[1] = si.GetStringValue("MemoryCards", "Card2Path", ""); 398 memory_card_use_playlist_title = si.GetBoolValue("MemoryCards", "UsePlaylistTitle", true); 399 400 achievements_enabled = si.GetBoolValue("Cheevos", "Enabled", false); 401 achievements_hardcore_mode = si.GetBoolValue("Cheevos", "ChallengeMode", false); 402 achievements_notifications = si.GetBoolValue("Cheevos", "Notifications", true); 403 achievements_leaderboard_notifications = si.GetBoolValue("Cheevos", "LeaderboardNotifications", true); 404 achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true); 405 achievements_overlays = si.GetBoolValue("Cheevos", "Overlays", true); 406 achievements_encore_mode = si.GetBoolValue("Cheevos", "EncoreMode", false); 407 achievements_spectator_mode = si.GetBoolValue("Cheevos", "SpectatorMode", false); 408 achievements_unofficial_test_mode = si.GetBoolValue("Cheevos", "UnofficialTestMode", false); 409 achievements_use_first_disc_from_playlist = si.GetBoolValue("Cheevos", "UseFirstDiscFromPlaylist", true); 410 achievements_use_raintegration = si.GetBoolValue("Cheevos", "UseRAIntegration", false); 411 achievements_notification_duration = 412 si.GetIntValue("Cheevos", "NotificationsDuration", DEFAULT_ACHIEVEMENT_NOTIFICATION_TIME); 413 achievements_leaderboard_duration = 414 si.GetIntValue("Cheevos", "LeaderboardsDuration", DEFAULT_LEADERBOARD_NOTIFICATION_TIME); 415 416 log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str()) 417 .value_or(DEFAULT_LOG_LEVEL); 418 log_filter = si.GetStringValue("Logging", "LogFilter", ""); 419 log_timestamps = si.GetBoolValue("Logging", "LogTimestamps", true); 420 log_to_console = si.GetBoolValue("Logging", "LogToConsole", DEFAULT_LOG_TO_CONSOLE); 421 log_to_debug = si.GetBoolValue("Logging", "LogToDebug", false); 422 log_to_window = si.GetBoolValue("Logging", "LogToWindow", false); 423 log_to_file = si.GetBoolValue("Logging", "LogToFile", false); 424 425 debugging.show_vram = si.GetBoolValue("Debug", "ShowVRAM"); 426 debugging.dump_cpu_to_vram_copies = si.GetBoolValue("Debug", "DumpCPUToVRAMCopies"); 427 debugging.dump_vram_to_cpu_copies = si.GetBoolValue("Debug", "DumpVRAMToCPUCopies"); 428 debugging.enable_gdb_server = si.GetBoolValue("Debug", "EnableGDBServer"); 429 debugging.gdb_server_port = static_cast<u16>(si.GetIntValue("Debug", "GDBServerPort")); 430 debugging.show_gpu_state = si.GetBoolValue("Debug", "ShowGPUState"); 431 debugging.show_cdrom_state = si.GetBoolValue("Debug", "ShowCDROMState"); 432 debugging.show_spu_state = si.GetBoolValue("Debug", "ShowSPUState"); 433 debugging.show_timers_state = si.GetBoolValue("Debug", "ShowTimersState"); 434 debugging.show_mdec_state = si.GetBoolValue("Debug", "ShowMDECState"); 435 debugging.show_dma_state = si.GetBoolValue("Debug", "ShowDMAState"); 436 437 texture_replacements.enable_vram_write_replacements = 438 si.GetBoolValue("TextureReplacements", "EnableVRAMWriteReplacements", false); 439 texture_replacements.preload_textures = si.GetBoolValue("TextureReplacements", "PreloadTextures", false); 440 texture_replacements.dump_vram_writes = si.GetBoolValue("TextureReplacements", "DumpVRAMWrites", false); 441 texture_replacements.dump_vram_write_force_alpha_channel = 442 si.GetBoolValue("TextureReplacements", "DumpVRAMWriteForceAlphaChannel", true); 443 texture_replacements.dump_vram_write_width_threshold = 444 si.GetIntValue("TextureReplacements", "DumpVRAMWriteWidthThreshold", 128); 445 texture_replacements.dump_vram_write_height_threshold = 446 si.GetIntValue("TextureReplacements", "DumpVRAMWriteHeightThreshold", 128); 447 448 #ifdef __ANDROID__ 449 // No expansion due to license incompatibility. 450 audio_expansion_mode = AudioExpansionMode::Disabled; 451 452 // Android users are incredibly silly and don't understand that stretch is in the aspect ratio list... 453 if (si.GetBoolValue("Display", "Stretch", false)) 454 display_aspect_ratio = DisplayAspectRatio::MatchWindow; 455 #endif 456 } 457 458 void Settings::Save(SettingsInterface& si, bool ignore_base) const 459 { 460 si.SetStringValue("Console", "Region", GetConsoleRegionName(region)); 461 si.SetBoolValue("Console", "Enable8MBRAM", enable_8mb_ram); 462 463 si.SetFloatValue("Main", "EmulationSpeed", emulation_speed); 464 si.SetFloatValue("Main", "FastForwardSpeed", fast_forward_speed); 465 si.SetFloatValue("Main", "TurboSpeed", turbo_speed); 466 467 if (!ignore_base) 468 { 469 si.SetBoolValue("Main", "SyncToHostRefreshRate", sync_to_host_refresh_rate); 470 si.SetBoolValue("Main", "IncreaseTimerResolution", increase_timer_resolution); 471 si.SetBoolValue("Main", "InhibitScreensaver", inhibit_screensaver); 472 si.SetBoolValue("Main", "StartPaused", start_paused); 473 si.SetBoolValue("Main", "StartFullscreen", start_fullscreen); 474 si.SetBoolValue("Main", "PauseOnFocusLoss", pause_on_focus_loss); 475 si.SetBoolValue("Main", "PauseOnControllerDisconnection", pause_on_controller_disconnection); 476 si.SetBoolValue("Main", "SaveStateOnExit", save_state_on_exit); 477 si.SetBoolValue("Main", "CreateSaveStateBackups", create_save_state_backups); 478 si.SetStringValue("Main", "SaveStateCompression", GetSaveStateCompressionModeName(save_state_compression)); 479 si.SetBoolValue("Main", "ConfirmPowerOff", confim_power_off); 480 si.SetBoolValue("Main", "EnableDiscordPresence", enable_discord_presence); 481 } 482 483 si.SetBoolValue("Main", "LoadDevicesFromSaveStates", load_devices_from_save_states); 484 si.SetBoolValue("Console", "EnableCheats", enable_cheats); 485 si.SetBoolValue("Main", "DisableAllEnhancements", disable_all_enhancements); 486 si.SetBoolValue("Main", "RewindEnable", rewind_enable); 487 si.SetFloatValue("Main", "RewindFrequency", rewind_save_frequency); 488 si.SetIntValue("Main", "RewindSaveSlots", rewind_save_slots); 489 si.SetIntValue("Main", "RunaheadFrameCount", runahead_frames); 490 491 si.SetBoolValue("PINE", "Enabled", pine_enable); 492 si.SetUIntValue("PINE", "Slot", pine_slot); 493 494 si.SetStringValue("CPU", "ExecutionMode", GetCPUExecutionModeName(cpu_execution_mode)); 495 si.SetBoolValue("CPU", "OverclockEnable", cpu_overclock_enable); 496 si.SetIntValue("CPU", "OverclockNumerator", cpu_overclock_numerator); 497 si.SetIntValue("CPU", "OverclockDenominator", cpu_overclock_denominator); 498 si.SetBoolValue("CPU", "RecompilerMemoryExceptions", cpu_recompiler_memory_exceptions); 499 si.SetBoolValue("CPU", "RecompilerBlockLinking", cpu_recompiler_block_linking); 500 si.SetBoolValue("CPU", "RecompilerICache", cpu_recompiler_icache); 501 si.SetStringValue("CPU", "FastmemMode", GetCPUFastmemModeName(cpu_fastmem_mode)); 502 503 si.SetStringValue("GPU", "Renderer", GetRendererName(gpu_renderer)); 504 si.SetStringValue("GPU", "Adapter", gpu_adapter.c_str()); 505 si.SetIntValue("GPU", "ResolutionScale", static_cast<long>(gpu_resolution_scale)); 506 si.SetIntValue("GPU", "Multisamples", static_cast<long>(gpu_multisamples)); 507 508 if (!ignore_base) 509 { 510 si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device); 511 si.SetBoolValue("GPU", "DisableShaderCache", gpu_disable_shader_cache); 512 si.SetBoolValue("GPU", "DisableDualSourceBlend", gpu_disable_dual_source_blend); 513 si.SetBoolValue("GPU", "DisableFramebufferFetch", gpu_disable_framebuffer_fetch); 514 si.SetBoolValue("GPU", "DisableTextureBuffers", gpu_disable_texture_buffers); 515 si.SetBoolValue("GPU", "DisableTextureCopyToSelf", gpu_disable_texture_copy_to_self); 516 si.SetBoolValue("GPU", "DisableMemoryImport", gpu_disable_memory_import); 517 si.SetBoolValue("GPU", "DisableRasterOrderViews", gpu_disable_raster_order_views); 518 } 519 520 si.SetBoolValue("GPU", "PerSampleShading", gpu_per_sample_shading); 521 si.SetBoolValue("GPU", "UseThread", gpu_use_thread); 522 si.SetBoolValue("GPU", "ThreadedPresentation", gpu_threaded_presentation); 523 si.SetBoolValue("GPU", "UseSoftwareRendererForReadbacks", gpu_use_software_renderer_for_readbacks); 524 si.SetBoolValue("GPU", "TrueColor", gpu_true_color); 525 si.SetBoolValue("GPU", "Debanding", gpu_debanding); 526 si.SetBoolValue("GPU", "ScaledDithering", gpu_scaled_dithering); 527 si.SetBoolValue("GPU", "ForceRoundTextureCoordinates", gpu_force_round_texcoords); 528 si.SetBoolValue("GPU", "AccurateBlending", gpu_accurate_blending); 529 si.SetStringValue("GPU", "TextureFilter", GetTextureFilterName(gpu_texture_filter)); 530 si.SetStringValue( 531 "GPU", "SpriteTextureFilter", 532 (gpu_sprite_texture_filter != gpu_texture_filter) ? GetTextureFilterName(gpu_sprite_texture_filter) : ""); 533 si.SetStringValue("GPU", "LineDetectMode", GetLineDetectModeName(gpu_line_detect_mode)); 534 si.SetStringValue("GPU", "DownsampleMode", GetDownsampleModeName(gpu_downsample_mode)); 535 si.SetUIntValue("GPU", "DownsampleScale", gpu_downsample_scale); 536 si.SetStringValue("GPU", "WireframeMode", GetGPUWireframeModeName(gpu_wireframe_mode)); 537 si.SetBoolValue("GPU", "DisableInterlacing", gpu_disable_interlacing); 538 si.SetBoolValue("GPU", "ForceNTSCTimings", gpu_force_ntsc_timings); 539 si.SetBoolValue("GPU", "WidescreenHack", gpu_widescreen_hack); 540 si.SetBoolValue("GPU", "ChromaSmoothing24Bit", display_24bit_chroma_smoothing); 541 si.SetBoolValue("GPU", "PGXPEnable", gpu_pgxp_enable); 542 si.SetBoolValue("GPU", "PGXPCulling", gpu_pgxp_culling); 543 si.SetBoolValue("GPU", "PGXPTextureCorrection", gpu_pgxp_texture_correction); 544 si.SetBoolValue("GPU", "PGXPColorCorrection", gpu_pgxp_color_correction); 545 si.SetBoolValue("GPU", "PGXPVertexCache", gpu_pgxp_vertex_cache); 546 si.SetBoolValue("GPU", "PGXPCPU", gpu_pgxp_cpu); 547 si.SetBoolValue("GPU", "PGXPPreserveProjFP", gpu_pgxp_preserve_proj_fp); 548 si.SetFloatValue("GPU", "PGXPTolerance", gpu_pgxp_tolerance); 549 si.SetBoolValue("GPU", "PGXPDepthBuffer", gpu_pgxp_depth_buffer); 550 si.SetBoolValue("GPU", "PGXPDisableOn2DPolygons", gpu_pgxp_disable_2d); 551 si.SetFloatValue("GPU", "PGXPDepthClearThreshold", GetPGXPDepthClearThreshold()); 552 553 si.SetStringValue("Display", "DeinterlacingMode", GetDisplayDeinterlacingModeName(display_deinterlacing_mode)); 554 si.SetStringValue("Display", "CropMode", GetDisplayCropModeName(display_crop_mode)); 555 si.SetIntValue("Display", "ActiveStartOffset", display_active_start_offset); 556 si.SetIntValue("Display", "ActiveEndOffset", display_active_end_offset); 557 si.SetIntValue("Display", "LineStartOffset", display_line_start_offset); 558 si.SetIntValue("Display", "LineEndOffset", display_line_end_offset); 559 si.SetBoolValue("Display", "Force4_3For24Bit", display_force_4_3_for_24bit); 560 si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio)); 561 si.SetStringValue("Display", "Alignment", GetDisplayAlignmentName(display_alignment)); 562 si.SetStringValue("Display", "Rotation", GetDisplayRotationName(display_rotation)); 563 si.SetStringValue("Display", "Scaling", GetDisplayScalingName(display_scaling)); 564 si.SetBoolValue("Display", "OptimalFramePacing", display_optimal_frame_pacing); 565 si.SetBoolValue("Display", "PreFrameSleep", display_pre_frame_sleep); 566 si.SetBoolValue("Display", "SkipPresentingDuplicateFrames", display_skip_presenting_duplicate_frames); 567 si.SetFloatValue("Display", "PreFrameSleepBuffer", display_pre_frame_sleep_buffer); 568 si.SetBoolValue("Display", "VSync", display_vsync); 569 si.SetBoolValue("Display", "DisableMailboxPresentation", display_disable_mailbox_presentation); 570 si.SetStringValue("Display", "ExclusiveFullscreenControl", 571 GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control)); 572 si.SetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(display_screenshot_mode)); 573 si.SetStringValue("Display", "ScreenshotFormat", GetDisplayScreenshotFormatName(display_screenshot_format)); 574 si.SetUIntValue("Display", "ScreenshotQuality", display_screenshot_quality); 575 si.SetIntValue("Display", "CustomAspectRatioNumerator", display_aspect_ratio_custom_numerator); 576 si.GetIntValue("Display", "CustomAspectRatioDenominator", display_aspect_ratio_custom_denominator); 577 if (!ignore_base) 578 { 579 si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages); 580 si.SetBoolValue("Display", "ShowFPS", display_show_fps); 581 si.SetBoolValue("Display", "ShowSpeed", display_show_speed); 582 si.SetBoolValue("Display", "ShowResolution", display_show_resolution); 583 si.SetBoolValue("Display", "ShowLatencyStatistics", display_show_latency_stats); 584 si.SetBoolValue("Display", "ShowGPUStatistics", display_show_gpu_stats); 585 si.SetBoolValue("Display", "ShowCPU", display_show_cpu_usage); 586 si.SetBoolValue("Display", "ShowGPU", display_show_gpu_usage); 587 si.SetBoolValue("Display", "ShowFrameTimes", display_show_frame_times); 588 si.SetBoolValue("Display", "ShowStatusIndicators", display_show_status_indicators); 589 si.SetBoolValue("Display", "ShowInputs", display_show_inputs); 590 si.SetBoolValue("Display", "ShowEnhancements", display_show_enhancements); 591 si.SetFloatValue("Display", "OSDScale", display_osd_scale); 592 } 593 594 si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically); 595 596 si.SetIntValue("CDROM", "ReadaheadSectors", cdrom_readahead_sectors); 597 si.SetStringValue("CDROM", "MechaconVersion", GetCDROMMechVersionName(cdrom_mechacon_version)); 598 si.SetBoolValue("CDROM", "RegionCheck", cdrom_region_check); 599 si.SetBoolValue("CDROM", "LoadImageToRAM", cdrom_load_image_to_ram); 600 si.SetBoolValue("CDROM", "LoadImagePatches", cdrom_load_image_patches); 601 si.SetBoolValue("CDROM", "MuteCDAudio", cdrom_mute_cd_audio); 602 si.SetIntValue("CDROM", "ReadSpeedup", cdrom_read_speedup); 603 si.SetIntValue("CDROM", "SeekSpeedup", cdrom_seek_speedup); 604 605 si.SetStringValue("Audio", "Backend", AudioStream::GetBackendName(audio_backend)); 606 si.SetStringValue("Audio", "Driver", audio_driver.c_str()); 607 si.SetStringValue("Audio", "OutputDevice", audio_output_device.c_str()); 608 audio_stream_parameters.Save(si, "Audio"); 609 si.SetUIntValue("Audio", "OutputVolume", audio_output_volume); 610 si.SetUIntValue("Audio", "FastForwardVolume", audio_fast_forward_volume); 611 si.SetBoolValue("Audio", "OutputMuted", audio_output_muted); 612 613 si.SetBoolValue("Hacks", "UseOldMDECRoutines", use_old_mdec_routines); 614 si.SetBoolValue("Hacks", "ExportSharedMemory", export_shared_memory); 615 616 if (!ignore_base) 617 { 618 si.SetIntValue("Hacks", "DMAMaxSliceTicks", dma_max_slice_ticks); 619 si.SetIntValue("Hacks", "DMAHaltTicks", dma_halt_ticks); 620 si.SetIntValue("Hacks", "GPUFIFOSize", gpu_fifo_size); 621 si.SetIntValue("Hacks", "GPUMaxRunAhead", gpu_max_run_ahead); 622 } 623 624 si.SetBoolValue("PCDrv", "Enabled", pcdrv_enable); 625 si.SetBoolValue("PCDrv", "EnableWrites", pcdrv_enable_writes); 626 si.SetStringValue("PCDrv", "Root", pcdrv_root.c_str()); 627 628 si.SetBoolValue("BIOS", "TTYLogging", bios_tty_logging); 629 si.SetBoolValue("BIOS", "PatchFastBoot", bios_patch_fast_boot); 630 631 for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) 632 { 633 const Controller::ControllerInfo* cinfo = Controller::GetControllerInfo(controller_types[i]); 634 DebugAssert(cinfo); 635 si.SetStringValue(Controller::GetSettingsSection(i).c_str(), "Type", cinfo->name); 636 } 637 638 si.SetStringValue("MemoryCards", "Card1Type", GetMemoryCardTypeName(memory_card_types[0])); 639 si.SetStringValue("MemoryCards", "Card2Type", GetMemoryCardTypeName(memory_card_types[1])); 640 if (!memory_card_paths[0].empty()) 641 si.SetStringValue("MemoryCards", "Card1Path", memory_card_paths[0].c_str()); 642 else 643 si.DeleteValue("MemoryCards", "Card1Path"); 644 645 if (!memory_card_paths[1].empty()) 646 si.SetStringValue("MemoryCards", "Card2Path", memory_card_paths[1].c_str()); 647 else 648 si.DeleteValue("MemoryCards", "Card2Path"); 649 650 si.SetBoolValue("MemoryCards", "UsePlaylistTitle", memory_card_use_playlist_title); 651 652 si.SetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(multitap_mode)); 653 654 si.SetBoolValue("Cheevos", "Enabled", achievements_enabled); 655 si.SetBoolValue("Cheevos", "ChallengeMode", achievements_hardcore_mode); 656 si.SetBoolValue("Cheevos", "Notifications", achievements_notifications); 657 si.SetBoolValue("Cheevos", "LeaderboardNotifications", achievements_leaderboard_notifications); 658 si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects); 659 si.SetBoolValue("Cheevos", "Overlays", achievements_overlays); 660 si.SetBoolValue("Cheevos", "EncoreMode", achievements_encore_mode); 661 si.SetBoolValue("Cheevos", "SpectatorMode", achievements_spectator_mode); 662 si.SetBoolValue("Cheevos", "UnofficialTestMode", achievements_unofficial_test_mode); 663 si.SetBoolValue("Cheevos", "UseFirstDiscFromPlaylist", achievements_use_first_disc_from_playlist); 664 si.SetBoolValue("Cheevos", "UseRAIntegration", achievements_use_raintegration); 665 si.SetIntValue("Cheevos", "NotificationsDuration", achievements_notification_duration); 666 si.SetIntValue("Cheevos", "LeaderboardsDuration", achievements_leaderboard_duration); 667 668 if (!ignore_base) 669 { 670 si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level)); 671 si.SetStringValue("Logging", "LogFilter", log_filter.c_str()); 672 si.SetBoolValue("Logging", "LogTimestamps", log_timestamps); 673 si.SetBoolValue("Logging", "LogToConsole", log_to_console); 674 si.SetBoolValue("Logging", "LogToDebug", log_to_debug); 675 si.SetBoolValue("Logging", "LogToWindow", log_to_window); 676 si.SetBoolValue("Logging", "LogToFile", log_to_file); 677 678 si.SetBoolValue("Debug", "ShowVRAM", debugging.show_vram); 679 si.SetBoolValue("Debug", "DumpCPUToVRAMCopies", debugging.dump_cpu_to_vram_copies); 680 si.SetBoolValue("Debug", "DumpVRAMToCPUCopies", debugging.dump_vram_to_cpu_copies); 681 si.SetBoolValue("Debug", "ShowGPUState", debugging.show_gpu_state); 682 si.SetBoolValue("Debug", "ShowCDROMState", debugging.show_cdrom_state); 683 si.SetBoolValue("Debug", "ShowSPUState", debugging.show_spu_state); 684 si.SetBoolValue("Debug", "ShowTimersState", debugging.show_timers_state); 685 si.SetBoolValue("Debug", "ShowMDECState", debugging.show_mdec_state); 686 si.SetBoolValue("Debug", "ShowDMAState", debugging.show_dma_state); 687 } 688 689 si.SetBoolValue("TextureReplacements", "EnableVRAMWriteReplacements", 690 texture_replacements.enable_vram_write_replacements); 691 si.SetBoolValue("TextureReplacements", "PreloadTextures", texture_replacements.preload_textures); 692 si.SetBoolValue("TextureReplacements", "DumpVRAMWrites", texture_replacements.dump_vram_writes); 693 si.SetBoolValue("TextureReplacements", "DumpVRAMWriteForceAlphaChannel", 694 texture_replacements.dump_vram_write_force_alpha_channel); 695 si.SetIntValue("TextureReplacements", "DumpVRAMWriteWidthThreshold", 696 texture_replacements.dump_vram_write_width_threshold); 697 si.SetIntValue("TextureReplacements", "DumpVRAMWriteHeightThreshold", 698 texture_replacements.dump_vram_write_height_threshold); 699 } 700 701 void Settings::Clear(SettingsInterface& si) 702 { 703 si.ClearSection("Main"); 704 si.ClearSection("Console"); 705 si.ClearSection("CPU"); 706 si.ClearSection("GPU"); 707 si.ClearSection("Display"); 708 si.ClearSection("CDROM"); 709 si.ClearSection("Audio"); 710 si.ClearSection("Hacks"); 711 si.ClearSection("PCDrv"); 712 si.ClearSection("BIOS"); 713 714 for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) 715 si.ClearSection(Controller::GetSettingsSection(i).c_str()); 716 717 si.ClearSection("MemoryCards"); 718 719 // Can't wipe out this section, because input profiles. 720 si.DeleteValue("ControllerPorts", "MultitapMode"); 721 722 si.ClearSection("Cheevos"); 723 si.ClearSection("Logging"); 724 si.ClearSection("Debug"); 725 si.ClearSection("TextureReplacements"); 726 } 727 728 void Settings::FixIncompatibleSettings(bool display_osd_messages) 729 { 730 if (g_settings.disable_all_enhancements) 731 { 732 g_settings.cpu_overclock_enable = false; 733 g_settings.cpu_overclock_active = false; 734 g_settings.enable_8mb_ram = false; 735 g_settings.enable_cheats = false; 736 g_settings.gpu_resolution_scale = 1; 737 g_settings.gpu_multisamples = 1; 738 g_settings.gpu_per_sample_shading = false; 739 g_settings.gpu_true_color = false; 740 g_settings.gpu_debanding = false; 741 g_settings.gpu_scaled_dithering = false; 742 g_settings.gpu_force_round_texcoords = false; 743 g_settings.gpu_texture_filter = GPUTextureFilter::Nearest; 744 g_settings.gpu_sprite_texture_filter = GPUTextureFilter::Nearest; 745 g_settings.gpu_line_detect_mode = GPULineDetectMode::Disabled; 746 g_settings.gpu_disable_interlacing = false; 747 g_settings.gpu_force_ntsc_timings = false; 748 g_settings.gpu_widescreen_hack = false; 749 g_settings.gpu_pgxp_enable = false; 750 g_settings.display_24bit_chroma_smoothing = false; 751 g_settings.cdrom_read_speedup = 1; 752 g_settings.cdrom_seek_speedup = 1; 753 g_settings.cdrom_mute_cd_audio = false; 754 g_settings.texture_replacements.enable_vram_write_replacements = false; 755 g_settings.use_old_mdec_routines = false; 756 g_settings.pcdrv_enable = false; 757 g_settings.bios_patch_fast_boot = false; 758 } 759 760 if (g_settings.pcdrv_enable && g_settings.pcdrv_root.empty()) 761 { 762 Host::AddKeyedOSDMessage("pcdrv_disabled_no_root", 763 TRANSLATE_STR("OSDMessage", "Disabling PCDrv because no root directory is specified."), 764 Host::OSD_WARNING_DURATION); 765 g_settings.pcdrv_enable = false; 766 } 767 768 if (g_settings.gpu_pgxp_enable) 769 { 770 if (g_settings.gpu_renderer == GPURenderer::Software) 771 { 772 if (display_osd_messages) 773 { 774 Host::AddKeyedOSDMessage( 775 "pgxp_disabled_sw", 776 TRANSLATE_STR("OSDMessage", "PGXP is incompatible with the software renderer, disabling PGXP."), 10.0f); 777 } 778 g_settings.gpu_pgxp_enable = false; 779 } 780 } 781 else 782 { 783 g_settings.gpu_pgxp_culling = false; 784 g_settings.gpu_pgxp_texture_correction = false; 785 g_settings.gpu_pgxp_color_correction = false; 786 g_settings.gpu_pgxp_vertex_cache = false; 787 g_settings.gpu_pgxp_cpu = false; 788 g_settings.gpu_pgxp_preserve_proj_fp = false; 789 g_settings.gpu_pgxp_depth_buffer = false; 790 g_settings.gpu_pgxp_disable_2d = false; 791 } 792 793 #ifndef ENABLE_MMAP_FASTMEM 794 if (g_settings.cpu_fastmem_mode == CPUFastmemMode::MMap) 795 { 796 WARNING_LOG("mmap fastmem is not available on this platform, using LUT instead."); 797 g_settings.cpu_fastmem_mode = CPUFastmemMode::LUT; 798 } 799 #endif 800 801 #if defined(__ANDROID__) && defined(__arm__) && !defined(__aarch64__) && !defined(_M_ARM64) 802 if (g_settings.rewind_enable) 803 { 804 Host::AddKeyedOSDMessage("rewind_disabled_android", 805 TRANSLATE_STR("OSDMessage", "Rewind is not supported on 32-bit ARM for Android."), 30.0f); 806 g_settings.rewind_enable = false; 807 } 808 if (g_settings.IsRunaheadEnabled()) 809 { 810 Host::AddKeyedOSDMessage("rewind_disabled_android", 811 TRANSLATE_STR("OSDMessage", "Runahead is not supported on 32-bit ARM for Android."), 812 30.0f); 813 g_settings.runahead_frames = 0; 814 } 815 #endif 816 817 if (g_settings.IsRunaheadEnabled() && g_settings.rewind_enable) 818 { 819 Host::AddKeyedOSDMessage("rewind_disabled", 820 TRANSLATE_STR("OSDMessage", "Rewind is disabled because runahead is enabled."), 821 Host::OSD_WARNING_DURATION); 822 g_settings.rewind_enable = false; 823 } 824 825 if (g_settings.IsRunaheadEnabled()) 826 { 827 // Block linking is good for performance, but hurts when regularly loading (i.e. runahead), since everything has to 828 // be unlinked. Which would be thousands of blocks. 829 if (g_settings.cpu_recompiler_block_linking) 830 { 831 WARNING_LOG("Disabling block linking due to runahead."); 832 g_settings.cpu_recompiler_block_linking = false; 833 } 834 } 835 836 // if challenge mode is enabled, disable things like rewind since they use save states 837 if (Achievements::IsHardcoreModeActive()) 838 { 839 g_settings.emulation_speed = 840 (g_settings.emulation_speed != 0.0f) ? std::max(g_settings.emulation_speed, 1.0f) : 0.0f; 841 g_settings.fast_forward_speed = 842 (g_settings.fast_forward_speed != 0.0f) ? std::max(g_settings.fast_forward_speed, 1.0f) : 0.0f; 843 g_settings.turbo_speed = (g_settings.turbo_speed != 0.0f) ? std::max(g_settings.turbo_speed, 1.0f) : 0.0f; 844 g_settings.rewind_enable = false; 845 g_settings.enable_cheats = false; 846 if (g_settings.cpu_overclock_enable && g_settings.GetCPUOverclockPercent() < 100) 847 { 848 g_settings.cpu_overclock_enable = false; 849 g_settings.UpdateOverclockActive(); 850 } 851 g_settings.debugging.enable_gdb_server = false; 852 g_settings.debugging.show_vram = false; 853 g_settings.debugging.show_gpu_state = false; 854 g_settings.debugging.show_cdrom_state = false; 855 g_settings.debugging.show_spu_state = false; 856 g_settings.debugging.show_timers_state = false; 857 g_settings.debugging.show_mdec_state = false; 858 g_settings.debugging.show_dma_state = false; 859 g_settings.debugging.dump_cpu_to_vram_copies = false; 860 g_settings.debugging.dump_vram_to_cpu_copies = false; 861 } 862 } 863 864 void Settings::UpdateLogSettings() 865 { 866 Log::SetLogLevel(log_level); 867 Log::SetLogFilter(log_filter); 868 Log::SetConsoleOutputParams(log_to_console, log_timestamps); 869 Log::SetDebugOutputParams(log_to_debug); 870 871 if (log_to_file) 872 { 873 Log::SetFileOutputParams(log_to_file, Path::Combine(EmuFolders::DataRoot, "duckstation.log").c_str(), 874 log_timestamps); 875 } 876 else 877 { 878 Log::SetFileOutputParams(false, nullptr); 879 } 880 } 881 882 void Settings::SetDefaultControllerConfig(SettingsInterface& si) 883 { 884 // Global Settings 885 si.SetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(Settings::DEFAULT_MULTITAP_MODE)); 886 si.SetFloatValue("ControllerPorts", "PointerXScale", 8.0f); 887 si.SetFloatValue("ControllerPorts", "PointerYScale", 8.0f); 888 si.SetBoolValue("ControllerPorts", "PointerXInvert", false); 889 si.SetBoolValue("ControllerPorts", "PointerYInvert", false); 890 891 // Default pad types and parameters. 892 for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) 893 { 894 const std::string section(Controller::GetSettingsSection(i)); 895 si.ClearSection(section.c_str()); 896 si.SetStringValue(section.c_str(), "Type", Controller::GetDefaultPadType(i)); 897 } 898 899 #ifndef __ANDROID__ 900 // Use the automapper to set this up. 901 InputManager::MapController(si, 0, InputManager::GetGenericBindingMapping("Keyboard")); 902 #endif 903 } 904 905 static constexpr const std::array s_log_level_names = { 906 "None", "Error", "Warning", "Info", "Verbose", "Dev", "Debug", "Trace", 907 }; 908 static constexpr const std::array s_log_level_display_names = { 909 TRANSLATE_NOOP("LogLevel", "None"), TRANSLATE_NOOP("LogLevel", "Error"), 910 TRANSLATE_NOOP("LogLevel", "Warning"), TRANSLATE_NOOP("LogLevel", "Information"), 911 TRANSLATE_NOOP("LogLevel", "Verbose"), TRANSLATE_NOOP("LogLevel", "Developer"), 912 TRANSLATE_NOOP("LogLevel", "Debug"), TRANSLATE_NOOP("LogLevel", "Trace"), 913 }; 914 915 std::optional<LOGLEVEL> Settings::ParseLogLevelName(const char* str) 916 { 917 int index = 0; 918 for (const char* name : s_log_level_names) 919 { 920 if (StringUtil::Strcasecmp(name, str) == 0) 921 return static_cast<LOGLEVEL>(index); 922 923 index++; 924 } 925 926 return std::nullopt; 927 } 928 929 const char* Settings::GetLogLevelName(LOGLEVEL level) 930 { 931 return s_log_level_names[static_cast<int>(level)]; 932 } 933 934 const char* Settings::GetLogLevelDisplayName(LOGLEVEL level) 935 { 936 return Host::TranslateToCString("LogLevel", s_log_level_display_names[static_cast<int>(level)]); 937 } 938 939 static constexpr const std::array s_console_region_names = {"Auto", "NTSC-J", "NTSC-U", "PAL"}; 940 static constexpr const std::array s_console_region_display_names = { 941 TRANSLATE_NOOP("ConsoleRegion", "Auto-Detect"), TRANSLATE_NOOP("ConsoleRegion", "NTSC-J (Japan)"), 942 TRANSLATE_NOOP("ConsoleRegion", "NTSC-U/C (US, Canada)"), TRANSLATE_NOOP("ConsoleRegion", "PAL (Europe, Australia)")}; 943 944 std::optional<ConsoleRegion> Settings::ParseConsoleRegionName(const char* str) 945 { 946 int index = 0; 947 for (const char* name : s_console_region_names) 948 { 949 if (StringUtil::Strcasecmp(name, str) == 0) 950 return static_cast<ConsoleRegion>(index); 951 952 index++; 953 } 954 955 return std::nullopt; 956 } 957 958 const char* Settings::GetConsoleRegionName(ConsoleRegion region) 959 { 960 return s_console_region_names[static_cast<int>(region)]; 961 } 962 963 const char* Settings::GetConsoleRegionDisplayName(ConsoleRegion region) 964 { 965 return Host::TranslateToCString("ConsoleRegion", s_console_region_display_names[static_cast<int>(region)]); 966 } 967 968 static constexpr const std::array s_disc_region_names = {"NTSC-J", "NTSC-U", "PAL", "Other", "Non-PS1"}; 969 static constexpr const std::array s_disc_region_display_names = { 970 TRANSLATE_NOOP("DiscRegion", "NTSC-J (Japan)"), TRANSLATE_NOOP("DiscRegion", "NTSC-U/C (US, Canada)"), 971 TRANSLATE_NOOP("DiscRegion", "PAL (Europe, Australia)"), TRANSLATE_NOOP("DiscRegion", "Other"), 972 TRANSLATE_NOOP("DiscRegion", "Non-PS1")}; 973 974 std::optional<DiscRegion> Settings::ParseDiscRegionName(const char* str) 975 { 976 int index = 0; 977 for (const char* name : s_disc_region_names) 978 { 979 if (StringUtil::Strcasecmp(name, str) == 0) 980 return static_cast<DiscRegion>(index); 981 982 index++; 983 } 984 985 return std::nullopt; 986 } 987 988 const char* Settings::GetDiscRegionName(DiscRegion region) 989 { 990 return s_disc_region_names[static_cast<int>(region)]; 991 } 992 993 const char* Settings::GetDiscRegionDisplayName(DiscRegion region) 994 { 995 return Host::TranslateToCString("DiscRegion", s_disc_region_display_names[static_cast<int>(region)]); 996 } 997 998 static constexpr const std::array s_cpu_execution_mode_names = {"Interpreter", "CachedInterpreter", "Recompiler", 999 "NewRec"}; 1000 static constexpr const std::array s_cpu_execution_mode_display_names = { 1001 TRANSLATE_NOOP("CPUExecutionMode", "Interpreter (Slowest)"), 1002 TRANSLATE_NOOP("CPUExecutionMode", "Cached Interpreter (Faster)"), 1003 TRANSLATE_NOOP("CPUExecutionMode", "Recompiler (Fastest)"), 1004 TRANSLATE_NOOP("CPUExecutionMode", "New Recompiler (Experimental)")}; 1005 1006 std::optional<CPUExecutionMode> Settings::ParseCPUExecutionMode(const char* str) 1007 { 1008 u8 index = 0; 1009 for (const char* name : s_cpu_execution_mode_names) 1010 { 1011 if (StringUtil::Strcasecmp(name, str) == 0) 1012 return static_cast<CPUExecutionMode>(index); 1013 1014 index++; 1015 } 1016 1017 return std::nullopt; 1018 } 1019 1020 const char* Settings::GetCPUExecutionModeName(CPUExecutionMode mode) 1021 { 1022 return s_cpu_execution_mode_names[static_cast<u8>(mode)]; 1023 } 1024 1025 const char* Settings::GetCPUExecutionModeDisplayName(CPUExecutionMode mode) 1026 { 1027 return Host::TranslateToCString("CPUExecutionMode", s_cpu_execution_mode_display_names[static_cast<u8>(mode)]); 1028 } 1029 1030 static constexpr const std::array s_cpu_fastmem_mode_names = {"Disabled", "MMap", "LUT"}; 1031 static constexpr const std::array s_cpu_fastmem_mode_display_names = { 1032 TRANSLATE_NOOP("CPUFastmemMode", "Disabled (Slowest)"), 1033 TRANSLATE_NOOP("CPUFastmemMode", "MMap (Hardware, Fastest, 64-Bit Only)"), 1034 TRANSLATE_NOOP("CPUFastmemMode", "LUT (Faster)")}; 1035 1036 std::optional<CPUFastmemMode> Settings::ParseCPUFastmemMode(const char* str) 1037 { 1038 u8 index = 0; 1039 for (const char* name : s_cpu_fastmem_mode_names) 1040 { 1041 if (StringUtil::Strcasecmp(name, str) == 0) 1042 return static_cast<CPUFastmemMode>(index); 1043 1044 index++; 1045 } 1046 1047 return std::nullopt; 1048 } 1049 1050 const char* Settings::GetCPUFastmemModeName(CPUFastmemMode mode) 1051 { 1052 return s_cpu_fastmem_mode_names[static_cast<u8>(mode)]; 1053 } 1054 1055 const char* Settings::GetCPUFastmemModeDisplayName(CPUFastmemMode mode) 1056 { 1057 return Host::TranslateToCString("CPUFastmemMode", s_cpu_fastmem_mode_display_names[static_cast<u8>(mode)]); 1058 } 1059 1060 static constexpr const std::array s_gpu_renderer_names = { 1061 "Automatic", 1062 #ifdef _WIN32 1063 "D3D11", "D3D12", 1064 #endif 1065 #ifdef __APPLE__ 1066 "Metal", 1067 #endif 1068 #ifdef ENABLE_VULKAN 1069 "Vulkan", 1070 #endif 1071 #ifdef ENABLE_OPENGL 1072 "OpenGL", 1073 #endif 1074 "Software", 1075 }; 1076 static constexpr const std::array s_gpu_renderer_display_names = { 1077 TRANSLATE_NOOP("GPURenderer", "Automatic"), 1078 #ifdef _WIN32 1079 TRANSLATE_NOOP("GPURenderer", "Direct3D 11"), TRANSLATE_NOOP("GPURenderer", "Direct3D 12"), 1080 #endif 1081 #ifdef __APPLE__ 1082 TRANSLATE_NOOP("GPURenderer", "Metal"), 1083 #endif 1084 #ifdef ENABLE_VULKAN 1085 TRANSLATE_NOOP("GPURenderer", "Vulkan"), 1086 #endif 1087 #ifdef ENABLE_OPENGL 1088 TRANSLATE_NOOP("GPURenderer", "OpenGL"), 1089 #endif 1090 TRANSLATE_NOOP("GPURenderer", "Software"), 1091 }; 1092 1093 std::optional<GPURenderer> Settings::ParseRendererName(const char* str) 1094 { 1095 int index = 0; 1096 for (const char* name : s_gpu_renderer_names) 1097 { 1098 if (StringUtil::Strcasecmp(name, str) == 0) 1099 return static_cast<GPURenderer>(index); 1100 1101 index++; 1102 } 1103 1104 return std::nullopt; 1105 } 1106 1107 const char* Settings::GetRendererName(GPURenderer renderer) 1108 { 1109 return s_gpu_renderer_names[static_cast<int>(renderer)]; 1110 } 1111 1112 const char* Settings::GetRendererDisplayName(GPURenderer renderer) 1113 { 1114 return Host::TranslateToCString("GPURenderer", s_gpu_renderer_display_names[static_cast<int>(renderer)]); 1115 } 1116 1117 RenderAPI Settings::GetRenderAPIForRenderer(GPURenderer renderer) 1118 { 1119 switch (renderer) 1120 { 1121 #ifdef _WIN32 1122 case GPURenderer::HardwareD3D11: 1123 return RenderAPI::D3D11; 1124 case GPURenderer::HardwareD3D12: 1125 return RenderAPI::D3D12; 1126 #endif 1127 #ifdef __APPLE__ 1128 return RenderAPI::Metal; 1129 #endif 1130 #ifdef ENABLE_VULKAN 1131 case GPURenderer::HardwareVulkan: 1132 return RenderAPI::Vulkan; 1133 #endif 1134 #ifdef ENABLE_OPENGL 1135 case GPURenderer::HardwareOpenGL: 1136 return RenderAPI::OpenGL; 1137 #endif 1138 case GPURenderer::Software: 1139 case GPURenderer::Automatic: 1140 default: 1141 return GPUDevice::GetPreferredAPI(); 1142 } 1143 } 1144 1145 GPURenderer Settings::GetRendererForRenderAPI(RenderAPI api) 1146 { 1147 switch (api) 1148 { 1149 #ifdef _WIN32 1150 case RenderAPI::D3D11: 1151 return GPURenderer::HardwareD3D11; 1152 1153 case RenderAPI::D3D12: 1154 return GPURenderer::HardwareD3D12; 1155 #endif 1156 1157 #ifdef __APPLE__ 1158 case RenderAPI::Metal: 1159 return GPURenderer::HardwareMetal; 1160 #endif 1161 1162 #ifdef ENABLE_VULKAN 1163 case RenderAPI::Vulkan: 1164 return GPURenderer::HardwareVulkan; 1165 #endif 1166 1167 #ifdef ENABLE_OPENGL 1168 case RenderAPI::OpenGL: 1169 case RenderAPI::OpenGLES: 1170 return GPURenderer::HardwareOpenGL; 1171 #endif 1172 1173 default: 1174 return GPURenderer::Automatic; 1175 } 1176 } 1177 1178 GPURenderer Settings::GetAutomaticRenderer() 1179 { 1180 return GetRendererForRenderAPI(GPUDevice::GetPreferredAPI()); 1181 } 1182 1183 static constexpr const std::array s_texture_filter_names = { 1184 "Nearest", "Bilinear", "BilinearBinAlpha", "JINC2", "JINC2BinAlpha", "xBR", "xBRBinAlpha", 1185 }; 1186 static constexpr const std::array s_texture_filter_display_names = { 1187 TRANSLATE_NOOP("GPUTextureFilter", "Nearest-Neighbor"), 1188 TRANSLATE_NOOP("GPUTextureFilter", "Bilinear"), 1189 TRANSLATE_NOOP("GPUTextureFilter", "Bilinear (No Edge Blending)"), 1190 TRANSLATE_NOOP("GPUTextureFilter", "JINC2 (Slow)"), 1191 TRANSLATE_NOOP("GPUTextureFilter", "JINC2 (Slow, No Edge Blending)"), 1192 TRANSLATE_NOOP("GPUTextureFilter", "xBR (Very Slow)"), 1193 TRANSLATE_NOOP("GPUTextureFilter", "xBR (Very Slow, No Edge Blending)"), 1194 }; 1195 1196 std::optional<GPUTextureFilter> Settings::ParseTextureFilterName(const char* str) 1197 { 1198 int index = 0; 1199 for (const char* name : s_texture_filter_names) 1200 { 1201 if (StringUtil::Strcasecmp(name, str) == 0) 1202 return static_cast<GPUTextureFilter>(index); 1203 1204 index++; 1205 } 1206 1207 return std::nullopt; 1208 } 1209 1210 const char* Settings::GetTextureFilterName(GPUTextureFilter filter) 1211 { 1212 return s_texture_filter_names[static_cast<size_t>(filter)]; 1213 } 1214 1215 const char* Settings::GetTextureFilterDisplayName(GPUTextureFilter filter) 1216 { 1217 return Host::TranslateToCString("GPUTextureFilter", s_texture_filter_display_names[static_cast<int>(filter)]); 1218 } 1219 1220 static constexpr const std::array s_line_detect_mode_names = { 1221 "Disabled", 1222 "Quads", 1223 "BasicTriangles", 1224 "AggressiveTriangles", 1225 }; 1226 static constexpr const std::array s_line_detect_mode_detect_names = { 1227 TRANSLATE_NOOP("GPULineDetectMode", "Disabled"), 1228 TRANSLATE_NOOP("GPULineDetectMode", "Quads"), 1229 TRANSLATE_NOOP("GPULineDetectMode", "Triangles (Basic)"), 1230 TRANSLATE_NOOP("GPULineDetectMode", "Triangles (Aggressive)"), 1231 }; 1232 1233 std::optional<GPULineDetectMode> Settings::ParseLineDetectModeName(const char* str) 1234 { 1235 int index = 0; 1236 for (const char* name : s_line_detect_mode_names) 1237 { 1238 if (StringUtil::Strcasecmp(name, str) == 0) 1239 return static_cast<GPULineDetectMode>(index); 1240 1241 index++; 1242 } 1243 1244 return std::nullopt; 1245 } 1246 1247 const char* Settings::GetLineDetectModeName(GPULineDetectMode mode) 1248 { 1249 return s_line_detect_mode_names[static_cast<size_t>(mode)]; 1250 } 1251 1252 const char* Settings::GetLineDetectModeDisplayName(GPULineDetectMode mode) 1253 { 1254 return Host::TranslateToCString("GPULineDetectMode", s_line_detect_mode_detect_names[static_cast<size_t>(mode)]); 1255 } 1256 1257 static constexpr const std::array s_downsample_mode_names = {"Disabled", "Box", "Adaptive"}; 1258 static constexpr const std::array s_downsample_mode_display_names = { 1259 TRANSLATE_NOOP("GPUDownsampleMode", "Disabled"), 1260 TRANSLATE_NOOP("GPUDownsampleMode", "Box (Downsample 3D/Smooth All)"), 1261 TRANSLATE_NOOP("GPUDownsampleMode", "Adaptive (Preserve 3D/Smooth 2D)")}; 1262 1263 std::optional<GPUDownsampleMode> Settings::ParseDownsampleModeName(const char* str) 1264 { 1265 int index = 0; 1266 for (const char* name : s_downsample_mode_names) 1267 { 1268 if (StringUtil::Strcasecmp(name, str) == 0) 1269 return static_cast<GPUDownsampleMode>(index); 1270 1271 index++; 1272 } 1273 1274 return std::nullopt; 1275 } 1276 1277 const char* Settings::GetDownsampleModeName(GPUDownsampleMode mode) 1278 { 1279 return s_downsample_mode_names[static_cast<int>(mode)]; 1280 } 1281 1282 const char* Settings::GetDownsampleModeDisplayName(GPUDownsampleMode mode) 1283 { 1284 return Host::TranslateToCString("GPUDownsampleMode", s_downsample_mode_display_names[static_cast<int>(mode)]); 1285 } 1286 1287 static constexpr const std::array s_wireframe_mode_names = {"Disabled", "OverlayWireframe", "OnlyWireframe"}; 1288 static constexpr const std::array s_wireframe_mode_display_names = { 1289 TRANSLATE_NOOP("GPUWireframeMode", "Disabled"), TRANSLATE_NOOP("GPUWireframeMode", "Overlay Wireframe"), 1290 TRANSLATE_NOOP("GPUWireframeMode", "Only Wireframe")}; 1291 1292 std::optional<GPUWireframeMode> Settings::ParseGPUWireframeMode(const char* str) 1293 { 1294 int index = 0; 1295 for (const char* name : s_wireframe_mode_names) 1296 { 1297 if (StringUtil::Strcasecmp(name, str) == 0) 1298 return static_cast<GPUWireframeMode>(index); 1299 1300 index++; 1301 } 1302 1303 return std::nullopt; 1304 } 1305 1306 const char* Settings::GetGPUWireframeModeName(GPUWireframeMode mode) 1307 { 1308 return s_wireframe_mode_names[static_cast<int>(mode)]; 1309 } 1310 1311 const char* Settings::GetGPUWireframeModeDisplayName(GPUWireframeMode mode) 1312 { 1313 return Host::TranslateToCString("GPUWireframeMode", s_wireframe_mode_display_names[static_cast<int>(mode)]); 1314 } 1315 1316 static constexpr const std::array s_display_deinterlacing_mode_names = { 1317 "Disabled", 1318 "Weave", 1319 "Blend", 1320 "Adaptive", 1321 }; 1322 static constexpr const std::array s_display_deinterlacing_mode_display_names = { 1323 TRANSLATE_NOOP("DisplayDeinterlacingMode", "Disabled (Flickering)"), 1324 TRANSLATE_NOOP("DisplayDeinterlacingMode", "Weave (Combing)"), 1325 TRANSLATE_NOOP("DisplayDeinterlacingMode", "Blend (Blur)"), 1326 TRANSLATE_NOOP("DisplayDeinterlacingMode", "Adaptive (FastMAD)"), 1327 }; 1328 1329 std::optional<DisplayDeinterlacingMode> Settings::ParseDisplayDeinterlacingMode(const char* str) 1330 { 1331 int index = 0; 1332 for (const char* name : s_display_deinterlacing_mode_names) 1333 { 1334 if (StringUtil::Strcasecmp(name, str) == 0) 1335 return static_cast<DisplayDeinterlacingMode>(index); 1336 1337 index++; 1338 } 1339 1340 return std::nullopt; 1341 } 1342 1343 const char* Settings::GetDisplayDeinterlacingModeName(DisplayDeinterlacingMode mode) 1344 { 1345 return s_display_deinterlacing_mode_names[static_cast<int>(mode)]; 1346 } 1347 1348 const char* Settings::GetDisplayDeinterlacingModeDisplayName(DisplayDeinterlacingMode mode) 1349 { 1350 return Host::TranslateToCString("DisplayDeinterlacingMode", 1351 s_display_deinterlacing_mode_display_names[static_cast<int>(mode)]); 1352 } 1353 1354 static constexpr const std::array s_display_crop_mode_names = {"None", "Overscan", "Borders"}; 1355 static constexpr const std::array s_display_crop_mode_display_names = { 1356 TRANSLATE_NOOP("DisplayCropMode", "None"), TRANSLATE_NOOP("DisplayCropMode", "Only Overscan Area"), 1357 TRANSLATE_NOOP("DisplayCropMode", "All Borders")}; 1358 1359 std::optional<DisplayCropMode> Settings::ParseDisplayCropMode(const char* str) 1360 { 1361 int index = 0; 1362 for (const char* name : s_display_crop_mode_names) 1363 { 1364 if (StringUtil::Strcasecmp(name, str) == 0) 1365 return static_cast<DisplayCropMode>(index); 1366 1367 index++; 1368 } 1369 1370 return std::nullopt; 1371 } 1372 1373 const char* Settings::GetDisplayCropModeName(DisplayCropMode crop_mode) 1374 { 1375 return s_display_crop_mode_names[static_cast<int>(crop_mode)]; 1376 } 1377 1378 const char* Settings::GetDisplayCropModeDisplayName(DisplayCropMode crop_mode) 1379 { 1380 return Host::TranslateToCString("DisplayCropMode", s_display_crop_mode_display_names[static_cast<int>(crop_mode)]); 1381 } 1382 1383 static constexpr const std::array s_display_aspect_ratio_names = { 1384 #ifndef __ANDROID__ 1385 TRANSLATE_NOOP("DisplayAspectRatio", "Auto (Game Native)"), 1386 TRANSLATE_NOOP("DisplayAspectRatio", "Stretch To Fill"), 1387 TRANSLATE_NOOP("DisplayAspectRatio", "Custom"), 1388 #else 1389 "Auto (Game Native)", 1390 "Auto (Match Window)", 1391 "Custom", 1392 #endif 1393 "4:3", 1394 "16:9", 1395 "19:9", 1396 "20:9", 1397 "PAR 1:1"}; 1398 static constexpr const std::array s_display_aspect_ratio_values = { 1399 -1.0f, -1.0f, -1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 19.0f / 9.0f, 20.0f / 9.0f, -1.0f}; 1400 1401 std::optional<DisplayAspectRatio> Settings::ParseDisplayAspectRatio(const char* str) 1402 { 1403 int index = 0; 1404 for (const char* name : s_display_aspect_ratio_names) 1405 { 1406 if (StringUtil::Strcasecmp(name, str) == 0) 1407 return static_cast<DisplayAspectRatio>(index); 1408 1409 index++; 1410 } 1411 1412 return std::nullopt; 1413 } 1414 1415 const char* Settings::GetDisplayAspectRatioName(DisplayAspectRatio ar) 1416 { 1417 return s_display_aspect_ratio_names[static_cast<int>(ar)]; 1418 } 1419 1420 const char* Settings::GetDisplayAspectRatioDisplayName(DisplayAspectRatio ar) 1421 { 1422 return Host::TranslateToCString("DisplayAspectRatio", s_display_aspect_ratio_names[static_cast<int>(ar)]); 1423 } 1424 1425 float Settings::GetDisplayAspectRatioValue() const 1426 { 1427 switch (display_aspect_ratio) 1428 { 1429 case DisplayAspectRatio::MatchWindow: 1430 { 1431 if (!g_gpu_device) 1432 return s_display_aspect_ratio_values[static_cast<int>(DEFAULT_DISPLAY_ASPECT_RATIO)]; 1433 1434 return static_cast<float>(g_gpu_device->GetWindowWidth()) / static_cast<float>(g_gpu_device->GetWindowHeight()); 1435 } 1436 1437 case DisplayAspectRatio::Custom: 1438 { 1439 return static_cast<float>(display_aspect_ratio_custom_numerator) / 1440 static_cast<float>(display_aspect_ratio_custom_denominator); 1441 } 1442 1443 default: 1444 { 1445 return s_display_aspect_ratio_values[static_cast<int>(display_aspect_ratio)]; 1446 } 1447 } 1448 } 1449 1450 static constexpr const std::array s_display_alignment_names = {"LeftOrTop", "Center", "RightOrBottom"}; 1451 static constexpr const std::array s_display_alignment_display_names = { 1452 TRANSLATE_NOOP("DisplayAlignment", "Left / Top"), TRANSLATE_NOOP("DisplayAlignment", "Center"), 1453 TRANSLATE_NOOP("DisplayAlignment", "Right / Bottom")}; 1454 1455 std::optional<DisplayAlignment> Settings::ParseDisplayAlignment(const char* str) 1456 { 1457 int index = 0; 1458 for (const char* name : s_display_alignment_names) 1459 { 1460 if (StringUtil::Strcasecmp(name, str) == 0) 1461 return static_cast<DisplayAlignment>(index); 1462 1463 index++; 1464 } 1465 1466 return std::nullopt; 1467 } 1468 1469 const char* Settings::GetDisplayAlignmentName(DisplayAlignment alignment) 1470 { 1471 return s_display_alignment_names[static_cast<int>(alignment)]; 1472 } 1473 1474 const char* Settings::GetDisplayAlignmentDisplayName(DisplayAlignment alignment) 1475 { 1476 return Host::TranslateToCString("DisplayAlignment", s_display_alignment_display_names[static_cast<int>(alignment)]); 1477 } 1478 1479 static constexpr const std::array s_display_rotation_names = {"Normal", "Rotate90", "Rotate180", "Rotate270"}; 1480 static constexpr const std::array s_display_rotation_display_names = { 1481 TRANSLATE_NOOP("Settings", "No Rotation"), 1482 TRANSLATE_NOOP("Settings", "Rotate 90° (Clockwise)"), 1483 TRANSLATE_NOOP("Settings", "Rotate 180° (Vertical Flip)"), 1484 TRANSLATE_NOOP("Settings", "Rotate 270° (Clockwise)"), 1485 }; 1486 1487 std::optional<DisplayRotation> Settings::ParseDisplayRotation(const char* str) 1488 { 1489 int index = 0; 1490 for (const char* name : s_display_rotation_names) 1491 { 1492 if (StringUtil::Strcasecmp(name, str) == 0) 1493 return static_cast<DisplayRotation>(index); 1494 1495 index++; 1496 } 1497 1498 return std::nullopt; 1499 } 1500 1501 const char* Settings::GetDisplayRotationName(DisplayRotation rotation) 1502 { 1503 return s_display_rotation_names[static_cast<int>(rotation)]; 1504 } 1505 1506 const char* Settings::GetDisplayRotationDisplayName(DisplayRotation rotation) 1507 { 1508 return Host::TranslateToCString("Settings", s_display_rotation_display_names[static_cast<size_t>(rotation)]); 1509 } 1510 1511 static constexpr const std::array s_display_scaling_names = { 1512 "Nearest", "NearestInteger", "BilinearSmooth", "BilinearSharp", "BilinearInteger", 1513 }; 1514 static constexpr const std::array s_display_scaling_display_names = { 1515 TRANSLATE_NOOP("DisplayScalingMode", "Nearest-Neighbor"), 1516 TRANSLATE_NOOP("DisplayScalingMode", "Nearest-Neighbor (Integer)"), 1517 TRANSLATE_NOOP("DisplayScalingMode", "Bilinear (Smooth)"), 1518 TRANSLATE_NOOP("DisplayScalingMode", "Bilinear (Sharp)"), 1519 TRANSLATE_NOOP("DisplayScalingMode", "Bilinear (Integer)"), 1520 }; 1521 1522 std::optional<DisplayScalingMode> Settings::ParseDisplayScaling(const char* str) 1523 { 1524 int index = 0; 1525 for (const char* name : s_display_scaling_names) 1526 { 1527 if (StringUtil::Strcasecmp(name, str) == 0) 1528 return static_cast<DisplayScalingMode>(index); 1529 1530 index++; 1531 } 1532 1533 return std::nullopt; 1534 } 1535 1536 const char* Settings::GetDisplayScalingName(DisplayScalingMode mode) 1537 { 1538 return s_display_scaling_names[static_cast<int>(mode)]; 1539 } 1540 1541 const char* Settings::GetDisplayScalingDisplayName(DisplayScalingMode mode) 1542 { 1543 return Host::TranslateToCString("DisplayScalingMode", s_display_scaling_display_names[static_cast<int>(mode)]); 1544 } 1545 1546 static constexpr const std::array s_display_exclusive_fullscreen_mode_names = { 1547 "Automatic", 1548 "Disallowed", 1549 "Allowed", 1550 }; 1551 static constexpr const std::array s_display_exclusive_fullscreen_mode_display_names = { 1552 TRANSLATE_NOOP("Settings", "Automatic"), 1553 TRANSLATE_NOOP("Settings", "Disallowed"), 1554 TRANSLATE_NOOP("Settings", "Allowed"), 1555 }; 1556 1557 std::optional<DisplayExclusiveFullscreenControl> Settings::ParseDisplayExclusiveFullscreenControl(const char* str) 1558 { 1559 int index = 0; 1560 for (const char* name : s_display_exclusive_fullscreen_mode_names) 1561 { 1562 if (StringUtil::Strcasecmp(name, str) == 0) 1563 return static_cast<DisplayExclusiveFullscreenControl>(index); 1564 1565 index++; 1566 } 1567 1568 return std::nullopt; 1569 } 1570 1571 const char* Settings::GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode) 1572 { 1573 return s_display_exclusive_fullscreen_mode_names[static_cast<int>(mode)]; 1574 } 1575 1576 const char* Settings::GetDisplayExclusiveFullscreenControlDisplayName(DisplayExclusiveFullscreenControl mode) 1577 { 1578 return Host::TranslateToCString("Settings", 1579 s_display_exclusive_fullscreen_mode_display_names[static_cast<int>(mode)]); 1580 } 1581 1582 static constexpr const std::array s_display_screenshot_mode_names = { 1583 "ScreenResolution", 1584 "InternalResolution", 1585 "UncorrectedInternalResolution", 1586 }; 1587 static constexpr const std::array s_display_screenshot_mode_display_names = { 1588 TRANSLATE_NOOP("Settings", "Screen Resolution"), 1589 TRANSLATE_NOOP("Settings", "Internal Resolution"), 1590 TRANSLATE_NOOP("Settings", "Internal Resolution (Aspect Uncorrected)"), 1591 }; 1592 1593 std::optional<DisplayScreenshotMode> Settings::ParseDisplayScreenshotMode(const char* str) 1594 { 1595 int index = 0; 1596 for (const char* name : s_display_screenshot_mode_names) 1597 { 1598 if (StringUtil::Strcasecmp(name, str) == 0) 1599 return static_cast<DisplayScreenshotMode>(index); 1600 1601 index++; 1602 } 1603 1604 return std::nullopt; 1605 } 1606 1607 const char* Settings::GetDisplayScreenshotModeName(DisplayScreenshotMode mode) 1608 { 1609 return s_display_screenshot_mode_names[static_cast<size_t>(mode)]; 1610 } 1611 1612 const char* Settings::GetDisplayScreenshotModeDisplayName(DisplayScreenshotMode mode) 1613 { 1614 return Host::TranslateToCString("Settings", s_display_screenshot_mode_display_names[static_cast<size_t>(mode)]); 1615 } 1616 1617 static constexpr const std::array s_display_screenshot_format_names = { 1618 "PNG", 1619 "JPEG", 1620 "WebP", 1621 }; 1622 static constexpr const std::array s_display_screenshot_format_display_names = { 1623 TRANSLATE_NOOP("Settings", "PNG"), 1624 TRANSLATE_NOOP("Settings", "JPEG"), 1625 TRANSLATE_NOOP("Settings", "WebP"), 1626 }; 1627 static constexpr const std::array s_display_screenshot_format_extensions = { 1628 "png", 1629 "jpg", 1630 "webp", 1631 }; 1632 1633 std::optional<DisplayScreenshotFormat> Settings::ParseDisplayScreenshotFormat(const char* str) 1634 { 1635 int index = 0; 1636 for (const char* name : s_display_screenshot_format_names) 1637 { 1638 if (StringUtil::Strcasecmp(name, str) == 0) 1639 return static_cast<DisplayScreenshotFormat>(index); 1640 1641 index++; 1642 } 1643 1644 return std::nullopt; 1645 } 1646 1647 const char* Settings::GetDisplayScreenshotFormatName(DisplayScreenshotFormat format) 1648 { 1649 return s_display_screenshot_format_names[static_cast<size_t>(format)]; 1650 } 1651 1652 const char* Settings::GetDisplayScreenshotFormatDisplayName(DisplayScreenshotFormat mode) 1653 { 1654 return Host::TranslateToCString("Settings", s_display_screenshot_format_display_names[static_cast<size_t>(mode)]); 1655 } 1656 1657 const char* Settings::GetDisplayScreenshotFormatExtension(DisplayScreenshotFormat format) 1658 { 1659 return s_display_screenshot_format_extensions[static_cast<size_t>(format)]; 1660 } 1661 1662 static constexpr const std::array s_memory_card_type_names = {"None", "Shared", "PerGame", 1663 "PerGameTitle", "PerGameFileTitle", "NonPersistent"}; 1664 static constexpr const std::array s_memory_card_type_display_names = { 1665 TRANSLATE_NOOP("MemoryCardType", "No Memory Card"), 1666 TRANSLATE_NOOP("MemoryCardType", "Shared Between All Games"), 1667 TRANSLATE_NOOP("MemoryCardType", "Separate Card Per Game (Serial)"), 1668 TRANSLATE_NOOP("MemoryCardType", "Separate Card Per Game (Title)"), 1669 TRANSLATE_NOOP("MemoryCardType", "Separate Card Per Game (File Title)"), 1670 TRANSLATE_NOOP("MemoryCardType", "Non-Persistent Card (Do Not Save)")}; 1671 1672 std::optional<MemoryCardType> Settings::ParseMemoryCardTypeName(const char* str) 1673 { 1674 int index = 0; 1675 for (const char* name : s_memory_card_type_names) 1676 { 1677 if (StringUtil::Strcasecmp(name, str) == 0) 1678 return static_cast<MemoryCardType>(index); 1679 1680 index++; 1681 } 1682 1683 return std::nullopt; 1684 } 1685 1686 const char* Settings::GetMemoryCardTypeName(MemoryCardType type) 1687 { 1688 return s_memory_card_type_names[static_cast<int>(type)]; 1689 } 1690 1691 const char* Settings::GetMemoryCardTypeDisplayName(MemoryCardType type) 1692 { 1693 return Host::TranslateToCString("MemoryCardType", s_memory_card_type_display_names[static_cast<int>(type)]); 1694 } 1695 1696 std::string Settings::GetDefaultSharedMemoryCardName(u32 slot) 1697 { 1698 return fmt::format("shared_card_{}.mcd", slot + 1); 1699 } 1700 1701 std::string Settings::GetSharedMemoryCardPath(u32 slot) const 1702 { 1703 std::string ret; 1704 1705 if (memory_card_paths[slot].empty()) 1706 ret = Path::Combine(EmuFolders::MemoryCards, GetDefaultSharedMemoryCardName(slot)); 1707 else if (!Path::IsAbsolute(memory_card_paths[slot])) 1708 ret = Path::Combine(EmuFolders::MemoryCards, memory_card_paths[slot]); 1709 else 1710 ret = memory_card_paths[slot]; 1711 1712 return ret; 1713 } 1714 1715 std::string Settings::GetGameMemoryCardPath(std::string_view serial, u32 slot) 1716 { 1717 return Path::Combine(EmuFolders::MemoryCards, fmt::format("{}_{}.mcd", serial, slot + 1)); 1718 } 1719 1720 static constexpr const std::array s_multitap_enable_mode_names = {"Disabled", "Port1Only", "Port2Only", "BothPorts"}; 1721 static constexpr const std::array s_multitap_enable_mode_display_names = { 1722 TRANSLATE_NOOP("MultitapMode", "Disabled"), TRANSLATE_NOOP("MultitapMode", "Enable on Port 1 Only"), 1723 TRANSLATE_NOOP("MultitapMode", "Enable on Port 2 Only"), TRANSLATE_NOOP("MultitapMode", "Enable on Ports 1 and 2")}; 1724 1725 std::optional<MultitapMode> Settings::ParseMultitapModeName(const char* str) 1726 { 1727 u32 index = 0; 1728 for (const char* name : s_multitap_enable_mode_names) 1729 { 1730 if (StringUtil::Strcasecmp(name, str) == 0) 1731 return static_cast<MultitapMode>(index); 1732 1733 index++; 1734 } 1735 1736 return std::nullopt; 1737 } 1738 1739 const char* Settings::GetMultitapModeName(MultitapMode mode) 1740 { 1741 return s_multitap_enable_mode_names[static_cast<size_t>(mode)]; 1742 } 1743 1744 const char* Settings::GetMultitapModeDisplayName(MultitapMode mode) 1745 { 1746 return Host::TranslateToCString("MultitapMode", s_multitap_enable_mode_display_names[static_cast<size_t>(mode)]); 1747 } 1748 1749 static constexpr const std::array s_mechacon_version_names = {"VC0A", "VC0B", "VC1A", "VC1B", "VD1", "VC2", "VC1", 1750 "VC2J", "VC2A", "VC2B", "VC3A", "VC3B", "VC3C"}; 1751 static constexpr const std::array s_mechacon_version_display_names = { 1752 "94/09/19 (VC0A)", "94/11/18 (VC0B)", "95/05/16 (VC1A)", "95/07/24 (VC1B)", "95/07/24 (VD1)", 1753 "96/08/15 (VC2)", "96/08/18 (VC1)", "96/09/12 (VC2J)", "97/01/10 (VC2A)", "97/08/14 (VC2B)", 1754 "98/06/10 (VC3A)", "99/02/01 (VC3B)", "01/03/06 (VC3C)"}; 1755 1756 std::optional<CDROMMechaconVersion> Settings::ParseCDROMMechVersionName(const char* str) 1757 { 1758 u32 index = 0; 1759 for (const char* name : s_mechacon_version_names) 1760 { 1761 if (StringUtil::Strcasecmp(name, str) == 0) 1762 return static_cast<CDROMMechaconVersion>(index); 1763 1764 index++; 1765 } 1766 1767 return std::nullopt; 1768 } 1769 1770 const char* Settings::GetCDROMMechVersionName(CDROMMechaconVersion mode) 1771 { 1772 return s_mechacon_version_names[static_cast<u32>(mode)]; 1773 } 1774 1775 const char* Settings::GetCDROMMechVersionDisplayName(CDROMMechaconVersion mode) 1776 { 1777 return s_mechacon_version_display_names[static_cast<size_t>(mode)]; 1778 } 1779 1780 static constexpr const std::array s_save_state_compression_mode_names = { 1781 "Uncompressed", "DeflateLow", "DeflateDefault", "DeflateHigh", "ZstLow", "ZstDefault", "ZstHigh", 1782 }; 1783 static constexpr const std::array s_save_state_compression_mode_display_names = { 1784 TRANSLATE_NOOP("Settings", "Uncompressed"), TRANSLATE_NOOP("Settings", "Deflate (Low)"), 1785 TRANSLATE_NOOP("Settings", "Deflate (Default)"), TRANSLATE_NOOP("Settings", "Deflate (High)"), 1786 TRANSLATE_NOOP("Settings", "Zstandard (Low)"), TRANSLATE_NOOP("Settings", "Zstandard (Default)"), 1787 TRANSLATE_NOOP("Settings", "Zstandard (High)"), 1788 }; 1789 static_assert(s_save_state_compression_mode_names.size() == static_cast<size_t>(SaveStateCompressionMode::Count)); 1790 static_assert(s_save_state_compression_mode_display_names.size() == 1791 static_cast<size_t>(SaveStateCompressionMode::Count)); 1792 1793 std::optional<SaveStateCompressionMode> Settings::ParseSaveStateCompressionModeName(const char* str) 1794 { 1795 u32 index = 0; 1796 for (const char* name : s_save_state_compression_mode_names) 1797 { 1798 if (StringUtil::Strcasecmp(name, str) == 0) 1799 return static_cast<SaveStateCompressionMode>(index); 1800 1801 index++; 1802 } 1803 1804 return std::nullopt; 1805 } 1806 1807 const char* Settings::GetSaveStateCompressionModeName(SaveStateCompressionMode mode) 1808 { 1809 return s_save_state_compression_mode_names[static_cast<size_t>(mode)]; 1810 } 1811 1812 const char* Settings::GetSaveStateCompressionModeDisplayName(SaveStateCompressionMode mode) 1813 { 1814 return Host::TranslateToCString("Settings", s_save_state_compression_mode_display_names[static_cast<size_t>(mode)]); 1815 } 1816 1817 std::string EmuFolders::AppRoot; 1818 std::string EmuFolders::DataRoot; 1819 std::string EmuFolders::Bios; 1820 std::string EmuFolders::Cache; 1821 std::string EmuFolders::Cheats; 1822 std::string EmuFolders::Covers; 1823 std::string EmuFolders::Dumps; 1824 std::string EmuFolders::GameIcons; 1825 std::string EmuFolders::GameSettings; 1826 std::string EmuFolders::InputProfiles; 1827 std::string EmuFolders::MemoryCards; 1828 std::string EmuFolders::Resources; 1829 std::string EmuFolders::SaveStates; 1830 std::string EmuFolders::Screenshots; 1831 std::string EmuFolders::Shaders; 1832 std::string EmuFolders::Textures; 1833 std::string EmuFolders::UserResources; 1834 std::string EmuFolders::Videos; 1835 1836 void EmuFolders::SetDefaults() 1837 { 1838 Bios = Path::Combine(DataRoot, "bios"); 1839 Cache = Path::Combine(DataRoot, "cache"); 1840 Cheats = Path::Combine(DataRoot, "cheats"); 1841 Covers = Path::Combine(DataRoot, "covers"); 1842 Dumps = Path::Combine(DataRoot, "dump"); 1843 GameIcons = Path::Combine(DataRoot, "gameicons"); 1844 GameSettings = Path::Combine(DataRoot, "gamesettings"); 1845 InputProfiles = Path::Combine(DataRoot, "inputprofiles"); 1846 MemoryCards = Path::Combine(DataRoot, "memcards"); 1847 SaveStates = Path::Combine(DataRoot, "savestates"); 1848 Screenshots = Path::Combine(DataRoot, "screenshots"); 1849 Shaders = Path::Combine(DataRoot, "shaders"); 1850 Textures = Path::Combine(DataRoot, "textures"); 1851 UserResources = Path::Combine(DataRoot, "resources"); 1852 Videos = Path::Combine(DataRoot, "videos"); 1853 } 1854 1855 static std::string LoadPathFromSettings(SettingsInterface& si, const std::string& root, const char* section, 1856 const char* name, const char* def) 1857 { 1858 std::string value = si.GetStringValue(section, name, def); 1859 if (value.empty()) 1860 value = def; 1861 if (!Path::IsAbsolute(value)) 1862 value = Path::Combine(root, value); 1863 value = Path::RealPath(value); 1864 return value; 1865 } 1866 1867 void EmuFolders::LoadConfig(SettingsInterface& si) 1868 { 1869 Bios = LoadPathFromSettings(si, DataRoot, "BIOS", "SearchDirectory", "bios"); 1870 Cache = LoadPathFromSettings(si, DataRoot, "Folders", "Cache", "cache"); 1871 Cheats = LoadPathFromSettings(si, DataRoot, "Folders", "Cheats", "cheats"); 1872 Covers = LoadPathFromSettings(si, DataRoot, "Folders", "Covers", "covers"); 1873 Dumps = LoadPathFromSettings(si, DataRoot, "Folders", "Dumps", "dump"); 1874 GameIcons = LoadPathFromSettings(si, DataRoot, "Folders", "GameIcons", "gameicons"); 1875 GameSettings = LoadPathFromSettings(si, DataRoot, "Folders", "GameSettings", "gamesettings"); 1876 InputProfiles = LoadPathFromSettings(si, DataRoot, "Folders", "InputProfiles", "inputprofiles"); 1877 MemoryCards = LoadPathFromSettings(si, DataRoot, "MemoryCards", "Directory", "memcards"); 1878 SaveStates = LoadPathFromSettings(si, DataRoot, "Folders", "SaveStates", "savestates"); 1879 Screenshots = LoadPathFromSettings(si, DataRoot, "Folders", "Screenshots", "screenshots"); 1880 Shaders = LoadPathFromSettings(si, DataRoot, "Folders", "Shaders", "shaders"); 1881 Textures = LoadPathFromSettings(si, DataRoot, "Folders", "Textures", "textures"); 1882 UserResources = LoadPathFromSettings(si, DataRoot, "Folders", "UserResources", "resources"); 1883 Videos = LoadPathFromSettings(si, DataRoot, "Folders", "Videos", "videos"); 1884 1885 DEV_LOG("BIOS Directory: {}", Bios); 1886 DEV_LOG("Cache Directory: {}", Cache); 1887 DEV_LOG("Cheats Directory: {}", Cheats); 1888 DEV_LOG("Covers Directory: {}", Covers); 1889 DEV_LOG("Dumps Directory: {}", Dumps); 1890 DEV_LOG("Game Icons Directory: {}", GameIcons); 1891 DEV_LOG("Game Settings Directory: {}", GameSettings); 1892 DEV_LOG("Input Profile Directory: {}", InputProfiles); 1893 DEV_LOG("MemoryCards Directory: {}", MemoryCards); 1894 DEV_LOG("Resources Directory: {}", Resources); 1895 DEV_LOG("SaveStates Directory: {}", SaveStates); 1896 DEV_LOG("Screenshots Directory: {}", Screenshots); 1897 DEV_LOG("Shaders Directory: {}", Shaders); 1898 DEV_LOG("Textures Directory: {}", Textures); 1899 DEV_LOG("User Resources Directory: {}", UserResources); 1900 DEV_LOG("Videos Directory: {}", Videos); 1901 } 1902 1903 void EmuFolders::Save(SettingsInterface& si) 1904 { 1905 // convert back to relative 1906 si.SetStringValue("BIOS", "SearchDirectory", Path::MakeRelative(Bios, DataRoot).c_str()); 1907 si.SetStringValue("Folders", "Cache", Path::MakeRelative(Cache, DataRoot).c_str()); 1908 si.SetStringValue("Folders", "Cheats", Path::MakeRelative(Cheats, DataRoot).c_str()); 1909 si.SetStringValue("Folders", "Covers", Path::MakeRelative(Covers, DataRoot).c_str()); 1910 si.SetStringValue("Folders", "Dumps", Path::MakeRelative(Dumps, DataRoot).c_str()); 1911 si.SetStringValue("Folders", "GameIcons", Path::MakeRelative(GameIcons, DataRoot).c_str()); 1912 si.SetStringValue("Folders", "GameSettings", Path::MakeRelative(GameSettings, DataRoot).c_str()); 1913 si.SetStringValue("Folders", "InputProfiles", Path::MakeRelative(InputProfiles, DataRoot).c_str()); 1914 si.SetStringValue("MemoryCards", "Directory", Path::MakeRelative(MemoryCards, DataRoot).c_str()); 1915 si.SetStringValue("Folders", "SaveStates", Path::MakeRelative(SaveStates, DataRoot).c_str()); 1916 si.SetStringValue("Folders", "Screenshots", Path::MakeRelative(Screenshots, DataRoot).c_str()); 1917 si.SetStringValue("Folders", "Shaders", Path::MakeRelative(Shaders, DataRoot).c_str()); 1918 si.SetStringValue("Folders", "Textures", Path::MakeRelative(Textures, DataRoot).c_str()); 1919 si.SetStringValue("Folders", "UserResources", Path::MakeRelative(UserResources, DataRoot).c_str()); 1920 si.SetStringValue("Folders", "Videos", Path::MakeRelative(Videos, DataRoot).c_str()); 1921 } 1922 1923 void EmuFolders::Update() 1924 { 1925 const std::string old_gamesettings(EmuFolders::GameSettings); 1926 const std::string old_inputprofiles(EmuFolders::InputProfiles); 1927 const std::string old_memorycards(EmuFolders::MemoryCards); 1928 1929 // have to manually grab the lock here, because of the ReloadGameSettings() below. 1930 { 1931 auto lock = Host::GetSettingsLock(); 1932 LoadConfig(*Host::Internal::GetBaseSettingsLayer()); 1933 EnsureFoldersExist(); 1934 } 1935 1936 if (old_gamesettings != EmuFolders::GameSettings || old_inputprofiles != EmuFolders::InputProfiles) 1937 System::ReloadGameSettings(false); 1938 1939 if (System::IsValid() && old_memorycards != EmuFolders::MemoryCards) 1940 System::UpdateMemoryCardTypes(); 1941 } 1942 1943 bool EmuFolders::EnsureFoldersExist() 1944 { 1945 bool result = FileSystem::EnsureDirectoryExists(Bios.c_str(), false); 1946 result = FileSystem::EnsureDirectoryExists(Cache.c_str(), false) && result; 1947 result = FileSystem::EnsureDirectoryExists(Path::Combine(Cache, "achievement_images").c_str(), false) && result; 1948 result = FileSystem::EnsureDirectoryExists(Cheats.c_str(), false) && result; 1949 result = FileSystem::EnsureDirectoryExists(Covers.c_str(), false) && result; 1950 result = FileSystem::EnsureDirectoryExists(Dumps.c_str(), false) && result; 1951 result = FileSystem::EnsureDirectoryExists(Path::Combine(Dumps, "audio").c_str(), false) && result; 1952 result = FileSystem::EnsureDirectoryExists(Path::Combine(Dumps, "textures").c_str(), false) && result; 1953 result = FileSystem::EnsureDirectoryExists(GameIcons.c_str(), false) && result; 1954 result = FileSystem::EnsureDirectoryExists(GameSettings.c_str(), false) && result; 1955 result = FileSystem::EnsureDirectoryExists(InputProfiles.c_str(), false) && result; 1956 result = FileSystem::EnsureDirectoryExists(MemoryCards.c_str(), false) && result; 1957 result = FileSystem::EnsureDirectoryExists(SaveStates.c_str(), false) && result; 1958 result = FileSystem::EnsureDirectoryExists(Screenshots.c_str(), false) && result; 1959 result = FileSystem::EnsureDirectoryExists(Shaders.c_str(), false) && result; 1960 result = FileSystem::EnsureDirectoryExists(Path::Combine(Shaders, "reshade").c_str(), false) && result; 1961 result = FileSystem::EnsureDirectoryExists( 1962 Path::Combine(Shaders, "reshade" FS_OSPATH_SEPARATOR_STR "Shaders").c_str(), false) && 1963 result; 1964 result = FileSystem::EnsureDirectoryExists( 1965 Path::Combine(Shaders, "reshade" FS_OSPATH_SEPARATOR_STR "Textures").c_str(), false) && 1966 result; 1967 result = FileSystem::EnsureDirectoryExists(Textures.c_str(), false) && result; 1968 result = FileSystem::EnsureDirectoryExists(UserResources.c_str(), false) && result; 1969 result = FileSystem::EnsureDirectoryExists(Videos.c_str(), false) && result; 1970 return result; 1971 } 1972 1973 std::string EmuFolders::GetOverridableResourcePath(std::string_view name) 1974 { 1975 std::string upath = Path::Combine(UserResources, name); 1976 if (FileSystem::FileExists(upath.c_str())) 1977 { 1978 if (UserResources != Resources) 1979 WARNING_LOG("Using user-provided resource file {}", name); 1980 } 1981 else 1982 { 1983 upath = Path::Combine(Resources, name); 1984 } 1985 1986 return upath; 1987 } 1988 1989 static const char* s_log_filters[] = { 1990 "Achievements", 1991 "AnalogController", 1992 "AnalogJoystick", 1993 "AudioStream", 1994 "AutoUpdaterDialog", 1995 "BIOS", 1996 "Bus", 1997 "ByteStream", 1998 "CDImage", 1999 "CDImageBin", 2000 "CDImageCHD", 2001 "CDImageCueSheet", 2002 "CDImageDevice", 2003 "CDImageEcm", 2004 "CDImageMds", 2005 "CDImageMemory", 2006 "CDImagePBP", 2007 "CDImagePPF", 2008 "CDROM", 2009 "CDROMAsyncReader", 2010 "CDSubChannelReplacement", 2011 "CPU::CodeCache", 2012 "CPU::Core", 2013 "CPU::Recompiler", 2014 "Common::PageFaultHandler", 2015 "ControllerBindingWidget", 2016 "CueParser", 2017 "Cheats", 2018 "DMA", 2019 "DisplayWidget", 2020 "FileSystem", 2021 "FullscreenUI", 2022 "GDBConnection", 2023 "GDBProtocol", 2024 "GDBServer", 2025 "GPU", 2026 "GPUBackend", 2027 "GPUDevice", 2028 "GPUShaderCache", 2029 "GPUTexture", 2030 "GPU_HW", 2031 "GPU_SW", 2032 "GameDatabase", 2033 "GameList", 2034 "GunCon", 2035 "HTTPDownloader", 2036 "Host", 2037 "HostInterfaceProgressCallback", 2038 "INISettingsInterface", 2039 "ISOReader", 2040 "ImGuiFullscreen", 2041 "ImGuiManager", 2042 "Image", 2043 "InputManager", 2044 "InterruptController", 2045 "JitCodeBuffer", 2046 "MDEC", 2047 "MainWindow", 2048 "MemoryArena", 2049 "MemoryCard", 2050 "Multitap", 2051 "NoGUIHost", 2052 "PCDrv", 2053 "PGXP", 2054 "PSFLoader", 2055 "Pad", 2056 "PlatformMisc", 2057 "PlayStationMouse", 2058 "PostProcessing", 2059 "ProgressCallback", 2060 "QTTranslations", 2061 "QtHost", 2062 "ReShadeFXShader", 2063 "Recompiler::CodeGenerator", 2064 "RegTestHost", 2065 "SDLInputSource", 2066 "SIO", 2067 "SPIRVCompiler", 2068 "SPU", 2069 "Settings", 2070 "ShaderGen", 2071 "StateWrapper", 2072 "System", 2073 "TextureReplacements", 2074 "Timers", 2075 "TimingEvents", 2076 "WAVWriter", 2077 "WindowInfo", 2078 2079 #ifndef __ANDROID__ 2080 "CubebAudioStream", 2081 "SDLAudioStream", 2082 #endif 2083 2084 #ifdef ENABLE_OPENGL 2085 "OpenGLContext", 2086 "OpenGLDevice", 2087 #endif 2088 2089 #ifdef ENABLE_VULKAN 2090 "VulkanDevice", 2091 #endif 2092 2093 #if defined(_WIN32) 2094 "D3D11Device", 2095 "D3D12Device", 2096 "D3D12StreamBuffer", 2097 "D3DCommon", 2098 "DInputSource", 2099 "Win32ProgressCallback", 2100 "Win32RawInputSource", 2101 "XAudio2AudioStream", 2102 "XInputSource", 2103 #elif defined(__APPLE__) 2104 "CocoaNoGUIPlatform", 2105 "CocoaProgressCallback", 2106 "MetalDevice", 2107 #else 2108 "X11NoGUIPlatform", 2109 "WaylandNoGUIPlatform", 2110 #endif 2111 }; 2112 2113 std::span<const char*> Settings::GetLogFilters() 2114 { 2115 return s_log_filters; 2116 }