mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / winex11.drv / xrandr.c
blobfa748c2af047a6c0da3bdab2d11ccb3887c2a61a
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 #include "config.h"
24 #include "wine/port.h"
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
32 #ifdef HAVE_XRRGETPROVIDERRESOURCES
33 WINE_DECLARE_DEBUG_CHANNEL(winediag);
34 #endif
36 #ifdef SONAME_LIBXRANDR
38 #include <assert.h>
39 #include <X11/Xlib.h>
40 #include <X11/extensions/Xrandr.h>
41 #include "x11drv.h"
43 #define VK_NO_PROTOTYPES
44 #define WINE_VK_HOST
46 #include "wine/heap.h"
47 #include "wine/unicode.h"
48 #include "wine/vulkan.h"
49 #include "wine/vulkan_driver.h"
51 static void *xrandr_handle;
53 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
54 MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
55 MAKE_FUNCPTR(XRRConfigCurrentRate)
56 MAKE_FUNCPTR(XRRFreeScreenConfigInfo)
57 MAKE_FUNCPTR(XRRGetScreenInfo)
58 MAKE_FUNCPTR(XRRQueryExtension)
59 MAKE_FUNCPTR(XRRQueryVersion)
60 MAKE_FUNCPTR(XRRRates)
61 MAKE_FUNCPTR(XRRSetScreenConfig)
62 MAKE_FUNCPTR(XRRSetScreenConfigAndRate)
63 MAKE_FUNCPTR(XRRSizes)
65 #ifdef HAVE_XRRGETPROVIDERRESOURCES
66 MAKE_FUNCPTR(XRRFreeCrtcInfo)
67 MAKE_FUNCPTR(XRRFreeOutputInfo)
68 MAKE_FUNCPTR(XRRFreeScreenResources)
69 MAKE_FUNCPTR(XRRGetCrtcInfo)
70 MAKE_FUNCPTR(XRRGetOutputInfo)
71 MAKE_FUNCPTR(XRRGetScreenResources)
72 MAKE_FUNCPTR(XRRGetScreenResourcesCurrent)
73 MAKE_FUNCPTR(XRRGetScreenSizeRange)
74 MAKE_FUNCPTR(XRRSetCrtcConfig)
75 MAKE_FUNCPTR(XRRSetScreenSize)
76 MAKE_FUNCPTR(XRRSelectInput)
77 MAKE_FUNCPTR(XRRGetOutputPrimary)
78 MAKE_FUNCPTR(XRRGetProviderResources)
79 MAKE_FUNCPTR(XRRFreeProviderResources)
80 MAKE_FUNCPTR(XRRGetProviderInfo)
81 MAKE_FUNCPTR(XRRFreeProviderInfo)
82 #endif
84 #undef MAKE_FUNCPTR
86 static int load_xrandr(void)
88 int r = 0;
90 if (dlopen(SONAME_LIBXRENDER, RTLD_NOW|RTLD_GLOBAL) &&
91 (xrandr_handle = dlopen(SONAME_LIBXRANDR, RTLD_NOW)))
94 #define LOAD_FUNCPTR(f) \
95 if((p##f = dlsym(xrandr_handle, #f)) == NULL) goto sym_not_found
97 LOAD_FUNCPTR(XRRConfigCurrentConfiguration);
98 LOAD_FUNCPTR(XRRConfigCurrentRate);
99 LOAD_FUNCPTR(XRRFreeScreenConfigInfo);
100 LOAD_FUNCPTR(XRRGetScreenInfo);
101 LOAD_FUNCPTR(XRRQueryExtension);
102 LOAD_FUNCPTR(XRRQueryVersion);
103 LOAD_FUNCPTR(XRRRates);
104 LOAD_FUNCPTR(XRRSetScreenConfig);
105 LOAD_FUNCPTR(XRRSetScreenConfigAndRate);
106 LOAD_FUNCPTR(XRRSizes);
107 r = 1;
109 #ifdef HAVE_XRRGETPROVIDERRESOURCES
110 LOAD_FUNCPTR(XRRFreeCrtcInfo);
111 LOAD_FUNCPTR(XRRFreeOutputInfo);
112 LOAD_FUNCPTR(XRRFreeScreenResources);
113 LOAD_FUNCPTR(XRRGetCrtcInfo);
114 LOAD_FUNCPTR(XRRGetOutputInfo);
115 LOAD_FUNCPTR(XRRGetScreenResources);
116 LOAD_FUNCPTR(XRRGetScreenResourcesCurrent);
117 LOAD_FUNCPTR(XRRGetScreenSizeRange);
118 LOAD_FUNCPTR(XRRSetCrtcConfig);
119 LOAD_FUNCPTR(XRRSetScreenSize);
120 LOAD_FUNCPTR(XRRSelectInput);
121 LOAD_FUNCPTR(XRRGetOutputPrimary);
122 LOAD_FUNCPTR(XRRGetProviderResources);
123 LOAD_FUNCPTR(XRRFreeProviderResources);
124 LOAD_FUNCPTR(XRRGetProviderInfo);
125 LOAD_FUNCPTR(XRRFreeProviderInfo);
126 r = 4;
127 #endif
129 #undef LOAD_FUNCPTR
131 sym_not_found:
132 if (!r) TRACE("Unable to load function ptrs from XRandR library\n");
134 return r;
137 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
139 return 1;
142 /* XRandR 1.0 display settings handler */
143 static BOOL xrandr10_get_id( const WCHAR *device_name, ULONG_PTR *id )
145 WCHAR primary_adapter[CCHDEVICENAME];
147 if (!get_primary_adapter( primary_adapter ))
148 return FALSE;
150 /* RandR 1.0 only supports changing the primary adapter settings.
151 * For non-primary adapters, an id is still provided but getting
152 * and changing non-primary adapters' settings will be ignored. */
153 *id = !lstrcmpiW( device_name, primary_adapter ) ? 1 : 0;
154 return TRUE;
157 static void add_xrandr10_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height,
158 DWORD frequency, SizeID size_id )
160 mode->dmSize = sizeof(*mode);
161 mode->dmDriverExtra = sizeof(SizeID);
162 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
163 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
164 if (frequency)
166 mode->dmFields |= DM_DISPLAYFREQUENCY;
167 mode->dmDisplayFrequency = frequency;
169 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
170 mode->dmBitsPerPel = depth;
171 mode->dmPelsWidth = width;
172 mode->dmPelsHeight = height;
173 mode->u2.dmDisplayFlags = 0;
174 memcpy( (BYTE *)mode + sizeof(*mode), &size_id, sizeof(size_id) );
177 static BOOL xrandr10_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *new_mode_count )
179 INT size_idx, depth_idx, rate_idx, mode_idx = 0;
180 INT size_count, rate_count, mode_count = 0;
181 DEVMODEW *modes, *mode;
182 XRRScreenSize *sizes;
183 short *rates;
185 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
186 if (size_count <= 0)
187 return FALSE;
189 for (size_idx = 0; size_idx < size_count; ++size_idx)
191 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
192 if (rate_count)
193 mode_count += rate_count;
194 else
195 ++mode_count;
198 /* Allocate space for reported modes in three depths, and put an SizeID at the end of DEVMODEW as
199 * driver private data */
200 modes = heap_calloc( mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID) );
201 if (!modes)
203 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
204 return FALSE;
207 for (size_idx = 0; size_idx < size_count; ++size_idx)
209 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
211 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
212 if (!rate_count)
214 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
215 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
216 sizes[size_idx].height, 0, size_idx );
217 continue;
220 for (rate_idx = 0; rate_idx < rate_count; ++rate_idx)
222 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
223 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
224 sizes[size_idx].height, rates[rate_idx], size_idx );
229 *new_modes = modes;
230 *new_mode_count = mode_idx;
231 return TRUE;
234 static void xrandr10_free_modes( DEVMODEW *modes )
236 heap_free( modes );
239 static BOOL xrandr10_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
241 XRRScreenConfiguration *screen_config;
242 XRRScreenSize *sizes;
243 Rotation rotation;
244 SizeID size_id;
245 INT size_count;
246 short rate;
248 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
249 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
250 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
251 mode->u2.dmDisplayFlags = 0;
252 mode->u1.s2.dmPosition.x = 0;
253 mode->u1.s2.dmPosition.y = 0;
255 if (id != 1)
257 FIXME("Non-primary adapters are unsupported.\n");
258 mode->dmBitsPerPel = 0;
259 mode->dmPelsWidth = 0;
260 mode->dmPelsHeight = 0;
261 mode->dmDisplayFrequency = 0;
262 return TRUE;
265 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
266 if (size_count <= 0)
267 return FALSE;
269 screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) );
270 size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation );
271 rate = pXRRConfigCurrentRate( screen_config );
272 pXRRFreeScreenConfigInfo( screen_config );
274 mode->dmBitsPerPel = screen_bpp;
275 mode->dmPelsWidth = sizes[size_id].width;
276 mode->dmPelsHeight = sizes[size_id].height;
277 mode->dmDisplayFrequency = rate;
278 return TRUE;
281 static LONG xrandr10_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
283 XRRScreenConfiguration *screen_config;
284 Rotation rotation;
285 SizeID size_id;
286 Window root;
287 Status stat;
289 if (id != 1)
291 FIXME("Non-primary adapters are unsupported.\n");
292 return DISP_CHANGE_SUCCESSFUL;
295 if (is_detached_mode(mode))
297 FIXME("Detaching adapters is unsupported.\n");
298 return DISP_CHANGE_SUCCESSFUL;
301 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
302 WARN("Cannot change screen bit depth from %dbits to %dbits!\n", screen_bpp, mode->dmBitsPerPel);
304 root = DefaultRootWindow( gdi_display );
305 screen_config = pXRRGetScreenInfo( gdi_display, root );
306 pXRRConfigCurrentConfiguration( screen_config, &rotation );
308 assert( mode->dmDriverExtra == sizeof(SizeID) );
309 memcpy( &size_id, (BYTE *)mode + sizeof(*mode), sizeof(size_id) );
311 if (mode->dmFields & DM_DISPLAYFREQUENCY && mode->dmDisplayFrequency)
312 stat = pXRRSetScreenConfigAndRate( gdi_display, screen_config, root, size_id, rotation,
313 mode->dmDisplayFrequency, CurrentTime );
314 else
315 stat = pXRRSetScreenConfig( gdi_display, screen_config, root, size_id, rotation, CurrentTime );
316 pXRRFreeScreenConfigInfo( screen_config );
318 if (stat != RRSetConfigSuccess)
319 return DISP_CHANGE_FAILED;
321 XFlush( gdi_display );
322 return DISP_CHANGE_SUCCESSFUL;
325 #ifdef HAVE_XRRGETPROVIDERRESOURCES
327 static XRRScreenResources *xrandr_get_screen_resources(void)
329 XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window );
330 if (resources && !resources->ncrtc)
332 pXRRFreeScreenResources( resources );
333 resources = pXRRGetScreenResources( gdi_display, root_window );
336 if (!resources)
337 ERR("Failed to get screen resources.\n");
338 return resources;
341 /* Some (304.64, possibly earlier) versions of the NVIDIA driver only
342 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
343 * are only listed through RandR 1.0 / 1.1. This is completely useless,
344 * but NVIDIA considers this a feature, so it's unlikely to change. The
345 * best we can do is to fall back to RandR 1.0 and encourage users to
346 * consider more cooperative driver vendors when we detect such a
347 * configuration. */
348 static BOOL is_broken_driver(void)
350 XRRScreenResources *screen_resources;
351 XRROutputInfo *output_info;
352 XRRModeInfo *first_mode;
353 INT major, event, error;
354 INT output_idx, i, j;
355 BOOL only_one_mode;
357 screen_resources = xrandr_get_screen_resources();
358 if (!screen_resources)
359 return TRUE;
361 /* Check if any output only has one native mode */
362 for (output_idx = 0; output_idx < screen_resources->noutput; ++output_idx)
364 output_info = pXRRGetOutputInfo( gdi_display, screen_resources,
365 screen_resources->outputs[output_idx] );
366 if (!output_info)
367 continue;
369 if (output_info->connection != RR_Connected)
371 pXRRFreeOutputInfo( output_info );
372 continue;
375 first_mode = NULL;
376 only_one_mode = TRUE;
377 for (i = 0; i < output_info->nmode; ++i)
379 for (j = 0; j < screen_resources->nmode; ++j)
381 if (output_info->modes[i] != screen_resources->modes[j].id)
382 continue;
384 if (!first_mode)
386 first_mode = &screen_resources->modes[j];
387 break;
390 if (first_mode->width != screen_resources->modes[j].width ||
391 first_mode->height != screen_resources->modes[j].height)
392 only_one_mode = FALSE;
394 break;
397 if (!only_one_mode)
398 break;
400 pXRRFreeOutputInfo( output_info );
402 if (!only_one_mode)
403 continue;
405 /* Check if it is NVIDIA proprietary driver */
406 if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error ))
408 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
409 "Please consider using the Nouveau driver instead.\n");
410 pXRRFreeScreenResources( screen_resources );
411 return TRUE;
414 pXRRFreeScreenResources( screen_resources );
415 return FALSE;
418 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
420 int min_width = 0, min_height = 0, max_width, max_height;
421 XRRCrtcInfo *crtc_info;
422 int i;
424 pXRRGetScreenSizeRange( gdi_display, root_window, &min_width, &min_height, &max_width, &max_height );
425 *width = min_width;
426 *height = min_height;
428 for (i = 0; i < resources->ncrtc; ++i)
430 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
431 continue;
433 if (crtc_info->mode != None)
435 *width = max(*width, crtc_info->x + crtc_info->width);
436 *height = max(*height, crtc_info->y + crtc_info->height);
439 pXRRFreeCrtcInfo( crtc_info );
443 static void set_screen_size( int width, int height )
445 int screen = default_visual.screen;
446 int mm_width, mm_height;
448 mm_width = width * DisplayWidthMM( gdi_display, screen ) / DisplayWidth( gdi_display, screen );
449 mm_height = height * DisplayHeightMM( gdi_display, screen ) / DisplayHeight( gdi_display, screen );
450 pXRRSetScreenSize( gdi_display, root_window, width, height, mm_width, mm_height );
453 static unsigned int get_frequency( const XRRModeInfo *mode )
455 unsigned int dots = mode->hTotal * mode->vTotal;
457 if (!dots)
458 return 0;
460 if (mode->modeFlags & RR_DoubleScan)
461 dots *= 2;
462 if (mode->modeFlags & RR_Interlace)
463 dots /= 2;
465 return (mode->dotClock + dots / 2) / dots;
468 static DWORD get_orientation( Rotation rotation )
470 if (rotation & RR_Rotate_270) return DMDO_270;
471 if (rotation & RR_Rotate_180) return DMDO_180;
472 if (rotation & RR_Rotate_90) return DMDO_90;
473 return DMDO_DEFAULT;
476 static DWORD get_orientation_count( Rotation rotations )
478 DWORD count = 0;
480 if (rotations & RR_Rotate_0) ++count;
481 if (rotations & RR_Rotate_90) ++count;
482 if (rotations & RR_Rotate_180) ++count;
483 if (rotations & RR_Rotate_270) ++count;
484 return count;
487 static Rotation get_rotation( DWORD orientation )
489 return (Rotation)(1 << orientation);
492 static RRCrtc get_output_free_crtc( XRRScreenResources *resources, XRROutputInfo *output_info )
494 XRRCrtcInfo *crtc_info;
495 INT crtc_idx;
496 RRCrtc crtc;
498 for (crtc_idx = 0; crtc_idx < output_info->ncrtc; ++crtc_idx)
500 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtcs[crtc_idx] );
501 if (!crtc_info)
502 continue;
504 if (!crtc_info->noutput)
506 crtc = output_info->crtcs[crtc_idx];
507 pXRRFreeCrtcInfo( crtc_info );
508 return crtc;
511 pXRRFreeCrtcInfo( crtc_info );
514 return 0;
517 static RECT get_primary_rect( XRRScreenResources *resources )
519 XRROutputInfo *output_info = NULL;
520 XRRCrtcInfo *crtc_info = NULL;
521 RROutput primary_output;
522 RECT primary_rect = {0};
523 RECT first_rect = {0};
524 INT i;
526 primary_output = pXRRGetOutputPrimary( gdi_display, root_window );
527 if (!primary_output)
528 goto fallback;
530 output_info = pXRRGetOutputInfo( gdi_display, resources, primary_output );
531 if (!output_info || output_info->connection != RR_Connected || !output_info->crtc)
532 goto fallback;
534 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtc );
535 if (!crtc_info || !crtc_info->mode)
536 goto fallback;
538 SetRect( &primary_rect, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
539 pXRRFreeCrtcInfo( crtc_info );
540 pXRRFreeOutputInfo( output_info );
541 return primary_rect;
543 /* Fallback when XRandR primary output is a disconnected output.
544 * Try to find a crtc with (x, y) being (0, 0). If it's found then get the primary rect from that crtc,
545 * otherwise use the first active crtc to get the primary rect */
546 fallback:
547 if (crtc_info)
548 pXRRFreeCrtcInfo( crtc_info );
549 if (output_info)
550 pXRRFreeOutputInfo( output_info );
552 WARN("Primary is set to a disconnected XRandR output.\n");
553 for (i = 0; i < resources->ncrtc; ++i)
555 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
556 if (!crtc_info)
557 continue;
559 if (!crtc_info->mode)
561 pXRRFreeCrtcInfo( crtc_info );
562 continue;
565 if (!crtc_info->x && !crtc_info->y)
567 SetRect( &primary_rect, 0, 0, crtc_info->width, crtc_info->height );
568 pXRRFreeCrtcInfo( crtc_info );
569 break;
572 if (IsRectEmpty( &first_rect ))
573 SetRect( &first_rect, crtc_info->x, crtc_info->y,
574 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
576 pXRRFreeCrtcInfo( crtc_info );
579 return IsRectEmpty( &primary_rect ) ? first_rect : primary_rect;
582 static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
584 return crtc &&
585 crtc->mode &&
586 crtc->x == primary.left &&
587 crtc->y == primary.top &&
588 crtc->x + crtc->width == primary.right &&
589 crtc->y + crtc->height == primary.bottom;
592 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
594 static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRProviderInfo *provider_info )
596 static const char *extensions[] =
598 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
599 "VK_EXT_acquire_xlib_display",
600 "VK_EXT_direct_mode_display",
602 const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION );
603 VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
604 PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
605 PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
606 uint32_t device_count, device_idx, output_idx;
607 VkPhysicalDevice *vk_physical_devices = NULL;
608 VkPhysicalDeviceProperties2 properties2;
609 VkInstanceCreateInfo create_info;
610 VkPhysicalDeviceIDProperties id;
611 VkInstance vk_instance = NULL;
612 VkDisplayKHR vk_display;
613 BOOL ret = FALSE;
614 VkResult vr;
616 if (!vulkan_funcs)
617 goto done;
619 memset( &create_info, 0, sizeof(create_info) );
620 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
621 create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
622 create_info.ppEnabledExtensionNames = extensions;
624 vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance );
625 if (vr != VK_SUCCESS)
627 WARN("Failed to create a Vulkan instance, vr %d.\n", vr);
628 goto done;
631 #define LOAD_VK_FUNC(f) \
632 if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \
634 WARN("Failed to load " #f ".\n"); \
635 goto done; \
638 LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
639 LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
640 LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
641 #undef LOAD_VK_FUNC
643 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
644 if (vr != VK_SUCCESS || !device_count)
646 WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
647 goto done;
650 if (!(vk_physical_devices = heap_calloc( device_count, sizeof(*vk_physical_devices) )))
651 goto done;
653 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
654 if (vr != VK_SUCCESS)
656 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
657 goto done;
660 for (device_idx = 0; device_idx < device_count; ++device_idx)
662 for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
664 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
665 vr = pvkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
666 provider_info->outputs[output_idx], &vk_display );
667 XSync( gdi_display, FALSE );
668 if (X11DRV_check_error() || vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
669 continue;
671 memset( &id, 0, sizeof(id) );
672 id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
673 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
674 properties2.pNext = &id;
676 pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
677 memcpy( &gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) );
678 /* Ignore Khronos vendor IDs */
679 if (properties2.properties.vendorID < 0x10000)
681 gpu->vendor_id = properties2.properties.vendorID;
682 gpu->device_id = properties2.properties.deviceID;
684 MultiByteToWideChar( CP_UTF8, 0, properties2.properties.deviceName, -1, gpu->name, ARRAY_SIZE(gpu->name) );
685 ret = TRUE;
686 goto done;
690 done:
691 heap_free( vk_physical_devices );
692 if (vk_instance)
693 vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL );
694 return ret;
697 /* Get a list of GPUs reported by XRandR 1.4. Set get_properties to FALSE if GPU properties are
698 * not needed to avoid unnecessary querying */
699 static BOOL xrandr14_get_gpus2( struct x11drv_gpu **new_gpus, int *count, BOOL get_properties )
701 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
702 struct x11drv_gpu *gpus = NULL;
703 XRRScreenResources *screen_resources = NULL;
704 XRRProviderResources *provider_resources = NULL;
705 XRRProviderInfo *provider_info = NULL;
706 XRRCrtcInfo *crtc_info = NULL;
707 INT primary_provider = -1;
708 RECT primary_rect;
709 BOOL ret = FALSE;
710 INT i, j;
712 screen_resources = xrandr_get_screen_resources();
713 if (!screen_resources)
714 goto done;
716 provider_resources = pXRRGetProviderResources( gdi_display, root_window );
717 if (!provider_resources)
718 goto done;
720 gpus = heap_calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) );
721 if (!gpus)
722 goto done;
724 /* Some XRandR implementations don't support providers.
725 * In this case, report a fake one to try searching adapters in screen resources */
726 if (!provider_resources->nproviders)
728 WARN("XRandR implementation doesn't report any providers, faking one.\n");
729 lstrcpyW( gpus[0].name, wine_adapterW );
730 *new_gpus = gpus;
731 *count = 1;
732 ret = TRUE;
733 goto done;
736 primary_rect = get_primary_rect( screen_resources );
737 for (i = 0; i < provider_resources->nproviders; ++i)
739 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, provider_resources->providers[i] );
740 if (!provider_info)
741 goto done;
743 /* Find primary provider */
744 for (j = 0; primary_provider == -1 && j < provider_info->ncrtcs; ++j)
746 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, provider_info->crtcs[j] );
747 if (!crtc_info)
748 continue;
750 if (is_crtc_primary( primary_rect, crtc_info ))
752 primary_provider = i;
753 pXRRFreeCrtcInfo( crtc_info );
754 break;
757 pXRRFreeCrtcInfo( crtc_info );
760 gpus[i].id = provider_resources->providers[i];
761 if (get_properties)
763 if (!get_gpu_properties_from_vulkan( &gpus[i], provider_info ))
764 MultiByteToWideChar( CP_UTF8, 0, provider_info->name, -1, gpus[i].name, ARRAY_SIZE(gpus[i].name) );
765 /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */
767 pXRRFreeProviderInfo( provider_info );
770 /* Make primary GPU the first */
771 if (primary_provider > 0)
773 struct x11drv_gpu tmp = gpus[0];
774 gpus[0] = gpus[primary_provider];
775 gpus[primary_provider] = tmp;
778 *new_gpus = gpus;
779 *count = provider_resources->nproviders;
780 ret = TRUE;
781 done:
782 if (provider_resources)
783 pXRRFreeProviderResources( provider_resources );
784 if (screen_resources)
785 pXRRFreeScreenResources( screen_resources );
786 if (!ret)
788 heap_free( gpus );
789 ERR("Failed to get gpus\n");
791 return ret;
794 static BOOL xrandr14_get_gpus( struct x11drv_gpu **new_gpus, int *count )
796 return xrandr14_get_gpus2( new_gpus, count, TRUE );
799 static void xrandr14_free_gpus( struct x11drv_gpu *gpus )
801 heap_free( gpus );
804 static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct x11drv_adapter **new_adapters, int *count )
806 struct x11drv_adapter *adapters = NULL;
807 XRRScreenResources *screen_resources = NULL;
808 XRRProviderInfo *provider_info = NULL;
809 XRRCrtcInfo *enum_crtc_info, *crtc_info = NULL;
810 XRROutputInfo *enum_output_info, *output_info = NULL;
811 RROutput *outputs;
812 INT crtc_count, output_count;
813 INT primary_adapter = 0;
814 INT adapter_count = 0;
815 BOOL mirrored, detached;
816 RECT primary_rect;
817 BOOL ret = FALSE;
818 INT i, j;
820 screen_resources = xrandr_get_screen_resources();
821 if (!screen_resources)
822 goto done;
824 if (gpu_id)
826 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id );
827 if (!provider_info)
828 goto done;
830 crtc_count = provider_info->ncrtcs;
831 output_count = provider_info->noutputs;
832 outputs = provider_info->outputs;
834 /* Fake provider id, search adapters in screen resources */
835 else
837 crtc_count = screen_resources->ncrtc;
838 output_count = screen_resources->noutput;
839 outputs = screen_resources->outputs;
842 /* Actual adapter count could be less */
843 adapters = heap_calloc( crtc_count, sizeof(*adapters) );
844 if (!adapters)
845 goto done;
847 primary_rect = get_primary_rect( screen_resources );
848 for (i = 0; i < output_count; ++i)
850 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, outputs[i] );
851 if (!output_info)
852 goto done;
854 /* Only connected output are considered as monitors */
855 if (output_info->connection != RR_Connected)
857 pXRRFreeOutputInfo( output_info );
858 output_info = NULL;
859 continue;
862 /* Connected output doesn't mean the output is attached to a crtc */
863 detached = FALSE;
864 if (output_info->crtc)
866 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
867 if (!crtc_info)
868 goto done;
871 if (!output_info->crtc || !crtc_info->mode)
872 detached = TRUE;
874 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
875 mirrored = FALSE;
876 if (!detached)
878 for (j = 0; j < screen_resources->noutput; ++j)
880 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[j] );
881 if (!enum_output_info)
882 continue;
884 if (enum_output_info->connection != RR_Connected || !enum_output_info->crtc)
886 pXRRFreeOutputInfo( enum_output_info );
887 continue;
890 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
891 pXRRFreeOutputInfo( enum_output_info );
892 if (!enum_crtc_info)
893 continue;
895 /* Some outputs may have the same coordinates, aka mirrored. Choose the output with
896 * the lowest value as primary and the rest will then be replicas in a mirroring set */
897 if (crtc_info->x == enum_crtc_info->x &&
898 crtc_info->y == enum_crtc_info->y &&
899 crtc_info->width == enum_crtc_info->width &&
900 crtc_info->height == enum_crtc_info->height &&
901 outputs[i] > screen_resources->outputs[j])
903 mirrored = TRUE;
904 pXRRFreeCrtcInfo( enum_crtc_info );
905 break;
908 pXRRFreeCrtcInfo( enum_crtc_info );
912 if (!mirrored || detached)
914 /* Use RROutput as adapter id. The reason of not using RRCrtc is that we need to detect inactive but
915 * attached monitors */
916 adapters[adapter_count].id = outputs[i];
917 if (!detached)
918 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
919 if (is_crtc_primary( primary_rect, crtc_info ))
921 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
922 primary_adapter = adapter_count;
925 ++adapter_count;
928 pXRRFreeOutputInfo( output_info );
929 output_info = NULL;
930 if (crtc_info)
932 pXRRFreeCrtcInfo( crtc_info );
933 crtc_info = NULL;
937 /* Make primary adapter the first */
938 if (primary_adapter)
940 struct x11drv_adapter tmp = adapters[0];
941 adapters[0] = adapters[primary_adapter];
942 adapters[primary_adapter] = tmp;
945 *new_adapters = adapters;
946 *count = adapter_count;
947 ret = TRUE;
948 done:
949 if (screen_resources)
950 pXRRFreeScreenResources( screen_resources );
951 if (provider_info)
952 pXRRFreeProviderInfo( provider_info );
953 if (output_info)
954 pXRRFreeOutputInfo( output_info );
955 if (crtc_info)
956 pXRRFreeCrtcInfo( crtc_info );
957 if (!ret)
959 heap_free( adapters );
960 ERR("Failed to get adapters\n");
962 return ret;
965 static void xrandr14_free_adapters( struct x11drv_adapter *adapters )
967 heap_free( adapters );
970 static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor **new_monitors, int *count )
972 static const WCHAR generic_nonpnp_monitorW[] = {
973 'G','e','n','e','r','i','c',' ',
974 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
975 struct x11drv_monitor *realloc_monitors, *monitors = NULL;
976 XRRScreenResources *screen_resources = NULL;
977 XRROutputInfo *output_info = NULL, *enum_output_info = NULL;
978 XRRCrtcInfo *crtc_info = NULL, *enum_crtc_info;
979 INT primary_index = 0, monitor_count = 0, capacity;
980 RECT primary_rect;
981 BOOL ret = FALSE;
982 INT i;
984 screen_resources = xrandr_get_screen_resources();
985 if (!screen_resources)
986 goto done;
988 /* First start with a 2 monitors, should be enough for most cases */
989 capacity = 2;
990 monitors = heap_calloc( capacity, sizeof(*monitors) );
991 if (!monitors)
992 goto done;
994 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, adapter_id );
995 if (!output_info)
996 goto done;
998 if (output_info->crtc)
1000 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1001 if (!crtc_info)
1002 goto done;
1005 /* Inactive but attached monitor, no need to check for mirrored/replica monitors */
1006 if (!output_info->crtc || !crtc_info->mode)
1008 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
1009 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1010 monitor_count = 1;
1012 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
1013 else
1015 primary_rect = get_primary_rect( screen_resources );
1017 for (i = 0; i < screen_resources->noutput; ++i)
1019 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1020 if (!enum_output_info)
1021 goto done;
1023 /* Detached outputs don't count */
1024 if (enum_output_info->connection != RR_Connected)
1026 pXRRFreeOutputInfo( enum_output_info );
1027 enum_output_info = NULL;
1028 continue;
1031 /* Allocate more space if needed */
1032 if (monitor_count >= capacity)
1034 capacity *= 2;
1035 realloc_monitors = heap_realloc( monitors, capacity * sizeof(*monitors) );
1036 if (!realloc_monitors)
1037 goto done;
1038 monitors = realloc_monitors;
1041 if (enum_output_info->crtc)
1043 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
1044 if (!enum_crtc_info)
1045 goto done;
1047 if (enum_crtc_info->x == crtc_info->x &&
1048 enum_crtc_info->y == crtc_info->y &&
1049 enum_crtc_info->width == crtc_info->width &&
1050 enum_crtc_info->height == crtc_info->height)
1052 /* FIXME: Read output EDID property and parse the data to get the correct name */
1053 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
1055 SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y,
1056 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
1057 monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor );
1059 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1060 if (!IsRectEmpty( &monitors[monitor_count].rc_monitor ))
1061 monitors[monitor_count].state_flags |= DISPLAY_DEVICE_ACTIVE;
1063 if (is_crtc_primary( primary_rect, crtc_info ))
1064 primary_index = monitor_count;
1065 monitor_count++;
1068 pXRRFreeCrtcInfo( enum_crtc_info );
1071 pXRRFreeOutputInfo( enum_output_info );
1072 enum_output_info = NULL;
1075 /* Make sure the first monitor is the primary */
1076 if (primary_index)
1078 struct x11drv_monitor tmp = monitors[0];
1079 monitors[0] = monitors[primary_index];
1080 monitors[primary_index] = tmp;
1083 /* Make sure the primary monitor origin is at (0, 0) */
1084 for (i = 0; i < monitor_count; i++)
1086 OffsetRect( &monitors[i].rc_monitor, -primary_rect.left, -primary_rect.top );
1087 OffsetRect( &monitors[i].rc_work, -primary_rect.left, -primary_rect.top );
1091 *new_monitors = monitors;
1092 *count = monitor_count;
1093 ret = TRUE;
1094 done:
1095 if (screen_resources)
1096 pXRRFreeScreenResources( screen_resources );
1097 if (output_info)
1098 pXRRFreeOutputInfo( output_info);
1099 if (crtc_info)
1100 pXRRFreeCrtcInfo( crtc_info );
1101 if (enum_output_info)
1102 pXRRFreeOutputInfo( enum_output_info );
1103 if (!ret)
1105 heap_free( monitors );
1106 ERR("Failed to get monitors\n");
1108 return ret;
1111 static void xrandr14_free_monitors( struct x11drv_monitor *monitors )
1113 heap_free( monitors );
1116 static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
1118 if (hwnd == GetDesktopWindow() && GetWindowThreadProcessId( hwnd, NULL ) == GetCurrentThreadId())
1120 /* Don't send a WM_DISPLAYCHANGE message here because this event may be a result from
1121 * ChangeDisplaySettings(). Otherwise, ChangeDisplaySettings() would send multiple
1122 * WM_DISPLAYCHANGE messages instead of just one */
1123 X11DRV_DisplayDevices_Update( FALSE );
1125 init_registry_display_settings();
1127 return FALSE;
1130 static void xrandr14_register_event_handlers(void)
1132 Display *display = thread_init_display();
1133 int event_base, error_base;
1135 if (!pXRRQueryExtension( display, &event_base, &error_base ))
1136 return;
1138 pXRRSelectInput( display, root_window,
1139 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RRProviderChangeNotifyMask );
1140 X11DRV_register_event_handler( event_base + RRNotify_CrtcChange, xrandr14_device_change_handler,
1141 "XRandR CrtcChange" );
1142 X11DRV_register_event_handler( event_base + RRNotify_OutputChange, xrandr14_device_change_handler,
1143 "XRandR OutputChange" );
1144 X11DRV_register_event_handler( event_base + RRNotify_ProviderChange, xrandr14_device_change_handler,
1145 "XRandR ProviderChange" );
1148 /* XRandR 1.4 display settings handler */
1149 static BOOL xrandr14_get_id( const WCHAR *device_name, ULONG_PTR *id )
1151 INT gpu_count, adapter_count, display_count = 0;
1152 INT gpu_idx, adapter_idx, display_idx;
1153 struct x11drv_adapter *adapters;
1154 struct x11drv_gpu *gpus;
1155 WCHAR *end;
1157 /* Parse \\.\DISPLAY%d */
1158 display_idx = strtolW( device_name + 11, &end, 10 ) - 1;
1159 if (*end)
1160 return FALSE;
1162 if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE ))
1163 return FALSE;
1165 for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx)
1167 if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count ))
1169 xrandr14_free_gpus( gpus );
1170 return FALSE;
1173 adapter_idx = display_idx - display_count;
1174 if (adapter_idx < adapter_count)
1176 *id = adapters[adapter_idx].id;
1177 xrandr14_free_adapters( adapters );
1178 xrandr14_free_gpus( gpus );
1179 return TRUE;
1182 display_count += adapter_count;
1183 xrandr14_free_adapters( adapters );
1185 xrandr14_free_gpus( gpus );
1186 return FALSE;
1189 static void add_xrandr14_mode( DEVMODEW *mode, XRRModeInfo *info, DWORD depth, DWORD frequency,
1190 DWORD orientation )
1192 mode->dmSize = sizeof(*mode);
1193 mode->dmDriverExtra = sizeof(RRMode);
1194 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
1195 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
1196 if (frequency)
1198 mode->dmFields |= DM_DISPLAYFREQUENCY;
1199 mode->dmDisplayFrequency = frequency;
1201 if (orientation == DMDO_DEFAULT || orientation == DMDO_180)
1203 mode->dmPelsWidth = info->width;
1204 mode->dmPelsHeight = info->height;
1206 else
1208 mode->dmPelsWidth = info->height;
1209 mode->dmPelsHeight = info->width;
1211 mode->u1.s2.dmDisplayOrientation = orientation;
1212 mode->dmBitsPerPel = depth;
1213 mode->u2.dmDisplayFlags = 0;
1214 memcpy( (BYTE *)mode + sizeof(*mode), &info->id, sizeof(info->id) );
1217 static BOOL xrandr14_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count )
1219 DWORD frequency, orientation, orientation_count;
1220 XRRScreenResources *screen_resources;
1221 XRROutputInfo *output_info = NULL;
1222 RROutput output = (RROutput)id;
1223 XRRCrtcInfo *crtc_info = NULL;
1224 UINT depth_idx, mode_idx = 0;
1225 XRRModeInfo *mode_info;
1226 DEVMODEW *mode, *modes;
1227 Rotation rotations;
1228 BOOL ret = FALSE;
1229 RRCrtc crtc;
1230 INT i, j;
1232 screen_resources = xrandr_get_screen_resources();
1233 if (!screen_resources)
1234 goto done;
1236 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1237 if (!output_info)
1238 goto done;
1240 if (output_info->connection != RR_Connected)
1242 ret = TRUE;
1243 *new_modes = NULL;
1244 *mode_count = 0;
1245 goto done;
1248 crtc = output_info->crtc;
1249 if (!crtc)
1250 crtc = get_output_free_crtc( screen_resources, output_info );
1251 if (crtc)
1252 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1254 /* If the output is connected to a CRTC, use rotations reported by the CRTC */
1255 if (crtc_info)
1257 if (flags & EDS_ROTATEDMODE)
1259 rotations = crtc_info->rotations;
1261 else
1263 /* According to the RandR spec, RRGetCrtcInfo should set the active rotation to Rotate_0
1264 * when a CRTC is disabled. However, some RandR implementations report 0 in this case */
1265 rotations = (crtc_info->rotation & 0xf) ? crtc_info->rotation : RR_Rotate_0;
1268 /* Not connected to CRTC, assume all rotations are supported */
1269 else
1271 if (flags & EDS_ROTATEDMODE)
1273 rotations = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
1275 else
1277 rotations = RR_Rotate_0;
1280 orientation_count = get_orientation_count( rotations );
1282 /* Allocate space for display modes in different color depths and orientations.
1283 * Store a RRMode at the end of each DEVMODEW as private driver data */
1284 modes = heap_calloc( output_info->nmode * DEPTH_COUNT * orientation_count,
1285 sizeof(*modes) + sizeof(RRMode) );
1286 if (!modes)
1287 goto done;
1289 for (i = 0; i < output_info->nmode; ++i)
1291 for (j = 0; j < screen_resources->nmode; ++j)
1293 if (output_info->modes[i] != screen_resources->modes[j].id)
1294 continue;
1296 mode_info = &screen_resources->modes[j];
1297 frequency = get_frequency( mode_info );
1299 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
1301 for (orientation = DMDO_DEFAULT; orientation <= DMDO_270; ++orientation)
1303 if (!((1 << orientation) & rotations))
1304 continue;
1306 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*modes) + sizeof(RRMode)) * mode_idx);
1307 add_xrandr14_mode( mode, mode_info, depths[depth_idx], frequency, orientation );
1308 ++mode_idx;
1312 break;
1316 ret = TRUE;
1317 *new_modes = modes;
1318 *mode_count = mode_idx;
1319 done:
1320 if (crtc_info)
1321 pXRRFreeCrtcInfo( crtc_info );
1322 if (output_info)
1323 pXRRFreeOutputInfo( output_info );
1324 if (screen_resources)
1325 pXRRFreeScreenResources( screen_resources );
1326 return ret;
1329 static void xrandr14_free_modes( DEVMODEW *modes )
1331 heap_free( modes );
1334 static BOOL xrandr14_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
1336 XRRScreenResources *screen_resources;
1337 XRROutputInfo *output_info = NULL;
1338 RROutput output = (RROutput)id;
1339 XRRModeInfo *mode_info = NULL;
1340 XRRCrtcInfo *crtc_info = NULL;
1341 BOOL ret = FALSE;
1342 RECT primary;
1343 INT mode_idx;
1345 screen_resources = xrandr_get_screen_resources();
1346 if (!screen_resources)
1347 goto done;
1349 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1350 if (!output_info)
1351 goto done;
1353 if (output_info->crtc)
1355 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1356 if (!crtc_info)
1357 goto done;
1360 /* Detached */
1361 if (output_info->connection != RR_Connected || !output_info->crtc || !crtc_info->mode)
1363 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1364 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1365 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
1366 mode->dmBitsPerPel = 0;
1367 mode->dmPelsWidth = 0;
1368 mode->dmPelsHeight = 0;
1369 mode->u2.dmDisplayFlags = 0;
1370 mode->dmDisplayFrequency = 0;
1371 mode->u1.s2.dmPosition.x = 0;
1372 mode->u1.s2.dmPosition.y = 0;
1373 ret = TRUE;
1374 goto done;
1377 /* Attached */
1378 for (mode_idx = 0; mode_idx < screen_resources->nmode; ++mode_idx)
1380 if (crtc_info->mode == screen_resources->modes[mode_idx].id)
1382 mode_info = &screen_resources->modes[mode_idx];
1383 break;
1387 if (!mode_info)
1388 goto done;
1390 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1391 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1392 mode->u1.s2.dmDisplayOrientation = get_orientation( crtc_info->rotation );
1393 mode->dmBitsPerPel = screen_bpp;
1394 mode->dmPelsWidth = crtc_info->width;
1395 mode->dmPelsHeight = crtc_info->height;
1396 mode->u2.dmDisplayFlags = 0;
1397 mode->dmDisplayFrequency = get_frequency( mode_info );
1398 /* Convert RandR coordinates to virtual screen coordinates */
1399 primary = get_primary_rect( screen_resources );
1400 mode->u1.s2.dmPosition.x = crtc_info->x - primary.left;
1401 mode->u1.s2.dmPosition.y = crtc_info->y - primary.top;
1402 ret = TRUE;
1403 done:
1404 if (crtc_info)
1405 pXRRFreeCrtcInfo( crtc_info );
1406 if (output_info)
1407 pXRRFreeOutputInfo( output_info );
1408 if (screen_resources)
1409 pXRRFreeScreenResources( screen_resources );
1410 return ret;
1413 static LONG xrandr14_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
1415 unsigned int screen_width, screen_height;
1416 RROutput output = (RROutput)id, *outputs;
1417 XRRScreenResources *screen_resources;
1418 XRROutputInfo *output_info = NULL;
1419 XRRCrtcInfo *crtc_info = NULL;
1420 LONG ret = DISP_CHANGE_FAILED;
1421 Rotation rotation;
1422 INT output_count;
1423 RRCrtc crtc = 0;
1424 Status status;
1425 RRMode rrmode;
1427 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
1428 WARN("Cannot change screen color depth from %ubits to %ubits!\n", screen_bpp, mode->dmBitsPerPel);
1430 screen_resources = xrandr_get_screen_resources();
1431 if (!screen_resources)
1432 return ret;
1434 XGrabServer( gdi_display );
1436 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1437 if (!output_info || output_info->connection != RR_Connected)
1438 goto done;
1440 if (is_detached_mode(mode))
1442 /* Already detached */
1443 if (!output_info->crtc)
1445 ret = DISP_CHANGE_SUCCESSFUL;
1446 goto done;
1449 /* Execute detach operation */
1450 status = pXRRSetCrtcConfig( gdi_display, screen_resources, output_info->crtc,
1451 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0 );
1452 if (status == RRSetConfigSuccess)
1454 get_screen_size( screen_resources, &screen_width, &screen_height );
1455 set_screen_size( screen_width, screen_height );
1456 ret = DISP_CHANGE_SUCCESSFUL;
1458 goto done;
1461 /* Attached */
1462 if (output_info->crtc)
1464 crtc = output_info->crtc;
1466 /* Detached, need to find a free CRTC */
1467 else
1469 if (!(crtc = get_output_free_crtc( screen_resources, output_info )))
1470 goto done;
1473 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1474 if (!crtc_info)
1475 goto done;
1477 assert( mode->dmDriverExtra == sizeof(RRMode) );
1478 memcpy( &rrmode, (BYTE *)mode + sizeof(*mode), sizeof(rrmode) );
1480 if (crtc_info->noutput)
1482 outputs = crtc_info->outputs;
1483 output_count = crtc_info->noutput;
1485 else
1487 outputs = &output;
1488 output_count = 1;
1490 rotation = get_rotation( mode->u1.s2.dmDisplayOrientation );
1492 /* According to the RandR spec, the entire CRTC must fit inside the screen.
1493 * Since we use the union of all enabled CRTCs to determine the necessary
1494 * screen size, this might involve shrinking the screen, so we must disable
1495 * the CRTC in question first. */
1496 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime, 0, 0, None,
1497 RR_Rotate_0, NULL, 0 );
1498 if (status != RRSetConfigSuccess)
1499 goto done;
1501 get_screen_size( screen_resources, &screen_width, &screen_height );
1502 screen_width = max( screen_width, mode->u1.s2.dmPosition.x + mode->dmPelsWidth );
1503 screen_height = max( screen_height, mode->u1.s2.dmPosition.y + mode->dmPelsHeight );
1504 set_screen_size( screen_width, screen_height );
1506 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
1507 mode->u1.s2.dmPosition.x, mode->u1.s2.dmPosition.y, rrmode,
1508 rotation, outputs, output_count );
1509 if (status == RRSetConfigSuccess)
1510 ret = DISP_CHANGE_SUCCESSFUL;
1512 done:
1513 XUngrabServer( gdi_display );
1514 XFlush( gdi_display );
1515 if (crtc_info)
1516 pXRRFreeCrtcInfo( crtc_info );
1517 if (output_info)
1518 pXRRFreeOutputInfo( output_info );
1519 pXRRFreeScreenResources( screen_resources );
1520 return ret;
1523 #endif
1525 void X11DRV_XRandR_Init(void)
1527 struct x11drv_display_device_handler display_handler;
1528 struct x11drv_settings_handler settings_handler;
1529 int event_base, error_base, minor, ret;
1530 static int major;
1531 Bool ok;
1533 if (major) return; /* already initialized? */
1534 if (!usexrandr) return; /* disabled in config */
1535 if (is_virtual_desktop()) return;
1536 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
1538 /* see if Xrandr is available */
1539 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
1540 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
1541 ok = pXRRQueryVersion( gdi_display, &major, &minor );
1542 if (X11DRV_check_error() || !ok) return;
1544 TRACE("Found XRandR %d.%d.\n", major, minor);
1546 settings_handler.name = "XRandR 1.0";
1547 settings_handler.priority = 200;
1548 settings_handler.get_id = xrandr10_get_id;
1549 settings_handler.get_modes = xrandr10_get_modes;
1550 settings_handler.free_modes = xrandr10_free_modes;
1551 settings_handler.get_current_mode = xrandr10_get_current_mode;
1552 settings_handler.set_current_mode = xrandr10_set_current_mode;
1553 X11DRV_Settings_SetHandler( &settings_handler );
1555 #ifdef HAVE_XRRGETPROVIDERRESOURCES
1556 if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))
1558 XRRScreenResources *screen_resources;
1559 XRROutputInfo *output_info;
1560 BOOL found_output = FALSE;
1561 INT i;
1563 screen_resources = xrandr_get_screen_resources();
1564 if (!screen_resources)
1565 return;
1567 for (i = 0; i < screen_resources->noutput; ++i)
1569 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1570 if (!output_info)
1571 continue;
1573 if (output_info->connection == RR_Connected)
1575 pXRRFreeOutputInfo( output_info );
1576 found_output = TRUE;
1577 break;
1580 pXRRFreeOutputInfo( output_info );
1582 pXRRFreeScreenResources( screen_resources );
1584 if (!found_output)
1586 WARN("No connected outputs found.\n");
1587 return;
1590 display_handler.name = "XRandR 1.4";
1591 display_handler.priority = 200;
1592 display_handler.get_gpus = xrandr14_get_gpus;
1593 display_handler.get_adapters = xrandr14_get_adapters;
1594 display_handler.get_monitors = xrandr14_get_monitors;
1595 display_handler.free_gpus = xrandr14_free_gpus;
1596 display_handler.free_adapters = xrandr14_free_adapters;
1597 display_handler.free_monitors = xrandr14_free_monitors;
1598 display_handler.register_event_handlers = xrandr14_register_event_handlers;
1599 X11DRV_DisplayDevices_SetHandler( &display_handler );
1601 if (is_broken_driver())
1602 return;
1604 settings_handler.name = "XRandR 1.4";
1605 settings_handler.priority = 300;
1606 settings_handler.get_id = xrandr14_get_id;
1607 settings_handler.get_modes = xrandr14_get_modes;
1608 settings_handler.free_modes = xrandr14_free_modes;
1609 settings_handler.get_current_mode = xrandr14_get_current_mode;
1610 settings_handler.set_current_mode = xrandr14_set_current_mode;
1611 X11DRV_Settings_SetHandler( &settings_handler );
1613 #endif
1616 #else /* SONAME_LIBXRANDR */
1618 void X11DRV_XRandR_Init(void)
1620 TRACE("XRandR support not compiled in.\n");
1623 #endif /* SONAME_LIBXRANDR */