host.cpp (14941B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0) 3 4 #include "host.h" 5 #include "fullscreen_ui.h" 6 #include "gpu.h" 7 #include "imgui_overlays.h" 8 #include "shader_cache_version.h" 9 #include "system.h" 10 11 #include "scmversion/scmversion.h" 12 13 #include "util/compress_helpers.h" 14 #include "util/gpu_device.h" 15 #include "util/imgui_manager.h" 16 #include "util/input_manager.h" 17 18 #include "common/assert.h" 19 #include "common/error.h" 20 #include "common/layered_settings_interface.h" 21 #include "common/log.h" 22 #include "common/path.h" 23 #include "common/string_util.h" 24 25 #include "imgui.h" 26 27 #include <cstdarg> 28 #include <limits> 29 30 Log_SetChannel(Host); 31 32 namespace Host { 33 static std::mutex s_settings_mutex; 34 static LayeredSettingsInterface s_layered_settings_interface; 35 } // namespace Host 36 37 std::unique_lock<std::mutex> Host::GetSettingsLock() 38 { 39 return std::unique_lock<std::mutex>(s_settings_mutex); 40 } 41 42 SettingsInterface* Host::GetSettingsInterface() 43 { 44 return &s_layered_settings_interface; 45 } 46 47 std::optional<DynamicHeapArray<u8>> Host::ReadCompressedResourceFile(std::string_view filename, bool allow_override) 48 { 49 std::optional<DynamicHeapArray<u8>> ret = Host::ReadResourceFile(filename, allow_override); 50 if (ret.has_value()) 51 { 52 Error error; 53 ret = CompressHelpers::DecompressFile(filename, std::move(ret), std::nullopt, &error); 54 if (!ret.has_value()) 55 ERROR_LOG("Failed to decompress '{}': {}", Path::GetFileName(filename), error.GetDescription()); 56 } 57 58 return ret; 59 } 60 61 std::string Host::GetBaseStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/) 62 { 63 std::unique_lock lock(s_settings_mutex); 64 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 65 ->GetStringValue(section, key, default_value); 66 } 67 68 SmallString Host::GetBaseSmallStringSettingValue(const char* section, const char* key, 69 const char* default_value /*= ""*/) 70 { 71 std::unique_lock lock(s_settings_mutex); 72 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 73 ->GetSmallStringValue(section, key, default_value); 74 } 75 76 TinyString Host::GetBaseTinyStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/) 77 { 78 std::unique_lock lock(s_settings_mutex); 79 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 80 ->GetTinyStringValue(section, key, default_value); 81 } 82 83 bool Host::GetBaseBoolSettingValue(const char* section, const char* key, bool default_value /*= false*/) 84 { 85 std::unique_lock lock(s_settings_mutex); 86 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 87 ->GetBoolValue(section, key, default_value); 88 } 89 90 s32 Host::GetBaseIntSettingValue(const char* section, const char* key, s32 default_value /*= 0*/) 91 { 92 std::unique_lock lock(s_settings_mutex); 93 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 94 ->GetIntValue(section, key, default_value); 95 } 96 97 u32 Host::GetBaseUIntSettingValue(const char* section, const char* key, u32 default_value /*= 0*/) 98 { 99 std::unique_lock lock(s_settings_mutex); 100 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 101 ->GetUIntValue(section, key, default_value); 102 } 103 104 float Host::GetBaseFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/) 105 { 106 std::unique_lock lock(s_settings_mutex); 107 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 108 ->GetFloatValue(section, key, default_value); 109 } 110 111 double Host::GetBaseDoubleSettingValue(const char* section, const char* key, double default_value /* = 0.0f */) 112 { 113 std::unique_lock lock(s_settings_mutex); 114 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 115 ->GetDoubleValue(section, key, default_value); 116 } 117 118 std::vector<std::string> Host::GetBaseStringListSetting(const char* section, const char* key) 119 { 120 std::unique_lock lock(s_settings_mutex); 121 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetStringList(section, key); 122 } 123 124 std::string Host::GetStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/) 125 { 126 std::unique_lock lock(s_settings_mutex); 127 return s_layered_settings_interface.GetStringValue(section, key, default_value); 128 } 129 130 SmallString Host::GetSmallStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/) 131 { 132 std::unique_lock lock(s_settings_mutex); 133 return s_layered_settings_interface.GetSmallStringValue(section, key, default_value); 134 } 135 136 TinyString Host::GetTinyStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/) 137 { 138 std::unique_lock lock(s_settings_mutex); 139 return s_layered_settings_interface.GetTinyStringValue(section, key, default_value); 140 } 141 142 bool Host::GetBoolSettingValue(const char* section, const char* key, bool default_value /*= false*/) 143 { 144 std::unique_lock lock(s_settings_mutex); 145 return s_layered_settings_interface.GetBoolValue(section, key, default_value); 146 } 147 148 s32 Host::GetIntSettingValue(const char* section, const char* key, s32 default_value /*= 0*/) 149 { 150 std::unique_lock lock(s_settings_mutex); 151 return s_layered_settings_interface.GetIntValue(section, key, default_value); 152 } 153 154 u32 Host::GetUIntSettingValue(const char* section, const char* key, u32 default_value /*= 0*/) 155 { 156 std::unique_lock lock(s_settings_mutex); 157 return s_layered_settings_interface.GetUIntValue(section, key, default_value); 158 } 159 160 float Host::GetFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/) 161 { 162 std::unique_lock lock(s_settings_mutex); 163 return s_layered_settings_interface.GetFloatValue(section, key, default_value); 164 } 165 166 double Host::GetDoubleSettingValue(const char* section, const char* key, double default_value /*= 0.0f*/) 167 { 168 std::unique_lock lock(s_settings_mutex); 169 return s_layered_settings_interface.GetDoubleValue(section, key, default_value); 170 } 171 172 std::vector<std::string> Host::GetStringListSetting(const char* section, const char* key) 173 { 174 std::unique_lock lock(s_settings_mutex); 175 return s_layered_settings_interface.GetStringList(section, key); 176 } 177 178 void Host::SetBaseBoolSettingValue(const char* section, const char* key, bool value) 179 { 180 std::unique_lock lock(s_settings_mutex); 181 s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetBoolValue(section, key, value); 182 } 183 184 void Host::SetBaseIntSettingValue(const char* section, const char* key, int value) 185 { 186 std::unique_lock lock(s_settings_mutex); 187 s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetIntValue(section, key, value); 188 } 189 190 void Host::SetBaseFloatSettingValue(const char* section, const char* key, float value) 191 { 192 std::unique_lock lock(s_settings_mutex); 193 s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetFloatValue(section, key, value); 194 } 195 196 void Host::SetBaseStringSettingValue(const char* section, const char* key, const char* value) 197 { 198 std::unique_lock lock(s_settings_mutex); 199 s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetStringValue(section, key, value); 200 } 201 202 void Host::SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values) 203 { 204 std::unique_lock lock(s_settings_mutex); 205 s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetStringList(section, key, values); 206 } 207 208 bool Host::AddValueToBaseStringListSetting(const char* section, const char* key, const char* value) 209 { 210 std::unique_lock lock(s_settings_mutex); 211 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 212 ->AddToStringList(section, key, value); 213 } 214 215 bool Host::RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value) 216 { 217 std::unique_lock lock(s_settings_mutex); 218 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) 219 ->RemoveFromStringList(section, key, value); 220 } 221 222 bool Host::ContainsBaseSettingValue(const char* section, const char* key) 223 { 224 std::unique_lock lock(s_settings_mutex); 225 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->ContainsValue(section, key); 226 } 227 228 void Host::DeleteBaseSettingValue(const char* section, const char* key) 229 { 230 std::unique_lock lock(s_settings_mutex); 231 s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->DeleteValue(section, key); 232 } 233 234 SettingsInterface* Host::Internal::GetBaseSettingsLayer() 235 { 236 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE); 237 } 238 239 SettingsInterface* Host::Internal::GetGameSettingsLayer() 240 { 241 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_GAME); 242 } 243 244 SettingsInterface* Host::Internal::GetInputSettingsLayer() 245 { 246 return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_INPUT); 247 } 248 249 void Host::Internal::SetBaseSettingsLayer(SettingsInterface* sif) 250 { 251 AssertMsg(s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) == nullptr, 252 "Base layer has not been set"); 253 s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_BASE, sif); 254 } 255 256 void Host::Internal::SetGameSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& lock) 257 { 258 s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_GAME, sif); 259 } 260 261 void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& lock) 262 { 263 s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_INPUT, sif); 264 } 265 266 std::string Host::GetHTTPUserAgent() 267 { 268 return fmt::format("DuckStation for {} ({}) {}", TARGET_OS_STR, CPU_ARCH_STR, g_scm_tag_str); 269 } 270 271 bool Host::CreateGPUDevice(RenderAPI api, Error* error) 272 { 273 DebugAssert(!g_gpu_device); 274 275 INFO_LOG("Trying to create a {} GPU device...", GPUDevice::RenderAPIToString(api)); 276 g_gpu_device = GPUDevice::CreateDeviceForAPI(api); 277 278 std::optional<bool> exclusive_fullscreen_control; 279 if (g_settings.display_exclusive_fullscreen_control != DisplayExclusiveFullscreenControl::Automatic) 280 { 281 exclusive_fullscreen_control = 282 (g_settings.display_exclusive_fullscreen_control == DisplayExclusiveFullscreenControl::Allowed); 283 } 284 285 u32 disabled_features = 0; 286 if (g_settings.gpu_disable_dual_source_blend) 287 disabled_features |= GPUDevice::FEATURE_MASK_DUAL_SOURCE_BLEND; 288 if (g_settings.gpu_disable_framebuffer_fetch) 289 disabled_features |= GPUDevice::FEATURE_MASK_FRAMEBUFFER_FETCH; 290 if (g_settings.gpu_disable_texture_buffers) 291 disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_BUFFERS; 292 if (g_settings.gpu_disable_memory_import) 293 disabled_features |= GPUDevice::FEATURE_MASK_MEMORY_IMPORT; 294 if (g_settings.gpu_disable_raster_order_views) 295 disabled_features |= GPUDevice::FEATURE_MASK_RASTER_ORDER_VIEWS; 296 297 Error create_error; 298 if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter, 299 g_settings.gpu_disable_shader_cache ? std::string_view() : 300 std::string_view(EmuFolders::Cache), 301 SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, 302 System::GetEffectiveVSyncMode(), System::ShouldAllowPresentThrottle(), 303 g_settings.gpu_threaded_presentation, exclusive_fullscreen_control, 304 static_cast<GPUDevice::FeatureMask>(disabled_features), &create_error)) 305 { 306 ERROR_LOG("Failed to create GPU device: {}", create_error.GetDescription()); 307 if (g_gpu_device) 308 g_gpu_device->Destroy(); 309 g_gpu_device.reset(); 310 311 Error::SetStringFmt( 312 error, 313 TRANSLATE_FS("System", "Failed to create render device:\n\n{0}\n\nThis may be due to your GPU not supporting the " 314 "chosen renderer ({1}), or because your graphics drivers need to be updated."), 315 create_error.GetDescription(), GPUDevice::RenderAPIToString(api)); 316 return false; 317 } 318 319 if (!ImGuiManager::Initialize(g_settings.display_osd_scale / 100.0f, g_settings.display_show_osd_messages, 320 &create_error)) 321 { 322 ERROR_LOG("Failed to initialize ImGuiManager: {}", create_error.GetDescription()); 323 Error::SetStringFmt(error, "Failed to initialize ImGuiManager: {}", create_error.GetDescription()); 324 g_gpu_device->Destroy(); 325 g_gpu_device.reset(); 326 return false; 327 } 328 329 InputManager::SetDisplayWindowSize(static_cast<float>(g_gpu_device->GetWindowWidth()), 330 static_cast<float>(g_gpu_device->GetWindowHeight())); 331 return true; 332 } 333 334 void Host::UpdateDisplayWindow() 335 { 336 if (!g_gpu_device) 337 return; 338 339 if (!g_gpu_device->UpdateWindow()) 340 { 341 Host::ReportErrorAsync("Error", "Failed to change window after update. The log may contain more information."); 342 return; 343 } 344 345 const float f_width = static_cast<float>(g_gpu_device->GetWindowWidth()); 346 const float f_height = static_cast<float>(g_gpu_device->GetWindowHeight()); 347 ImGuiManager::WindowResized(f_width, f_height); 348 InputManager::SetDisplayWindowSize(f_width, f_height); 349 350 if (System::IsValid()) 351 { 352 // Fix up vsync etc. 353 System::UpdateSpeedLimiterState(); 354 355 // If we're paused, re-present the current frame at the new window size. 356 if (System::IsPaused()) 357 System::InvalidateDisplay(); 358 } 359 } 360 361 void Host::ResizeDisplayWindow(s32 width, s32 height, float scale) 362 { 363 if (!g_gpu_device) 364 return; 365 366 DEV_LOG("Display window resized to {}x{}", width, height); 367 368 g_gpu_device->ResizeWindow(width, height, scale); 369 370 const float f_width = static_cast<float>(g_gpu_device->GetWindowWidth()); 371 const float f_height = static_cast<float>(g_gpu_device->GetWindowHeight()); 372 ImGuiManager::WindowResized(f_width, f_height); 373 InputManager::SetDisplayWindowSize(f_width, f_height); 374 375 // If we're paused, re-present the current frame at the new window size. 376 if (System::IsValid()) 377 { 378 if (System::IsPaused()) 379 { 380 // Hackity hack, on some systems, presenting a single frame isn't enough to actually get it 381 // displayed. Two seems to be good enough. Maybe something to do with direct scanout. 382 System::InvalidateDisplay(); 383 System::InvalidateDisplay(); 384 } 385 386 System::HostDisplayResized(); 387 } 388 } 389 390 void Host::ReleaseGPUDevice() 391 { 392 if (!g_gpu_device) 393 return; 394 395 ImGuiManager::DestroyOverlayTextures(); 396 FullscreenUI::Shutdown(); 397 ImGuiManager::Shutdown(); 398 399 INFO_LOG("Destroying {} GPU device...", GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI())); 400 g_gpu_device->Destroy(); 401 g_gpu_device.reset(); 402 }