[PATCH] winex11.drv: Use XRRSetScreenSize with XRRSetCrtcConfig

Gabriel Corona gabriel.corona at enst-bretagne.fr
Fri Jul 15 17:48:43 CDT 2016


Fixes https://bugs.winehq.org/show_bug.cgi?id=33290

The nvidia driver is not so happy about using XRRSetCrtcConfig alone
and generates a panning configuration. We set the screen size
accordingly. Moreover we disable the CRT during the transition.

Tested on Debian.

Signed-off-by: Gabriel Corona <gabriel.corona at enst-bretagne.fr>
---
 dlls/winex11.drv/xrandr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c
index 2fee851..d467832 100644
--- a/dlls/winex11.drv/xrandr.c
+++ b/dlls/winex11.drv/xrandr.c
@@ -48,6 +48,7 @@ MAKE_FUNCPTR(XRRQueryVersion)
 MAKE_FUNCPTR(XRRRates)
 MAKE_FUNCPTR(XRRSetScreenConfig)
 MAKE_FUNCPTR(XRRSetScreenConfigAndRate)
+MAKE_FUNCPTR(XRRSetScreenSize)
 MAKE_FUNCPTR(XRRSizes)
 
 #ifdef HAVE_XRRGETSCREENRESOURCES
@@ -91,6 +92,7 @@ static int load_xrandr(void)
         LOAD_FUNCPTR(XRRRates)
         LOAD_FUNCPTR(XRRSetScreenConfig)
         LOAD_FUNCPTR(XRRSetScreenConfigAndRate)
+        LOAD_FUNCPTR(XRRSetScreenSize)
         LOAD_FUNCPTR(XRRSizes)
         r = 1;
 
@@ -323,10 +325,14 @@ static int xrandr12_get_current_mode(void)
 static LONG xrandr12_set_current_mode( int mode )
 {
     Status status = RRSetConfigFailed;
+    int screen;
     XRRScreenResources *resources;
     XRRCrtcInfo *crtc_info;
+    XRRModeInfo* mode_info;
+    int i;
 
     mode = mode % xrandr_mode_count;
+    screen = DefaultScreen( gdi_display );
 
     if (!(resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window )))
     {
@@ -345,9 +351,76 @@ static LONG xrandr12_set_current_mode( int mode )
     TRACE("CRTC %d: mode %#lx, %ux%u+%d+%d.\n", primary_crtc, crtc_info->mode,
           crtc_info->width, crtc_info->height, crtc_info->x, crtc_info->y);
 
+    // Find the mode_indo:
+    mode_info = NULL;
+    for (i = 0; i < resources->nmode; ++i)
+    {
+      if (xrandr12_modes[mode] == resources->modes[i].id) {
+        mode_info = &resources->modes[i];
+        break;
+      }
+    }
+    if (mode_info == NULL)
+    {
+      pXRRFreeScreenResources( resources );
+      ERR("Invalid mode.\n");
+      return DISP_CHANGE_FAILED;
+    }
+
+    // As per randrproto.txt:
+    // > The entire area of the CRTC must fit within the screen size,
+    // > else a Match error results. As an example, rotating the
+    // > screen so that a single CRTC fills the entire screen before
+    // > and after may necessitate disabling the CRTC, resizing the
+    // > screen, then re-enabling the CRTC at the new configuration to
+    // > avoid an invalid intermediate configuration.
+
+    // Don't let other clients see that we disable the CRT:
+    XGrabServer( gdi_display );
+
+    // Disable the CRT:
+    status = pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc],
+                                CurrentTime, crtc_info->x, crtc_info->y, None,
+                                crtc_info->rotation, NULL, 0 );
+    if (status != RRSetConfigSuccess)
+    {
+      WARN("Could not disable the CRT before changing resolution\n");
+    }
+
+    // Configure the screen size accordingly:
+    pXRRSetScreenSize( gdi_display, root_window, mode_info->width, mode_info->height,
+                       DisplayWidthMM( gdi_display, screen ),
+                       DisplayHeightMM( gdi_display, screen ));
+
+    // Set the CRT mode:
     status = pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc],
                                 CurrentTime, crtc_info->x, crtc_info->y, xrandr12_modes[mode],
                                 crtc_info->rotation, crtc_info->outputs, crtc_info->noutput );
+    if (status != RRSetConfigSuccess )
+    {
+      // Try to revert to the previous mode
+      mode_info = NULL;
+      for (i = 0; i < resources->nmode; ++i)
+      {
+        if (xrandr12_modes[xrandr_current_mode] == resources->modes[i].id)
+        {
+          mode_info = &resources->modes[i];
+          break;
+        }
+      }
+      if (mode_info != NULL)
+      {
+        pXRRSetScreenSize( gdi_display, root_window, mode_info->width, mode_info->height,
+                           DisplayWidthMM( gdi_display, screen ),
+                           DisplayHeightMM( gdi_display, screen ));
+        pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc],
+                           CurrentTime, crtc_info->x, crtc_info->y,
+                           xrandr12_modes[xrandr_current_mode],
+                           crtc_info->rotation, crtc_info->outputs, crtc_info->noutput );
+      }
+    }
+
+    XUngrabServer( gdi_display );
 
     pXRRFreeCrtcInfo( crtc_info );
     pXRRFreeScreenResources( resources );
-- 
2.8.1




More information about the wine-patches mailing list