duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 }