[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