diff --git a/Source/Core/Common/Timer.cpp b/Source/Core/Common/Timer.cpp
index fb81164390..0a23080c6f 100644
--- a/Source/Core/Common/Timer.cpp
+++ b/Source/Core/Common/Timer.cpp
@@ -4,6 +4,7 @@
 #include "Common/Timer.h"
 
 #include <chrono>
+#include <thread>
 
 #ifdef _WIN32
 #include <Windows.h>
@@ -13,6 +14,7 @@
 #endif
 
 #include "Common/CommonTypes.h"
+#include "Common/Logging/Log.h"
 
 namespace Common
 {
@@ -91,6 +93,10 @@ u64 Timer::GetLocalTimeSinceJan1970()
 #endif
 }
 
+// This is requested by Timer::IncreaseResolution on Windows.
+// On Linux/other we hope/assume we already have 1ms scheduling granularity.
+static constexpr int TIMER_RESOLUTION_MS = 1;
+
 void Timer::IncreaseResolution()
 {
 #ifdef _WIN32
@@ -110,15 +116,82 @@ void Timer::IncreaseResolution()
                         sizeof(PowerThrottling));
 
   // Not actually sure how useful this is these days.. :')
-  timeBeginPeriod(1);
+  timeBeginPeriod(TIMER_RESOLUTION_MS);
 #endif
 }
 
 void Timer::RestoreResolution()
 {
 #ifdef _WIN32
-  timeEndPeriod(1);
+  timeEndPeriod(TIMER_RESOLUTION_MS);
 #endif
 }
 
+PrecisionTimer::PrecisionTimer()
+{
+#if defined(_WIN32)
+  // "TIMER_HIGH_RESOLUTION" requires Windows 10, version 1803, and later.
+  m_timer_handle =
+      CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
+
+  if (m_timer_handle == NULL)
+  {
+    ERROR_LOG_FMT(COMMON, "CREATE_WAITABLE_TIMER_HIGH_RESOLUTION: Error:{}", GetLastError());
+
+    // Create a normal timer if "HIGH_RESOLUTION" isn't available.
+    m_timer_handle = CreateWaitableTimerExW(NULL, NULL, 0, TIMER_ALL_ACCESS);
+    if (m_timer_handle == NULL)
+      ERROR_LOG_FMT(COMMON, "CreateWaitableTimerExW: Error:{}", GetLastError());
+  }
+#endif
+}
+
+PrecisionTimer::~PrecisionTimer()
+{
+#if defined(_WIN32)
+  CloseHandle(m_timer_handle);
+#endif
+}
+
+void PrecisionTimer::SleepUntil(Clock::time_point target)
+{
+  constexpr auto SPIN_TIME =
+      std::chrono::milliseconds{TIMER_RESOLUTION_MS} + std::chrono::microseconds{20};
+
+#if defined(_WIN32)
+  while (true)
+  {
+    // SetWaitableTimerEx takes time in "100 nanosecond intervals".
+    using TimerDuration = std::chrono::duration<LONGLONG, std::ratio<100, std::nano::den>::type>;
+
+    // Apparently waiting longer than the timer resolution gives terrible accuracy.
+    // We'll wait in steps of 95% of the time period.
+    constexpr auto MAX_TICKS =
+        duration_cast<TimerDuration>(std::chrono::milliseconds{TIMER_RESOLUTION_MS}) * 95 / 100;
+
+    const auto wait_time = target - Clock::now() - SPIN_TIME;
+    const auto ticks = std::min(duration_cast<TimerDuration>(wait_time), MAX_TICKS).count();
+    if (ticks <= 0)
+      break;
+
+    const LARGE_INTEGER due_time{.QuadPart = -ticks};
+    SetWaitableTimerEx(m_timer_handle, &due_time, 0, NULL, NULL, NULL, 0);
+    WaitForSingleObject(m_timer_handle, INFINITE);
+  }
+#else
+  // Sleeping on Linux generally isn't as terrible as it is on Windows.
+  std::this_thread::sleep_until(target - SPIN_TIME);
+#endif
+
+  // Spin for the remaining time.
+  while (Clock::now() < target)
+  {
+#if defined(_WIN32)
+    YieldProcessor();
+#else
+    std::this_thread::yield();
+#endif
+  }
+}
+
 }  // Namespace Common
