[PATCH] winex11.drv: Use XRRSetScreenSize with XRRSetCrtcConfig

Gabriel Corona gabriel.corona at enst-bretagne.fr
Sat Jul 16 03:46:18 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 need to disable the CRT during the
transition.

Changing the screen size is necessary in order to siwtch to a higher
resolution anyway.

Tested on Debian.

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

diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c
index 2fee851..960297e 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;
 
@@ -272,6 +274,9 @@ static void xrandr10_init_modes(void)
 
 #ifdef HAVE_XRRGETSCREENRESOURCES
 
+static int xrandr12_width_mm = 0;
+static int xrandr12_height_mm = 0;
+
 static int xrandr12_get_current_mode(void)
 {
     XRRScreenResources *resources;
@@ -323,10 +328,19 @@ 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;
+    double dpi;
+    int width_mm;
+    int height_mm;
+    double output_ratio;
+    double config_ratio;
 
     mode = mode % xrandr_mode_count;
+    screen = DefaultScreen( gdi_display );
 
     if (!(resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window )))
     {
@@ -345,9 +359,93 @@ 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_index: */
+    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");
+    }
+
+    /* Try to compute a physical size */
+    if (xrandr12_width_mm == 0 || xrandr12_height_mm == 0)
+    {
+        dpi = 96.0;
+    }
+    else
+    {
+        output_ratio = (double) xrandr12_width_mm / xrandr12_height_mm;
+        config_ratio = (double) mode_info->width / mode_info->height;
+        if (output_ratio >= config_ratio)
+            dpi = (25.4 * mode_info->height) / xrandr12_height_mm;
+        else
+            dpi = (25.4 * mode_info->width) / xrandr12_width_mm;
+    }
+    width_mm = (25.4 * mode_info->width) / dpi;
+    height_mm = (25.4 * mode_info->height) / dpi;
+
+    /* Configure the screen size accordingly */
+    pXRRSetScreenSize( gdi_display, root_window, mode_info->width, mode_info->height,
+                       width_mm, height_mm );
+
+    /* 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 );
@@ -429,6 +527,9 @@ static int xrandr12_init_modes(void)
 
     TRACE("OUTPUT 0: name %s.\n", debugstr_a(output_info->name));
 
+    xrandr12_width_mm = output_info->mm_width;
+    xrandr12_height_mm = output_info->mm_height;
+
     if (!output_info->nmode)
     {
         WARN("Output has no modes.\n");
-- 
2.8.1




More information about the wine-patches mailing list