From c9b051454c99fbf712a0ebce5f6b46f7bf32ca38 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Tue, 3 Mar 2015 10:33:38 -0700
Subject: winex11: Return the actual refresh rate for NVIDIA cards with Dynamic
 TwinView enabled.

---
 dlls/winex11.drv/xrandr.c | 58 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 44 insertions(+), 14 deletions(-)

diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c
index e7fbf91..8e8be24 100644
--- a/dlls/winex11.drv/xrandr.c
+++ b/dlls/winex11.drv/xrandr.c
@@ -68,8 +68,13 @@ static int primary_crtc;
 
 #undef MAKE_FUNCPTR
 
+struct xrandr10_mode
+{
+    SizeID id;
+    short  rate;
+};
 static struct x11drv_mode_info *dd_modes;
-static SizeID *xrandr10_modes;
+static struct xrandr10_mode *xrandr10_modes;
 static unsigned int xrandr_mode_count;
 static int xrandr_current_mode = -1;
 
@@ -139,7 +144,7 @@ static int xrandr10_get_current_mode(void)
 
     for (i = 0; i < xrandr_mode_count; ++i)
     {
-        if (xrandr10_modes[i] == size && dd_modes[i].refresh_rate == rate)
+        if (xrandr10_modes[i].id == size && xrandr10_modes[i].rate == rate)
         {
             res = i;
             break;
@@ -174,8 +179,8 @@ static LONG xrandr10_set_current_mode( int mode )
           dd_modes[mode].height,
           dd_modes[mode].refresh_rate);
 
-    size = xrandr10_modes[mode];
-    rate = dd_modes[mode].refresh_rate;
+    size = xrandr10_modes[mode].id;
+    rate = xrandr10_modes[mode].rate;
 
     if (rate)
         stat = pXRRSetScreenConfigAndRate( gdi_display, sc, root, size, rot, rate, CurrentTime );
@@ -195,10 +200,10 @@ static LONG xrandr10_set_current_mode( int mode )
     return DISP_CHANGE_FAILED;
 }
 
-static void xrandr10_nvidia_rate(void)
+static void xrandr10_nvidia_rate(short *override_rate)
 {
 #ifdef HAVE_NVCTRL
-    int major, minor, twinview;
+    int major, minor, twinview, mask, devices;
 
     if (!XNVCTRLIsNvScreen( gdi_display, DefaultScreen(gdi_display) )) return;
     if (!XNVCTRLQueryVersion( gdi_display, &major, &minor )) return;
@@ -206,6 +211,27 @@ static void xrandr10_nvidia_rate(void)
                                 NV_CTRL_DYNAMIC_TWINVIEW, &twinview )) return;
     if (!twinview) return;
 
+    if (!XNVCTRLQueryAttribute( gdi_display, DefaultScreen(gdi_display), 0,
+                                NV_CTRL_CONNECTED_DISPLAYS, &devices)) goto failed;
+    for (mask = 1; mask < (1 << 24); mask <<= 1)
+    {
+        int refresh_rate;
+
+        if (!(devices & mask)) continue;
+
+        if (!XNVCTRLQueryAttribute( gdi_display, DefaultScreen(gdi_display), mask,
+                                    NV_CTRL_REFRESH_RATE, &refresh_rate)) goto failed;
+
+        /* The first device gives us the true refresh rate of the primary display, use this to
+         * override the false refresh rate the driver reports to XRandR. */
+        *override_rate = (short) round(refresh_rate / 100.0f);
+
+        ERR_(winediag)("NVIDIA Dynamic TwinView detected, replacing inaccurate XRandR refresh rates "
+                       "with the true rate of the primary display.\n");
+        return;
+    }
+
+failed:
     ERR_(winediag)("NVIDIA Dynamic TwinView detected, XRandR will report inaccurate refresh rates. "
                    "Please consider disabling the \"DynamicTwinView\" option in your X config.\n");
 #endif
@@ -213,6 +239,7 @@ static void xrandr10_nvidia_rate(void)
 
 static void xrandr10_init_modes(void)
 {
+    short override_rate = 0;
     XRRScreenSize *sizes;
     int sizes_count;
     int i, j, nmodes = 0;
@@ -221,7 +248,7 @@ static void xrandr10_init_modes(void)
     if (sizes_count <= 0) return;
 
     /* Output a warning about nVidia Dynamic TwinView (if applicable) */
-    xrandr10_nvidia_rate();
+    xrandr10_nvidia_rate(&override_rate);
 
     TRACE("XRandR: found %d sizes.\n", sizes_count);
     for (i = 0; i < sizes_count; ++i)
@@ -230,15 +257,15 @@ static void xrandr10_init_modes(void)
         short *rates;
 
         rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count );
+        rates_count = (rates_count && override_rate ? 1 : rates_count);
         TRACE("- at %d: %dx%d (%d rates):", i, sizes[i].width, sizes[i].height, rates_count);
         if (rates_count)
         {
             nmodes += rates_count;
             for (j = 0; j < rates_count; ++j)
             {
-                if (j > 0)
-                    TRACE(",");
-                TRACE("  %d", rates[j]);
+                short rate = (override_rate ? override_rate : rates[j]);
+                TRACE("%s %d", (j > 0 ? "," : ""), rate);
             }
         }
         else
@@ -269,19 +296,22 @@ static void xrandr10_init_modes(void)
         short *rates;
 
         rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count );
-
+        rates_count = (rates_count && override_rate ? 1 : rates_count);
         if (rates_count)
         {
             for (j = 0; j < rates_count; ++j)
             {
-                X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, rates[j] );
-                xrandr10_modes[xrandr_mode_count++] = i;
+                short rate = (override_rate ? override_rate : rates[j]);
+                X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, rate );
+                xrandr10_modes[xrandr_mode_count].id = i;
+                xrandr10_modes[xrandr_mode_count++].rate = rates[j];
             }
         }
         else
         {
             X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, 0 );
-            xrandr10_modes[xrandr_mode_count++] = i;
+            xrandr10_modes[xrandr_mode_count].id = i;
+            xrandr10_modes[xrandr_mode_count++].rate = 0;
         }
     }
 
-- 
2.3.0