diff --git a/Source/Core/Common/Timer.h b/Source/Core/Common/Timer.h
index 7298f4a368..7f36308e78 100644
--- a/Source/Core/Common/Timer.h
+++ b/Source/Core/Common/Timer.h
@@ -5,6 +5,10 @@
 
 #include "Common/CommonTypes.h"
 
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+
 namespace Common
 {
 class Timer
@@ -32,4 +36,21 @@ private:
   bool m_running{false};
 };
 
+class PrecisionTimer
+{
+public:
+  PrecisionTimer();
+  ~PrecisionTimer();
+
+  PrecisionTimer(const PrecisionTimer&) = delete;
+  PrecisionTimer& operator=(const PrecisionTimer&) = delete;
+
+  void SleepUntil(Clock::time_point);
+
+private:
+#ifdef _WIN32
+  HANDLE m_timer_handle;
+#endif
+};
+
 }  // Namespace Common
diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp
index bd43c721c8..37f2a6054e 100644
--- a/Source/Core/Core/Config/MainSettings.cpp
+++ b/Source/Core/Core/Config/MainSettings.cpp
@@ -211,6 +211,15 @@ const Info<bool> MAIN_FPRF{{System::Main, "Core", "FPRF"}, false};
 const Info<bool> MAIN_ACCURATE_NANS{{System::Main, "Core", "AccurateNaNs"}, false};
 const Info<bool> MAIN_DISABLE_ICACHE{{System::Main, "Core", "DisableICache"}, false};
 const Info<float> MAIN_EMULATION_SPEED{{System::Main, "Core", "EmulationSpeed"}, 1.0f};
+#if defined(ANDROID)
+// Currently disabled by default on Android for concern of increased power usage while on battery.
+// It is also not yet exposed in the UI on Android.
+constexpr bool DEFAULT_PRECISION_FRAME_TIMING = false;
+#else
+constexpr bool DEFAULT_PRECISION_FRAME_TIMING = true;
+#endif
+const Info<bool> MAIN_PRECISION_FRAME_TIMING{{System::Main, "Core", "PrecisionFrameTiming"},
+                                             DEFAULT_PRECISION_FRAME_TIMING};
 const Info<float> MAIN_OVERCLOCK{{System::Main, "Core", "Overclock"}, 1.0f};
 const Info<bool> MAIN_OVERCLOCK_ENABLE{{System::Main, "Core", "OverclockEnable"}, false};
 const Info<bool> MAIN_RAM_OVERRIDE_ENABLE{{System::Main, "Core", "RAMOverrideEnable"}, false};
diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h
index 68fb75e6ef..51aa7ec8aa 100644
--- a/Source/Core/Core/Config/MainSettings.h
+++ b/Source/Core/Core/Config/MainSettings.h
@@ -125,6 +125,7 @@ extern const Info<bool> MAIN_FPRF;
 extern const Info<bool> MAIN_ACCURATE_NANS;
 extern const Info<bool> MAIN_DISABLE_ICACHE;
 extern const Info<float> MAIN_EMULATION_SPEED;
+extern const Info<bool> MAIN_PRECISION_FRAME_TIMING;
 extern const Info<float> MAIN_OVERCLOCK;
 extern const Info<bool> MAIN_OVERCLOCK_ENABLE;
 extern const Info<bool> MAIN_RAM_OVERRIDE_ENABLE;
diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp
index 6893bc2b91..b0aca0168a 100644
--- a/Source/Core/Core/CoreTiming.cpp
+++ b/Source/Core/Core/CoreTiming.cpp
@@ -137,6 +137,8 @@ void CoreTimingManager::RefreshConfig()
   }
 
   m_emulation_speed = Config::Get(Config::MAIN_EMULATION_SPEED);
+
+  m_use_precision_timer = Config::Get(Config::MAIN_PRECISION_FRAME_TIMING);
 }
 
 void CoreTimingManager::DoState(PointerWrap& p)
