From 9a23c5547acf8ce42433ee2c31fdbd8737a9a63e Mon Sep 17 00:00:00 2001
From: Connor McLaughlin <stenzek@gmail.com>
Date: Wed, 30 Sep 2020 23:46:35 +1000
Subject: [PATCH] GameSettings: Add CPU overclocking as game option

---
 src/core/settings.cpp                 |  7 ++++-
 src/core/settings.h                   |  1 +
 src/frontend-common/game_list.h       |  2 +-
 src/frontend-common/game_settings.cpp | 37 ++++++++++++++++++++++++---
 src/frontend-common/game_settings.h   |  3 +++
 5 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index e4abe54cb..9c67ac9cc 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -98,6 +98,11 @@ u32 Settings::GetCPUOverclockPercent() const
   return CPUOverclockFractionToPercent(cpu_overclock_numerator, cpu_overclock_denominator);
 }
 
+void Settings::UpdateOverclockActive()
+{
+  cpu_overclock_active = (cpu_overclock_enable && (cpu_overclock_numerator != 1 || cpu_overclock_denominator != 1));
+}
+
 void Settings::Load(SettingsInterface& si)
 {
   region =
@@ -121,7 +126,7 @@ void Settings::Load(SettingsInterface& si)
   cpu_overclock_numerator = std::max(si.GetIntValue("CPU", "OverclockNumerator", 1), 1);
   cpu_overclock_denominator = std::max(si.GetIntValue("CPU", "OverclockDenominator", 1), 1);
   cpu_overclock_enable = si.GetBoolValue("CPU", "OverclockEnable", false);
-  cpu_overclock_active = (cpu_overclock_enable && (cpu_overclock_numerator != 1 || cpu_overclock_denominator != 1));
+  UpdateOverclockActive();
   cpu_recompiler_memory_exceptions = si.GetBoolValue("CPU", "RecompilerMemoryExceptions", false);
   cpu_recompiler_icache = si.GetBoolValue("CPU", "RecompilerICache", false);
 
diff --git a/src/core/settings.h b/src/core/settings.h
index 5d4c72b77..24471d268 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -183,6 +183,7 @@ struct Settings
 
   void SetCPUOverclockPercent(u32 percent);
   u32 GetCPUOverclockPercent() const;
+  void UpdateOverclockActive();
 
   enum : u32
   {
diff --git a/src/frontend-common/game_list.h b/src/frontend-common/game_list.h
index ac80389c5..c9ff32efe 100644
--- a/src/frontend-common/game_list.h
+++ b/src/frontend-common/game_list.h
@@ -114,7 +114,7 @@ private:
   enum : u32
   {
     GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
-    GAME_LIST_CACHE_VERSION = 10
+    GAME_LIST_CACHE_VERSION = 11
   };
 
   using DatabaseMap = std::unordered_map<std::string, GameListDatabaseEntry>;
diff --git a/src/frontend-common/game_settings.cpp b/src/frontend-common/game_settings.cpp
index 7098b4903..5e8e30dd7 100644
--- a/src/frontend-common/game_settings.cpp
+++ b/src/frontend-common/game_settings.cpp
@@ -104,7 +104,10 @@ bool Entry::LoadFromStream(ByteStream* stream)
   constexpr u32 num_bytes = (static_cast<u32>(Trait::Count) + 7) / 8;
   std::array<u8, num_bytes> bits;
 
-  if (!stream->Read2(bits.data(), num_bytes) || !ReadOptionalFromStream(stream, &display_active_start_offset) ||
+  if (!stream->Read2(bits.data(), num_bytes) || !ReadOptionalFromStream(stream, &cpu_overclock_numerator) ||
+      !ReadOptionalFromStream(stream, &cpu_overclock_denominator) ||
+      !ReadOptionalFromStream(stream, &cpu_overclock_enable) ||
+      !ReadOptionalFromStream(stream, &display_active_start_offset) ||
       !ReadOptionalFromStream(stream, &display_active_end_offset) ||
       !ReadOptionalFromStream(stream, &display_crop_mode) || !ReadOptionalFromStream(stream, &display_aspect_ratio) ||
       !ReadOptionalFromStream(stream, &display_linear_upscaling) ||
@@ -144,7 +147,10 @@ bool Entry::SaveToStream(ByteStream* stream) const
       bits[i / 8] |= (1u << (i % 8));
   }
 
-  return stream->Write2(bits.data(), num_bytes) && WriteOptionalToStream(stream, display_active_start_offset) &&
+  return stream->Write2(bits.data(), num_bytes) && WriteOptionalToStream(stream, cpu_overclock_numerator) &&
+         WriteOptionalToStream(stream, cpu_overclock_denominator) &&
+         WriteOptionalToStream(stream, cpu_overclock_enable) &&
+         WriteOptionalToStream(stream, display_active_start_offset) &&
          WriteOptionalToStream(stream, display_active_end_offset) && WriteOptionalToStream(stream, display_crop_mode) &&
          WriteOptionalToStream(stream, display_aspect_ratio) &&
          WriteOptionalToStream(stream, display_linear_upscaling) &&
@@ -167,6 +173,16 @@ static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA
       entry->AddTrait(static_cast<Trait>(trait));
   }
 
+  const char* cvalue = ini.GetValue(section, "CPUOverclockNumerator", nullptr);
+  if (cvalue)
+    entry->cpu_overclock_numerator = StringUtil::FromChars<u32>(cvalue);
+  cvalue = ini.GetValue(section, "CPUOverclockDenominator", nullptr);
+  if (cvalue)
+    entry->cpu_overclock_denominator = StringUtil::FromChars<u32>(cvalue);
+  cvalue = ini.GetValue(section, "CPUOverclockEnable", nullptr);
+  if (cvalue)
+    entry->cpu_overclock_enable = StringUtil::FromChars<bool>(cvalue);
+
   long lvalue = ini.GetLongValue(section, "DisplayActiveStartOffset", 0);
   if (lvalue != 0)
     entry->display_active_start_offset = static_cast<s16>(lvalue);
@@ -174,7 +190,7 @@ static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA
   if (lvalue != 0)
     entry->display_active_end_offset = static_cast<s16>(lvalue);
 
-  const char* cvalue = ini.GetValue(section, "DisplayCropMode", nullptr);
+  cvalue = ini.GetValue(section, "DisplayCropMode", nullptr);
   if (cvalue)
     entry->display_crop_mode = Settings::ParseDisplayCropMode(cvalue);
   cvalue = ini.GetValue(section, "DisplayAspectRatio", nullptr);
@@ -241,6 +257,13 @@ static void StoreIniSection(const Entry& entry, const char* section, CSimpleIniA
       ini.SetBoolValue(section, s_trait_names[trait].first, true);
   }
 
+  if (entry.cpu_overclock_numerator.has_value())
+    ini.SetLongValue(section, "CPUOverclockNumerator", static_cast<long>(entry.cpu_overclock_numerator.value()));
+  if (entry.cpu_overclock_denominator.has_value())
+    ini.SetLongValue(section, "CPUOverclockDenominator", static_cast<long>(entry.cpu_overclock_denominator.value()));
+  if (entry.cpu_overclock_enable.has_value())
+    ini.SetBoolValue(section, "CPUOverclockEnable", entry.cpu_overclock_enable.value());
+
   if (entry.display_active_start_offset.has_value())
     ini.SetLongValue(section, "DisplayActiveStartOffset", entry.display_active_start_offset.value());
 
@@ -394,6 +417,14 @@ void Entry::ApplySettings(bool display_osd_messages) const
 {
   constexpr float osd_duration = 10.0f;
 
+  if (cpu_overclock_numerator.has_value())
+    g_settings.cpu_overclock_numerator = cpu_overclock_numerator.value();
+  if (cpu_overclock_denominator.has_value())
+    g_settings.cpu_overclock_denominator = cpu_overclock_denominator.value();
+  if (cpu_overclock_enable.has_value())
+    g_settings.cpu_overclock_enable = cpu_overclock_enable.value();
+  g_settings.UpdateOverclockActive();
+
   if (display_active_start_offset.has_value())
     g_settings.display_active_start_offset = display_active_start_offset.value();
   if (display_active_end_offset.has_value())
diff --git a/src/frontend-common/game_settings.h b/src/frontend-common/game_settings.h
index 9f99d8c60..23e88ffa3 100644
--- a/src/frontend-common/game_settings.h
+++ b/src/frontend-common/game_settings.h
@@ -40,6 +40,9 @@ struct Entry
   std::optional<s16> display_active_end_offset;
 
   // user settings
+  std::optional<u32> cpu_overclock_numerator;
+  std::optional<u32> cpu_overclock_denominator;
+  std::optional<bool> cpu_overclock_enable;
   std::optional<DisplayCropMode> display_crop_mode;
   std::optional<DisplayAspectRatio> display_aspect_ratio;
   std::optional<bool> display_linear_upscaling;