From b285991b886c0097f9d7ef9875eac158b9a3b6c0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 20 Sep 2020 13:58:17 +0200 Subject: [PATCH 1/3] Turn Config::Info into a class with getters --- Source/Core/Common/Config/Config.h | 8 ++--- Source/Core/Common/Config/ConfigInfo.h | 21 +++++++----- Source/Core/Common/Config/Layer.h | 6 ++-- .../Core/ConfigLoaders/BaseConfigLoader.cpp | 13 +++---- .../Core/ConfigLoaders/GameConfigLoader.cpp | 8 ++--- .../Core/ConfigLoaders/IsSettingSaveable.cpp | 34 +++++++++---------- .../DolphinQt/Config/Graphics/GraphicsBool.h | 2 +- .../Config/Graphics/GraphicsInteger.h | 2 +- .../Config/Graphics/GraphicsSlider.h | 2 +- .../DolphinQt/NetPlay/NetPlaySetupDialog.cpp | 8 ++--- Source/Core/UICommon/CommandLineParse.cpp | 9 +++-- Source/Core/UICommon/DiscordPresence.cpp | 2 +- 12 files changed, 62 insertions(+), 53 deletions(-) diff --git a/Source/Core/Common/Config/Config.h b/Source/Core/Common/Config/Config.h index 1fbaef0f88..21662d4167 100644 --- a/Source/Core/Common/Config/Config.h +++ b/Source/Core/Common/Config/Config.h @@ -52,11 +52,11 @@ T Get(LayerType layer, const Info& info) template T Get(const Info& info) { - const std::optional str = GetAsString(info.location); + const std::optional str = GetAsString(info.GetLocation()); if (!str) - return info.default_value; + return info.GetDefaultValue(); - return detail::TryParse(*str).value_or(info.default_value); + return detail::TryParse(*str).value_or(info.GetDefaultValue()); } template @@ -68,7 +68,7 @@ T GetBase(const Info& info) template LayerType GetActiveLayerForConfig(const Info& info) { - return GetActiveLayerForConfig(info.location); + return GetActiveLayerForConfig(info.GetLocation()); } template diff --git a/Source/Core/Common/Config/ConfigInfo.h b/Source/Core/Common/Config/ConfigInfo.h index 20051c1003..56d3a43a31 100644 --- a/Source/Core/Common/Config/ConfigInfo.h +++ b/Source/Core/Common/Config/ConfigInfo.h @@ -30,10 +30,11 @@ struct Location }; template -struct Info +class Info { - Info(const Location& location_, const T& default_value_) - : location{location_}, default_value{default_value_} +public: + constexpr Info(const Location& location, const T& default_value) + : m_location{location}, m_default_value{default_value} { } @@ -41,13 +42,17 @@ struct Info // so that enum settings can still easily work with code that doesn't care about the enum values. template >::value>* = nullptr> - Info(const Info& other) - : location{other.location}, default_value{static_cast>( - other.default_value)} + constexpr Info(const Info& other) + : m_location{other.GetLocation()}, m_default_value{static_cast>( + other.GetDefaultValue())} { } - Location location; - T default_value; + constexpr const Location& GetLocation() const { return m_location; } + constexpr const T& GetDefaultValue() const { return m_default_value; } + +private: + Location m_location; + T m_default_value; }; } // namespace Config diff --git a/Source/Core/Common/Config/Layer.h b/Source/Core/Common/Config/Layer.h index c309810719..cbfbbe6aae 100644 --- a/Source/Core/Common/Config/Layer.h +++ b/Source/Core/Common/Config/Layer.h @@ -45,7 +45,7 @@ inline std::optional TryParse(const std::string& str_value) } // namespace detail template -struct Info; +class Info; class Layer; using LayerMap = std::map>; @@ -105,7 +105,7 @@ public: template T Get(const Info& config_info) const { - return Get(config_info.location).value_or(config_info.default_value); + return Get(config_info.GetLocation()).value_or(config_info.GetDefaultValue()); } template @@ -120,7 +120,7 @@ public: template void Set(const Info& config_info, const std::common_type_t& value) { - Set(config_info.location, value); + Set(config_info.GetLocation(), value); } template diff --git a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp index eadb007ae6..6598561e32 100644 --- a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp @@ -41,7 +41,7 @@ void SaveToSYSCONF(Config::LayerType layer) { std::visit( [layer, &setting, &sysconf](auto& info) { - const std::string key = info.location.section + "." + info.location.key; + const std::string key = info.GetLocation().section + "." + info.GetLocation().key; if (setting.type == SysConf::Entry::Type::Long) { @@ -180,27 +180,28 @@ private: { std::visit( [&](auto& info) { - const std::string key = info.location.section + "." + info.location.key; + const Config::Location location = info.GetLocation(); + const std::string key = location.section + "." + location.key; if (setting.type == SysConf::Entry::Type::Long) { - layer->Set(info.location, sysconf.GetData(key, info.default_value)); + layer->Set(location, sysconf.GetData(key, info.GetDefaultValue())); } else if (setting.type == SysConf::Entry::Type::Byte) { - layer->Set(info.location, sysconf.GetData(key, info.default_value)); + layer->Set(location, sysconf.GetData(key, info.GetDefaultValue())); } else if (setting.type == SysConf::Entry::Type::BigArray) { // Somewhat hacky support for IPL.SADR. The setting only stores the // first 4 bytes even thought the SYSCONF entry is much bigger. - u32 value = info.default_value; + u32 value = info.GetDefaultValue(); SysConf::Entry* entry = sysconf.GetEntry(key); if (entry) { std::memcpy(&value, entry->bytes.data(), std::min(entry->bytes.size(), sizeof(u32))); } - layer->Set(info.location, value); + layer->Set(location, value); } }, setting.config_info); diff --git a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp index fde97589a1..eb4e71a352 100644 --- a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp @@ -69,10 +69,10 @@ using INIToSectionMap = std::map s_setting_saveable = { // Main.Core - &Config::MAIN_DEFAULT_ISO.location, - &Config::MAIN_MEMCARD_A_PATH.location, - &Config::MAIN_MEMCARD_B_PATH.location, - &Config::MAIN_AUTO_DISC_CHANGE.location, - &Config::MAIN_ALLOW_SD_WRITES.location, - &Config::MAIN_DPL2_DECODER.location, - &Config::MAIN_DPL2_QUALITY.location, - &Config::MAIN_RAM_OVERRIDE_ENABLE.location, - &Config::MAIN_MEM1_SIZE.location, - &Config::MAIN_MEM2_SIZE.location, - &Config::MAIN_GFX_BACKEND.location, - &Config::MAIN_ENABLE_SAVESTATES.location, - &Config::MAIN_FALLBACK_REGION.location, + &Config::MAIN_DEFAULT_ISO.GetLocation(), + &Config::MAIN_MEMCARD_A_PATH.GetLocation(), + &Config::MAIN_MEMCARD_B_PATH.GetLocation(), + &Config::MAIN_AUTO_DISC_CHANGE.GetLocation(), + &Config::MAIN_ALLOW_SD_WRITES.GetLocation(), + &Config::MAIN_DPL2_DECODER.GetLocation(), + &Config::MAIN_DPL2_QUALITY.GetLocation(), + &Config::MAIN_RAM_OVERRIDE_ENABLE.GetLocation(), + &Config::MAIN_MEM1_SIZE.GetLocation(), + &Config::MAIN_MEM2_SIZE.GetLocation(), + &Config::MAIN_GFX_BACKEND.GetLocation(), + &Config::MAIN_ENABLE_SAVESTATES.GetLocation(), + &Config::MAIN_FALLBACK_REGION.GetLocation(), // Main.Interface - &Config::MAIN_USE_PANIC_HANDLERS.location, - &Config::MAIN_OSD_MESSAGES.location, + &Config::MAIN_USE_PANIC_HANDLERS.GetLocation(), + &Config::MAIN_OSD_MESSAGES.GetLocation(), // Main.Interface - &Config::MAIN_SKIP_NKIT_WARNING.location, + &Config::MAIN_SKIP_NKIT_WARNING.GetLocation(), // UI.General - &Config::MAIN_USE_DISCORD_PRESENCE.location, + &Config::MAIN_USE_DISCORD_PRESENCE.GetLocation(), }; return std::any_of(s_setting_saveable.cbegin(), s_setting_saveable.cend(), diff --git a/Source/Core/DolphinQt/Config/Graphics/GraphicsBool.h b/Source/Core/DolphinQt/Config/Graphics/GraphicsBool.h index 1d3ceb4d5d..794a210c6e 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GraphicsBool.h +++ b/Source/Core/DolphinQt/Config/Graphics/GraphicsBool.h @@ -10,7 +10,7 @@ namespace Config { template -struct Info; +class Info; } class GraphicsBool : public ToolTipCheckBox diff --git a/Source/Core/DolphinQt/Config/Graphics/GraphicsInteger.h b/Source/Core/DolphinQt/Config/Graphics/GraphicsInteger.h index 4f0cea9cb3..e7d105da89 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GraphicsInteger.h +++ b/Source/Core/DolphinQt/Config/Graphics/GraphicsInteger.h @@ -9,7 +9,7 @@ namespace Config { template -struct Info; +class Info; } class GraphicsInteger : public ToolTipSpinBox diff --git a/Source/Core/DolphinQt/Config/Graphics/GraphicsSlider.h b/Source/Core/DolphinQt/Config/Graphics/GraphicsSlider.h index 9c45f81ac4..9a8cc75fde 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GraphicsSlider.h +++ b/Source/Core/DolphinQt/Config/Graphics/GraphicsSlider.h @@ -9,7 +9,7 @@ namespace Config { template -struct Info; +class Info; } class GraphicsSlider : public ToolTipSlider diff --git a/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp index 521ec48745..12726019f6 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp +++ b/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp @@ -381,13 +381,13 @@ void NetPlaySetupDialog::PopulateGameList() void NetPlaySetupDialog::ResetTraversalHost() { Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_SERVER, - Config::NETPLAY_TRAVERSAL_SERVER.default_value); + Config::NETPLAY_TRAVERSAL_SERVER.GetDefaultValue()); Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_PORT, - Config::NETPLAY_TRAVERSAL_PORT.default_value); + Config::NETPLAY_TRAVERSAL_PORT.GetDefaultValue()); ModalMessageBox::information( this, tr("Reset Traversal Server"), tr("Reset Traversal Server to %1:%2") - .arg(QString::fromStdString(Config::NETPLAY_TRAVERSAL_SERVER.default_value), - QString::number(Config::NETPLAY_TRAVERSAL_PORT.default_value))); + .arg(QString::fromStdString(Config::NETPLAY_TRAVERSAL_SERVER.GetDefaultValue()), + QString::number(Config::NETPLAY_TRAVERSAL_PORT.GetDefaultValue()))); } diff --git a/Source/Core/UICommon/CommandLineParse.cpp b/Source/Core/UICommon/CommandLineParse.cpp index 6c06cb2ef2..5d37d34b32 100644 --- a/Source/Core/UICommon/CommandLineParse.cpp +++ b/Source/Core/UICommon/CommandLineParse.cpp @@ -26,15 +26,18 @@ public: : ConfigLayerLoader(Config::LayerType::CommandLine) { if (!video_backend.empty()) - m_values.emplace_back(Config::MAIN_GFX_BACKEND.location, video_backend); + m_values.emplace_back(Config::MAIN_GFX_BACKEND.GetLocation(), video_backend); if (!audio_backend.empty()) - m_values.emplace_back(Config::MAIN_DSP_HLE.location, ValueToString(audio_backend == "HLE")); + { + m_values.emplace_back(Config::MAIN_DSP_HLE.GetLocation(), + ValueToString(audio_backend == "HLE")); + } // Batch mode hides the main window, and render to main hides the render window. To avoid a // situation where we would have no window at all, disable render to main when using batch mode. if (batch) - m_values.emplace_back(Config::MAIN_RENDER_TO_MAIN.location, ValueToString(false)); + m_values.emplace_back(Config::MAIN_RENDER_TO_MAIN.GetLocation(), ValueToString(false)); // Arguments are in the format of .
.=Value for (const auto& arg : args) diff --git a/Source/Core/UICommon/DiscordPresence.cpp b/Source/Core/UICommon/DiscordPresence.cpp index c1aab0720b..de3d6973d7 100644 --- a/Source/Core/UICommon/DiscordPresence.cpp +++ b/Source/Core/UICommon/DiscordPresence.cpp @@ -50,7 +50,7 @@ void HandleDiscordJoin(const char* join_secret) if (event_handler == nullptr) return; - if (Config::Get(Config::NETPLAY_NICKNAME) == Config::NETPLAY_NICKNAME.default_value) + if (Config::Get(Config::NETPLAY_NICKNAME) == Config::NETPLAY_NICKNAME.GetDefaultValue()) Config::SetCurrent(Config::NETPLAY_NICKNAME, username); std::string secret(join_secret); From 633ab2dd7c42d2e3d35740b885b60fb3c18569ed Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 20 Sep 2020 19:11:20 +0200 Subject: [PATCH 2/3] Store pointers in Config::SYSCONF_SETTINGS Not strictly necessary, but it reduces memory usage a little, and the next commit will make copying an Info object slower. --- Source/Core/Core/BootManager.cpp | 6 ++--- Source/Core/Core/Config/SYSCONFSettings.cpp | 22 +++++++++---------- Source/Core/Core/Config/SYSCONFSettings.h | 2 +- .../Core/ConfigLoaders/BaseConfigLoader.cpp | 20 ++++++++--------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index a9f18b7ac8..a339ee80dd 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -472,11 +472,11 @@ static void RestoreSYSCONF() for (const auto& setting : Config::SYSCONF_SETTINGS) { std::visit( - [&](auto& info) { + [&](auto* info) { // If this setting was overridden, then we copy the base layer value back to the SYSCONF. // Otherwise we leave the new value in the SYSCONF. - if (Config::GetActiveLayerForConfig(info) == Config::LayerType::Base) - Config::SetBase(info, temp_layer.Get(info)); + if (Config::GetActiveLayerForConfig(*info) == Config::LayerType::Base) + Config::SetBase(*info, temp_layer.Get(*info)); }, setting.config_info); } diff --git a/Source/Core/Core/Config/SYSCONFSettings.cpp b/Source/Core/Core/Config/SYSCONFSettings.cpp index c2693a8d2b..3aaebc52bc 100644 --- a/Source/Core/Core/Config/SYSCONFSettings.cpp +++ b/Source/Core/Core/Config/SYSCONFSettings.cpp @@ -24,15 +24,15 @@ const Info SYSCONF_SPEAKER_VOLUME{{System::SYSCONF, "BT", "SPKV"}, 0x58}; const Info SYSCONF_WIIMOTE_MOTOR{{System::SYSCONF, "BT", "MOT"}, true}; const std::array SYSCONF_SETTINGS{ - {{SYSCONF_SCREENSAVER, SysConf::Entry::Type::Byte}, - {SYSCONF_LANGUAGE, SysConf::Entry::Type::Byte}, - {SYSCONF_COUNTRY, SysConf::Entry::Type::BigArray}, - {SYSCONF_WIDESCREEN, SysConf::Entry::Type::Byte}, - {SYSCONF_PROGRESSIVE_SCAN, SysConf::Entry::Type::Byte}, - {SYSCONF_PAL60, SysConf::Entry::Type::Byte}, - {SYSCONF_SOUND_MODE, SysConf::Entry::Type::Byte}, - {SYSCONF_SENSOR_BAR_POSITION, SysConf::Entry::Type::Byte}, - {SYSCONF_SENSOR_BAR_SENSITIVITY, SysConf::Entry::Type::Long}, - {SYSCONF_SPEAKER_VOLUME, SysConf::Entry::Type::Byte}, - {SYSCONF_WIIMOTE_MOTOR, SysConf::Entry::Type::Byte}}}; + {{&SYSCONF_SCREENSAVER, SysConf::Entry::Type::Byte}, + {&SYSCONF_LANGUAGE, SysConf::Entry::Type::Byte}, + {&SYSCONF_COUNTRY, SysConf::Entry::Type::BigArray}, + {&SYSCONF_WIDESCREEN, SysConf::Entry::Type::Byte}, + {&SYSCONF_PROGRESSIVE_SCAN, SysConf::Entry::Type::Byte}, + {&SYSCONF_PAL60, SysConf::Entry::Type::Byte}, + {&SYSCONF_SOUND_MODE, SysConf::Entry::Type::Byte}, + {&SYSCONF_SENSOR_BAR_POSITION, SysConf::Entry::Type::Byte}, + {&SYSCONF_SENSOR_BAR_SENSITIVITY, SysConf::Entry::Type::Long}, + {&SYSCONF_SPEAKER_VOLUME, SysConf::Entry::Type::Byte}, + {&SYSCONF_WIIMOTE_MOTOR, SysConf::Entry::Type::Byte}}}; } // namespace Config diff --git a/Source/Core/Core/Config/SYSCONFSettings.h b/Source/Core/Core/Config/SYSCONFSettings.h index 08efeb589e..e0f91b148c 100644 --- a/Source/Core/Core/Config/SYSCONFSettings.h +++ b/Source/Core/Core/Config/SYSCONFSettings.h @@ -33,7 +33,7 @@ extern const Info SYSCONF_WIIMOTE_MOTOR; struct SYSCONFSetting { - std::variant, Info> config_info; + std::variant*, const Info*> config_info; SysConf::Entry::Type type; }; diff --git a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp index 6598561e32..f54e2ac9f5 100644 --- a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp @@ -40,16 +40,16 @@ void SaveToSYSCONF(Config::LayerType layer) for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS) { std::visit( - [layer, &setting, &sysconf](auto& info) { - const std::string key = info.GetLocation().section + "." + info.GetLocation().key; + [layer, &setting, &sysconf](auto* info) { + const std::string key = info->GetLocation().section + "." + info->GetLocation().key; if (setting.type == SysConf::Entry::Type::Long) { - sysconf.SetData(key, setting.type, Config::Get(layer, info)); + sysconf.SetData(key, setting.type, Config::Get(layer, *info)); } else if (setting.type == SysConf::Entry::Type::Byte) { - sysconf.SetData(key, setting.type, static_cast(Config::Get(layer, info))); + sysconf.SetData(key, setting.type, static_cast(Config::Get(layer, *info))); } else if (setting.type == SysConf::Entry::Type::BigArray) { @@ -58,7 +58,7 @@ void SaveToSYSCONF(Config::LayerType layer) SysConf::Entry* entry = sysconf.GetOrAddEntry(key, setting.type); if (entry->bytes.size() < 0x1007 + 1) entry->bytes.resize(0x1007 + 1); - *reinterpret_cast(entry->bytes.data()) = Config::Get(layer, info); + *reinterpret_cast(entry->bytes.data()) = Config::Get(layer, *info); } }, setting.config_info); @@ -179,22 +179,22 @@ private: for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS) { std::visit( - [&](auto& info) { - const Config::Location location = info.GetLocation(); + [&](auto* info) { + const Config::Location location = info->GetLocation(); const std::string key = location.section + "." + location.key; if (setting.type == SysConf::Entry::Type::Long) { - layer->Set(location, sysconf.GetData(key, info.GetDefaultValue())); + layer->Set(location, sysconf.GetData(key, info->GetDefaultValue())); } else if (setting.type == SysConf::Entry::Type::Byte) { - layer->Set(location, sysconf.GetData(key, info.GetDefaultValue())); + layer->Set(location, sysconf.GetData(key, info->GetDefaultValue())); } else if (setting.type == SysConf::Entry::Type::BigArray) { // Somewhat hacky support for IPL.SADR. The setting only stores the // first 4 bytes even thought the SYSCONF entry is much bigger. - u32 value = info.GetDefaultValue(); + u32 value = info->GetDefaultValue(); SysConf::Entry* entry = sysconf.GetEntry(key); if (entry) { From d8744e6db8f97e4d721d098010d1b1115e31403f Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 5 Dec 2020 18:24:41 +0100 Subject: [PATCH 3/3] Add caching to Config::Info The goal of this change is to make Config::Get(const Info&) fast so that we can use it in hot paths. --- Source/Android/jni/NativeConfig.cpp | 2 +- Source/Core/Common/Config/Config.cpp | 21 +++++--- Source/Core/Common/Config/Config.h | 26 +++++++-- Source/Core/Common/Config/ConfigInfo.h | 75 ++++++++++++++++++++++++-- 4 files changed, 110 insertions(+), 14 deletions(-) diff --git a/Source/Android/jni/NativeConfig.cpp b/Source/Android/jni/NativeConfig.cpp index ef4c847ee2..9de9a16358 100644 --- a/Source/Android/jni/NativeConfig.cpp +++ b/Source/Android/jni/NativeConfig.cpp @@ -86,7 +86,7 @@ template static void Set(jint layer, const Config::Location& location, T value) { GetLayer(layer, location)->Set(location, value); - Config::InvokeConfigChangedCallbacks(); + Config::OnConfigChanged(); } #ifdef __cplusplus diff --git a/Source/Core/Common/Config/Config.cpp b/Source/Core/Common/Config/Config.cpp index 03c0aed72e..071d009b51 100644 --- a/Source/Core/Common/Config/Config.cpp +++ b/Source/Core/Common/Config/Config.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -17,6 +18,7 @@ using Layers = std::map>; static Layers s_layers; static std::list s_callbacks; static u32 s_callback_guards = 0; +static std::atomic s_config_version = 0; static std::shared_mutex s_layers_rw_lock; @@ -31,7 +33,7 @@ static void AddLayerInternal(std::shared_ptr layer) const Config::LayerType layer_type = layer->GetLayer(); s_layers.insert_or_assign(layer_type, std::move(layer)); } - InvokeConfigChangedCallbacks(); + OnConfigChanged(); } void AddLayer(std::unique_ptr loader) @@ -59,7 +61,7 @@ void RemoveLayer(LayerType layer) s_layers.erase(layer); } - InvokeConfigChangedCallbacks(); + OnConfigChanged(); } void AddConfigChangedCallback(ConfigChangedCallback func) @@ -67,15 +69,22 @@ void AddConfigChangedCallback(ConfigChangedCallback func) s_callbacks.emplace_back(std::move(func)); } -void InvokeConfigChangedCallbacks() +void OnConfigChanged() { if (s_callback_guards) return; + s_config_version.fetch_add(1, std::memory_order_relaxed); + for (const auto& callback : s_callbacks) callback(); } +u64 GetConfigVersion() +{ + return s_config_version.load(std::memory_order_relaxed); +} + // Explicit load and save of layers void Load() { @@ -85,7 +94,7 @@ void Load() for (auto& layer : s_layers) layer.second->Load(); } - InvokeConfigChangedCallbacks(); + OnConfigChanged(); } void Save() @@ -96,7 +105,7 @@ void Save() for (auto& layer : s_layers) layer.second->Save(); } - InvokeConfigChangedCallbacks(); + OnConfigChanged(); } void Init() @@ -207,7 +216,7 @@ ConfigChangeCallbackGuard::~ConfigChangeCallbackGuard() if (--s_callback_guards) return; - InvokeConfigChangedCallbacks(); + OnConfigChanged(); } } // namespace Config diff --git a/Source/Core/Common/Config/Config.h b/Source/Core/Common/Config/Config.h index 21662d4167..e0d110719e 100644 --- a/Source/Core/Common/Config/Config.h +++ b/Source/Core/Common/Config/Config.h @@ -24,7 +24,10 @@ std::shared_ptr GetLayer(LayerType layer); void RemoveLayer(LayerType layer); void AddConfigChangedCallback(ConfigChangedCallback func); -void InvokeConfigChangedCallbacks(); +void OnConfigChanged(); + +// Returns the number of times the config has changed in the current execution of the program +u64 GetConfigVersion(); // Explicit load and save of layers void Load(); @@ -51,6 +54,23 @@ T Get(LayerType layer, const Info& info) template T Get(const Info& info) +{ + CachedValue cached = info.GetCachedValue(); + const u64 config_version = GetConfigVersion(); + + if (cached.config_version < config_version) + { + cached.value = GetUncached(info); + cached.config_version = config_version; + + info.SetCachedValue(cached); + } + + return cached.value; +} + +template +T GetUncached(const Info& info) { const std::optional str = GetAsString(info.GetLocation()); if (!str) @@ -75,7 +95,7 @@ template void Set(LayerType layer, const Info& info, const std::common_type_t& value) { GetLayer(layer)->Set(info, value); - InvokeConfigChangedCallbacks(); + OnConfigChanged(); } template @@ -99,7 +119,7 @@ void SetBaseOrCurrent(const Info& info, const std::common_type_t& value) Set(LayerType::CurrentRun, info, value); } -// Used to defer InvokeConfigChangedCallbacks until after the completion of many config changes. +// Used to defer OnConfigChanged until after the completion of many config changes. class ConfigChangeCallbackGuard { public: diff --git a/Source/Core/Common/Config/ConfigInfo.h b/Source/Core/Common/Config/ConfigInfo.h index 56d3a43a31..0b9b0ad653 100644 --- a/Source/Core/Common/Config/ConfigInfo.h +++ b/Source/Core/Common/Config/ConfigInfo.h @@ -4,9 +4,13 @@ #pragma once +#include +#include #include #include +#include +#include "Common/CommonTypes.h" #include "Common/Config/Enums.h" namespace Config @@ -29,30 +33,93 @@ struct Location bool operator<(const Location& other) const; }; +template +struct CachedValue +{ + T value; + u64 config_version; +}; + template class Info { public: constexpr Info(const Location& location, const T& default_value) - : m_location{location}, m_default_value{default_value} + : m_location{location}, m_default_value{default_value}, m_cached_value{default_value, 0} { } + Info(const Info& other) { *this = other; } + + // Not thread-safe + Info(Info&& other) { *this = std::move(other); } + + // Make it easy to convert Info into Info> + // so that enum settings can still easily work with code that doesn't care about the enum values. + template >::value>* = nullptr> + Info(const Info& other) + { + *this = other; + } + + Info& operator=(const Info& other) + { + m_location = other.GetLocation(); + m_default_value = other.GetDefaultValue(); + m_cached_value = other.GetCachedValue(); + return *this; + } + + // Not thread-safe + Info& operator=(Info&& other) + { + m_location = std::move(other.m_location); + m_default_value = std::move(other.m_default_value); + m_cached_value = std::move(other.m_cached_value); + return *this; + } + // Make it easy to convert Info into Info> // so that enum settings can still easily work with code that doesn't care about the enum values. template >::value>* = nullptr> - constexpr Info(const Info& other) - : m_location{other.GetLocation()}, m_default_value{static_cast>( - other.GetDefaultValue())} + Info& operator=(const Info& other) { + m_location = other.GetLocation(); + m_default_value = static_cast(other.GetDefaultValue()); + m_cached_value = other.template GetCachedValueCasted(); + return *this; } constexpr const Location& GetLocation() const { return m_location; } constexpr const T& GetDefaultValue() const { return m_default_value; } + CachedValue GetCachedValue() const + { + std::shared_lock lock(m_cached_value_mutex); + return m_cached_value; + } + + template + CachedValue GetCachedValueCasted() const + { + std::shared_lock lock(m_cached_value_mutex); + return CachedValue{static_cast(m_cached_value.value), m_cached_value.config_version}; + } + + void SetCachedValue(const CachedValue& cached_value) const + { + std::unique_lock lock(m_cached_value_mutex); + if (m_cached_value.config_version < cached_value.config_version) + m_cached_value = cached_value; + } + private: Location m_location; T m_default_value; + + mutable CachedValue m_cached_value; + mutable std::shared_mutex m_cached_value_mutex; }; } // namespace Config