@@ -373,7 +375,13 @@ void CoreTimingManager::SleepUntil(TimePoint time_point)
 {
   const TimePoint time = Clock::now();
 
-  std::this_thread::sleep_until(time_point);
+  if (time >= time_point)
+    return;
+
+  if (m_use_precision_timer)
+    m_precision_timer.SleepUntil(time_point);
+  else
+    std::this_thread::sleep_until(time_point);
 
   if (Core::IsCPUThread())
   {
@@ -416,15 +424,7 @@ void CoreTimingManager::Throttle(const s64 target_cycle)
   // It doesn't matter what amount of lag we skip VI at, as long as it's constant.
   m_throttle_disable_vi_int = 0.0 < speed && m_throttle_deadline < vi_deadline;
 
-  // Only sleep if we are behind the deadline
-  if (time < m_throttle_deadline)
-  {
-    std::this_thread::sleep_until(m_throttle_deadline);
-
-    // Count amount of time sleeping for analytics
-    const TimePoint time_after_sleep = Clock::now();
-    g_perf_metrics.CountThrottleSleep(time_after_sleep - time);
-  }
+  SleepUntil(m_throttle_deadline);
 }
 
 void CoreTimingManager::ResetThrottle(s64 cycle)
diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h
index 88635e47ae..8200da3ded 100644
--- a/Source/Core/Core/CoreTiming.h
+++ b/Source/Core/Core/CoreTiming.h
@@ -24,6 +24,7 @@
 
 #include "Common/CommonTypes.h"
 #include "Common/SPSCQueue.h"
+#include "Common/Timer.h"
 #include "Core/CPUThreadConfigCallback.h"
 
 class PointerWrap;
@@ -214,6 +215,9 @@ private:
 
   int DowncountToCycles(int downcount) const;
   int CyclesToDowncount(int cycles) const;
+
+  bool m_use_precision_timer = false;
+  Common::PrecisionTimer m_precision_timer;
 };
 
 }  // namespace CoreTiming
diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp
index 19af3a47f6..b698fbdd77 100644
--- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp
+++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp
@@ -36,7 +36,6 @@
 GeneralWidget::GeneralWidget(GraphicsWindow* parent)
 {
   CreateWidgets();
-  LoadSettings();
   ConnectWidgets();
   AddDescriptions();
 
@@ -50,7 +49,6 @@ GeneralWidget::GeneralWidget(GraphicsWindow* parent)
 GeneralWidget::GeneralWidget(GameConfigWidget* parent, Config::Layer* layer) : m_game_layer(layer)
 {
   CreateWidgets();
-  LoadSettings();
   ConnectWidgets();
   AddDescriptions();
 }
@@ -61,7 +59,7 @@ void GeneralWidget::CreateWidgets()
 
   // Basic Section
   auto* m_video_box = new QGroupBox(tr("Basic"));
-  m_video_layout = new QGridLayout();
+  auto* const video_layout = new QGridLayout{m_video_box};
 
   std::vector<std::pair<QString, QString>> options;
   for (auto& backend : VideoBackendBase::GetAvailableBackends())
@@ -76,38 +74,41 @@ void GeneralWidget::CreateWidgets()
                                      tr("Stretch to Window"), tr("Custom"), tr("Custom (Stretch)")},
                                     Config::GFX_ASPECT_RATIO, m_game_layer);
   m_custom_aspect_label = new QLabel(tr("Custom Aspect Ratio:"));
-  m_custom_aspect_label->setHidden(true);
   constexpr int MAX_CUSTOM_ASPECT_RATIO_RESOLUTION = 10000;
   m_custom_aspect_width = new ConfigInteger(1, MAX_CUSTOM_ASPECT_RATIO_RESOLUTION,
                                             Config::GFX_CUSTOM_ASPECT_RATIO_WIDTH, m_game_layer);
-  m_custom_aspect_width->setEnabled(false);
-  m_custom_aspect_width->setHidden(true);
   m_custom_aspect_height = new ConfigInteger(1, MAX_CUSTOM_ASPECT_RATIO_RESOLUTION,
                                              Config::GFX_CUSTOM_ASPECT_RATIO_HEIGHT, m_game_layer);
-  m_custom_aspect_height->setEnabled(false);
-  m_custom_aspect_height->setHidden(true);
   m_adapter_combo = new ToolTipComboBox;
   m_enable_vsync = new ConfigBool(tr("V-Sync"), Config::GFX_VSYNC, m_game_layer);
   m_enable_fullscreen =
       new ConfigBool(tr("Start in Fullscreen"), Config::MAIN_FULLSCREEN, m_game_layer);
 
-  m_video_box->setLayout(m_video_layout);
+  video_layout->addWidget(new QLabel(tr("Backend:")), 0, 0);
+  video_layout->addWidget(m_backend_combo, 0, 1, 1, -1);
 
-  m_video_layout->addWidget(new QLabel(tr("Backend:")), 0, 0);
-  m_video_layout->addWidget(m_backend_combo, 0, 1, 1, -1);
+  video_layout->addWidget(new QLabel(tr("Adapter:")), 1, 0);
+  video_layout->addWidget(m_adapter_combo, 1, 1, 1, -1);
 
