diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp
index bac43529f..e1682f070 100644
--- a/src/core/host_display.cpp
+++ b/src/core/host_display.cpp
@@ -15,6 +15,11 @@
 #include <vector>
 Log_SetChannel(HostDisplay);
 
+#ifdef _WIN32
+#include "common/windows_headers.h"
+#include <dwmapi.h>
+#endif
+
 HostDisplayTexture::~HostDisplayTexture() = default;
 
 HostDisplay::~HostDisplay() = default;
@@ -85,6 +90,43 @@ bool HostDisplay::SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32
   return true;
 }
 
+bool HostDisplay::GetHostRefreshRate(float* refresh_rate)
+{
+#ifdef _WIN32
+  static HMODULE dwm_module = nullptr;
+  static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr;
+  static bool load_tried = false;
+  if (!load_tried)
+  {
+    load_tried = true;
+    dwm_module = LoadLibrary("dwmapi.dll");
+    if (dwm_module)
+    {
+      std::atexit([]() {
+        FreeLibrary(dwm_module);
+        dwm_module = nullptr;
+      });
+      get_timing_info =
+        reinterpret_cast<decltype(get_timing_info)>(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo"));
+    }
+  }
+
+  DWM_TIMING_INFO ti = {};
+  ti.cbSize = sizeof(ti);
+  HRESULT hr = get_timing_info(nullptr, &ti);
+  if (SUCCEEDED(hr))
+  {
+    if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0)
+      return false;
+
+    *refresh_rate = static_cast<float>(ti.rateRefresh.uiNumerator) / static_cast<float>(ti.rateRefresh.uiDenominator);
+    return true;
+  }
+#endif
+
+  return false;
+}
+
 void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/)
 {
   m_cursor_texture = std::move(texture);
diff --git a/src/core/host_display.h b/src/core/host_display.h
index c4024ca5c..1458a0666 100644
--- a/src/core/host_display.h
+++ b/src/core/host_display.h
@@ -163,6 +163,7 @@ public:
 
   static u32 GetDisplayPixelFormatSize(HostDisplayPixelFormat format);
 
+
   virtual bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const = 0;
 
   virtual bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
@@ -170,6 +171,8 @@ public:
   virtual void EndSetDisplayPixels() = 0;
   virtual bool SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, const void* buffer, u32 pitch);
 
+  virtual bool GetHostRefreshRate(float* refresh_rate);
+
   void SetDisplayLinearFiltering(bool enabled) { m_display_linear_filtering = enabled; }
   void SetDisplayTopMargin(s32 height) { m_display_top_margin = height; }
   void SetDisplayIntegerScaling(bool enabled) { m_display_integer_scaling = enabled; }
diff --git a/src/frontend-common/d3d11_host_display.cpp b/src/frontend-common/d3d11_host_display.cpp
index 2381b4594..e635d3b95 100644
--- a/src/frontend-common/d3d11_host_display.cpp
+++ b/src/frontend-common/d3d11_host_display.cpp
@@ -226,6 +226,25 @@ void D3D11HostDisplay::EndSetDisplayPixels()
   m_context->Unmap(m_display_pixels_texture.GetD3DTexture(), 0);
 }
 
+bool D3D11HostDisplay::GetHostRefreshRate(float* refresh_rate)
+{
+  if (m_swap_chain && IsFullscreen())
+  {
+    DXGI_SWAP_CHAIN_DESC desc;
+    if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 &&
+        desc.BufferDesc.RefreshRate.Denominator > 0)
+    {
+      Log_InfoPrintf("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator,
+                     desc.BufferDesc.RefreshRate.Denominator);
+      *refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
+                      static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
+      return true;
+    }
+  }
+
+  return HostDisplay::GetHostRefreshRate(refresh_rate);
+}
+
 void D3D11HostDisplay::SetVSync(bool enabled)
 {
   m_vsync = enabled;
diff --git a/src/frontend-common/d3d11_host_display.h b/src/frontend-common/d3d11_host_display.h
index 9623e8093..91497ddbe 100644
--- a/src/frontend-common/d3d11_host_display.h
+++ b/src/frontend-common/d3d11_host_display.h
@@ -61,6 +61,8 @@ public:
                              u32* out_pitch) override;
   void EndSetDisplayPixels() override;
 
+  bool GetHostRefreshRate(float* refresh_rate) override;
+
   virtual void SetVSync(bool enabled) override;
 
   virtual bool Render() override;