wow64: In wow64_NtSetInformationToken forward TokenIntegrityLevel.
[wine.git] / dlls / winex11.drv / xrandr.c
blobd8e6f476cf73bea0160ee3bbd471e0e0381172e4
1 /*
2 * Wine X11drv Xrandr interface
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2012 Henri Verbeet for CodeWeavers
6 * Copyright 2019 Zhiyi Zhang for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include "config.h"
29 #include <assert.h>
30 #include <X11/Xlib.h>
31 #ifdef HAVE_X11_EXTENSIONS_XRANDR_H
32 #include <X11/extensions/Xrandr.h>
33 #endif
34 #include <dlfcn.h>
35 #include "x11drv.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
39 #ifdef HAVE_XRRGETPROVIDERRESOURCES
40 WINE_DECLARE_DEBUG_CHANNEL(winediag);
41 #endif
43 #ifdef SONAME_LIBXRANDR
45 #define VK_NO_PROTOTYPES
46 #define WINE_VK_HOST
48 #include "wine/vulkan.h"
49 #include "wine/vulkan_driver.h"
51 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
53 static void *xrandr_handle;
55 static VkInstance vk_instance; /* Vulkan instance for XRandR functions */
56 static VkResult (*p_vkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
57 static PFN_vkGetPhysicalDeviceProperties2KHR p_vkGetPhysicalDeviceProperties2KHR;
58 static PFN_vkEnumeratePhysicalDevices p_vkEnumeratePhysicalDevices;
60 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
61 MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
62 MAKE_FUNCPTR(XRRConfigCurrentRate)
63 MAKE_FUNCPTR(XRRFreeScreenConfigInfo)
64 MAKE_FUNCPTR(XRRGetScreenInfo)
65 MAKE_FUNCPTR(XRRQueryExtension)
66 MAKE_FUNCPTR(XRRQueryVersion)
67 MAKE_FUNCPTR(XRRRates)
68 MAKE_FUNCPTR(XRRSetScreenConfig)
69 MAKE_FUNCPTR(XRRSetScreenConfigAndRate)
70 MAKE_FUNCPTR(XRRSizes)
72 #ifdef HAVE_XRRGETPROVIDERRESOURCES
73 MAKE_FUNCPTR(XRRFreeCrtcInfo)
74 MAKE_FUNCPTR(XRRFreeOutputInfo)
75 MAKE_FUNCPTR(XRRFreeScreenResources)
76 MAKE_FUNCPTR(XRRGetCrtcInfo)
77 MAKE_FUNCPTR(XRRGetOutputInfo)
78 MAKE_FUNCPTR(XRRGetOutputProperty)
79 MAKE_FUNCPTR(XRRGetScreenResources)
80 MAKE_FUNCPTR(XRRGetScreenResourcesCurrent)
81 MAKE_FUNCPTR(XRRGetScreenSizeRange)
82 MAKE_FUNCPTR(XRRSetCrtcConfig)
83 MAKE_FUNCPTR(XRRSetScreenSize)
84 MAKE_FUNCPTR(XRRSelectInput)
85 MAKE_FUNCPTR(XRRGetOutputPrimary)
86 MAKE_FUNCPTR(XRRGetProviderResources)
87 MAKE_FUNCPTR(XRRFreeProviderResources)
88 MAKE_FUNCPTR(XRRGetProviderInfo)
89 MAKE_FUNCPTR(XRRFreeProviderInfo)
90 #endif
92 #undef MAKE_FUNCPTR
94 static int load_xrandr(void)
96 int r = 0;
98 if (dlopen(SONAME_LIBXRENDER, RTLD_NOW|RTLD_GLOBAL) &&
99 (xrandr_handle = dlopen(SONAME_LIBXRANDR, RTLD_NOW)))
102 #define LOAD_FUNCPTR(f) \
103 if((p##f = dlsym(xrandr_handle, #f)) == NULL) goto sym_not_found
105 LOAD_FUNCPTR(XRRConfigCurrentConfiguration);
106 LOAD_FUNCPTR(XRRConfigCurrentRate);
107 LOAD_FUNCPTR(XRRFreeScreenConfigInfo);
108 LOAD_FUNCPTR(XRRGetScreenInfo);
109 LOAD_FUNCPTR(XRRQueryExtension);
110 LOAD_FUNCPTR(XRRQueryVersion);
111 LOAD_FUNCPTR(XRRRates);
112 LOAD_FUNCPTR(XRRSetScreenConfig);
113 LOAD_FUNCPTR(XRRSetScreenConfigAndRate);
114 LOAD_FUNCPTR(XRRSizes);
115 r = 1;
117 #ifdef HAVE_XRRGETPROVIDERRESOURCES
118 LOAD_FUNCPTR(XRRFreeCrtcInfo);
119 LOAD_FUNCPTR(XRRFreeOutputInfo);
120 LOAD_FUNCPTR(XRRFreeScreenResources);
121 LOAD_FUNCPTR(XRRGetCrtcInfo);
122 LOAD_FUNCPTR(XRRGetOutputInfo);
123 LOAD_FUNCPTR(XRRGetOutputProperty);
124 LOAD_FUNCPTR(XRRGetScreenResources);
125 LOAD_FUNCPTR(XRRGetScreenResourcesCurrent);
126 LOAD_FUNCPTR(XRRGetScreenSizeRange);
127 LOAD_FUNCPTR(XRRSetCrtcConfig);
128 LOAD_FUNCPTR(XRRSetScreenSize);
129 LOAD_FUNCPTR(XRRSelectInput);
130 LOAD_FUNCPTR(XRRGetOutputPrimary);
131 LOAD_FUNCPTR(XRRGetProviderResources);
132 LOAD_FUNCPTR(XRRFreeProviderResources);
133 LOAD_FUNCPTR(XRRGetProviderInfo);
134 LOAD_FUNCPTR(XRRFreeProviderInfo);
135 r = 4;
136 #endif
138 #undef LOAD_FUNCPTR
140 sym_not_found:
141 if (!r) TRACE("Unable to load function ptrs from XRandR library\n");
143 return r;
146 #ifdef SONAME_LIBVULKAN
148 static void *vulkan_handle;
149 static void *(*p_vkGetInstanceProcAddr)(VkInstance, const char *);
151 static void vulkan_init_once(void)
153 static const char *extensions[] =
155 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
156 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
157 "VK_EXT_acquire_xlib_display",
158 "VK_EXT_direct_mode_display",
159 "VK_KHR_display",
160 VK_KHR_SURFACE_EXTENSION_NAME,
162 VkInstanceCreateInfo create_info =
164 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
165 .ppEnabledExtensionNames = extensions,
166 .enabledExtensionCount = ARRAY_SIZE(extensions),
169 PFN_vkDestroyInstance p_vkDestroyInstance;
170 PFN_vkCreateInstance p_vkCreateInstance;
171 VkResult vr;
173 if (!(vulkan_handle = dlopen( SONAME_LIBVULKAN, RTLD_NOW )))
175 ERR( "Failed to load %s\n", SONAME_LIBVULKAN );
176 return;
179 #define LOAD_FUNCPTR( f ) \
180 if (!(p_##f = dlsym( vulkan_handle, #f ))) \
182 ERR( "Failed to find " #f "\n" ); \
183 dlclose( vulkan_handle ); \
184 return; \
187 LOAD_FUNCPTR( vkGetInstanceProcAddr );
188 #undef LOAD_FUNCPTR
190 p_vkCreateInstance = p_vkGetInstanceProcAddr( NULL, "vkCreateInstance" );
191 if ((vr = p_vkCreateInstance( &create_info, NULL, &vk_instance )))
193 WARN( "Failed to create a Vulkan instance, vr %d.\n", vr );
194 return;
197 p_vkDestroyInstance = p_vkGetInstanceProcAddr( vk_instance, "vkDestroyInstance" );
198 #define LOAD_VK_FUNC(f) \
199 if (!(p_##f = (void *)p_vkGetInstanceProcAddr( vk_instance, #f ))) \
201 WARN("Failed to load " #f ".\n"); \
202 p_vkDestroyInstance( vk_instance, NULL ); \
203 vk_instance = NULL; \
204 return; \
207 LOAD_VK_FUNC( vkEnumeratePhysicalDevices )
208 LOAD_VK_FUNC( vkGetPhysicalDeviceProperties2KHR )
209 LOAD_VK_FUNC( vkGetRandROutputDisplayEXT )
210 #undef LOAD_VK_FUNC
213 #else /* SONAME_LIBVULKAN */
215 static void vulkan_init_once(void)
217 ERR( "Wine was built without Vulkan support.\n" );
220 #endif /* SONAME_LIBVULKAN */
222 static BOOL vulkan_init(void)
224 static pthread_once_t init_once = PTHREAD_ONCE_INIT;
225 pthread_once( &init_once, vulkan_init_once );
226 return !!vk_instance;
229 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
231 return 1;
234 /* XRandR 1.0 display settings handler */
235 static BOOL xrandr10_get_id( const WCHAR *device_name, BOOL is_primary, x11drv_settings_id *id )
237 /* RandR 1.0 only supports changing the primary adapter settings.
238 * For non-primary adapters, an id is still provided but getting
239 * and changing non-primary adapters' settings will be ignored. */
240 id->id = is_primary ? 1 : 0;
241 return TRUE;
244 static void add_xrandr10_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height,
245 DWORD frequency, SizeID size_id, BOOL full )
247 mode->dmSize = sizeof(*mode);
248 mode->dmDriverExtra = full ? sizeof(SizeID) : 0;
249 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
250 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
251 if (frequency)
253 mode->dmFields |= DM_DISPLAYFREQUENCY;
254 mode->dmDisplayFrequency = frequency;
256 mode->dmDisplayOrientation = DMDO_DEFAULT;
257 mode->dmBitsPerPel = depth;
258 mode->dmPelsWidth = width;
259 mode->dmPelsHeight = height;
260 mode->dmDisplayFlags = 0;
261 if (full) memcpy( mode + 1, &size_id, sizeof(size_id) );
264 static BOOL xrandr10_get_modes( x11drv_settings_id id, DWORD flags, DEVMODEW **new_modes, UINT *new_mode_count, BOOL full )
266 INT size_idx, depth_idx, rate_idx, mode_idx = 0;
267 INT size_count, rate_count, mode_count = 0;
268 DEVMODEW *modes, *mode;
269 XRRScreenSize *sizes;
270 short *rates;
272 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
273 if (size_count <= 0)
274 return FALSE;
276 for (size_idx = 0; size_idx < size_count; ++size_idx)
278 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
279 if (rate_count)
280 mode_count += rate_count;
281 else
282 ++mode_count;
285 /* Allocate space for reported modes in three depths, and put an SizeID at the end of DEVMODEW as
286 * driver private data */
287 modes = calloc( mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID) );
288 if (!modes)
290 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY );
291 return FALSE;
294 for (size_idx = 0, mode = modes; size_idx < size_count; ++size_idx)
296 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
298 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
299 if (!rate_count)
301 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
302 sizes[size_idx].height, 0, size_idx, full );
303 mode = NEXT_DEVMODEW( mode );
304 mode_idx++;
305 continue;
308 for (rate_idx = 0; rate_idx < rate_count; ++rate_idx)
310 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
311 sizes[size_idx].height, rates[rate_idx], size_idx, full );
312 mode = NEXT_DEVMODEW( mode );
313 mode_idx++;
318 *new_modes = modes;
319 *new_mode_count = mode_idx;
320 return TRUE;
323 static void xrandr10_free_modes( DEVMODEW *modes )
325 free( modes );
328 static BOOL xrandr10_get_current_mode( x11drv_settings_id id, DEVMODEW *mode )
330 XRRScreenConfiguration *screen_config;
331 XRRScreenSize *sizes;
332 Rotation rotation;
333 SizeID size_id;
334 INT size_count;
335 short rate;
337 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
338 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
339 mode->dmDisplayOrientation = DMDO_DEFAULT;
340 mode->dmDisplayFlags = 0;
341 mode->dmPosition.x = 0;
342 mode->dmPosition.y = 0;
344 if (id.id != 1)
346 FIXME("Non-primary adapters are unsupported.\n");
347 mode->dmBitsPerPel = 0;
348 mode->dmPelsWidth = 0;
349 mode->dmPelsHeight = 0;
350 mode->dmDisplayFrequency = 0;
351 return TRUE;
354 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
355 if (size_count <= 0)
356 return FALSE;
358 screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) );
359 size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation );
360 rate = pXRRConfigCurrentRate( screen_config );
361 pXRRFreeScreenConfigInfo( screen_config );
363 mode->dmBitsPerPel = screen_bpp;
364 mode->dmPelsWidth = sizes[size_id].width;
365 mode->dmPelsHeight = sizes[size_id].height;
366 mode->dmDisplayFrequency = rate;
367 return TRUE;
370 static LONG xrandr10_set_current_mode( x11drv_settings_id id, const DEVMODEW *mode )
372 XRRScreenConfiguration *screen_config;
373 Rotation rotation;
374 SizeID size_id;
375 Window root;
376 Status stat;
378 if (id.id != 1)
380 FIXME("Non-primary adapters are unsupported.\n");
381 return DISP_CHANGE_SUCCESSFUL;
384 if (is_detached_mode(mode))
386 FIXME("Detaching adapters is unsupported.\n");
387 return DISP_CHANGE_SUCCESSFUL;
390 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
391 WARN("Cannot change screen bit depth from %dbits to %dbits!\n",
392 screen_bpp, (int)mode->dmBitsPerPel);
394 root = DefaultRootWindow( gdi_display );
395 screen_config = pXRRGetScreenInfo( gdi_display, root );
396 pXRRConfigCurrentConfiguration( screen_config, &rotation );
398 assert( mode->dmDriverExtra == sizeof(SizeID) );
399 memcpy( &size_id, (BYTE *)mode + sizeof(*mode), sizeof(size_id) );
401 if (mode->dmFields & DM_DISPLAYFREQUENCY && mode->dmDisplayFrequency)
402 stat = pXRRSetScreenConfigAndRate( gdi_display, screen_config, root, size_id, rotation,
403 mode->dmDisplayFrequency, CurrentTime );
404 else
405 stat = pXRRSetScreenConfig( gdi_display, screen_config, root, size_id, rotation, CurrentTime );
406 pXRRFreeScreenConfigInfo( screen_config );
408 if (stat != RRSetConfigSuccess)
409 return DISP_CHANGE_FAILED;
411 XFlush( gdi_display );
412 return DISP_CHANGE_SUCCESSFUL;
415 #ifdef HAVE_XRRGETPROVIDERRESOURCES
417 static struct current_mode
419 ULONG_PTR id;
420 BOOL loaded;
421 DEVMODEW mode;
422 } *current_modes;
423 static int current_mode_count;
425 static pthread_mutex_t xrandr_mutex = PTHREAD_MUTEX_INITIALIZER;
427 static void xrandr14_invalidate_current_mode_cache(void)
429 pthread_mutex_lock( &xrandr_mutex );
430 free( current_modes);
431 current_modes = NULL;
432 current_mode_count = 0;
433 pthread_mutex_unlock( &xrandr_mutex );
436 static XRRScreenResources *xrandr_get_screen_resources(void)
438 XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window );
439 if (resources && !resources->ncrtc)
441 pXRRFreeScreenResources( resources );
442 resources = pXRRGetScreenResources( gdi_display, root_window );
445 if (!resources)
446 ERR("Failed to get screen resources.\n");
447 return resources;
450 /* Some (304.64, possibly earlier) versions of the NVIDIA driver only
451 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
452 * are only listed through RandR 1.0 / 1.1. This is completely useless,
453 * but NVIDIA considers this a feature, so it's unlikely to change. The
454 * best we can do is to fall back to RandR 1.0 and encourage users to
455 * consider more cooperative driver vendors when we detect such a
456 * configuration. */
457 static BOOL is_broken_driver(void)
459 XRRScreenResources *screen_resources;
460 XRROutputInfo *output_info;
461 XRRModeInfo *first_mode;
462 INT major, event, error;
463 INT output_idx, i, j;
464 BOOL only_one_mode;
466 screen_resources = xrandr_get_screen_resources();
467 if (!screen_resources)
468 return TRUE;
470 /* Check if any output only has one native mode */
471 for (output_idx = 0; output_idx < screen_resources->noutput; ++output_idx)
473 output_info = pXRRGetOutputInfo( gdi_display, screen_resources,
474 screen_resources->outputs[output_idx] );
475 if (!output_info)
476 continue;
478 if (output_info->connection != RR_Connected)
480 pXRRFreeOutputInfo( output_info );
481 continue;
484 first_mode = NULL;
485 only_one_mode = TRUE;
486 for (i = 0; i < output_info->nmode; ++i)
488 for (j = 0; j < screen_resources->nmode; ++j)
490 if (output_info->modes[i] != screen_resources->modes[j].id)
491 continue;
493 if (!first_mode)
495 first_mode = &screen_resources->modes[j];
496 break;
499 if (first_mode->width != screen_resources->modes[j].width ||
500 first_mode->height != screen_resources->modes[j].height)
501 only_one_mode = FALSE;
503 break;
506 if (!only_one_mode)
507 break;
509 pXRRFreeOutputInfo( output_info );
511 if (!only_one_mode)
512 continue;
514 /* Check if it is NVIDIA proprietary driver */
515 if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error ))
517 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
518 "Please consider using the Nouveau driver instead.\n");
519 pXRRFreeScreenResources( screen_resources );
520 return TRUE;
523 pXRRFreeScreenResources( screen_resources );
524 return FALSE;
527 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
529 int min_width = 0, min_height = 0, max_width, max_height;
530 XRRCrtcInfo *crtc_info;
531 int i;
533 pXRRGetScreenSizeRange( gdi_display, root_window, &min_width, &min_height, &max_width, &max_height );
534 *width = min_width;
535 *height = min_height;
537 for (i = 0; i < resources->ncrtc; ++i)
539 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
540 continue;
542 if (crtc_info->mode != None)
544 *width = max(*width, crtc_info->x + crtc_info->width);
545 *height = max(*height, crtc_info->y + crtc_info->height);
548 pXRRFreeCrtcInfo( crtc_info );
552 static unsigned int get_edid( RROutput output, unsigned char **prop )
554 int result, actual_format;
555 unsigned long bytes_after, len;
556 Atom actual_type;
558 result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE,
559 AnyPropertyType, &actual_type, &actual_format, &len,
560 &bytes_after, prop );
562 if (result != Success)
564 WARN("Could not retrieve EDID property for output %#lx.\n", output);
565 *prop = NULL;
566 return 0;
568 return len;
571 static void set_screen_size( int width, int height )
573 int screen = default_visual.screen;
574 int mm_width, mm_height;
576 mm_width = width * DisplayWidthMM( gdi_display, screen ) / DisplayWidth( gdi_display, screen );
577 mm_height = height * DisplayHeightMM( gdi_display, screen ) / DisplayHeight( gdi_display, screen );
578 pXRRSetScreenSize( gdi_display, root_window, width, height, mm_width, mm_height );
581 static unsigned int get_frequency( const XRRModeInfo *mode )
583 unsigned int dots = mode->hTotal * mode->vTotal;
585 if (!dots)
586 return 0;
588 if (mode->modeFlags & RR_DoubleScan)
589 dots *= 2;
590 if (mode->modeFlags & RR_Interlace)
591 dots /= 2;
593 return (mode->dotClock + dots / 2) / dots;
596 static DWORD get_orientation( Rotation rotation )
598 if (rotation & RR_Rotate_270) return DMDO_270;
599 if (rotation & RR_Rotate_180) return DMDO_180;
600 if (rotation & RR_Rotate_90) return DMDO_90;
601 return DMDO_DEFAULT;
604 static DWORD get_orientation_count( Rotation rotations )
606 DWORD count = 0;
608 if (rotations & RR_Rotate_0) ++count;
609 if (rotations & RR_Rotate_90) ++count;
610 if (rotations & RR_Rotate_180) ++count;
611 if (rotations & RR_Rotate_270) ++count;
612 return count;
615 static Rotation get_rotation( DWORD orientation )
617 return (Rotation)(1 << orientation);
620 static RRCrtc get_output_free_crtc( XRRScreenResources *resources, XRROutputInfo *output_info )
622 XRRCrtcInfo *crtc_info;
623 INT crtc_idx;
624 RRCrtc crtc;
626 for (crtc_idx = 0; crtc_idx < output_info->ncrtc; ++crtc_idx)
628 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtcs[crtc_idx] );
629 if (!crtc_info)
630 continue;
632 if (!crtc_info->noutput)
634 crtc = output_info->crtcs[crtc_idx];
635 pXRRFreeCrtcInfo( crtc_info );
636 return crtc;
639 pXRRFreeCrtcInfo( crtc_info );
642 return 0;
645 static RECT get_primary_rect( XRRScreenResources *resources )
647 XRROutputInfo *output_info = NULL;
648 XRRCrtcInfo *crtc_info = NULL;
649 RROutput primary_output;
650 RECT primary_rect = {0};
651 RECT first_rect = {0};
652 INT i;
654 primary_output = pXRRGetOutputPrimary( gdi_display, root_window );
655 if (!primary_output)
656 goto fallback;
658 output_info = pXRRGetOutputInfo( gdi_display, resources, primary_output );
659 if (!output_info || output_info->connection != RR_Connected || !output_info->crtc)
660 goto fallback;
662 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtc );
663 if (!crtc_info || !crtc_info->mode)
664 goto fallback;
666 SetRect( &primary_rect, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
667 pXRRFreeCrtcInfo( crtc_info );
668 pXRRFreeOutputInfo( output_info );
669 return primary_rect;
671 /* Fallback when XRandR primary output is a disconnected output.
672 * Try to find a crtc with (x, y) being (0, 0). If it's found then get the primary rect from that crtc,
673 * otherwise use the first active crtc to get the primary rect */
674 fallback:
675 if (crtc_info)
676 pXRRFreeCrtcInfo( crtc_info );
677 if (output_info)
678 pXRRFreeOutputInfo( output_info );
680 WARN("Primary is set to a disconnected XRandR output.\n");
681 for (i = 0; i < resources->ncrtc; ++i)
683 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
684 if (!crtc_info)
685 continue;
687 if (!crtc_info->mode)
689 pXRRFreeCrtcInfo( crtc_info );
690 continue;
693 if (!crtc_info->x && !crtc_info->y)
695 SetRect( &primary_rect, 0, 0, crtc_info->width, crtc_info->height );
696 pXRRFreeCrtcInfo( crtc_info );
697 break;
700 if (IsRectEmpty( &first_rect ))
701 SetRect( &first_rect, crtc_info->x, crtc_info->y,
702 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
704 pXRRFreeCrtcInfo( crtc_info );
707 return IsRectEmpty( &primary_rect ) ? first_rect : primary_rect;
710 static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
712 return crtc &&
713 crtc->mode &&
714 crtc->x == primary.left &&
715 crtc->y == primary.top &&
716 crtc->x + crtc->width == primary.right &&
717 crtc->y + crtc->height == primary.bottom;
720 static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRProviderInfo *provider_info,
721 struct x11drv_gpu *prev_gpus, int prev_gpu_count )
723 uint32_t device_count, device_idx, output_idx, i;
724 VkPhysicalDevice *vk_physical_devices = NULL;
725 VkPhysicalDeviceProperties2 properties2;
726 VkPhysicalDeviceIDProperties id;
727 VkDisplayKHR vk_display;
728 BOOL ret = FALSE;
729 VkResult vr;
731 if (!vulkan_init()) goto done;
733 vr = p_vkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
734 if (vr != VK_SUCCESS || !device_count)
736 WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
737 goto done;
740 if (!(vk_physical_devices = calloc( device_count, sizeof(*vk_physical_devices) )))
741 goto done;
743 vr = p_vkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
744 if (vr != VK_SUCCESS)
746 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
747 goto done;
750 TRACE("provider name %s.\n", debugstr_a(provider_info->name));
752 for (device_idx = 0; device_idx < device_count; ++device_idx)
754 for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
756 vr = p_vkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
757 provider_info->outputs[output_idx], &vk_display );
758 if (vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
759 continue;
761 memset( &id, 0, sizeof(id) );
762 id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
763 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
764 properties2.pNext = &id;
766 p_vkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
767 for (i = 0; i < prev_gpu_count; ++i)
769 if (!memcmp( &prev_gpus[i].vulkan_uuid, &id.deviceUUID, sizeof(id.deviceUUID) ))
771 WARN( "device UUID %#x:%#x already assigned to GPU %u.\n", *((uint32_t *)id.deviceUUID + 1),
772 *(uint32_t *)id.deviceUUID, i );
773 break;
776 if (i < prev_gpu_count) continue;
778 memcpy( &gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) );
780 /* Ignore Khronos vendor IDs */
781 if (properties2.properties.vendorID < 0x10000)
783 gpu->pci_id.vendor = properties2.properties.vendorID;
784 gpu->pci_id.device = properties2.properties.deviceID;
786 gpu->name = strdup( properties2.properties.deviceName );
788 ret = TRUE;
789 goto done;
793 done:
794 free( vk_physical_devices );
795 return ret;
798 /* Get a list of GPUs reported by XRandR 1.4. Set get_properties to FALSE if GPU properties are
799 * not needed to avoid unnecessary querying */
800 static BOOL xrandr14_get_gpus( struct x11drv_gpu **new_gpus, int *count, BOOL get_properties )
802 struct x11drv_gpu *gpus = NULL;
803 XRRScreenResources *screen_resources = NULL;
804 XRRProviderResources *provider_resources = NULL;
805 XRRProviderInfo *provider_info = NULL;
806 XRRCrtcInfo *crtc_info = NULL;
807 INT primary_provider = -1;
808 RECT primary_rect;
809 BOOL ret = FALSE;
810 INT i, j;
812 screen_resources = xrandr_get_screen_resources();
813 if (!screen_resources)
814 goto done;
816 provider_resources = pXRRGetProviderResources( gdi_display, root_window );
817 if (!provider_resources)
818 goto done;
820 gpus = calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) );
821 if (!gpus)
822 goto done;
824 /* Some XRandR implementations don't support providers.
825 * In this case, report a fake one to try searching adapters in screen resources */
826 if (!provider_resources->nproviders)
828 WARN("XRandR implementation doesn't report any providers, faking one.\n");
829 gpus[0].name = strdup( "Wine GPU" );
830 *new_gpus = gpus;
831 *count = 1;
832 ret = TRUE;
833 goto done;
836 primary_rect = get_primary_rect( screen_resources );
837 for (i = 0; i < provider_resources->nproviders; ++i)
839 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, provider_resources->providers[i] );
840 if (!provider_info)
841 goto done;
843 /* Find primary provider */
844 for (j = 0; primary_provider == -1 && j < provider_info->ncrtcs; ++j)
846 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, provider_info->crtcs[j] );
847 if (!crtc_info)
848 continue;
850 if (is_crtc_primary( primary_rect, crtc_info ))
852 primary_provider = i;
853 pXRRFreeCrtcInfo( crtc_info );
854 break;
857 pXRRFreeCrtcInfo( crtc_info );
860 gpus[i].id = provider_resources->providers[i];
861 if (get_properties)
863 if (!get_gpu_properties_from_vulkan( &gpus[i], provider_info, gpus, i ))
864 gpus[i].name = strdup( provider_info->name );
865 /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */
867 pXRRFreeProviderInfo( provider_info );
870 /* Make primary GPU the first */
871 if (primary_provider > 0)
873 struct x11drv_gpu tmp = gpus[0];
874 gpus[0] = gpus[primary_provider];
875 gpus[primary_provider] = tmp;
878 *new_gpus = gpus;
879 *count = provider_resources->nproviders;
880 ret = TRUE;
881 done:
882 if (provider_resources)
883 pXRRFreeProviderResources( provider_resources );
884 if (screen_resources)
885 pXRRFreeScreenResources( screen_resources );
886 if (!ret)
888 free( gpus );
889 ERR("Failed to get gpus\n");
891 return ret;
894 static void xrandr14_free_gpus( struct x11drv_gpu *gpus, int count )
896 while (count--) free( gpus[count].name );
897 free( gpus );
900 static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct x11drv_adapter **new_adapters, int *count )
902 struct x11drv_adapter *adapters = NULL;
903 XRRScreenResources *screen_resources = NULL;
904 XRRProviderInfo *provider_info = NULL;
905 XRRCrtcInfo *enum_crtc_info, *crtc_info = NULL;
906 XRROutputInfo *enum_output_info, *output_info = NULL;
907 RROutput *outputs;
908 INT crtc_count, output_count;
909 INT primary_adapter = 0;
910 INT adapter_count = 0;
911 BOOL mirrored, detached;
912 RECT primary_rect;
913 BOOL ret = FALSE;
914 INT i, j;
916 screen_resources = xrandr_get_screen_resources();
917 if (!screen_resources)
918 goto done;
920 if (gpu_id)
922 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id );
923 if (!provider_info)
924 goto done;
926 crtc_count = provider_info->ncrtcs;
927 output_count = provider_info->noutputs;
928 outputs = provider_info->outputs;
930 /* Fake provider id, search adapters in screen resources */
931 else
933 crtc_count = screen_resources->ncrtc;
934 output_count = screen_resources->noutput;
935 outputs = screen_resources->outputs;
938 /* Actual adapter count could be less */
939 adapters = calloc( crtc_count, sizeof(*adapters) );
940 if (!adapters)
941 goto done;
943 primary_rect = get_primary_rect( screen_resources );
944 for (i = 0; i < output_count; ++i)
946 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, outputs[i] );
947 if (!output_info)
948 goto done;
950 /* Only connected output are considered as monitors */
951 if (output_info->connection != RR_Connected)
953 pXRRFreeOutputInfo( output_info );
954 output_info = NULL;
955 continue;
958 /* Connected output doesn't mean the output is attached to a crtc */
959 detached = FALSE;
960 if (output_info->crtc)
962 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
963 if (!crtc_info)
964 goto done;
967 if (!output_info->crtc || !crtc_info->mode)
968 detached = TRUE;
970 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
971 mirrored = FALSE;
972 if (!detached)
974 for (j = 0; j < screen_resources->noutput; ++j)
976 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[j] );
977 if (!enum_output_info)
978 continue;
980 if (enum_output_info->connection != RR_Connected || !enum_output_info->crtc)
982 pXRRFreeOutputInfo( enum_output_info );
983 continue;
986 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
987 pXRRFreeOutputInfo( enum_output_info );
988 if (!enum_crtc_info)
989 continue;
991 /* Some outputs may have the same coordinates, aka mirrored. Choose the output with
992 * the lowest value as primary and the rest will then be replicas in a mirroring set */
993 if (crtc_info->x == enum_crtc_info->x &&
994 crtc_info->y == enum_crtc_info->y &&
995 crtc_info->width == enum_crtc_info->width &&
996 crtc_info->height == enum_crtc_info->height &&
997 outputs[i] > screen_resources->outputs[j])
999 mirrored = TRUE;
1000 pXRRFreeCrtcInfo( enum_crtc_info );
1001 break;
1004 pXRRFreeCrtcInfo( enum_crtc_info );
1008 if (!mirrored || detached)
1010 /* Use RROutput as adapter id. The reason of not using RRCrtc is that we need to detect inactive but
1011 * attached monitors */
1012 adapters[adapter_count].id = outputs[i];
1013 if (!detached)
1014 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
1015 if (is_crtc_primary( primary_rect, crtc_info ))
1017 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
1018 primary_adapter = adapter_count;
1021 ++adapter_count;
1024 pXRRFreeOutputInfo( output_info );
1025 output_info = NULL;
1026 if (crtc_info)
1028 pXRRFreeCrtcInfo( crtc_info );
1029 crtc_info = NULL;
1033 /* Make primary adapter the first */
1034 if (primary_adapter)
1036 struct x11drv_adapter tmp = adapters[0];
1037 adapters[0] = adapters[primary_adapter];
1038 adapters[primary_adapter] = tmp;
1041 *new_adapters = adapters;
1042 *count = adapter_count;
1043 ret = TRUE;
1044 done:
1045 if (screen_resources)
1046 pXRRFreeScreenResources( screen_resources );
1047 if (provider_info)
1048 pXRRFreeProviderInfo( provider_info );
1049 if (output_info)
1050 pXRRFreeOutputInfo( output_info );
1051 if (crtc_info)
1052 pXRRFreeCrtcInfo( crtc_info );
1053 if (!ret)
1055 free( adapters );
1056 ERR("Failed to get adapters\n");
1058 return ret;
1061 static void xrandr14_free_adapters( struct x11drv_adapter *adapters )
1063 free( adapters );
1066 static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count )
1068 struct gdi_monitor *realloc_monitors, *monitors = NULL;
1069 XRRScreenResources *screen_resources = NULL;
1070 XRROutputInfo *output_info = NULL, *enum_output_info = NULL;
1071 XRRCrtcInfo *crtc_info = NULL, *enum_crtc_info;
1072 INT primary_index = 0, monitor_count = 0, capacity;
1073 RECT primary_rect;
1074 BOOL ret = FALSE;
1075 INT i;
1077 screen_resources = xrandr_get_screen_resources();
1078 if (!screen_resources)
1079 goto done;
1081 /* First start with a 2 monitors, should be enough for most cases */
1082 capacity = 2;
1083 monitors = calloc( capacity, sizeof(*monitors) );
1084 if (!monitors)
1085 goto done;
1087 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, adapter_id );
1088 if (!output_info)
1089 goto done;
1091 if (output_info->crtc)
1093 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1094 if (!crtc_info)
1095 goto done;
1098 /* Inactive but attached monitor, no need to check for mirrored/replica monitors */
1099 if (!output_info->crtc || !crtc_info->mode)
1101 monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid );
1102 monitor_count = 1;
1104 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
1105 else
1107 primary_rect = get_primary_rect( screen_resources );
1109 for (i = 0; i < screen_resources->noutput; ++i)
1111 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1112 if (!enum_output_info)
1113 goto done;
1115 /* Detached outputs don't count */
1116 if (enum_output_info->connection != RR_Connected)
1118 pXRRFreeOutputInfo( enum_output_info );
1119 enum_output_info = NULL;
1120 continue;
1123 /* Allocate more space if needed */
1124 if (monitor_count >= capacity)
1126 capacity *= 2;
1127 realloc_monitors = realloc( monitors, capacity * sizeof(*monitors) );
1128 if (!realloc_monitors)
1129 goto done;
1130 monitors = realloc_monitors;
1133 if (enum_output_info->crtc)
1135 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
1136 if (!enum_crtc_info)
1137 goto done;
1139 if (enum_crtc_info->x == crtc_info->x &&
1140 enum_crtc_info->y == crtc_info->y &&
1141 enum_crtc_info->width == crtc_info->width &&
1142 enum_crtc_info->height == crtc_info->height)
1144 SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y,
1145 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
1146 monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor );
1148 if (is_crtc_primary( primary_rect, crtc_info ))
1149 primary_index = monitor_count;
1151 monitors[monitor_count].edid_len = get_edid( screen_resources->outputs[i],
1152 &monitors[monitor_count].edid );
1153 monitor_count++;
1156 pXRRFreeCrtcInfo( enum_crtc_info );
1159 pXRRFreeOutputInfo( enum_output_info );
1160 enum_output_info = NULL;
1163 /* Make sure the first monitor is the primary */
1164 if (primary_index)
1166 struct gdi_monitor tmp = monitors[0];
1167 monitors[0] = monitors[primary_index];
1168 monitors[primary_index] = tmp;
1171 /* Make sure the primary monitor origin is at (0, 0) */
1172 for (i = 0; i < monitor_count; i++)
1174 OffsetRect( &monitors[i].rc_monitor, -primary_rect.left, -primary_rect.top );
1175 OffsetRect( &monitors[i].rc_work, -primary_rect.left, -primary_rect.top );
1179 *new_monitors = monitors;
1180 *count = monitor_count;
1181 ret = TRUE;
1182 done:
1183 if (screen_resources)
1184 pXRRFreeScreenResources( screen_resources );
1185 if (output_info)
1186 pXRRFreeOutputInfo( output_info);
1187 if (crtc_info)
1188 pXRRFreeCrtcInfo( crtc_info );
1189 if (enum_output_info)
1190 pXRRFreeOutputInfo( enum_output_info );
1191 if (!ret)
1193 for (i = 0; i < monitor_count; i++)
1195 if (monitors[i].edid)
1196 XFree( monitors[i].edid );
1198 free( monitors );
1199 ERR("Failed to get monitors\n");
1201 return ret;
1204 static void xrandr14_free_monitors( struct gdi_monitor *monitors, int count )
1206 int i;
1208 for (i = 0; i < count; i++)
1210 if (monitors[i].edid)
1211 XFree( monitors[i].edid );
1213 free( monitors );
1216 static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
1218 RECT rect;
1220 xrandr14_invalidate_current_mode_cache();
1221 if (hwnd == NtUserGetDesktopWindow() && NtUserGetWindowThread( hwnd, NULL ) == GetCurrentThreadId())
1222 NtUserCallNoParam( NtUserCallNoParam_DisplayModeChanged );
1223 /* Update xinerama monitors for xinerama_get_fullscreen_monitors() */
1224 rect = get_host_primary_monitor_rect();
1225 xinerama_init( rect.right - rect.left, rect.bottom - rect.top );
1226 return FALSE;
1229 static void xrandr14_register_event_handlers(void)
1231 Display *display = thread_init_display();
1232 int event_base, error_base;
1234 if (!pXRRQueryExtension( display, &event_base, &error_base ))
1235 return;
1237 pXRRSelectInput( display, root_window,
1238 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RRProviderChangeNotifyMask );
1239 X11DRV_register_event_handler( event_base + RRNotify_CrtcChange, xrandr14_device_change_handler,
1240 "XRandR CrtcChange" );
1241 X11DRV_register_event_handler( event_base + RRNotify_OutputChange, xrandr14_device_change_handler,
1242 "XRandR OutputChange" );
1243 X11DRV_register_event_handler( event_base + RRNotify_ProviderChange, xrandr14_device_change_handler,
1244 "XRandR ProviderChange" );
1247 static Bool filter_rrnotify_event( Display *display, XEvent *event, char *arg )
1249 ULONG_PTR event_base = (ULONG_PTR)arg;
1251 if (event->type == event_base + RRNotify_CrtcChange
1252 || event->type == event_base + RRNotify_OutputChange
1253 || event->type == event_base + RRNotify_ProviderChange)
1254 return 1;
1256 return 0;
1259 static void process_rrnotify_events(void)
1261 struct x11drv_thread_data *data = x11drv_thread_data();
1262 int event_base, error_base;
1264 if (!data) return;
1265 if (data->current_event) return; /* don't process nested events */
1267 if (!pXRRQueryExtension( data->display, &event_base, &error_base ))
1268 return;
1270 process_events( data->display, filter_rrnotify_event, event_base );
1273 /* XRandR 1.4 display settings handler */
1274 static BOOL xrandr14_get_id( const WCHAR *device_name, BOOL is_primary, x11drv_settings_id *id )
1276 struct current_mode *tmp_modes, *new_current_modes = NULL;
1277 INT gpu_count, adapter_count, new_current_mode_count = 0;
1278 INT gpu_idx, adapter_idx, display_idx;
1279 struct x11drv_adapter *adapters;
1280 struct x11drv_gpu *gpus;
1281 WCHAR *end;
1283 /* Parse \\.\DISPLAY%d */
1284 display_idx = wcstol( device_name + 11, &end, 10 ) - 1;
1285 if (*end)
1286 return FALSE;
1288 process_rrnotify_events();
1290 /* Update cache */
1291 pthread_mutex_lock( &xrandr_mutex );
1292 if (!current_modes)
1294 if (!xrandr14_get_gpus( &gpus, &gpu_count, FALSE ))
1296 pthread_mutex_unlock( &xrandr_mutex );
1297 return FALSE;
1300 for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx)
1302 if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count ))
1303 break;
1305 tmp_modes = realloc( new_current_modes, (new_current_mode_count + adapter_count) * sizeof(*tmp_modes) );
1306 if (!tmp_modes)
1308 xrandr14_free_adapters( adapters );
1309 break;
1311 new_current_modes = tmp_modes;
1313 for (adapter_idx = 0; adapter_idx < adapter_count; ++adapter_idx)
1315 new_current_modes[new_current_mode_count + adapter_idx].id = adapters[adapter_idx].id;
1316 new_current_modes[new_current_mode_count + adapter_idx].loaded = FALSE;
1318 new_current_mode_count += adapter_count;
1319 xrandr14_free_adapters( adapters );
1321 xrandr14_free_gpus( gpus, gpu_count );
1323 if (new_current_modes)
1325 free( current_modes );
1326 current_modes = new_current_modes;
1327 current_mode_count = new_current_mode_count;
1331 if (display_idx >= current_mode_count)
1333 pthread_mutex_unlock( &xrandr_mutex );
1334 return FALSE;
1337 id->id = current_modes[display_idx].id;
1338 pthread_mutex_unlock( &xrandr_mutex );
1339 return TRUE;
1342 static void add_xrandr14_mode( DEVMODEW *mode, XRRModeInfo *info, DWORD depth, DWORD frequency,
1343 DWORD orientation, BOOL full )
1345 mode->dmSize = sizeof(*mode);
1346 mode->dmDriverExtra = full ? sizeof(RRMode) : 0;
1347 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
1348 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
1349 if (frequency)
1351 mode->dmFields |= DM_DISPLAYFREQUENCY;
1352 mode->dmDisplayFrequency = frequency;
1354 if (orientation == DMDO_DEFAULT || orientation == DMDO_180)
1356 mode->dmPelsWidth = info->width;
1357 mode->dmPelsHeight = info->height;
1359 else
1361 mode->dmPelsWidth = info->height;
1362 mode->dmPelsHeight = info->width;
1364 mode->dmDisplayOrientation = orientation;
1365 mode->dmBitsPerPel = depth;
1366 mode->dmDisplayFlags = 0;
1367 if (full) memcpy( mode + 1, &info->id, sizeof(info->id) );
1370 static BOOL xrandr14_get_modes( x11drv_settings_id id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count, BOOL full )
1372 DWORD frequency, orientation, orientation_count;
1373 XRRScreenResources *screen_resources;
1374 XRROutputInfo *output_info = NULL;
1375 RROutput output = (RROutput)id.id;
1376 XRRCrtcInfo *crtc_info = NULL;
1377 UINT depth_idx, mode_idx = 0;
1378 XRRModeInfo *mode_info;
1379 DEVMODEW *mode, *modes;
1380 Rotation rotations;
1381 BOOL ret = FALSE;
1382 RRCrtc crtc;
1383 INT i, j;
1385 screen_resources = xrandr_get_screen_resources();
1386 if (!screen_resources)
1387 goto done;
1389 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1390 if (!output_info)
1391 goto done;
1393 if (output_info->connection != RR_Connected)
1395 ret = TRUE;
1396 *new_modes = NULL;
1397 *mode_count = 0;
1398 goto done;
1401 crtc = output_info->crtc;
1402 if (!crtc)
1403 crtc = get_output_free_crtc( screen_resources, output_info );
1404 if (crtc)
1405 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1407 /* If the output is connected to a CRTC, use rotations reported by the CRTC */
1408 if (crtc_info)
1410 if (flags & EDS_ROTATEDMODE)
1412 rotations = crtc_info->rotations;
1414 else
1416 /* According to the RandR spec, RRGetCrtcInfo should set the active rotation to Rotate_0
1417 * when a CRTC is disabled. However, some RandR implementations report 0 in this case */
1418 rotations = (crtc_info->rotation & 0xf) ? crtc_info->rotation : RR_Rotate_0;
1421 /* Not connected to CRTC, assume all rotations are supported */
1422 else
1424 if (flags & EDS_ROTATEDMODE)
1426 rotations = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
1428 else
1430 rotations = RR_Rotate_0;
1433 orientation_count = get_orientation_count( rotations );
1435 /* Allocate space for display modes in different color depths and orientations.
1436 * Store a RRMode at the end of each DEVMODEW as private driver data */
1437 modes = calloc( output_info->nmode * DEPTH_COUNT * orientation_count,
1438 sizeof(*modes) + sizeof(RRMode) );
1439 if (!modes)
1440 goto done;
1442 for (i = 0, mode = modes; i < output_info->nmode; ++i)
1444 for (j = 0; j < screen_resources->nmode; ++j)
1446 if (output_info->modes[i] != screen_resources->modes[j].id)
1447 continue;
1449 mode_info = &screen_resources->modes[j];
1450 frequency = get_frequency( mode_info );
1452 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
1454 for (orientation = DMDO_DEFAULT; orientation <= DMDO_270; ++orientation)
1456 if (!((1 << orientation) & rotations))
1457 continue;
1459 add_xrandr14_mode( mode, mode_info, depths[depth_idx], frequency, orientation, full );
1460 mode = NEXT_DEVMODEW( mode );
1461 ++mode_idx;
1465 break;
1469 ret = TRUE;
1470 *new_modes = modes;
1471 *mode_count = mode_idx;
1472 done:
1473 if (crtc_info)
1474 pXRRFreeCrtcInfo( crtc_info );
1475 if (output_info)
1476 pXRRFreeOutputInfo( output_info );
1477 if (screen_resources)
1478 pXRRFreeScreenResources( screen_resources );
1479 return ret;
1482 static void xrandr14_free_modes( DEVMODEW *modes )
1484 free( modes );
1487 static BOOL xrandr14_get_current_mode( x11drv_settings_id id, DEVMODEW *mode )
1489 struct current_mode *mode_ptr = NULL;
1490 XRRScreenResources *screen_resources;
1491 XRROutputInfo *output_info = NULL;
1492 RROutput output = (RROutput)id.id;
1493 XRRModeInfo *mode_info = NULL;
1494 XRRCrtcInfo *crtc_info = NULL;
1495 BOOL ret = FALSE;
1496 RECT primary;
1497 INT mode_idx;
1499 pthread_mutex_lock( &xrandr_mutex );
1500 for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx)
1502 if (current_modes[mode_idx].id != id.id)
1503 continue;
1505 if (!current_modes[mode_idx].loaded)
1507 mode_ptr = &current_modes[mode_idx];
1508 break;
1511 memcpy( mode, &current_modes[mode_idx].mode, sizeof(*mode) );
1512 pthread_mutex_unlock( &xrandr_mutex );
1513 return TRUE;
1516 screen_resources = xrandr_get_screen_resources();
1517 if (!screen_resources)
1518 goto done;
1520 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1521 if (!output_info)
1522 goto done;
1524 if (output_info->crtc)
1526 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1527 if (!crtc_info)
1528 goto done;
1531 /* Detached */
1532 if (output_info->connection != RR_Connected || !output_info->crtc || !crtc_info->mode)
1534 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1535 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1536 mode->dmDisplayOrientation = DMDO_DEFAULT;
1537 mode->dmBitsPerPel = 0;
1538 mode->dmPelsWidth = 0;
1539 mode->dmPelsHeight = 0;
1540 mode->dmDisplayFlags = 0;
1541 mode->dmDisplayFrequency = 0;
1542 mode->dmPosition.x = 0;
1543 mode->dmPosition.y = 0;
1544 ret = TRUE;
1545 goto done;
1548 /* Attached */
1549 for (mode_idx = 0; mode_idx < screen_resources->nmode; ++mode_idx)
1551 if (crtc_info->mode == screen_resources->modes[mode_idx].id)
1553 mode_info = &screen_resources->modes[mode_idx];
1554 break;
1558 if (!mode_info)
1559 goto done;
1561 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1562 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1563 mode->dmDisplayOrientation = get_orientation( crtc_info->rotation );
1564 mode->dmBitsPerPel = screen_bpp;
1565 mode->dmPelsWidth = crtc_info->width;
1566 mode->dmPelsHeight = crtc_info->height;
1567 mode->dmDisplayFlags = 0;
1568 mode->dmDisplayFrequency = get_frequency( mode_info );
1569 /* Convert RandR coordinates to virtual screen coordinates */
1570 primary = get_primary_rect( screen_resources );
1571 mode->dmPosition.x = crtc_info->x - primary.left;
1572 mode->dmPosition.y = crtc_info->y - primary.top;
1573 ret = TRUE;
1575 done:
1576 if (ret && mode_ptr)
1578 memcpy( &mode_ptr->mode, mode, sizeof(*mode) );
1579 mode_ptr->mode.dmSize = sizeof(*mode);
1580 mode_ptr->mode.dmDriverExtra = 0;
1581 mode_ptr->loaded = TRUE;
1583 pthread_mutex_unlock( &xrandr_mutex );
1584 if (crtc_info)
1585 pXRRFreeCrtcInfo( crtc_info );
1586 if (output_info)
1587 pXRRFreeOutputInfo( output_info );
1588 if (screen_resources)
1589 pXRRFreeScreenResources( screen_resources );
1590 return ret;
1593 static LONG xrandr14_set_current_mode( x11drv_settings_id id, const DEVMODEW *mode )
1595 unsigned int screen_width, screen_height;
1596 RROutput output = (RROutput)id.id, *outputs;
1597 XRRScreenResources *screen_resources;
1598 XRROutputInfo *output_info = NULL;
1599 XRRCrtcInfo *crtc_info = NULL;
1600 LONG ret = DISP_CHANGE_FAILED;
1601 Rotation rotation;
1602 INT output_count;
1603 RRCrtc crtc = 0;
1604 Status status;
1605 RRMode rrmode;
1607 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
1608 WARN("Cannot change screen color depth from %ubits to %ubits!\n",
1609 screen_bpp, (int)mode->dmBitsPerPel);
1611 screen_resources = xrandr_get_screen_resources();
1612 if (!screen_resources)
1613 return ret;
1615 XGrabServer( gdi_display );
1617 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1618 if (!output_info || output_info->connection != RR_Connected)
1619 goto done;
1621 if (is_detached_mode(mode))
1623 /* Already detached */
1624 if (!output_info->crtc)
1626 ret = DISP_CHANGE_SUCCESSFUL;
1627 goto done;
1630 /* Execute detach operation */
1631 status = pXRRSetCrtcConfig( gdi_display, screen_resources, output_info->crtc,
1632 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0 );
1633 if (status == RRSetConfigSuccess)
1635 get_screen_size( screen_resources, &screen_width, &screen_height );
1636 set_screen_size( screen_width, screen_height );
1637 ret = DISP_CHANGE_SUCCESSFUL;
1639 goto done;
1642 /* Attached */
1643 if (output_info->crtc)
1645 crtc = output_info->crtc;
1647 /* Detached, need to find a free CRTC */
1648 else
1650 if (!(crtc = get_output_free_crtc( screen_resources, output_info )))
1651 goto done;
1654 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1655 if (!crtc_info)
1656 goto done;
1658 assert( mode->dmDriverExtra == sizeof(RRMode) );
1659 memcpy( &rrmode, (BYTE *)mode + sizeof(*mode), sizeof(rrmode) );
1661 if (crtc_info->noutput)
1663 outputs = crtc_info->outputs;
1664 output_count = crtc_info->noutput;
1666 else
1668 outputs = &output;
1669 output_count = 1;
1671 rotation = get_rotation( mode->dmDisplayOrientation );
1673 /* According to the RandR spec, the entire CRTC must fit inside the screen.
1674 * Since we use the union of all enabled CRTCs to determine the necessary
1675 * screen size, this might involve shrinking the screen, so we must disable
1676 * the CRTC in question first. */
1677 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime, 0, 0, None,
1678 RR_Rotate_0, NULL, 0 );
1679 if (status != RRSetConfigSuccess)
1680 goto done;
1682 get_screen_size( screen_resources, &screen_width, &screen_height );
1683 screen_width = max( screen_width, mode->dmPosition.x + mode->dmPelsWidth );
1684 screen_height = max( screen_height, mode->dmPosition.y + mode->dmPelsHeight );
1685 set_screen_size( screen_width, screen_height );
1687 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
1688 mode->dmPosition.x, mode->dmPosition.y, rrmode,
1689 rotation, outputs, output_count );
1690 if (status == RRSetConfigSuccess)
1691 ret = DISP_CHANGE_SUCCESSFUL;
1693 done:
1694 XUngrabServer( gdi_display );
1695 XFlush( gdi_display );
1696 if (crtc_info)
1697 pXRRFreeCrtcInfo( crtc_info );
1698 if (output_info)
1699 pXRRFreeOutputInfo( output_info );
1700 pXRRFreeScreenResources( screen_resources );
1701 xrandr14_invalidate_current_mode_cache();
1702 return ret;
1705 #endif
1707 void X11DRV_XRandR_Init(void)
1709 struct x11drv_display_device_handler display_handler;
1710 struct x11drv_settings_handler settings_handler;
1711 int event_base, error_base, minor, ret;
1712 static int major;
1713 Bool ok;
1715 if (major) return; /* already initialized? */
1716 if (!usexrandr) return; /* disabled in config */
1717 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
1719 /* see if Xrandr is available */
1720 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
1721 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
1722 ok = pXRRQueryVersion( gdi_display, &major, &minor );
1723 if (X11DRV_check_error() || !ok) return;
1725 TRACE("Found XRandR %d.%d.\n", major, minor);
1727 settings_handler.name = "XRandR 1.0";
1728 settings_handler.priority = 200;
1729 settings_handler.get_id = xrandr10_get_id;
1730 settings_handler.get_modes = xrandr10_get_modes;
1731 settings_handler.free_modes = xrandr10_free_modes;
1732 settings_handler.get_current_mode = xrandr10_get_current_mode;
1733 settings_handler.set_current_mode = xrandr10_set_current_mode;
1734 X11DRV_Settings_SetHandler( &settings_handler );
1736 #ifdef HAVE_XRRGETPROVIDERRESOURCES
1737 if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))
1739 XRRScreenResources *screen_resources;
1740 XRROutputInfo *output_info;
1741 BOOL found_output = FALSE;
1742 INT i;
1744 screen_resources = xrandr_get_screen_resources();
1745 if (!screen_resources)
1746 return;
1748 for (i = 0; i < screen_resources->noutput; ++i)
1750 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1751 if (!output_info)
1752 continue;
1754 if (output_info->connection == RR_Connected)
1756 pXRRFreeOutputInfo( output_info );
1757 found_output = TRUE;
1758 break;
1761 pXRRFreeOutputInfo( output_info );
1763 pXRRFreeScreenResources( screen_resources );
1765 if (!found_output)
1767 WARN("No connected outputs found.\n");
1768 return;
1771 display_handler.name = "XRandR 1.4";
1772 display_handler.priority = 200;
1773 display_handler.get_gpus = xrandr14_get_gpus;
1774 display_handler.get_adapters = xrandr14_get_adapters;
1775 display_handler.get_monitors = xrandr14_get_monitors;
1776 display_handler.free_gpus = xrandr14_free_gpus;
1777 display_handler.free_adapters = xrandr14_free_adapters;
1778 display_handler.free_monitors = xrandr14_free_monitors;
1779 display_handler.register_event_handlers = xrandr14_register_event_handlers;
1780 X11DRV_DisplayDevices_SetHandler( &display_handler );
1782 if (is_broken_driver())
1783 return;
1785 settings_handler.name = "XRandR 1.4";
1786 settings_handler.priority = 300;
1787 settings_handler.get_id = xrandr14_get_id;
1788 settings_handler.get_modes = xrandr14_get_modes;
1789 settings_handler.free_modes = xrandr14_free_modes;
1790 settings_handler.get_current_mode = xrandr14_get_current_mode;
1791 settings_handler.set_current_mode = xrandr14_set_current_mode;
1792 X11DRV_Settings_SetHandler( &settings_handler );
1794 #endif
1797 #else /* SONAME_LIBXRANDR */
1799 void X11DRV_XRandR_Init(void)
1801 TRACE("XRandR support not compiled in.\n");
1804 #endif /* SONAME_LIBXRANDR */