sapi: Implement ISpRegDataKey CreateKey.
[wine.git] / dlls / winex11.drv / xrandr.c
blobc7f922b1aaebc0bf751c039792e16bc8d4023e8c
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 #define NONAMELESSSTRUCT
30 #define NONAMELESSUNION
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
35 #ifdef HAVE_XRRGETPROVIDERRESOURCES
36 WINE_DECLARE_DEBUG_CHANNEL(winediag);
37 #endif
39 #ifdef SONAME_LIBXRANDR
41 #include <assert.h>
42 #include <X11/Xlib.h>
43 #include <X11/extensions/Xrandr.h>
44 #include <dlfcn.h>
45 #include "x11drv.h"
47 #define VK_NO_PROTOTYPES
48 #define WINE_VK_HOST
50 #include "wine/vulkan.h"
51 #include "wine/vulkan_driver.h"
53 static void *xrandr_handle;
55 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
56 MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
57 MAKE_FUNCPTR(XRRConfigCurrentRate)
58 MAKE_FUNCPTR(XRRFreeScreenConfigInfo)
59 MAKE_FUNCPTR(XRRGetScreenInfo)
60 MAKE_FUNCPTR(XRRQueryExtension)
61 MAKE_FUNCPTR(XRRQueryVersion)
62 MAKE_FUNCPTR(XRRRates)
63 MAKE_FUNCPTR(XRRSetScreenConfig)
64 MAKE_FUNCPTR(XRRSetScreenConfigAndRate)
65 MAKE_FUNCPTR(XRRSizes)
67 #ifdef HAVE_XRRGETPROVIDERRESOURCES
68 MAKE_FUNCPTR(XRRFreeCrtcInfo)
69 MAKE_FUNCPTR(XRRFreeOutputInfo)
70 MAKE_FUNCPTR(XRRFreeScreenResources)
71 MAKE_FUNCPTR(XRRGetCrtcInfo)
72 MAKE_FUNCPTR(XRRGetOutputInfo)
73 MAKE_FUNCPTR(XRRGetOutputProperty)
74 MAKE_FUNCPTR(XRRGetScreenResources)
75 MAKE_FUNCPTR(XRRGetScreenResourcesCurrent)
76 MAKE_FUNCPTR(XRRGetScreenSizeRange)
77 MAKE_FUNCPTR(XRRSetCrtcConfig)
78 MAKE_FUNCPTR(XRRSetScreenSize)
79 MAKE_FUNCPTR(XRRSelectInput)
80 MAKE_FUNCPTR(XRRGetOutputPrimary)
81 MAKE_FUNCPTR(XRRGetProviderResources)
82 MAKE_FUNCPTR(XRRFreeProviderResources)
83 MAKE_FUNCPTR(XRRGetProviderInfo)
84 MAKE_FUNCPTR(XRRFreeProviderInfo)
85 #endif
87 #undef MAKE_FUNCPTR
89 static int load_xrandr(void)
91 int r = 0;
93 if (dlopen(SONAME_LIBXRENDER, RTLD_NOW|RTLD_GLOBAL) &&
94 (xrandr_handle = dlopen(SONAME_LIBXRANDR, RTLD_NOW)))
97 #define LOAD_FUNCPTR(f) \
98 if((p##f = dlsym(xrandr_handle, #f)) == NULL) goto sym_not_found
100 LOAD_FUNCPTR(XRRConfigCurrentConfiguration);
101 LOAD_FUNCPTR(XRRConfigCurrentRate);
102 LOAD_FUNCPTR(XRRFreeScreenConfigInfo);
103 LOAD_FUNCPTR(XRRGetScreenInfo);
104 LOAD_FUNCPTR(XRRQueryExtension);
105 LOAD_FUNCPTR(XRRQueryVersion);
106 LOAD_FUNCPTR(XRRRates);
107 LOAD_FUNCPTR(XRRSetScreenConfig);
108 LOAD_FUNCPTR(XRRSetScreenConfigAndRate);
109 LOAD_FUNCPTR(XRRSizes);
110 r = 1;
112 #ifdef HAVE_XRRGETPROVIDERRESOURCES
113 LOAD_FUNCPTR(XRRFreeCrtcInfo);
114 LOAD_FUNCPTR(XRRFreeOutputInfo);
115 LOAD_FUNCPTR(XRRFreeScreenResources);
116 LOAD_FUNCPTR(XRRGetCrtcInfo);
117 LOAD_FUNCPTR(XRRGetOutputInfo);
118 LOAD_FUNCPTR(XRRGetOutputProperty);
119 LOAD_FUNCPTR(XRRGetScreenResources);
120 LOAD_FUNCPTR(XRRGetScreenResourcesCurrent);
121 LOAD_FUNCPTR(XRRGetScreenSizeRange);
122 LOAD_FUNCPTR(XRRSetCrtcConfig);
123 LOAD_FUNCPTR(XRRSetScreenSize);
124 LOAD_FUNCPTR(XRRSelectInput);
125 LOAD_FUNCPTR(XRRGetOutputPrimary);
126 LOAD_FUNCPTR(XRRGetProviderResources);
127 LOAD_FUNCPTR(XRRFreeProviderResources);
128 LOAD_FUNCPTR(XRRGetProviderInfo);
129 LOAD_FUNCPTR(XRRFreeProviderInfo);
130 r = 4;
131 #endif
133 #undef LOAD_FUNCPTR
135 sym_not_found:
136 if (!r) TRACE("Unable to load function ptrs from XRandR library\n");
138 return r;
141 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
143 return 1;
146 /* XRandR 1.0 display settings handler */
147 static BOOL xrandr10_get_id( const WCHAR *device_name, ULONG_PTR *id )
149 WCHAR primary_adapter[CCHDEVICENAME];
151 if (!get_primary_adapter( primary_adapter ))
152 return FALSE;
154 /* RandR 1.0 only supports changing the primary adapter settings.
155 * For non-primary adapters, an id is still provided but getting
156 * and changing non-primary adapters' settings will be ignored. */
157 *id = !wcsicmp( device_name, primary_adapter ) ? 1 : 0;
158 return TRUE;
161 static void add_xrandr10_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height,
162 DWORD frequency, SizeID size_id )
164 mode->dmSize = sizeof(*mode);
165 mode->dmDriverExtra = sizeof(SizeID);
166 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
167 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
168 if (frequency)
170 mode->dmFields |= DM_DISPLAYFREQUENCY;
171 mode->dmDisplayFrequency = frequency;
173 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
174 mode->dmBitsPerPel = depth;
175 mode->dmPelsWidth = width;
176 mode->dmPelsHeight = height;
177 mode->u2.dmDisplayFlags = 0;
178 memcpy( (BYTE *)mode + sizeof(*mode), &size_id, sizeof(size_id) );
181 static BOOL xrandr10_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *new_mode_count )
183 INT size_idx, depth_idx, rate_idx, mode_idx = 0;
184 INT size_count, rate_count, mode_count = 0;
185 DEVMODEW *modes, *mode;
186 XRRScreenSize *sizes;
187 short *rates;
189 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
190 if (size_count <= 0)
191 return FALSE;
193 for (size_idx = 0; size_idx < size_count; ++size_idx)
195 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
196 if (rate_count)
197 mode_count += rate_count;
198 else
199 ++mode_count;
202 /* Allocate space for reported modes in three depths, and put an SizeID at the end of DEVMODEW as
203 * driver private data */
204 modes = calloc( mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID) );
205 if (!modes)
207 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY );
208 return FALSE;
211 for (size_idx = 0; size_idx < size_count; ++size_idx)
213 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
215 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
216 if (!rate_count)
218 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
219 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
220 sizes[size_idx].height, 0, size_idx );
221 continue;
224 for (rate_idx = 0; rate_idx < rate_count; ++rate_idx)
226 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
227 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
228 sizes[size_idx].height, rates[rate_idx], size_idx );
233 *new_modes = modes;
234 *new_mode_count = mode_idx;
235 return TRUE;
238 static void xrandr10_free_modes( DEVMODEW *modes )
240 free( modes );
243 static BOOL xrandr10_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
245 XRRScreenConfiguration *screen_config;
246 XRRScreenSize *sizes;
247 Rotation rotation;
248 SizeID size_id;
249 INT size_count;
250 short rate;
252 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
253 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
254 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
255 mode->u2.dmDisplayFlags = 0;
256 mode->u1.s2.dmPosition.x = 0;
257 mode->u1.s2.dmPosition.y = 0;
259 if (id != 1)
261 FIXME("Non-primary adapters are unsupported.\n");
262 mode->dmBitsPerPel = 0;
263 mode->dmPelsWidth = 0;
264 mode->dmPelsHeight = 0;
265 mode->dmDisplayFrequency = 0;
266 return TRUE;
269 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
270 if (size_count <= 0)
271 return FALSE;
273 screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) );
274 size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation );
275 rate = pXRRConfigCurrentRate( screen_config );
276 pXRRFreeScreenConfigInfo( screen_config );
278 mode->dmBitsPerPel = screen_bpp;
279 mode->dmPelsWidth = sizes[size_id].width;
280 mode->dmPelsHeight = sizes[size_id].height;
281 mode->dmDisplayFrequency = rate;
282 return TRUE;
285 static LONG xrandr10_set_current_mode( ULONG_PTR id, const DEVMODEW *mode )
287 XRRScreenConfiguration *screen_config;
288 Rotation rotation;
289 SizeID size_id;
290 Window root;
291 Status stat;
293 if (id != 1)
295 FIXME("Non-primary adapters are unsupported.\n");
296 return DISP_CHANGE_SUCCESSFUL;
299 if (is_detached_mode(mode))
301 FIXME("Detaching adapters is unsupported.\n");
302 return DISP_CHANGE_SUCCESSFUL;
305 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
306 WARN("Cannot change screen bit depth from %dbits to %dbits!\n", screen_bpp, mode->dmBitsPerPel);
308 root = DefaultRootWindow( gdi_display );
309 screen_config = pXRRGetScreenInfo( gdi_display, root );
310 pXRRConfigCurrentConfiguration( screen_config, &rotation );
312 assert( mode->dmDriverExtra == sizeof(SizeID) );
313 memcpy( &size_id, (BYTE *)mode + sizeof(*mode), sizeof(size_id) );
315 if (mode->dmFields & DM_DISPLAYFREQUENCY && mode->dmDisplayFrequency)
316 stat = pXRRSetScreenConfigAndRate( gdi_display, screen_config, root, size_id, rotation,
317 mode->dmDisplayFrequency, CurrentTime );
318 else
319 stat = pXRRSetScreenConfig( gdi_display, screen_config, root, size_id, rotation, CurrentTime );
320 pXRRFreeScreenConfigInfo( screen_config );
322 if (stat != RRSetConfigSuccess)
323 return DISP_CHANGE_FAILED;
325 XFlush( gdi_display );
326 return DISP_CHANGE_SUCCESSFUL;
329 #ifdef HAVE_XRRGETPROVIDERRESOURCES
331 static struct current_mode
333 ULONG_PTR id;
334 BOOL loaded;
335 DEVMODEW mode;
336 } *current_modes;
337 static int current_mode_count;
339 static pthread_mutex_t xrandr_mutex = PTHREAD_MUTEX_INITIALIZER;
341 static void xrandr14_invalidate_current_mode_cache(void)
343 pthread_mutex_lock( &xrandr_mutex );
344 free( current_modes);
345 current_modes = NULL;
346 current_mode_count = 0;
347 pthread_mutex_unlock( &xrandr_mutex );
350 static XRRScreenResources *xrandr_get_screen_resources(void)
352 XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window );
353 if (resources && !resources->ncrtc)
355 pXRRFreeScreenResources( resources );
356 resources = pXRRGetScreenResources( gdi_display, root_window );
359 if (!resources)
360 ERR("Failed to get screen resources.\n");
361 return resources;
364 /* Some (304.64, possibly earlier) versions of the NVIDIA driver only
365 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
366 * are only listed through RandR 1.0 / 1.1. This is completely useless,
367 * but NVIDIA considers this a feature, so it's unlikely to change. The
368 * best we can do is to fall back to RandR 1.0 and encourage users to
369 * consider more cooperative driver vendors when we detect such a
370 * configuration. */
371 static BOOL is_broken_driver(void)
373 XRRScreenResources *screen_resources;
374 XRROutputInfo *output_info;
375 XRRModeInfo *first_mode;
376 INT major, event, error;
377 INT output_idx, i, j;
378 BOOL only_one_mode;
380 screen_resources = xrandr_get_screen_resources();
381 if (!screen_resources)
382 return TRUE;
384 /* Check if any output only has one native mode */
385 for (output_idx = 0; output_idx < screen_resources->noutput; ++output_idx)
387 output_info = pXRRGetOutputInfo( gdi_display, screen_resources,
388 screen_resources->outputs[output_idx] );
389 if (!output_info)
390 continue;
392 if (output_info->connection != RR_Connected)
394 pXRRFreeOutputInfo( output_info );
395 continue;
398 first_mode = NULL;
399 only_one_mode = TRUE;
400 for (i = 0; i < output_info->nmode; ++i)
402 for (j = 0; j < screen_resources->nmode; ++j)
404 if (output_info->modes[i] != screen_resources->modes[j].id)
405 continue;
407 if (!first_mode)
409 first_mode = &screen_resources->modes[j];
410 break;
413 if (first_mode->width != screen_resources->modes[j].width ||
414 first_mode->height != screen_resources->modes[j].height)
415 only_one_mode = FALSE;
417 break;
420 if (!only_one_mode)
421 break;
423 pXRRFreeOutputInfo( output_info );
425 if (!only_one_mode)
426 continue;
428 /* Check if it is NVIDIA proprietary driver */
429 if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error ))
431 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
432 "Please consider using the Nouveau driver instead.\n");
433 pXRRFreeScreenResources( screen_resources );
434 return TRUE;
437 pXRRFreeScreenResources( screen_resources );
438 return FALSE;
441 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
443 int min_width = 0, min_height = 0, max_width, max_height;
444 XRRCrtcInfo *crtc_info;
445 int i;
447 pXRRGetScreenSizeRange( gdi_display, root_window, &min_width, &min_height, &max_width, &max_height );
448 *width = min_width;
449 *height = min_height;
451 for (i = 0; i < resources->ncrtc; ++i)
453 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
454 continue;
456 if (crtc_info->mode != None)
458 *width = max(*width, crtc_info->x + crtc_info->width);
459 *height = max(*height, crtc_info->y + crtc_info->height);
462 pXRRFreeCrtcInfo( crtc_info );
466 static unsigned int get_edid( RROutput output, unsigned char **prop )
468 int result, actual_format;
469 unsigned long bytes_after, len;
470 Atom actual_type;
472 result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE,
473 AnyPropertyType, &actual_type, &actual_format, &len,
474 &bytes_after, prop );
476 if (result != Success)
478 WARN("Could not retrieve EDID property for output %#lx.\n", output);
479 *prop = NULL;
480 return 0;
482 return len;
485 static void set_screen_size( int width, int height )
487 int screen = default_visual.screen;
488 int mm_width, mm_height;
490 mm_width = width * DisplayWidthMM( gdi_display, screen ) / DisplayWidth( gdi_display, screen );
491 mm_height = height * DisplayHeightMM( gdi_display, screen ) / DisplayHeight( gdi_display, screen );
492 pXRRSetScreenSize( gdi_display, root_window, width, height, mm_width, mm_height );
495 static unsigned int get_frequency( const XRRModeInfo *mode )
497 unsigned int dots = mode->hTotal * mode->vTotal;
499 if (!dots)
500 return 0;
502 if (mode->modeFlags & RR_DoubleScan)
503 dots *= 2;
504 if (mode->modeFlags & RR_Interlace)
505 dots /= 2;
507 return (mode->dotClock + dots / 2) / dots;
510 static DWORD get_orientation( Rotation rotation )
512 if (rotation & RR_Rotate_270) return DMDO_270;
513 if (rotation & RR_Rotate_180) return DMDO_180;
514 if (rotation & RR_Rotate_90) return DMDO_90;
515 return DMDO_DEFAULT;
518 static DWORD get_orientation_count( Rotation rotations )
520 DWORD count = 0;
522 if (rotations & RR_Rotate_0) ++count;
523 if (rotations & RR_Rotate_90) ++count;
524 if (rotations & RR_Rotate_180) ++count;
525 if (rotations & RR_Rotate_270) ++count;
526 return count;
529 static Rotation get_rotation( DWORD orientation )
531 return (Rotation)(1 << orientation);
534 static RRCrtc get_output_free_crtc( XRRScreenResources *resources, XRROutputInfo *output_info )
536 XRRCrtcInfo *crtc_info;
537 INT crtc_idx;
538 RRCrtc crtc;
540 for (crtc_idx = 0; crtc_idx < output_info->ncrtc; ++crtc_idx)
542 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtcs[crtc_idx] );
543 if (!crtc_info)
544 continue;
546 if (!crtc_info->noutput)
548 crtc = output_info->crtcs[crtc_idx];
549 pXRRFreeCrtcInfo( crtc_info );
550 return crtc;
553 pXRRFreeCrtcInfo( crtc_info );
556 return 0;
559 static RECT get_primary_rect( XRRScreenResources *resources )
561 XRROutputInfo *output_info = NULL;
562 XRRCrtcInfo *crtc_info = NULL;
563 RROutput primary_output;
564 RECT primary_rect = {0};
565 RECT first_rect = {0};
566 INT i;
568 primary_output = pXRRGetOutputPrimary( gdi_display, root_window );
569 if (!primary_output)
570 goto fallback;
572 output_info = pXRRGetOutputInfo( gdi_display, resources, primary_output );
573 if (!output_info || output_info->connection != RR_Connected || !output_info->crtc)
574 goto fallback;
576 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtc );
577 if (!crtc_info || !crtc_info->mode)
578 goto fallback;
580 SetRect( &primary_rect, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
581 pXRRFreeCrtcInfo( crtc_info );
582 pXRRFreeOutputInfo( output_info );
583 return primary_rect;
585 /* Fallback when XRandR primary output is a disconnected output.
586 * Try to find a crtc with (x, y) being (0, 0). If it's found then get the primary rect from that crtc,
587 * otherwise use the first active crtc to get the primary rect */
588 fallback:
589 if (crtc_info)
590 pXRRFreeCrtcInfo( crtc_info );
591 if (output_info)
592 pXRRFreeOutputInfo( output_info );
594 WARN("Primary is set to a disconnected XRandR output.\n");
595 for (i = 0; i < resources->ncrtc; ++i)
597 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
598 if (!crtc_info)
599 continue;
601 if (!crtc_info->mode)
603 pXRRFreeCrtcInfo( crtc_info );
604 continue;
607 if (!crtc_info->x && !crtc_info->y)
609 SetRect( &primary_rect, 0, 0, crtc_info->width, crtc_info->height );
610 pXRRFreeCrtcInfo( crtc_info );
611 break;
614 if (IsRectEmpty( &first_rect ))
615 SetRect( &first_rect, crtc_info->x, crtc_info->y,
616 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
618 pXRRFreeCrtcInfo( crtc_info );
621 return IsRectEmpty( &primary_rect ) ? first_rect : primary_rect;
624 static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
626 return crtc &&
627 crtc->mode &&
628 crtc->x == primary.left &&
629 crtc->y == primary.top &&
630 crtc->x + crtc->width == primary.right &&
631 crtc->y + crtc->height == primary.bottom;
634 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
636 static BOOL get_gpu_properties_from_vulkan( struct gdi_gpu *gpu, const XRRProviderInfo *provider_info,
637 struct gdi_gpu *prev_gpus, int prev_gpu_count )
639 static const char *extensions[] =
641 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
642 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
643 "VK_EXT_acquire_xlib_display",
644 "VK_EXT_direct_mode_display",
645 "VK_KHR_display",
646 VK_KHR_SURFACE_EXTENSION_NAME,
648 const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION );
649 VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
650 PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
651 PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
652 uint32_t device_count, device_idx, output_idx, i;
653 VkPhysicalDevice *vk_physical_devices = NULL;
654 VkPhysicalDeviceProperties2 properties2;
655 VkInstanceCreateInfo create_info;
656 VkPhysicalDeviceIDProperties id;
657 VkInstance vk_instance = NULL;
658 VkDisplayKHR vk_display;
659 DWORD len;
660 BOOL ret = FALSE;
661 VkResult vr;
663 if (!vulkan_funcs)
664 goto done;
666 memset( &create_info, 0, sizeof(create_info) );
667 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
668 create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
669 create_info.ppEnabledExtensionNames = extensions;
671 vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance );
672 if (vr != VK_SUCCESS)
674 WARN("Failed to create a Vulkan instance, vr %d.\n", vr);
675 goto done;
678 #define LOAD_VK_FUNC(f) \
679 if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \
681 WARN("Failed to load " #f ".\n"); \
682 goto done; \
685 LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
686 LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
687 LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
688 #undef LOAD_VK_FUNC
690 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
691 if (vr != VK_SUCCESS || !device_count)
693 WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
694 goto done;
697 if (!(vk_physical_devices = calloc( device_count, sizeof(*vk_physical_devices) )))
698 goto done;
700 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
701 if (vr != VK_SUCCESS)
703 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
704 goto done;
707 TRACE("provider name %s.\n", debugstr_a(provider_info->name));
709 for (device_idx = 0; device_idx < device_count; ++device_idx)
711 for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
713 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
714 vr = pvkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
715 provider_info->outputs[output_idx], &vk_display );
716 XSync( gdi_display, FALSE );
717 if (X11DRV_check_error() || vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
718 continue;
720 memset( &id, 0, sizeof(id) );
721 id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
722 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
723 properties2.pNext = &id;
725 pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
726 for (i = 0; i < prev_gpu_count; ++i)
728 if (!memcmp( &prev_gpus[i].vulkan_uuid, &id.deviceUUID, sizeof(id.deviceUUID) ))
730 WARN( "device UUID %#x:%#x already assigned to GPU %u.\n", *((uint32_t *)id.deviceUUID + 1),
731 *(uint32_t *)id.deviceUUID, i );
732 break;
735 if (i < prev_gpu_count) continue;
737 memcpy( &gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) );
739 /* Ignore Khronos vendor IDs */
740 if (properties2.properties.vendorID < 0x10000)
742 gpu->vendor_id = properties2.properties.vendorID;
743 gpu->device_id = properties2.properties.deviceID;
745 RtlUTF8ToUnicodeN( gpu->name, sizeof(gpu->name), &len, properties2.properties.deviceName,
746 strlen( properties2.properties.deviceName ) + 1 );
747 ret = TRUE;
748 goto done;
752 done:
753 free( vk_physical_devices );
754 if (vk_instance)
755 vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL );
756 return ret;
759 /* Get a list of GPUs reported by XRandR 1.4. Set get_properties to FALSE if GPU properties are
760 * not needed to avoid unnecessary querying */
761 static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_properties )
763 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
764 struct gdi_gpu *gpus = NULL;
765 XRRScreenResources *screen_resources = NULL;
766 XRRProviderResources *provider_resources = NULL;
767 XRRProviderInfo *provider_info = NULL;
768 XRRCrtcInfo *crtc_info = NULL;
769 INT primary_provider = -1;
770 RECT primary_rect;
771 BOOL ret = FALSE;
772 DWORD len;
773 INT i, j;
775 screen_resources = xrandr_get_screen_resources();
776 if (!screen_resources)
777 goto done;
779 provider_resources = pXRRGetProviderResources( gdi_display, root_window );
780 if (!provider_resources)
781 goto done;
783 gpus = calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) );
784 if (!gpus)
785 goto done;
787 /* Some XRandR implementations don't support providers.
788 * In this case, report a fake one to try searching adapters in screen resources */
789 if (!provider_resources->nproviders)
791 WARN("XRandR implementation doesn't report any providers, faking one.\n");
792 lstrcpyW( gpus[0].name, wine_adapterW );
793 *new_gpus = gpus;
794 *count = 1;
795 ret = TRUE;
796 goto done;
799 primary_rect = get_primary_rect( screen_resources );
800 for (i = 0; i < provider_resources->nproviders; ++i)
802 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, provider_resources->providers[i] );
803 if (!provider_info)
804 goto done;
806 /* Find primary provider */
807 for (j = 0; primary_provider == -1 && j < provider_info->ncrtcs; ++j)
809 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, provider_info->crtcs[j] );
810 if (!crtc_info)
811 continue;
813 if (is_crtc_primary( primary_rect, crtc_info ))
815 primary_provider = i;
816 pXRRFreeCrtcInfo( crtc_info );
817 break;
820 pXRRFreeCrtcInfo( crtc_info );
823 gpus[i].id = provider_resources->providers[i];
824 if (get_properties)
826 if (!get_gpu_properties_from_vulkan( &gpus[i], provider_info, gpus, i ))
827 RtlUTF8ToUnicodeN( gpus[i].name, sizeof(gpus[i].name), &len, provider_info->name,
828 strlen( provider_info->name ) + 1 );
829 /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */
831 pXRRFreeProviderInfo( provider_info );
834 /* Make primary GPU the first */
835 if (primary_provider > 0)
837 struct gdi_gpu tmp = gpus[0];
838 gpus[0] = gpus[primary_provider];
839 gpus[primary_provider] = tmp;
842 *new_gpus = gpus;
843 *count = provider_resources->nproviders;
844 ret = TRUE;
845 done:
846 if (provider_resources)
847 pXRRFreeProviderResources( provider_resources );
848 if (screen_resources)
849 pXRRFreeScreenResources( screen_resources );
850 if (!ret)
852 free( gpus );
853 ERR("Failed to get gpus\n");
855 return ret;
858 static BOOL xrandr14_get_gpus( struct gdi_gpu **new_gpus, int *count )
860 return xrandr14_get_gpus2( new_gpus, count, TRUE );
863 static void xrandr14_free_gpus( struct gdi_gpu *gpus )
865 free( gpus );
868 static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_adapters, int *count )
870 struct gdi_adapter *adapters = NULL;
871 XRRScreenResources *screen_resources = NULL;
872 XRRProviderInfo *provider_info = NULL;
873 XRRCrtcInfo *enum_crtc_info, *crtc_info = NULL;
874 XRROutputInfo *enum_output_info, *output_info = NULL;
875 RROutput *outputs;
876 INT crtc_count, output_count;
877 INT primary_adapter = 0;
878 INT adapter_count = 0;
879 BOOL mirrored, detached;
880 RECT primary_rect;
881 BOOL ret = FALSE;
882 INT i, j;
884 screen_resources = xrandr_get_screen_resources();
885 if (!screen_resources)
886 goto done;
888 if (gpu_id)
890 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id );
891 if (!provider_info)
892 goto done;
894 crtc_count = provider_info->ncrtcs;
895 output_count = provider_info->noutputs;
896 outputs = provider_info->outputs;
898 /* Fake provider id, search adapters in screen resources */
899 else
901 crtc_count = screen_resources->ncrtc;
902 output_count = screen_resources->noutput;
903 outputs = screen_resources->outputs;
906 /* Actual adapter count could be less */
907 adapters = calloc( crtc_count, sizeof(*adapters) );
908 if (!adapters)
909 goto done;
911 primary_rect = get_primary_rect( screen_resources );
912 for (i = 0; i < output_count; ++i)
914 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, outputs[i] );
915 if (!output_info)
916 goto done;
918 /* Only connected output are considered as monitors */
919 if (output_info->connection != RR_Connected)
921 pXRRFreeOutputInfo( output_info );
922 output_info = NULL;
923 continue;
926 /* Connected output doesn't mean the output is attached to a crtc */
927 detached = FALSE;
928 if (output_info->crtc)
930 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
931 if (!crtc_info)
932 goto done;
935 if (!output_info->crtc || !crtc_info->mode)
936 detached = TRUE;
938 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
939 mirrored = FALSE;
940 if (!detached)
942 for (j = 0; j < screen_resources->noutput; ++j)
944 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[j] );
945 if (!enum_output_info)
946 continue;
948 if (enum_output_info->connection != RR_Connected || !enum_output_info->crtc)
950 pXRRFreeOutputInfo( enum_output_info );
951 continue;
954 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
955 pXRRFreeOutputInfo( enum_output_info );
956 if (!enum_crtc_info)
957 continue;
959 /* Some outputs may have the same coordinates, aka mirrored. Choose the output with
960 * the lowest value as primary and the rest will then be replicas in a mirroring set */
961 if (crtc_info->x == enum_crtc_info->x &&
962 crtc_info->y == enum_crtc_info->y &&
963 crtc_info->width == enum_crtc_info->width &&
964 crtc_info->height == enum_crtc_info->height &&
965 outputs[i] > screen_resources->outputs[j])
967 mirrored = TRUE;
968 pXRRFreeCrtcInfo( enum_crtc_info );
969 break;
972 pXRRFreeCrtcInfo( enum_crtc_info );
976 if (!mirrored || detached)
978 /* Use RROutput as adapter id. The reason of not using RRCrtc is that we need to detect inactive but
979 * attached monitors */
980 adapters[adapter_count].id = outputs[i];
981 if (!detached)
982 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
983 if (is_crtc_primary( primary_rect, crtc_info ))
985 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
986 primary_adapter = adapter_count;
989 ++adapter_count;
992 pXRRFreeOutputInfo( output_info );
993 output_info = NULL;
994 if (crtc_info)
996 pXRRFreeCrtcInfo( crtc_info );
997 crtc_info = NULL;
1001 /* Make primary adapter the first */
1002 if (primary_adapter)
1004 struct gdi_adapter tmp = adapters[0];
1005 adapters[0] = adapters[primary_adapter];
1006 adapters[primary_adapter] = tmp;
1009 *new_adapters = adapters;
1010 *count = adapter_count;
1011 ret = TRUE;
1012 done:
1013 if (screen_resources)
1014 pXRRFreeScreenResources( screen_resources );
1015 if (provider_info)
1016 pXRRFreeProviderInfo( provider_info );
1017 if (output_info)
1018 pXRRFreeOutputInfo( output_info );
1019 if (crtc_info)
1020 pXRRFreeCrtcInfo( crtc_info );
1021 if (!ret)
1023 free( adapters );
1024 ERR("Failed to get adapters\n");
1026 return ret;
1029 static void xrandr14_free_adapters( struct gdi_adapter *adapters )
1031 free( adapters );
1034 static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count )
1036 static const WCHAR generic_nonpnp_monitorW[] = {
1037 'G','e','n','e','r','i','c',' ',
1038 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
1039 struct gdi_monitor *realloc_monitors, *monitors = NULL;
1040 XRRScreenResources *screen_resources = NULL;
1041 XRROutputInfo *output_info = NULL, *enum_output_info = NULL;
1042 XRRCrtcInfo *crtc_info = NULL, *enum_crtc_info;
1043 INT primary_index = 0, monitor_count = 0, capacity;
1044 RECT primary_rect;
1045 BOOL ret = FALSE;
1046 INT i;
1048 screen_resources = xrandr_get_screen_resources();
1049 if (!screen_resources)
1050 goto done;
1052 /* First start with a 2 monitors, should be enough for most cases */
1053 capacity = 2;
1054 monitors = calloc( capacity, sizeof(*monitors) );
1055 if (!monitors)
1056 goto done;
1058 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, adapter_id );
1059 if (!output_info)
1060 goto done;
1062 if (output_info->crtc)
1064 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1065 if (!crtc_info)
1066 goto done;
1069 /* Inactive but attached monitor, no need to check for mirrored/replica monitors */
1070 if (!output_info->crtc || !crtc_info->mode)
1072 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
1073 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1074 monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid );
1075 monitor_count = 1;
1077 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
1078 else
1080 primary_rect = get_primary_rect( screen_resources );
1082 for (i = 0; i < screen_resources->noutput; ++i)
1084 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1085 if (!enum_output_info)
1086 goto done;
1088 /* Detached outputs don't count */
1089 if (enum_output_info->connection != RR_Connected)
1091 pXRRFreeOutputInfo( enum_output_info );
1092 enum_output_info = NULL;
1093 continue;
1096 /* Allocate more space if needed */
1097 if (monitor_count >= capacity)
1099 capacity *= 2;
1100 realloc_monitors = realloc( monitors, capacity * sizeof(*monitors) );
1101 if (!realloc_monitors)
1102 goto done;
1103 monitors = realloc_monitors;
1106 if (enum_output_info->crtc)
1108 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
1109 if (!enum_crtc_info)
1110 goto done;
1112 if (enum_crtc_info->x == crtc_info->x &&
1113 enum_crtc_info->y == crtc_info->y &&
1114 enum_crtc_info->width == crtc_info->width &&
1115 enum_crtc_info->height == crtc_info->height)
1117 /* FIXME: Read output EDID property and parse the data to get the correct name */
1118 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
1120 SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y,
1121 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
1122 monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor );
1124 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1125 if (!IsRectEmpty( &monitors[monitor_count].rc_monitor ))
1126 monitors[monitor_count].state_flags |= DISPLAY_DEVICE_ACTIVE;
1128 if (is_crtc_primary( primary_rect, crtc_info ))
1129 primary_index = monitor_count;
1131 monitors[monitor_count].edid_len = get_edid( screen_resources->outputs[i],
1132 &monitors[monitor_count].edid );
1133 monitor_count++;
1136 pXRRFreeCrtcInfo( enum_crtc_info );
1139 pXRRFreeOutputInfo( enum_output_info );
1140 enum_output_info = NULL;
1143 /* Make sure the first monitor is the primary */
1144 if (primary_index)
1146 struct gdi_monitor tmp = monitors[0];
1147 monitors[0] = monitors[primary_index];
1148 monitors[primary_index] = tmp;
1151 /* Make sure the primary monitor origin is at (0, 0) */
1152 for (i = 0; i < monitor_count; i++)
1154 OffsetRect( &monitors[i].rc_monitor, -primary_rect.left, -primary_rect.top );
1155 OffsetRect( &monitors[i].rc_work, -primary_rect.left, -primary_rect.top );
1159 *new_monitors = monitors;
1160 *count = monitor_count;
1161 ret = TRUE;
1162 done:
1163 if (screen_resources)
1164 pXRRFreeScreenResources( screen_resources );
1165 if (output_info)
1166 pXRRFreeOutputInfo( output_info);
1167 if (crtc_info)
1168 pXRRFreeCrtcInfo( crtc_info );
1169 if (enum_output_info)
1170 pXRRFreeOutputInfo( enum_output_info );
1171 if (!ret)
1173 for (i = 0; i < monitor_count; i++)
1175 if (monitors[i].edid)
1176 XFree( monitors[i].edid );
1178 free( monitors );
1179 ERR("Failed to get monitors\n");
1181 return ret;
1184 static void xrandr14_free_monitors( struct gdi_monitor *monitors, int count )
1186 int i;
1188 for (i = 0; i < count; i++)
1190 if (monitors[i].edid)
1191 XFree( monitors[i].edid );
1193 free( monitors );
1196 static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
1198 xrandr14_invalidate_current_mode_cache();
1199 if (hwnd == NtUserGetDesktopWindow() && NtUserGetWindowThread( hwnd, NULL ) == GetCurrentThreadId())
1201 X11DRV_DisplayDevices_Init( TRUE );
1202 init_registry_display_settings();
1203 X11DRV_resize_desktop();
1205 return FALSE;
1208 static void xrandr14_register_event_handlers(void)
1210 Display *display = thread_init_display();
1211 int event_base, error_base;
1213 if (!pXRRQueryExtension( display, &event_base, &error_base ))
1214 return;
1216 pXRRSelectInput( display, root_window,
1217 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RRProviderChangeNotifyMask );
1218 X11DRV_register_event_handler( event_base + RRNotify_CrtcChange, xrandr14_device_change_handler,
1219 "XRandR CrtcChange" );
1220 X11DRV_register_event_handler( event_base + RRNotify_OutputChange, xrandr14_device_change_handler,
1221 "XRandR OutputChange" );
1222 X11DRV_register_event_handler( event_base + RRNotify_ProviderChange, xrandr14_device_change_handler,
1223 "XRandR ProviderChange" );
1226 /* XRandR 1.4 display settings handler */
1227 static BOOL xrandr14_get_id( const WCHAR *device_name, ULONG_PTR *id )
1229 struct current_mode *tmp_modes, *new_current_modes = NULL;
1230 INT gpu_count, adapter_count, new_current_mode_count = 0;
1231 INT gpu_idx, adapter_idx, display_idx;
1232 struct gdi_adapter *adapters;
1233 struct gdi_gpu *gpus;
1234 WCHAR *end;
1236 /* Parse \\.\DISPLAY%d */
1237 display_idx = wcstol( device_name + 11, &end, 10 ) - 1;
1238 if (*end)
1239 return FALSE;
1241 /* Update cache */
1242 pthread_mutex_lock( &xrandr_mutex );
1243 if (!current_modes)
1245 if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE ))
1247 pthread_mutex_unlock( &xrandr_mutex );
1248 return FALSE;
1251 for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx)
1253 if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count ))
1254 break;
1256 tmp_modes = realloc( new_current_modes, (new_current_mode_count + adapter_count) * sizeof(*tmp_modes) );
1257 if (!tmp_modes)
1259 xrandr14_free_adapters( adapters );
1260 break;
1262 new_current_modes = tmp_modes;
1264 for (adapter_idx = 0; adapter_idx < adapter_count; ++adapter_idx)
1266 new_current_modes[new_current_mode_count + adapter_idx].id = adapters[adapter_idx].id;
1267 new_current_modes[new_current_mode_count + adapter_idx].loaded = FALSE;
1269 new_current_mode_count += adapter_count;
1270 xrandr14_free_adapters( adapters );
1272 xrandr14_free_gpus( gpus );
1274 if (new_current_modes)
1276 free( current_modes );
1277 current_modes = new_current_modes;
1278 current_mode_count = new_current_mode_count;
1282 if (display_idx >= current_mode_count)
1284 pthread_mutex_unlock( &xrandr_mutex );
1285 return FALSE;
1288 *id = current_modes[display_idx].id;
1289 pthread_mutex_unlock( &xrandr_mutex );
1290 return TRUE;
1293 static void add_xrandr14_mode( DEVMODEW *mode, XRRModeInfo *info, DWORD depth, DWORD frequency,
1294 DWORD orientation )
1296 mode->dmSize = sizeof(*mode);
1297 mode->dmDriverExtra = sizeof(RRMode);
1298 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
1299 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
1300 if (frequency)
1302 mode->dmFields |= DM_DISPLAYFREQUENCY;
1303 mode->dmDisplayFrequency = frequency;
1305 if (orientation == DMDO_DEFAULT || orientation == DMDO_180)
1307 mode->dmPelsWidth = info->width;
1308 mode->dmPelsHeight = info->height;
1310 else
1312 mode->dmPelsWidth = info->height;
1313 mode->dmPelsHeight = info->width;
1315 mode->u1.s2.dmDisplayOrientation = orientation;
1316 mode->dmBitsPerPel = depth;
1317 mode->u2.dmDisplayFlags = 0;
1318 memcpy( (BYTE *)mode + sizeof(*mode), &info->id, sizeof(info->id) );
1321 static BOOL xrandr14_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count )
1323 DWORD frequency, orientation, orientation_count;
1324 XRRScreenResources *screen_resources;
1325 XRROutputInfo *output_info = NULL;
1326 RROutput output = (RROutput)id;
1327 XRRCrtcInfo *crtc_info = NULL;
1328 UINT depth_idx, mode_idx = 0;
1329 XRRModeInfo *mode_info;
1330 DEVMODEW *mode, *modes;
1331 Rotation rotations;
1332 BOOL ret = FALSE;
1333 RRCrtc crtc;
1334 INT i, j;
1336 screen_resources = xrandr_get_screen_resources();
1337 if (!screen_resources)
1338 goto done;
1340 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1341 if (!output_info)
1342 goto done;
1344 if (output_info->connection != RR_Connected)
1346 ret = TRUE;
1347 *new_modes = NULL;
1348 *mode_count = 0;
1349 goto done;
1352 crtc = output_info->crtc;
1353 if (!crtc)
1354 crtc = get_output_free_crtc( screen_resources, output_info );
1355 if (crtc)
1356 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1358 /* If the output is connected to a CRTC, use rotations reported by the CRTC */
1359 if (crtc_info)
1361 if (flags & EDS_ROTATEDMODE)
1363 rotations = crtc_info->rotations;
1365 else
1367 /* According to the RandR spec, RRGetCrtcInfo should set the active rotation to Rotate_0
1368 * when a CRTC is disabled. However, some RandR implementations report 0 in this case */
1369 rotations = (crtc_info->rotation & 0xf) ? crtc_info->rotation : RR_Rotate_0;
1372 /* Not connected to CRTC, assume all rotations are supported */
1373 else
1375 if (flags & EDS_ROTATEDMODE)
1377 rotations = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
1379 else
1381 rotations = RR_Rotate_0;
1384 orientation_count = get_orientation_count( rotations );
1386 /* Allocate space for display modes in different color depths and orientations.
1387 * Store a RRMode at the end of each DEVMODEW as private driver data */
1388 modes = calloc( output_info->nmode * DEPTH_COUNT * orientation_count,
1389 sizeof(*modes) + sizeof(RRMode) );
1390 if (!modes)
1391 goto done;
1393 for (i = 0; i < output_info->nmode; ++i)
1395 for (j = 0; j < screen_resources->nmode; ++j)
1397 if (output_info->modes[i] != screen_resources->modes[j].id)
1398 continue;
1400 mode_info = &screen_resources->modes[j];
1401 frequency = get_frequency( mode_info );
1403 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
1405 for (orientation = DMDO_DEFAULT; orientation <= DMDO_270; ++orientation)
1407 if (!((1 << orientation) & rotations))
1408 continue;
1410 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*modes) + sizeof(RRMode)) * mode_idx);
1411 add_xrandr14_mode( mode, mode_info, depths[depth_idx], frequency, orientation );
1412 ++mode_idx;
1416 break;
1420 ret = TRUE;
1421 *new_modes = modes;
1422 *mode_count = mode_idx;
1423 done:
1424 if (crtc_info)
1425 pXRRFreeCrtcInfo( crtc_info );
1426 if (output_info)
1427 pXRRFreeOutputInfo( output_info );
1428 if (screen_resources)
1429 pXRRFreeScreenResources( screen_resources );
1430 return ret;
1433 static void xrandr14_free_modes( DEVMODEW *modes )
1435 free( modes );
1438 static BOOL xrandr14_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
1440 struct current_mode *mode_ptr = NULL;
1441 XRRScreenResources *screen_resources;
1442 XRROutputInfo *output_info = NULL;
1443 RROutput output = (RROutput)id;
1444 XRRModeInfo *mode_info = NULL;
1445 XRRCrtcInfo *crtc_info = NULL;
1446 BOOL ret = FALSE;
1447 RECT primary;
1448 INT mode_idx;
1450 pthread_mutex_lock( &xrandr_mutex );
1451 for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx)
1453 if (current_modes[mode_idx].id != id)
1454 continue;
1456 if (!current_modes[mode_idx].loaded)
1458 mode_ptr = &current_modes[mode_idx];
1459 break;
1462 memcpy( mode, &current_modes[mode_idx].mode, sizeof(*mode) );
1463 pthread_mutex_unlock( &xrandr_mutex );
1464 return TRUE;
1467 screen_resources = xrandr_get_screen_resources();
1468 if (!screen_resources)
1469 goto done;
1471 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1472 if (!output_info)
1473 goto done;
1475 if (output_info->crtc)
1477 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1478 if (!crtc_info)
1479 goto done;
1482 /* Detached */
1483 if (output_info->connection != RR_Connected || !output_info->crtc || !crtc_info->mode)
1485 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1486 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1487 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
1488 mode->dmBitsPerPel = 0;
1489 mode->dmPelsWidth = 0;
1490 mode->dmPelsHeight = 0;
1491 mode->u2.dmDisplayFlags = 0;
1492 mode->dmDisplayFrequency = 0;
1493 mode->u1.s2.dmPosition.x = 0;
1494 mode->u1.s2.dmPosition.y = 0;
1495 ret = TRUE;
1496 goto done;
1499 /* Attached */
1500 for (mode_idx = 0; mode_idx < screen_resources->nmode; ++mode_idx)
1502 if (crtc_info->mode == screen_resources->modes[mode_idx].id)
1504 mode_info = &screen_resources->modes[mode_idx];
1505 break;
1509 if (!mode_info)
1510 goto done;
1512 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1513 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1514 mode->u1.s2.dmDisplayOrientation = get_orientation( crtc_info->rotation );
1515 mode->dmBitsPerPel = screen_bpp;
1516 mode->dmPelsWidth = crtc_info->width;
1517 mode->dmPelsHeight = crtc_info->height;
1518 mode->u2.dmDisplayFlags = 0;
1519 mode->dmDisplayFrequency = get_frequency( mode_info );
1520 /* Convert RandR coordinates to virtual screen coordinates */
1521 primary = get_primary_rect( screen_resources );
1522 mode->u1.s2.dmPosition.x = crtc_info->x - primary.left;
1523 mode->u1.s2.dmPosition.y = crtc_info->y - primary.top;
1524 ret = TRUE;
1526 done:
1527 if (ret && mode_ptr)
1529 memcpy( &mode_ptr->mode, mode, sizeof(*mode) );
1530 mode_ptr->mode.dmSize = sizeof(*mode);
1531 mode_ptr->mode.dmDriverExtra = 0;
1532 mode_ptr->loaded = TRUE;
1534 pthread_mutex_unlock( &xrandr_mutex );
1535 if (crtc_info)
1536 pXRRFreeCrtcInfo( crtc_info );
1537 if (output_info)
1538 pXRRFreeOutputInfo( output_info );
1539 if (screen_resources)
1540 pXRRFreeScreenResources( screen_resources );
1541 return ret;
1544 static LONG xrandr14_set_current_mode( ULONG_PTR id, const DEVMODEW *mode )
1546 unsigned int screen_width, screen_height;
1547 RROutput output = (RROutput)id, *outputs;
1548 XRRScreenResources *screen_resources;
1549 XRROutputInfo *output_info = NULL;
1550 XRRCrtcInfo *crtc_info = NULL;
1551 LONG ret = DISP_CHANGE_FAILED;
1552 Rotation rotation;
1553 INT output_count;
1554 RRCrtc crtc = 0;
1555 Status status;
1556 RRMode rrmode;
1558 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
1559 WARN("Cannot change screen color depth from %ubits to %ubits!\n", screen_bpp, mode->dmBitsPerPel);
1561 screen_resources = xrandr_get_screen_resources();
1562 if (!screen_resources)
1563 return ret;
1565 XGrabServer( gdi_display );
1567 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1568 if (!output_info || output_info->connection != RR_Connected)
1569 goto done;
1571 if (is_detached_mode(mode))
1573 /* Already detached */
1574 if (!output_info->crtc)
1576 ret = DISP_CHANGE_SUCCESSFUL;
1577 goto done;
1580 /* Execute detach operation */
1581 status = pXRRSetCrtcConfig( gdi_display, screen_resources, output_info->crtc,
1582 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0 );
1583 if (status == RRSetConfigSuccess)
1585 get_screen_size( screen_resources, &screen_width, &screen_height );
1586 set_screen_size( screen_width, screen_height );
1587 ret = DISP_CHANGE_SUCCESSFUL;
1589 goto done;
1592 /* Attached */
1593 if (output_info->crtc)
1595 crtc = output_info->crtc;
1597 /* Detached, need to find a free CRTC */
1598 else
1600 if (!(crtc = get_output_free_crtc( screen_resources, output_info )))
1601 goto done;
1604 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1605 if (!crtc_info)
1606 goto done;
1608 assert( mode->dmDriverExtra == sizeof(RRMode) );
1609 memcpy( &rrmode, (BYTE *)mode + sizeof(*mode), sizeof(rrmode) );
1611 if (crtc_info->noutput)
1613 outputs = crtc_info->outputs;
1614 output_count = crtc_info->noutput;
1616 else
1618 outputs = &output;
1619 output_count = 1;
1621 rotation = get_rotation( mode->u1.s2.dmDisplayOrientation );
1623 /* According to the RandR spec, the entire CRTC must fit inside the screen.
1624 * Since we use the union of all enabled CRTCs to determine the necessary
1625 * screen size, this might involve shrinking the screen, so we must disable
1626 * the CRTC in question first. */
1627 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime, 0, 0, None,
1628 RR_Rotate_0, NULL, 0 );
1629 if (status != RRSetConfigSuccess)
1630 goto done;
1632 get_screen_size( screen_resources, &screen_width, &screen_height );
1633 screen_width = max( screen_width, mode->u1.s2.dmPosition.x + mode->dmPelsWidth );
1634 screen_height = max( screen_height, mode->u1.s2.dmPosition.y + mode->dmPelsHeight );
1635 set_screen_size( screen_width, screen_height );
1637 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
1638 mode->u1.s2.dmPosition.x, mode->u1.s2.dmPosition.y, rrmode,
1639 rotation, outputs, output_count );
1640 if (status == RRSetConfigSuccess)
1641 ret = DISP_CHANGE_SUCCESSFUL;
1643 done:
1644 XUngrabServer( gdi_display );
1645 XFlush( gdi_display );
1646 if (crtc_info)
1647 pXRRFreeCrtcInfo( crtc_info );
1648 if (output_info)
1649 pXRRFreeOutputInfo( output_info );
1650 pXRRFreeScreenResources( screen_resources );
1651 xrandr14_invalidate_current_mode_cache();
1652 return ret;
1655 #endif
1657 void X11DRV_XRandR_Init(void)
1659 struct x11drv_display_device_handler display_handler;
1660 struct x11drv_settings_handler settings_handler;
1661 int event_base, error_base, minor, ret;
1662 static int major;
1663 Bool ok;
1665 if (major) return; /* already initialized? */
1666 if (!usexrandr) return; /* disabled in config */
1667 if (is_virtual_desktop()) return;
1668 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
1670 /* see if Xrandr is available */
1671 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
1672 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
1673 ok = pXRRQueryVersion( gdi_display, &major, &minor );
1674 if (X11DRV_check_error() || !ok) return;
1676 TRACE("Found XRandR %d.%d.\n", major, minor);
1678 settings_handler.name = "XRandR 1.0";
1679 settings_handler.priority = 200;
1680 settings_handler.get_id = xrandr10_get_id;
1681 settings_handler.get_modes = xrandr10_get_modes;
1682 settings_handler.free_modes = xrandr10_free_modes;
1683 settings_handler.get_current_mode = xrandr10_get_current_mode;
1684 settings_handler.set_current_mode = xrandr10_set_current_mode;
1685 X11DRV_Settings_SetHandler( &settings_handler );
1687 #ifdef HAVE_XRRGETPROVIDERRESOURCES
1688 if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))
1690 XRRScreenResources *screen_resources;
1691 XRROutputInfo *output_info;
1692 BOOL found_output = FALSE;
1693 INT i;
1695 screen_resources = xrandr_get_screen_resources();
1696 if (!screen_resources)
1697 return;
1699 for (i = 0; i < screen_resources->noutput; ++i)
1701 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1702 if (!output_info)
1703 continue;
1705 if (output_info->connection == RR_Connected)
1707 pXRRFreeOutputInfo( output_info );
1708 found_output = TRUE;
1709 break;
1712 pXRRFreeOutputInfo( output_info );
1714 pXRRFreeScreenResources( screen_resources );
1716 if (!found_output)
1718 WARN("No connected outputs found.\n");
1719 return;
1722 display_handler.name = "XRandR 1.4";
1723 display_handler.priority = 200;
1724 display_handler.get_gpus = xrandr14_get_gpus;
1725 display_handler.get_adapters = xrandr14_get_adapters;
1726 display_handler.get_monitors = xrandr14_get_monitors;
1727 display_handler.free_gpus = xrandr14_free_gpus;
1728 display_handler.free_adapters = xrandr14_free_adapters;
1729 display_handler.free_monitors = xrandr14_free_monitors;
1730 display_handler.register_event_handlers = xrandr14_register_event_handlers;
1731 X11DRV_DisplayDevices_SetHandler( &display_handler );
1733 if (is_broken_driver())
1734 return;
1736 settings_handler.name = "XRandR 1.4";
1737 settings_handler.priority = 300;
1738 settings_handler.get_id = xrandr14_get_id;
1739 settings_handler.get_modes = xrandr14_get_modes;
1740 settings_handler.free_modes = xrandr14_free_modes;
1741 settings_handler.get_current_mode = xrandr14_get_current_mode;
1742 settings_handler.set_current_mode = xrandr14_set_current_mode;
1743 X11DRV_Settings_SetHandler( &settings_handler );
1745 #endif
1748 #else /* SONAME_LIBXRANDR */
1750 void X11DRV_XRandR_Init(void)
1752 TRACE("XRandR support not compiled in.\n");
1755 #endif /* SONAME_LIBXRANDR */