-  m_video_layout->addWidget(new QLabel(tr("Adapter:")), 1, 0);
-  m_video_layout->addWidget(m_adapter_combo, 1, 1, 1, -1);
+  video_layout->addWidget(new QLabel(tr("Aspect Ratio:")), 2, 0);
+  video_layout->addWidget(m_aspect_combo, 2, 1, 1, -1);
 
-  m_video_layout->addWidget(new QLabel(tr("Aspect Ratio:")), 3, 0);
-  m_video_layout->addWidget(m_aspect_combo, 3, 1, 1, -1);
+  video_layout->addWidget(m_custom_aspect_label, 3, 0);
+  video_layout->addWidget(m_custom_aspect_width, 3, 1);
+  video_layout->addWidget(m_custom_aspect_height, 3, 2);
 
-  m_video_layout->addWidget(m_custom_aspect_label, 4, 0);
-  m_video_layout->addWidget(m_custom_aspect_width, 4, 1);
-  m_video_layout->addWidget(m_custom_aspect_height, 4, 2);
+  auto* const basic_grid = new QGridLayout;
+  video_layout->addLayout(basic_grid, video_layout->rowCount(), 0, 1, -1);
+  basic_grid->addWidget(m_enable_vsync, 0, 0);
+  basic_grid->addWidget(m_enable_fullscreen, 0, 1);
 
-  m_video_layout->addWidget(m_enable_vsync, 5, 0);
-  m_video_layout->addWidget(m_enable_fullscreen, 5, 1, 1, -1);
+  auto* const precision_timing =
+      new ConfigBool(tr("Precision Frame Timing"), Config::MAIN_PRECISION_FRAME_TIMING);
+  precision_timing->SetDescription(
+      tr("Uses high resolution timers and \"busy waiting\" for improved frame pacing."
+         "<br><br>This will marginally increase power usage."
+         "<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>"));
+  basic_grid->addWidget(precision_timing, 1, 0);
 
   // Other
   auto* m_options_box = new QGroupBox(tr("Other"));
@@ -171,24 +172,11 @@ void GeneralWidget::ConnectWidgets()
   connect(m_aspect_combo, qOverload<int>(&QComboBox::currentIndexChanged), this, [&](int index) {
     const bool is_custom_aspect_ratio = (index == static_cast<int>(AspectMode::Custom)) ||
                                         (index == static_cast<int>(AspectMode::CustomStretch));
-    m_custom_aspect_width->setEnabled(is_custom_aspect_ratio);
-    m_custom_aspect_height->setEnabled(is_custom_aspect_ratio);
     m_custom_aspect_label->setHidden(!is_custom_aspect_ratio);
     m_custom_aspect_width->setHidden(!is_custom_aspect_ratio);
     m_custom_aspect_height->setHidden(!is_custom_aspect_ratio);
   });
-}
-
-void GeneralWidget::LoadSettings()
-{
-  const bool is_custom_aspect_ratio =
-      (Config::Get(Config::GFX_ASPECT_RATIO) == AspectMode::Custom) ||
-      (Config::Get(Config::GFX_ASPECT_RATIO) == AspectMode::CustomStretch);
-  m_custom_aspect_width->setEnabled(is_custom_aspect_ratio);
-  m_custom_aspect_height->setEnabled(is_custom_aspect_ratio);
-  m_custom_aspect_label->setHidden(!is_custom_aspect_ratio);
-  m_custom_aspect_width->setHidden(!is_custom_aspect_ratio);
-  m_custom_aspect_height->setHidden(!is_custom_aspect_ratio);
+  m_aspect_combo->currentIndexChanged(m_aspect_combo->currentIndex());
 }
 
 void GeneralWidget::BackendWarning()
diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h
index 5b4bf36441..42f74229d8 100644
--- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h
+++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h
@@ -37,7 +37,6 @@ signals:
   void BackendChanged(const QString& backend);
 
 private:
-  void LoadSettings();
   void BackendWarning();
 
   void CreateWidgets();
@@ -48,7 +47,6 @@ private:
   void OnEmulationStateChanged(bool running);
 
   // Video
-  QGridLayout* m_video_layout;
   ConfigStringChoice* m_backend_combo;
   ToolTipComboBox* m_adapter_combo;
   ConfigChoice* m_aspect_combo;