wined3d: Drop support for WINED3DFMT_D32_UNORM.
[wine.git] / dlls / winex11.drv / xrandr.c
blob9f6331029182f6eaff3d883e19570ba786efb218
1 /*
2 * Wine X11drv Xrandr interface
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2012 Henri Verbeet for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
27 #ifdef HAVE_XRRGETSCREENRESOURCES
28 WINE_DECLARE_DEBUG_CHANNEL(winediag);
29 #endif
31 #ifdef SONAME_LIBXRANDR
33 #include <X11/Xlib.h>
34 #include <X11/extensions/Xrandr.h>
35 #include "x11drv.h"
37 #include "wine/library.h"
39 static void *xrandr_handle;
41 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
42 MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
43 MAKE_FUNCPTR(XRRConfigCurrentRate)
44 MAKE_FUNCPTR(XRRFreeScreenConfigInfo)
45 MAKE_FUNCPTR(XRRGetScreenInfo)
46 MAKE_FUNCPTR(XRRQueryExtension)
47 MAKE_FUNCPTR(XRRQueryVersion)
48 MAKE_FUNCPTR(XRRRates)
49 MAKE_FUNCPTR(XRRSetScreenConfig)
50 MAKE_FUNCPTR(XRRSetScreenConfigAndRate)
51 MAKE_FUNCPTR(XRRSizes)
53 #ifdef HAVE_XRRGETSCREENRESOURCES
54 MAKE_FUNCPTR(XRRFreeCrtcInfo)
55 MAKE_FUNCPTR(XRRFreeOutputInfo)
56 MAKE_FUNCPTR(XRRFreeScreenResources)
57 MAKE_FUNCPTR(XRRGetCrtcInfo)
58 MAKE_FUNCPTR(XRRGetOutputInfo)
59 MAKE_FUNCPTR(XRRGetScreenResources)
60 MAKE_FUNCPTR(XRRSetCrtcConfig)
61 MAKE_FUNCPTR(XRRSetScreenSize)
62 static typeof(XRRGetScreenResources) *pXRRGetScreenResourcesCurrent;
63 static RRMode *xrandr12_modes;
64 static int primary_crtc;
65 #endif
67 #undef MAKE_FUNCPTR
69 static struct x11drv_mode_info *dd_modes;
70 static SizeID *xrandr10_modes;
71 static unsigned int xrandr_mode_count;
72 static int xrandr_current_mode = -1;
74 static int load_xrandr(void)
76 int r = 0;
78 if (wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
79 (xrandr_handle = wine_dlopen(SONAME_LIBXRANDR, RTLD_NOW, NULL, 0)))
82 #define LOAD_FUNCPTR(f) \
83 if((p##f = wine_dlsym(xrandr_handle, #f, NULL, 0)) == NULL) \
84 goto sym_not_found;
86 LOAD_FUNCPTR(XRRConfigCurrentConfiguration)
87 LOAD_FUNCPTR(XRRConfigCurrentRate)
88 LOAD_FUNCPTR(XRRFreeScreenConfigInfo)
89 LOAD_FUNCPTR(XRRGetScreenInfo)
90 LOAD_FUNCPTR(XRRQueryExtension)
91 LOAD_FUNCPTR(XRRQueryVersion)
92 LOAD_FUNCPTR(XRRRates)
93 LOAD_FUNCPTR(XRRSetScreenConfig)
94 LOAD_FUNCPTR(XRRSetScreenConfigAndRate)
95 LOAD_FUNCPTR(XRRSizes)
96 r = 1;
98 #ifdef HAVE_XRRGETSCREENRESOURCES
99 LOAD_FUNCPTR(XRRFreeCrtcInfo)
100 LOAD_FUNCPTR(XRRFreeOutputInfo)
101 LOAD_FUNCPTR(XRRFreeScreenResources)
102 LOAD_FUNCPTR(XRRGetCrtcInfo)
103 LOAD_FUNCPTR(XRRGetOutputInfo)
104 LOAD_FUNCPTR(XRRGetScreenResources)
105 LOAD_FUNCPTR(XRRSetCrtcConfig)
106 LOAD_FUNCPTR(XRRSetScreenSize)
107 r = 2;
108 #endif
109 #undef LOAD_FUNCPTR
111 sym_not_found:
112 if (!r) TRACE("Unable to load function ptrs from XRandR library\n");
114 return r;
117 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
119 return 1;
122 static int xrandr10_get_current_mode(void)
124 SizeID size;
125 Rotation rot;
126 XRRScreenConfiguration *sc;
127 short rate;
128 unsigned int i;
129 int res = -1;
131 if (xrandr_current_mode != -1)
132 return xrandr_current_mode;
134 sc = pXRRGetScreenInfo (gdi_display, DefaultRootWindow( gdi_display ));
135 size = pXRRConfigCurrentConfiguration (sc, &rot);
136 rate = pXRRConfigCurrentRate (sc);
137 pXRRFreeScreenConfigInfo(sc);
139 for (i = 0; i < xrandr_mode_count; ++i)
141 if (xrandr10_modes[i] == size && dd_modes[i].refresh_rate == rate)
143 res = i;
144 break;
147 if (res == -1)
149 ERR("In unknown mode, returning default\n");
150 return 0;
153 xrandr_current_mode = res;
154 return res;
157 static LONG xrandr10_set_current_mode( int mode )
159 SizeID size;
160 Rotation rot;
161 Window root;
162 XRRScreenConfiguration *sc;
163 Status stat;
164 short rate;
166 root = DefaultRootWindow( gdi_display );
167 sc = pXRRGetScreenInfo (gdi_display, root);
168 pXRRConfigCurrentConfiguration (sc, &rot);
169 mode = mode % xrandr_mode_count;
171 TRACE("Changing Resolution to %dx%d @%d Hz\n",
172 dd_modes[mode].width,
173 dd_modes[mode].height,
174 dd_modes[mode].refresh_rate);
176 size = xrandr10_modes[mode];
177 rate = dd_modes[mode].refresh_rate;
179 if (rate)
180 stat = pXRRSetScreenConfigAndRate( gdi_display, sc, root, size, rot, rate, CurrentTime );
181 else
182 stat = pXRRSetScreenConfig( gdi_display, sc, root, size, rot, CurrentTime );
184 pXRRFreeScreenConfigInfo(sc);
186 if (stat == RRSetConfigSuccess)
188 xrandr_current_mode = mode;
189 X11DRV_resize_desktop( dd_modes[mode].width, dd_modes[mode].height );
190 return DISP_CHANGE_SUCCESSFUL;
193 ERR("Resolution change not successful -- perhaps display has changed?\n");
194 return DISP_CHANGE_FAILED;
197 static void xrandr10_init_modes(void)
199 XRRScreenSize *sizes;
200 int sizes_count;
201 int i, j, nmodes = 0;
203 sizes = pXRRSizes( gdi_display, DefaultScreen(gdi_display), &sizes_count );
204 if (sizes_count <= 0) return;
206 TRACE("XRandR: found %d sizes.\n", sizes_count);
207 for (i = 0; i < sizes_count; ++i)
209 int rates_count;
210 short *rates;
212 rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count );
213 TRACE("- at %d: %dx%d (%d rates):", i, sizes[i].width, sizes[i].height, rates_count);
214 if (rates_count)
216 nmodes += rates_count;
217 for (j = 0; j < rates_count; ++j)
219 if (j > 0)
220 TRACE(",");
221 TRACE(" %d", rates[j]);
224 else
226 ++nmodes;
227 TRACE(" <default>");
229 TRACE(" Hz\n");
232 TRACE("XRandR modes: count=%d\n", nmodes);
234 if (!(xrandr10_modes = HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr10_modes) * nmodes )))
236 ERR("Failed to allocate xrandr mode info array.\n");
237 return;
240 dd_modes = X11DRV_Settings_SetHandlers( "XRandR 1.0",
241 xrandr10_get_current_mode,
242 xrandr10_set_current_mode,
243 nmodes, 1 );
245 xrandr_mode_count = 0;
246 for (i = 0; i < sizes_count; ++i)
248 int rates_count;
249 short *rates;
251 rates = pXRRRates( gdi_display, DefaultScreen(gdi_display), i, &rates_count );
253 if (rates_count)
255 for (j = 0; j < rates_count; ++j)
257 X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, rates[j] );
258 xrandr10_modes[xrandr_mode_count++] = i;
261 else
263 X11DRV_Settings_AddOneMode( sizes[i].width, sizes[i].height, 0, 0 );
264 xrandr10_modes[xrandr_mode_count++] = i;
268 X11DRV_Settings_AddDepthModes();
269 nmodes = X11DRV_Settings_GetModeCount();
271 TRACE("Available DD modes: count=%d\n", nmodes);
272 TRACE("Enabling XRandR\n");
275 #ifdef HAVE_XRRGETSCREENRESOURCES
277 static int xrandr12_get_current_mode(void)
279 XRRScreenResources *resources;
280 XRRCrtcInfo *crtc_info;
281 int i, ret = -1;
283 if (xrandr_current_mode != -1)
284 return xrandr_current_mode;
286 if (!(resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window )))
288 ERR("Failed to get screen resources.\n");
289 return 0;
292 if (resources->ncrtc <= primary_crtc ||
293 !(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[primary_crtc] )))
295 pXRRFreeScreenResources( resources );
296 ERR("Failed to get CRTC info.\n");
297 return 0;
300 TRACE("CRTC %d: mode %#lx, %ux%u+%d+%d.\n", primary_crtc, crtc_info->mode,
301 crtc_info->width, crtc_info->height, crtc_info->x, crtc_info->y);
303 for (i = 0; i < xrandr_mode_count; ++i)
305 if (xrandr12_modes[i] == crtc_info->mode)
307 ret = i;
308 break;
312 pXRRFreeCrtcInfo( crtc_info );
313 pXRRFreeScreenResources( resources );
315 if (ret == -1)
317 ERR("Unknown mode, returning default.\n");
318 return 0;
321 xrandr_current_mode = ret;
322 return ret;
325 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
327 XRRCrtcInfo *crtc_info;
328 int i;
329 *width = *height = 0;
331 for (i = 0; i < resources->ncrtc; ++i)
333 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
334 continue;
336 if (crtc_info->mode != None)
338 *width = max(*width, crtc_info->x + crtc_info->width);
339 *height = max(*height, crtc_info->y + crtc_info->height);
342 pXRRFreeCrtcInfo( crtc_info );
346 static LONG xrandr12_set_current_mode( int mode )
348 unsigned int screen_width, screen_height;
349 Status status = RRSetConfigFailed;
350 XRRScreenResources *resources;
351 XRRCrtcInfo *crtc_info;
353 mode = mode % xrandr_mode_count;
355 if (!(resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window )))
357 ERR("Failed to get screen resources.\n");
358 return DISP_CHANGE_FAILED;
361 if (resources->ncrtc <= primary_crtc ||
362 !(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[primary_crtc] )))
364 pXRRFreeScreenResources( resources );
365 ERR("Failed to get CRTC info.\n");
366 return DISP_CHANGE_FAILED;
369 TRACE("CRTC %d: mode %#lx, %ux%u+%d+%d.\n", primary_crtc, crtc_info->mode,
370 crtc_info->width, crtc_info->height, crtc_info->x, crtc_info->y);
372 /* According to the RandR spec, the entire CRTC must fit inside the screen.
373 * Since we use the union of all enabled CRTCs to determine the necessary
374 * screen size, this might involve shrinking the screen, so we must disable
375 * the CRTC in question first. */
377 XGrabServer( gdi_display );
379 status = pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc],
380 CurrentTime, crtc_info->x, crtc_info->y, None,
381 crtc_info->rotation, NULL, 0 );
382 if (status != RRSetConfigSuccess)
384 XUngrabServer( gdi_display );
385 ERR("Failed to disable CRTC.\n");
386 pXRRFreeCrtcInfo( crtc_info );
387 pXRRFreeScreenResources( resources );
388 return DISP_CHANGE_FAILED;
391 get_screen_size( resources, &screen_width, &screen_height );
392 screen_width = max( screen_width, crtc_info->x + dd_modes[mode].width );
393 screen_height = max( screen_height, crtc_info->y + dd_modes[mode].height );
395 pXRRSetScreenSize( gdi_display, root_window, screen_width, screen_height,
396 screen_width * DisplayWidthMM( gdi_display, default_visual.screen )
397 / DisplayWidth( gdi_display, default_visual.screen ),
398 screen_height * DisplayHeightMM( gdi_display, default_visual.screen )
399 / DisplayHeight( gdi_display, default_visual.screen ));
401 status = pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc],
402 CurrentTime, crtc_info->x, crtc_info->y, xrandr12_modes[mode],
403 crtc_info->rotation, crtc_info->outputs, crtc_info->noutput );
405 XUngrabServer( gdi_display );
407 pXRRFreeCrtcInfo( crtc_info );
408 pXRRFreeScreenResources( resources );
410 if (status != RRSetConfigSuccess)
412 ERR("Resolution change not successful -- perhaps display has changed?\n");
413 return DISP_CHANGE_FAILED;
416 xrandr_current_mode = mode;
417 X11DRV_resize_desktop( dd_modes[mode].width, dd_modes[mode].height );
418 return DISP_CHANGE_SUCCESSFUL;
421 static XRRCrtcInfo *xrandr12_get_primary_crtc_info( XRRScreenResources *resources, int *crtc_idx )
423 XRRCrtcInfo *crtc_info;
424 int i;
426 for (i = 0; i < resources->ncrtc; ++i)
428 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
429 if (!crtc_info || crtc_info->mode == None)
431 pXRRFreeCrtcInfo( crtc_info );
432 continue;
435 *crtc_idx = i;
436 return crtc_info;
439 return NULL;
442 static int xrandr12_init_modes(void)
444 unsigned int only_one_resolution = 1, mode_count;
445 XRRScreenResources *resources;
446 XRROutputInfo *output_info;
447 XRRCrtcInfo *crtc_info;
448 int ret = -1;
449 int i, j;
451 if (!(resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window )))
453 ERR("Failed to get screen resources.\n");
454 return ret;
457 if (!resources->ncrtc)
459 pXRRFreeScreenResources( resources );
460 if (!(resources = pXRRGetScreenResources( gdi_display, root_window )))
462 ERR("Failed to get screen resources.\n");
463 return ret;
467 if (!(crtc_info = xrandr12_get_primary_crtc_info( resources, &primary_crtc )))
469 pXRRFreeScreenResources( resources );
470 ERR("Failed to get primary CRTC info.\n");
471 return ret;
474 TRACE("CRTC %d: mode %#lx, %ux%u+%d+%d.\n", primary_crtc, crtc_info->mode,
475 crtc_info->width, crtc_info->height, crtc_info->x, crtc_info->y);
477 if (!crtc_info->noutput || !(output_info = pXRRGetOutputInfo( gdi_display, resources, crtc_info->outputs[0] )))
479 pXRRFreeCrtcInfo( crtc_info );
480 pXRRFreeScreenResources( resources );
481 ERR("Failed to get output info.\n");
482 return ret;
485 TRACE("OUTPUT 0: name %s.\n", debugstr_a(output_info->name));
487 if (!output_info->nmode)
489 WARN("Output has no modes.\n");
490 goto done;
493 if (!(xrandr12_modes = HeapAlloc( GetProcessHeap(), 0, sizeof(*xrandr12_modes) * output_info->nmode )))
495 ERR("Failed to allocate xrandr mode info array.\n");
496 goto done;
499 dd_modes = X11DRV_Settings_SetHandlers( "XRandR 1.2",
500 xrandr12_get_current_mode,
501 xrandr12_set_current_mode,
502 output_info->nmode, 1 );
504 xrandr_mode_count = 0;
505 for (i = 0; i < output_info->nmode; ++i)
507 for (j = 0; j < resources->nmode; ++j)
509 XRRModeInfo *mode = &resources->modes[j];
511 if (mode->id == output_info->modes[i])
513 unsigned int dots = mode->hTotal * mode->vTotal;
514 unsigned int refresh = dots ? (mode->dotClock + dots / 2) / dots : 0;
516 TRACE("Adding mode %#lx: %ux%u@%u.\n", mode->id, mode->width, mode->height, refresh);
517 X11DRV_Settings_AddOneMode( mode->width, mode->height, 0, refresh );
518 xrandr12_modes[xrandr_mode_count++] = mode->id;
519 break;
524 mode_count = X11DRV_Settings_GetModeCount();
525 for (i = 1; i < mode_count; ++i)
527 if (dd_modes[i].width != dd_modes[0].width || dd_modes[i].height != dd_modes[0].height)
529 only_one_resolution = 0;
530 break;
534 /* Recent (304.64, possibly earlier) versions of the nvidia driver only
535 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
536 * are only listed through RandR 1.0 / 1.1. This is completely useless,
537 * but NVIDIA considers this a feature, so it's unlikely to change. The
538 * best we can do is to fall back to RandR 1.0 and encourage users to
539 * consider more cooperative driver vendors when we detect such a
540 * configuration. */
541 if (only_one_resolution && XQueryExtension( gdi_display, "NV-CONTROL", &i, &j, &ret ))
543 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
544 "Please consider using the Nouveau driver instead.\n");
545 ret = -1;
546 HeapFree( GetProcessHeap(), 0, xrandr12_modes );
547 goto done;
550 X11DRV_Settings_AddDepthModes();
551 ret = 0;
553 done:
554 pXRRFreeOutputInfo( output_info );
555 pXRRFreeCrtcInfo( crtc_info );
556 pXRRFreeScreenResources( resources );
557 return ret;
560 #endif /* HAVE_XRRGETSCREENRESOURCES */
562 void X11DRV_XRandR_Init(void)
564 int event_base, error_base, minor, ret;
565 static int major;
566 Bool ok;
568 if (major) return; /* already initialized? */
569 if (!usexrandr) return; /* disabled in config */
570 if (root_window != DefaultRootWindow( gdi_display )) return;
571 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
573 /* see if Xrandr is available */
574 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
575 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
576 ok = pXRRQueryVersion( gdi_display, &major, &minor );
577 if (X11DRV_check_error() || !ok) return;
579 TRACE("Found XRandR %d.%d.\n", major, minor);
581 #ifdef HAVE_XRRGETSCREENRESOURCES
582 if (ret >= 2 && (major > 1 || (major == 1 && minor >= 2)))
584 if (major > 1 || (major == 1 && minor >= 3))
585 pXRRGetScreenResourcesCurrent = wine_dlsym( xrandr_handle, "XRRGetScreenResourcesCurrent", NULL, 0 );
586 if (!pXRRGetScreenResourcesCurrent)
587 pXRRGetScreenResourcesCurrent = pXRRGetScreenResources;
590 if (!pXRRGetScreenResourcesCurrent || xrandr12_init_modes() < 0)
591 #endif
592 xrandr10_init_modes();
595 #else /* SONAME_LIBXRANDR */
597 void X11DRV_XRandR_Init(void)
599 TRACE("XRandR support not compiled in.\n");
602 #endif /* SONAME_LIBXRANDR */