cmd: DIR command outputs free space for the path.
[wine.git] / dlls / winex11.drv / xrandr.c
blob23601b9e75e1c00f83e2a028f605eaad9d75a341
1 /*
2 * Wine X11drv Xrandr interface
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2012 Henri Verbeet for CodeWeavers
6 * Copyright 2019 Zhiyi Zhang for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include "config.h"
29 #include <assert.h>
30 #include <X11/Xlib.h>
31 #ifdef HAVE_X11_EXTENSIONS_XRANDR_H
32 #include <X11/extensions/Xrandr.h>
33 #endif
34 #include <dlfcn.h>
35 #include "x11drv.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
39 #ifdef HAVE_XRRGETPROVIDERRESOURCES
40 WINE_DECLARE_DEBUG_CHANNEL(winediag);
41 #endif
43 #ifdef SONAME_LIBXRANDR
45 #define VK_NO_PROTOTYPES
46 #define WINE_VK_HOST
48 #include "wine/vulkan.h"
49 #include "wine/vulkan_driver.h"
51 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(XRRGetOutputProperty)
72 MAKE_FUNCPTR(XRRGetScreenResources)
73 MAKE_FUNCPTR(XRRGetScreenResourcesCurrent)
74 MAKE_FUNCPTR(XRRGetScreenSizeRange)
75 MAKE_FUNCPTR(XRRSetCrtcConfig)
76 MAKE_FUNCPTR(XRRSetScreenSize)
77 MAKE_FUNCPTR(XRRSelectInput)
78 MAKE_FUNCPTR(XRRGetOutputPrimary)
79 MAKE_FUNCPTR(XRRGetProviderResources)
80 MAKE_FUNCPTR(XRRFreeProviderResources)
81 MAKE_FUNCPTR(XRRGetProviderInfo)
82 MAKE_FUNCPTR(XRRFreeProviderInfo)
83 #endif
85 #undef MAKE_FUNCPTR
87 static int load_xrandr(void)
89 int r = 0;
91 if (dlopen(SONAME_LIBXRENDER, RTLD_NOW|RTLD_GLOBAL) &&
92 (xrandr_handle = dlopen(SONAME_LIBXRANDR, RTLD_NOW)))
95 #define LOAD_FUNCPTR(f) \
96 if((p##f = dlsym(xrandr_handle, #f)) == NULL) goto sym_not_found
98 LOAD_FUNCPTR(XRRConfigCurrentConfiguration);
99 LOAD_FUNCPTR(XRRConfigCurrentRate);
100 LOAD_FUNCPTR(XRRFreeScreenConfigInfo);
101 LOAD_FUNCPTR(XRRGetScreenInfo);
102 LOAD_FUNCPTR(XRRQueryExtension);
103 LOAD_FUNCPTR(XRRQueryVersion);
104 LOAD_FUNCPTR(XRRRates);
105 LOAD_FUNCPTR(XRRSetScreenConfig);
106 LOAD_FUNCPTR(XRRSetScreenConfigAndRate);
107 LOAD_FUNCPTR(XRRSizes);
108 r = 1;
110 #ifdef HAVE_XRRGETPROVIDERRESOURCES
111 LOAD_FUNCPTR(XRRFreeCrtcInfo);
112 LOAD_FUNCPTR(XRRFreeOutputInfo);
113 LOAD_FUNCPTR(XRRFreeScreenResources);
114 LOAD_FUNCPTR(XRRGetCrtcInfo);
115 LOAD_FUNCPTR(XRRGetOutputInfo);
116 LOAD_FUNCPTR(XRRGetOutputProperty);
117 LOAD_FUNCPTR(XRRGetScreenResources);
118 LOAD_FUNCPTR(XRRGetScreenResourcesCurrent);
119 LOAD_FUNCPTR(XRRGetScreenSizeRange);
120 LOAD_FUNCPTR(XRRSetCrtcConfig);
121 LOAD_FUNCPTR(XRRSetScreenSize);
122 LOAD_FUNCPTR(XRRSelectInput);
123 LOAD_FUNCPTR(XRRGetOutputPrimary);
124 LOAD_FUNCPTR(XRRGetProviderResources);
125 LOAD_FUNCPTR(XRRFreeProviderResources);
126 LOAD_FUNCPTR(XRRGetProviderInfo);
127 LOAD_FUNCPTR(XRRFreeProviderInfo);
128 r = 4;
129 #endif
131 #undef LOAD_FUNCPTR
133 sym_not_found:
134 if (!r) TRACE("Unable to load function ptrs from XRandR library\n");
136 return r;
139 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
141 return 1;
144 /* XRandR 1.0 display settings handler */
145 static BOOL xrandr10_get_id( const WCHAR *device_name, BOOL is_primary, x11drv_settings_id *id )
147 /* RandR 1.0 only supports changing the primary adapter settings.
148 * For non-primary adapters, an id is still provided but getting
149 * and changing non-primary adapters' settings will be ignored. */
150 id->id = is_primary ? 1 : 0;
151 return TRUE;
154 static void add_xrandr10_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height,
155 DWORD frequency, SizeID size_id )
157 mode->dmSize = sizeof(*mode);
158 mode->dmDriverExtra = sizeof(SizeID);
159 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
160 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
161 if (frequency)
163 mode->dmFields |= DM_DISPLAYFREQUENCY;
164 mode->dmDisplayFrequency = frequency;
166 mode->dmDisplayOrientation = DMDO_DEFAULT;
167 mode->dmBitsPerPel = depth;
168 mode->dmPelsWidth = width;
169 mode->dmPelsHeight = height;
170 mode->dmDisplayFlags = 0;
171 memcpy( (BYTE *)mode + sizeof(*mode), &size_id, sizeof(size_id) );
174 static BOOL xrandr10_get_modes( x11drv_settings_id id, DWORD flags, DEVMODEW **new_modes, UINT *new_mode_count )
176 INT size_idx, depth_idx, rate_idx, mode_idx = 0;
177 INT size_count, rate_count, mode_count = 0;
178 DEVMODEW *modes, *mode;
179 XRRScreenSize *sizes;
180 short *rates;
182 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
183 if (size_count <= 0)
184 return FALSE;
186 for (size_idx = 0; size_idx < size_count; ++size_idx)
188 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
189 if (rate_count)
190 mode_count += rate_count;
191 else
192 ++mode_count;
195 /* Allocate space for reported modes in three depths, and put an SizeID at the end of DEVMODEW as
196 * driver private data */
197 modes = calloc( mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID) );
198 if (!modes)
200 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY );
201 return FALSE;
204 for (size_idx = 0; size_idx < size_count; ++size_idx)
206 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
208 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
209 if (!rate_count)
211 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
212 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
213 sizes[size_idx].height, 0, size_idx );
214 continue;
217 for (rate_idx = 0; rate_idx < rate_count; ++rate_idx)
219 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
220 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
221 sizes[size_idx].height, rates[rate_idx], size_idx );
226 *new_modes = modes;
227 *new_mode_count = mode_idx;
228 return TRUE;
231 static void xrandr10_free_modes( DEVMODEW *modes )
233 free( modes );
236 static BOOL xrandr10_get_current_mode( x11drv_settings_id id, DEVMODEW *mode )
238 XRRScreenConfiguration *screen_config;
239 XRRScreenSize *sizes;
240 Rotation rotation;
241 SizeID size_id;
242 INT size_count;
243 short rate;
245 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
246 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
247 mode->dmDisplayOrientation = DMDO_DEFAULT;
248 mode->dmDisplayFlags = 0;
249 mode->dmPosition.x = 0;
250 mode->dmPosition.y = 0;
252 if (id.id != 1)
254 FIXME("Non-primary adapters are unsupported.\n");
255 mode->dmBitsPerPel = 0;
256 mode->dmPelsWidth = 0;
257 mode->dmPelsHeight = 0;
258 mode->dmDisplayFrequency = 0;
259 return TRUE;
262 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
263 if (size_count <= 0)
264 return FALSE;
266 screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) );
267 size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation );
268 rate = pXRRConfigCurrentRate( screen_config );
269 pXRRFreeScreenConfigInfo( screen_config );
271 mode->dmBitsPerPel = screen_bpp;
272 mode->dmPelsWidth = sizes[size_id].width;
273 mode->dmPelsHeight = sizes[size_id].height;
274 mode->dmDisplayFrequency = rate;
275 return TRUE;
278 static LONG xrandr10_set_current_mode( x11drv_settings_id id, const DEVMODEW *mode )
280 XRRScreenConfiguration *screen_config;
281 Rotation rotation;
282 SizeID size_id;
283 Window root;
284 Status stat;
286 if (id.id != 1)
288 FIXME("Non-primary adapters are unsupported.\n");
289 return DISP_CHANGE_SUCCESSFUL;
292 if (is_detached_mode(mode))
294 FIXME("Detaching adapters is unsupported.\n");
295 return DISP_CHANGE_SUCCESSFUL;
298 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
299 WARN("Cannot change screen bit depth from %dbits to %dbits!\n",
300 screen_bpp, (int)mode->dmBitsPerPel);
302 root = DefaultRootWindow( gdi_display );
303 screen_config = pXRRGetScreenInfo( gdi_display, root );
304 pXRRConfigCurrentConfiguration( screen_config, &rotation );
306 assert( mode->dmDriverExtra == sizeof(SizeID) );
307 memcpy( &size_id, (BYTE *)mode + sizeof(*mode), sizeof(size_id) );
309 if (mode->dmFields & DM_DISPLAYFREQUENCY && mode->dmDisplayFrequency)
310 stat = pXRRSetScreenConfigAndRate( gdi_display, screen_config, root, size_id, rotation,
311 mode->dmDisplayFrequency, CurrentTime );
312 else
313 stat = pXRRSetScreenConfig( gdi_display, screen_config, root, size_id, rotation, CurrentTime );
314 pXRRFreeScreenConfigInfo( screen_config );
316 if (stat != RRSetConfigSuccess)
317 return DISP_CHANGE_FAILED;
319 XFlush( gdi_display );
320 return DISP_CHANGE_SUCCESSFUL;
323 #ifdef HAVE_XRRGETPROVIDERRESOURCES
325 static struct current_mode
327 ULONG_PTR id;
328 BOOL loaded;
329 DEVMODEW mode;
330 } *current_modes;
331 static int current_mode_count;
333 static pthread_mutex_t xrandr_mutex = PTHREAD_MUTEX_INITIALIZER;
335 static void xrandr14_invalidate_current_mode_cache(void)
337 pthread_mutex_lock( &xrandr_mutex );
338 free( current_modes);
339 current_modes = NULL;
340 current_mode_count = 0;
341 pthread_mutex_unlock( &xrandr_mutex );
344 static XRRScreenResources *xrandr_get_screen_resources(void)
346 XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window );
347 if (resources && !resources->ncrtc)
349 pXRRFreeScreenResources( resources );
350 resources = pXRRGetScreenResources( gdi_display, root_window );
353 if (!resources)
354 ERR("Failed to get screen resources.\n");
355 return resources;
358 /* Some (304.64, possibly earlier) versions of the NVIDIA driver only
359 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
360 * are only listed through RandR 1.0 / 1.1. This is completely useless,
361 * but NVIDIA considers this a feature, so it's unlikely to change. The
362 * best we can do is to fall back to RandR 1.0 and encourage users to
363 * consider more cooperative driver vendors when we detect such a
364 * configuration. */
365 static BOOL is_broken_driver(void)
367 XRRScreenResources *screen_resources;
368 XRROutputInfo *output_info;
369 XRRModeInfo *first_mode;
370 INT major, event, error;
371 INT output_idx, i, j;
372 BOOL only_one_mode;
374 screen_resources = xrandr_get_screen_resources();
375 if (!screen_resources)
376 return TRUE;
378 /* Check if any output only has one native mode */
379 for (output_idx = 0; output_idx < screen_resources->noutput; ++output_idx)
381 output_info = pXRRGetOutputInfo( gdi_display, screen_resources,
382 screen_resources->outputs[output_idx] );
383 if (!output_info)
384 continue;
386 if (output_info->connection != RR_Connected)
388 pXRRFreeOutputInfo( output_info );
389 continue;
392 first_mode = NULL;
393 only_one_mode = TRUE;
394 for (i = 0; i < output_info->nmode; ++i)
396 for (j = 0; j < screen_resources->nmode; ++j)
398 if (output_info->modes[i] != screen_resources->modes[j].id)
399 continue;
401 if (!first_mode)
403 first_mode = &screen_resources->modes[j];
404 break;
407 if (first_mode->width != screen_resources->modes[j].width ||
408 first_mode->height != screen_resources->modes[j].height)
409 only_one_mode = FALSE;
411 break;
414 if (!only_one_mode)
415 break;
417 pXRRFreeOutputInfo( output_info );
419 if (!only_one_mode)
420 continue;
422 /* Check if it is NVIDIA proprietary driver */
423 if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error ))
425 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
426 "Please consider using the Nouveau driver instead.\n");
427 pXRRFreeScreenResources( screen_resources );
428 return TRUE;
431 pXRRFreeScreenResources( screen_resources );
432 return FALSE;
435 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
437 int min_width = 0, min_height = 0, max_width, max_height;
438 XRRCrtcInfo *crtc_info;
439 int i;
441 pXRRGetScreenSizeRange( gdi_display, root_window, &min_width, &min_height, &max_width, &max_height );
442 *width = min_width;
443 *height = min_height;
445 for (i = 0; i < resources->ncrtc; ++i)
447 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
448 continue;
450 if (crtc_info->mode != None)
452 *width = max(*width, crtc_info->x + crtc_info->width);
453 *height = max(*height, crtc_info->y + crtc_info->height);
456 pXRRFreeCrtcInfo( crtc_info );
460 static unsigned int get_edid( RROutput output, unsigned char **prop )
462 int result, actual_format;
463 unsigned long bytes_after, len;
464 Atom actual_type;
466 result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE,
467 AnyPropertyType, &actual_type, &actual_format, &len,
468 &bytes_after, prop );
470 if (result != Success)
472 WARN("Could not retrieve EDID property for output %#lx.\n", output);
473 *prop = NULL;
474 return 0;
476 return len;
479 static void set_screen_size( int width, int height )
481 int screen = default_visual.screen;
482 int mm_width, mm_height;
484 mm_width = width * DisplayWidthMM( gdi_display, screen ) / DisplayWidth( gdi_display, screen );
485 mm_height = height * DisplayHeightMM( gdi_display, screen ) / DisplayHeight( gdi_display, screen );
486 pXRRSetScreenSize( gdi_display, root_window, width, height, mm_width, mm_height );
489 static unsigned int get_frequency( const XRRModeInfo *mode )
491 unsigned int dots = mode->hTotal * mode->vTotal;
493 if (!dots)
494 return 0;
496 if (mode->modeFlags & RR_DoubleScan)
497 dots *= 2;
498 if (mode->modeFlags & RR_Interlace)
499 dots /= 2;
501 return (mode->dotClock + dots / 2) / dots;
504 static DWORD get_orientation( Rotation rotation )
506 if (rotation & RR_Rotate_270) return DMDO_270;
507 if (rotation & RR_Rotate_180) return DMDO_180;
508 if (rotation & RR_Rotate_90) return DMDO_90;
509 return DMDO_DEFAULT;
512 static DWORD get_orientation_count( Rotation rotations )
514 DWORD count = 0;
516 if (rotations & RR_Rotate_0) ++count;
517 if (rotations & RR_Rotate_90) ++count;
518 if (rotations & RR_Rotate_180) ++count;
519 if (rotations & RR_Rotate_270) ++count;
520 return count;
523 static Rotation get_rotation( DWORD orientation )
525 return (Rotation)(1 << orientation);
528 static RRCrtc get_output_free_crtc( XRRScreenResources *resources, XRROutputInfo *output_info )
530 XRRCrtcInfo *crtc_info;
531 INT crtc_idx;
532 RRCrtc crtc;
534 for (crtc_idx = 0; crtc_idx < output_info->ncrtc; ++crtc_idx)
536 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtcs[crtc_idx] );
537 if (!crtc_info)
538 continue;
540 if (!crtc_info->noutput)
542 crtc = output_info->crtcs[crtc_idx];
543 pXRRFreeCrtcInfo( crtc_info );
544 return crtc;
547 pXRRFreeCrtcInfo( crtc_info );
550 return 0;
553 static RECT get_primary_rect( XRRScreenResources *resources )
555 XRROutputInfo *output_info = NULL;
556 XRRCrtcInfo *crtc_info = NULL;
557 RROutput primary_output;
558 RECT primary_rect = {0};
559 RECT first_rect = {0};
560 INT i;
562 primary_output = pXRRGetOutputPrimary( gdi_display, root_window );
563 if (!primary_output)
564 goto fallback;
566 output_info = pXRRGetOutputInfo( gdi_display, resources, primary_output );
567 if (!output_info || output_info->connection != RR_Connected || !output_info->crtc)
568 goto fallback;
570 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtc );
571 if (!crtc_info || !crtc_info->mode)
572 goto fallback;
574 SetRect( &primary_rect, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
575 pXRRFreeCrtcInfo( crtc_info );
576 pXRRFreeOutputInfo( output_info );
577 return primary_rect;
579 /* Fallback when XRandR primary output is a disconnected output.
580 * Try to find a crtc with (x, y) being (0, 0). If it's found then get the primary rect from that crtc,
581 * otherwise use the first active crtc to get the primary rect */
582 fallback:
583 if (crtc_info)
584 pXRRFreeCrtcInfo( crtc_info );
585 if (output_info)
586 pXRRFreeOutputInfo( output_info );
588 WARN("Primary is set to a disconnected XRandR output.\n");
589 for (i = 0; i < resources->ncrtc; ++i)
591 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
592 if (!crtc_info)
593 continue;
595 if (!crtc_info->mode)
597 pXRRFreeCrtcInfo( crtc_info );
598 continue;
601 if (!crtc_info->x && !crtc_info->y)
603 SetRect( &primary_rect, 0, 0, crtc_info->width, crtc_info->height );
604 pXRRFreeCrtcInfo( crtc_info );
605 break;
608 if (IsRectEmpty( &first_rect ))
609 SetRect( &first_rect, crtc_info->x, crtc_info->y,
610 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
612 pXRRFreeCrtcInfo( crtc_info );
615 return IsRectEmpty( &primary_rect ) ? first_rect : primary_rect;
618 static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
620 return crtc &&
621 crtc->mode &&
622 crtc->x == primary.left &&
623 crtc->y == primary.top &&
624 crtc->x + crtc->width == primary.right &&
625 crtc->y + crtc->height == primary.bottom;
628 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
630 static BOOL get_gpu_properties_from_vulkan( struct gdi_gpu *gpu, const XRRProviderInfo *provider_info,
631 struct gdi_gpu *prev_gpus, int prev_gpu_count )
633 static const char *extensions[] =
635 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
636 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
637 "VK_EXT_acquire_xlib_display",
638 "VK_EXT_direct_mode_display",
639 "VK_KHR_display",
640 VK_KHR_SURFACE_EXTENSION_NAME,
642 const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION );
643 VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
644 PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
645 PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
646 uint32_t device_count, device_idx, output_idx, i;
647 VkPhysicalDevice *vk_physical_devices = NULL;
648 VkPhysicalDeviceProperties2 properties2;
649 VkInstanceCreateInfo create_info;
650 VkPhysicalDeviceIDProperties id;
651 VkInstance vk_instance = NULL;
652 VkDisplayKHR vk_display;
653 DWORD len;
654 BOOL ret = FALSE;
655 VkResult vr;
657 if (!vulkan_funcs)
658 goto done;
660 memset( &create_info, 0, sizeof(create_info) );
661 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
662 create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
663 create_info.ppEnabledExtensionNames = extensions;
665 vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance );
666 if (vr != VK_SUCCESS)
668 WARN("Failed to create a Vulkan instance, vr %d.\n", vr);
669 goto done;
672 #define LOAD_VK_FUNC(f) \
673 if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \
675 WARN("Failed to load " #f ".\n"); \
676 goto done; \
679 LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
680 LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
681 LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
682 #undef LOAD_VK_FUNC
684 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
685 if (vr != VK_SUCCESS || !device_count)
687 WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
688 goto done;
691 if (!(vk_physical_devices = calloc( device_count, sizeof(*vk_physical_devices) )))
692 goto done;
694 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
695 if (vr != VK_SUCCESS)
697 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
698 goto done;
701 TRACE("provider name %s.\n", debugstr_a(provider_info->name));
703 for (device_idx = 0; device_idx < device_count; ++device_idx)
705 for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
707 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
708 vr = pvkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
709 provider_info->outputs[output_idx], &vk_display );
710 XSync( gdi_display, FALSE );
711 if (X11DRV_check_error() || vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
712 continue;
714 memset( &id, 0, sizeof(id) );
715 id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
716 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
717 properties2.pNext = &id;
719 pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
720 for (i = 0; i < prev_gpu_count; ++i)
722 if (!memcmp( &prev_gpus[i].vulkan_uuid, &id.deviceUUID, sizeof(id.deviceUUID) ))
724 WARN( "device UUID %#x:%#x already assigned to GPU %u.\n", *((uint32_t *)id.deviceUUID + 1),
725 *(uint32_t *)id.deviceUUID, i );
726 break;
729 if (i < prev_gpu_count) continue;
731 memcpy( &gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) );
733 /* Ignore Khronos vendor IDs */
734 if (properties2.properties.vendorID < 0x10000)
736 gpu->vendor_id = properties2.properties.vendorID;
737 gpu->device_id = properties2.properties.deviceID;
739 RtlUTF8ToUnicodeN( gpu->name, sizeof(gpu->name), &len, properties2.properties.deviceName,
740 strlen( properties2.properties.deviceName ) + 1 );
741 ret = TRUE;
742 goto done;
746 done:
747 free( vk_physical_devices );
748 if (vk_instance)
749 vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL );
750 return ret;
753 /* Get a list of GPUs reported by XRandR 1.4. Set get_properties to FALSE if GPU properties are
754 * not needed to avoid unnecessary querying */
755 static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_properties )
757 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
758 struct gdi_gpu *gpus = NULL;
759 XRRScreenResources *screen_resources = NULL;
760 XRRProviderResources *provider_resources = NULL;
761 XRRProviderInfo *provider_info = NULL;
762 XRRCrtcInfo *crtc_info = NULL;
763 INT primary_provider = -1;
764 RECT primary_rect;
765 BOOL ret = FALSE;
766 DWORD len;
767 INT i, j;
769 screen_resources = xrandr_get_screen_resources();
770 if (!screen_resources)
771 goto done;
773 provider_resources = pXRRGetProviderResources( gdi_display, root_window );
774 if (!provider_resources)
775 goto done;
777 gpus = calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) );
778 if (!gpus)
779 goto done;
781 /* Some XRandR implementations don't support providers.
782 * In this case, report a fake one to try searching adapters in screen resources */
783 if (!provider_resources->nproviders)
785 WARN("XRandR implementation doesn't report any providers, faking one.\n");
786 lstrcpyW( gpus[0].name, wine_adapterW );
787 *new_gpus = gpus;
788 *count = 1;
789 ret = TRUE;
790 goto done;
793 primary_rect = get_primary_rect( screen_resources );
794 for (i = 0; i < provider_resources->nproviders; ++i)
796 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, provider_resources->providers[i] );
797 if (!provider_info)
798 goto done;
800 /* Find primary provider */
801 for (j = 0; primary_provider == -1 && j < provider_info->ncrtcs; ++j)
803 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, provider_info->crtcs[j] );
804 if (!crtc_info)
805 continue;
807 if (is_crtc_primary( primary_rect, crtc_info ))
809 primary_provider = i;
810 pXRRFreeCrtcInfo( crtc_info );
811 break;
814 pXRRFreeCrtcInfo( crtc_info );
817 gpus[i].id = provider_resources->providers[i];
818 if (get_properties)
820 if (!get_gpu_properties_from_vulkan( &gpus[i], provider_info, gpus, i ))
821 RtlUTF8ToUnicodeN( gpus[i].name, sizeof(gpus[i].name), &len, provider_info->name,
822 strlen( provider_info->name ) + 1 );
823 /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */
825 pXRRFreeProviderInfo( provider_info );
828 /* Make primary GPU the first */
829 if (primary_provider > 0)
831 struct gdi_gpu tmp = gpus[0];
832 gpus[0] = gpus[primary_provider];
833 gpus[primary_provider] = tmp;
836 *new_gpus = gpus;
837 *count = provider_resources->nproviders;
838 ret = TRUE;
839 done:
840 if (provider_resources)
841 pXRRFreeProviderResources( provider_resources );
842 if (screen_resources)
843 pXRRFreeScreenResources( screen_resources );
844 if (!ret)
846 free( gpus );
847 ERR("Failed to get gpus\n");
849 return ret;
852 static BOOL xrandr14_get_gpus( struct gdi_gpu **new_gpus, int *count )
854 return xrandr14_get_gpus2( new_gpus, count, TRUE );
857 static void xrandr14_free_gpus( struct gdi_gpu *gpus )
859 free( gpus );
862 static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_adapters, int *count )
864 struct gdi_adapter *adapters = NULL;
865 XRRScreenResources *screen_resources = NULL;
866 XRRProviderInfo *provider_info = NULL;
867 XRRCrtcInfo *enum_crtc_info, *crtc_info = NULL;
868 XRROutputInfo *enum_output_info, *output_info = NULL;
869 RROutput *outputs;
870 INT crtc_count, output_count;
871 INT primary_adapter = 0;
872 INT adapter_count = 0;
873 BOOL mirrored, detached;
874 RECT primary_rect;
875 BOOL ret = FALSE;
876 INT i, j;
878 screen_resources = xrandr_get_screen_resources();
879 if (!screen_resources)
880 goto done;
882 if (gpu_id)
884 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id );
885 if (!provider_info)
886 goto done;
888 crtc_count = provider_info->ncrtcs;
889 output_count = provider_info->noutputs;
890 outputs = provider_info->outputs;
892 /* Fake provider id, search adapters in screen resources */
893 else
895 crtc_count = screen_resources->ncrtc;
896 output_count = screen_resources->noutput;
897 outputs = screen_resources->outputs;
900 /* Actual adapter count could be less */
901 adapters = calloc( crtc_count, sizeof(*adapters) );
902 if (!adapters)
903 goto done;
905 primary_rect = get_primary_rect( screen_resources );
906 for (i = 0; i < output_count; ++i)
908 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, outputs[i] );
909 if (!output_info)
910 goto done;
912 /* Only connected output are considered as monitors */
913 if (output_info->connection != RR_Connected)
915 pXRRFreeOutputInfo( output_info );
916 output_info = NULL;
917 continue;
920 /* Connected output doesn't mean the output is attached to a crtc */
921 detached = FALSE;
922 if (output_info->crtc)
924 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
925 if (!crtc_info)
926 goto done;
929 if (!output_info->crtc || !crtc_info->mode)
930 detached = TRUE;
932 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
933 mirrored = FALSE;
934 if (!detached)
936 for (j = 0; j < screen_resources->noutput; ++j)
938 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[j] );
939 if (!enum_output_info)
940 continue;
942 if (enum_output_info->connection != RR_Connected || !enum_output_info->crtc)
944 pXRRFreeOutputInfo( enum_output_info );
945 continue;
948 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
949 pXRRFreeOutputInfo( enum_output_info );
950 if (!enum_crtc_info)
951 continue;
953 /* Some outputs may have the same coordinates, aka mirrored. Choose the output with
954 * the lowest value as primary and the rest will then be replicas in a mirroring set */
955 if (crtc_info->x == enum_crtc_info->x &&
956 crtc_info->y == enum_crtc_info->y &&
957 crtc_info->width == enum_crtc_info->width &&
958 crtc_info->height == enum_crtc_info->height &&
959 outputs[i] > screen_resources->outputs[j])
961 mirrored = TRUE;
962 pXRRFreeCrtcInfo( enum_crtc_info );
963 break;
966 pXRRFreeCrtcInfo( enum_crtc_info );
970 if (!mirrored || detached)
972 /* Use RROutput as adapter id. The reason of not using RRCrtc is that we need to detect inactive but
973 * attached monitors */
974 adapters[adapter_count].id = outputs[i];
975 if (!detached)
976 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
977 if (is_crtc_primary( primary_rect, crtc_info ))
979 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
980 primary_adapter = adapter_count;
983 ++adapter_count;
986 pXRRFreeOutputInfo( output_info );
987 output_info = NULL;
988 if (crtc_info)
990 pXRRFreeCrtcInfo( crtc_info );
991 crtc_info = NULL;
995 /* Make primary adapter the first */
996 if (primary_adapter)
998 struct gdi_adapter tmp = adapters[0];
999 adapters[0] = adapters[primary_adapter];
1000 adapters[primary_adapter] = tmp;
1003 *new_adapters = adapters;
1004 *count = adapter_count;
1005 ret = TRUE;
1006 done:
1007 if (screen_resources)
1008 pXRRFreeScreenResources( screen_resources );
1009 if (provider_info)
1010 pXRRFreeProviderInfo( provider_info );
1011 if (output_info)
1012 pXRRFreeOutputInfo( output_info );
1013 if (crtc_info)
1014 pXRRFreeCrtcInfo( crtc_info );
1015 if (!ret)
1017 free( adapters );
1018 ERR("Failed to get adapters\n");
1020 return ret;
1023 static void xrandr14_free_adapters( struct gdi_adapter *adapters )
1025 free( adapters );
1028 static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count )
1030 struct gdi_monitor *realloc_monitors, *monitors = NULL;
1031 XRRScreenResources *screen_resources = NULL;
1032 XRROutputInfo *output_info = NULL, *enum_output_info = NULL;
1033 XRRCrtcInfo *crtc_info = NULL, *enum_crtc_info;
1034 INT primary_index = 0, monitor_count = 0, capacity;
1035 RECT primary_rect;
1036 BOOL ret = FALSE;
1037 INT i;
1039 screen_resources = xrandr_get_screen_resources();
1040 if (!screen_resources)
1041 goto done;
1043 /* First start with a 2 monitors, should be enough for most cases */
1044 capacity = 2;
1045 monitors = calloc( capacity, sizeof(*monitors) );
1046 if (!monitors)
1047 goto done;
1049 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, adapter_id );
1050 if (!output_info)
1051 goto done;
1053 if (output_info->crtc)
1055 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1056 if (!crtc_info)
1057 goto done;
1060 /* Inactive but attached monitor, no need to check for mirrored/replica monitors */
1061 if (!output_info->crtc || !crtc_info->mode)
1063 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1064 monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid );
1065 monitor_count = 1;
1067 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
1068 else
1070 primary_rect = get_primary_rect( screen_resources );
1072 for (i = 0; i < screen_resources->noutput; ++i)
1074 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1075 if (!enum_output_info)
1076 goto done;
1078 /* Detached outputs don't count */
1079 if (enum_output_info->connection != RR_Connected)
1081 pXRRFreeOutputInfo( enum_output_info );
1082 enum_output_info = NULL;
1083 continue;
1086 /* Allocate more space if needed */
1087 if (monitor_count >= capacity)
1089 capacity *= 2;
1090 realloc_monitors = realloc( monitors, capacity * sizeof(*monitors) );
1091 if (!realloc_monitors)
1092 goto done;
1093 monitors = realloc_monitors;
1096 if (enum_output_info->crtc)
1098 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
1099 if (!enum_crtc_info)
1100 goto done;
1102 if (enum_crtc_info->x == crtc_info->x &&
1103 enum_crtc_info->y == crtc_info->y &&
1104 enum_crtc_info->width == crtc_info->width &&
1105 enum_crtc_info->height == crtc_info->height)
1107 SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y,
1108 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
1109 monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor );
1111 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1112 if (!IsRectEmpty( &monitors[monitor_count].rc_monitor ))
1113 monitors[monitor_count].state_flags |= DISPLAY_DEVICE_ACTIVE;
1115 if (is_crtc_primary( primary_rect, crtc_info ))
1116 primary_index = monitor_count;
1118 monitors[monitor_count].edid_len = get_edid( screen_resources->outputs[i],
1119 &monitors[monitor_count].edid );
1120 monitor_count++;
1123 pXRRFreeCrtcInfo( enum_crtc_info );
1126 pXRRFreeOutputInfo( enum_output_info );
1127 enum_output_info = NULL;
1130 /* Make sure the first monitor is the primary */
1131 if (primary_index)
1133 struct gdi_monitor tmp = monitors[0];
1134 monitors[0] = monitors[primary_index];
1135 monitors[primary_index] = tmp;
1138 /* Make sure the primary monitor origin is at (0, 0) */
1139 for (i = 0; i < monitor_count; i++)
1141 OffsetRect( &monitors[i].rc_monitor, -primary_rect.left, -primary_rect.top );
1142 OffsetRect( &monitors[i].rc_work, -primary_rect.left, -primary_rect.top );
1146 *new_monitors = monitors;
1147 *count = monitor_count;
1148 ret = TRUE;
1149 done:
1150 if (screen_resources)
1151 pXRRFreeScreenResources( screen_resources );
1152 if (output_info)
1153 pXRRFreeOutputInfo( output_info);
1154 if (crtc_info)
1155 pXRRFreeCrtcInfo( crtc_info );
1156 if (enum_output_info)
1157 pXRRFreeOutputInfo( enum_output_info );
1158 if (!ret)
1160 for (i = 0; i < monitor_count; i++)
1162 if (monitors[i].edid)
1163 XFree( monitors[i].edid );
1165 free( monitors );
1166 ERR("Failed to get monitors\n");
1168 return ret;
1171 static void xrandr14_free_monitors( struct gdi_monitor *monitors, int count )
1173 int i;
1175 for (i = 0; i < count; i++)
1177 if (monitors[i].edid)
1178 XFree( monitors[i].edid );
1180 free( monitors );
1183 static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
1185 RECT rect;
1187 xrandr14_invalidate_current_mode_cache();
1188 if (hwnd == NtUserGetDesktopWindow() && NtUserGetWindowThread( hwnd, NULL ) == GetCurrentThreadId())
1190 X11DRV_DisplayDevices_Init( TRUE );
1191 X11DRV_resize_desktop();
1193 /* Update xinerama monitors for xinerama_get_fullscreen_monitors() */
1194 rect = get_host_primary_monitor_rect();
1195 xinerama_init( rect.right - rect.left, rect.bottom - rect.top );
1196 return FALSE;
1199 static void xrandr14_register_event_handlers(void)
1201 Display *display = thread_init_display();
1202 int event_base, error_base;
1204 if (!pXRRQueryExtension( display, &event_base, &error_base ))
1205 return;
1207 pXRRSelectInput( display, root_window,
1208 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RRProviderChangeNotifyMask );
1209 X11DRV_register_event_handler( event_base + RRNotify_CrtcChange, xrandr14_device_change_handler,
1210 "XRandR CrtcChange" );
1211 X11DRV_register_event_handler( event_base + RRNotify_OutputChange, xrandr14_device_change_handler,
1212 "XRandR OutputChange" );
1213 X11DRV_register_event_handler( event_base + RRNotify_ProviderChange, xrandr14_device_change_handler,
1214 "XRandR ProviderChange" );
1217 /* XRandR 1.4 display settings handler */
1218 static BOOL xrandr14_get_id( const WCHAR *device_name, BOOL is_primary, x11drv_settings_id *id )
1220 struct current_mode *tmp_modes, *new_current_modes = NULL;
1221 INT gpu_count, adapter_count, new_current_mode_count = 0;
1222 INT gpu_idx, adapter_idx, display_idx;
1223 struct gdi_adapter *adapters;
1224 struct gdi_gpu *gpus;
1225 WCHAR *end;
1227 /* Parse \\.\DISPLAY%d */
1228 display_idx = wcstol( device_name + 11, &end, 10 ) - 1;
1229 if (*end)
1230 return FALSE;
1232 /* Update cache */
1233 pthread_mutex_lock( &xrandr_mutex );
1234 if (!current_modes)
1236 if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE ))
1238 pthread_mutex_unlock( &xrandr_mutex );
1239 return FALSE;
1242 for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx)
1244 if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count ))
1245 break;
1247 tmp_modes = realloc( new_current_modes, (new_current_mode_count + adapter_count) * sizeof(*tmp_modes) );
1248 if (!tmp_modes)
1250 xrandr14_free_adapters( adapters );
1251 break;
1253 new_current_modes = tmp_modes;
1255 for (adapter_idx = 0; adapter_idx < adapter_count; ++adapter_idx)
1257 new_current_modes[new_current_mode_count + adapter_idx].id = adapters[adapter_idx].id;
1258 new_current_modes[new_current_mode_count + adapter_idx].loaded = FALSE;
1260 new_current_mode_count += adapter_count;
1261 xrandr14_free_adapters( adapters );
1263 xrandr14_free_gpus( gpus );
1265 if (new_current_modes)
1267 free( current_modes );
1268 current_modes = new_current_modes;
1269 current_mode_count = new_current_mode_count;
1273 if (display_idx >= current_mode_count)
1275 pthread_mutex_unlock( &xrandr_mutex );
1276 return FALSE;
1279 id->id = current_modes[display_idx].id;
1280 pthread_mutex_unlock( &xrandr_mutex );
1281 return TRUE;
1284 static void add_xrandr14_mode( DEVMODEW *mode, XRRModeInfo *info, DWORD depth, DWORD frequency,
1285 DWORD orientation )
1287 mode->dmSize = sizeof(*mode);
1288 mode->dmDriverExtra = sizeof(RRMode);
1289 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
1290 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
1291 if (frequency)
1293 mode->dmFields |= DM_DISPLAYFREQUENCY;
1294 mode->dmDisplayFrequency = frequency;
1296 if (orientation == DMDO_DEFAULT || orientation == DMDO_180)
1298 mode->dmPelsWidth = info->width;
1299 mode->dmPelsHeight = info->height;
1301 else
1303 mode->dmPelsWidth = info->height;
1304 mode->dmPelsHeight = info->width;
1306 mode->dmDisplayOrientation = orientation;
1307 mode->dmBitsPerPel = depth;
1308 mode->dmDisplayFlags = 0;
1309 memcpy( (BYTE *)mode + sizeof(*mode), &info->id, sizeof(info->id) );
1312 static BOOL xrandr14_get_modes( x11drv_settings_id id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count )
1314 DWORD frequency, orientation, orientation_count;
1315 XRRScreenResources *screen_resources;
1316 XRROutputInfo *output_info = NULL;
1317 RROutput output = (RROutput)id.id;
1318 XRRCrtcInfo *crtc_info = NULL;
1319 UINT depth_idx, mode_idx = 0;
1320 XRRModeInfo *mode_info;
1321 DEVMODEW *mode, *modes;
1322 Rotation rotations;
1323 BOOL ret = FALSE;
1324 RRCrtc crtc;
1325 INT i, j;
1327 screen_resources = xrandr_get_screen_resources();
1328 if (!screen_resources)
1329 goto done;
1331 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1332 if (!output_info)
1333 goto done;
1335 if (output_info->connection != RR_Connected)
1337 ret = TRUE;
1338 *new_modes = NULL;
1339 *mode_count = 0;
1340 goto done;
1343 crtc = output_info->crtc;
1344 if (!crtc)
1345 crtc = get_output_free_crtc( screen_resources, output_info );
1346 if (crtc)
1347 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1349 /* If the output is connected to a CRTC, use rotations reported by the CRTC */
1350 if (crtc_info)
1352 if (flags & EDS_ROTATEDMODE)
1354 rotations = crtc_info->rotations;
1356 else
1358 /* According to the RandR spec, RRGetCrtcInfo should set the active rotation to Rotate_0
1359 * when a CRTC is disabled. However, some RandR implementations report 0 in this case */
1360 rotations = (crtc_info->rotation & 0xf) ? crtc_info->rotation : RR_Rotate_0;
1363 /* Not connected to CRTC, assume all rotations are supported */
1364 else
1366 if (flags & EDS_ROTATEDMODE)
1368 rotations = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
1370 else
1372 rotations = RR_Rotate_0;
1375 orientation_count = get_orientation_count( rotations );
1377 /* Allocate space for display modes in different color depths and orientations.
1378 * Store a RRMode at the end of each DEVMODEW as private driver data */
1379 modes = calloc( output_info->nmode * DEPTH_COUNT * orientation_count,
1380 sizeof(*modes) + sizeof(RRMode) );
1381 if (!modes)
1382 goto done;
1384 for (i = 0; i < output_info->nmode; ++i)
1386 for (j = 0; j < screen_resources->nmode; ++j)
1388 if (output_info->modes[i] != screen_resources->modes[j].id)
1389 continue;
1391 mode_info = &screen_resources->modes[j];
1392 frequency = get_frequency( mode_info );
1394 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
1396 for (orientation = DMDO_DEFAULT; orientation <= DMDO_270; ++orientation)
1398 if (!((1 << orientation) & rotations))
1399 continue;
1401 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*modes) + sizeof(RRMode)) * mode_idx);
1402 add_xrandr14_mode( mode, mode_info, depths[depth_idx], frequency, orientation );
1403 ++mode_idx;
1407 break;
1411 ret = TRUE;
1412 *new_modes = modes;
1413 *mode_count = mode_idx;
1414 done:
1415 if (crtc_info)
1416 pXRRFreeCrtcInfo( crtc_info );
1417 if (output_info)
1418 pXRRFreeOutputInfo( output_info );
1419 if (screen_resources)
1420 pXRRFreeScreenResources( screen_resources );
1421 return ret;
1424 static void xrandr14_free_modes( DEVMODEW *modes )
1426 free( modes );
1429 static BOOL xrandr14_get_current_mode( x11drv_settings_id id, DEVMODEW *mode )
1431 struct current_mode *mode_ptr = NULL;
1432 XRRScreenResources *screen_resources;
1433 XRROutputInfo *output_info = NULL;
1434 RROutput output = (RROutput)id.id;
1435 XRRModeInfo *mode_info = NULL;
1436 XRRCrtcInfo *crtc_info = NULL;
1437 BOOL ret = FALSE;
1438 RECT primary;
1439 INT mode_idx;
1441 pthread_mutex_lock( &xrandr_mutex );
1442 for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx)
1444 if (current_modes[mode_idx].id != id.id)
1445 continue;
1447 if (!current_modes[mode_idx].loaded)
1449 mode_ptr = &current_modes[mode_idx];
1450 break;
1453 memcpy( mode, &current_modes[mode_idx].mode, sizeof(*mode) );
1454 pthread_mutex_unlock( &xrandr_mutex );
1455 return TRUE;
1458 screen_resources = xrandr_get_screen_resources();
1459 if (!screen_resources)
1460 goto done;
1462 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1463 if (!output_info)
1464 goto done;
1466 if (output_info->crtc)
1468 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1469 if (!crtc_info)
1470 goto done;
1473 /* Detached */
1474 if (output_info->connection != RR_Connected || !output_info->crtc || !crtc_info->mode)
1476 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1477 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1478 mode->dmDisplayOrientation = DMDO_DEFAULT;
1479 mode->dmBitsPerPel = 0;
1480 mode->dmPelsWidth = 0;
1481 mode->dmPelsHeight = 0;
1482 mode->dmDisplayFlags = 0;
1483 mode->dmDisplayFrequency = 0;
1484 mode->dmPosition.x = 0;
1485 mode->dmPosition.y = 0;
1486 ret = TRUE;
1487 goto done;
1490 /* Attached */
1491 for (mode_idx = 0; mode_idx < screen_resources->nmode; ++mode_idx)
1493 if (crtc_info->mode == screen_resources->modes[mode_idx].id)
1495 mode_info = &screen_resources->modes[mode_idx];
1496 break;
1500 if (!mode_info)
1501 goto done;
1503 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1504 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1505 mode->dmDisplayOrientation = get_orientation( crtc_info->rotation );
1506 mode->dmBitsPerPel = screen_bpp;
1507 mode->dmPelsWidth = crtc_info->width;
1508 mode->dmPelsHeight = crtc_info->height;
1509 mode->dmDisplayFlags = 0;
1510 mode->dmDisplayFrequency = get_frequency( mode_info );
1511 /* Convert RandR coordinates to virtual screen coordinates */
1512 primary = get_primary_rect( screen_resources );
1513 mode->dmPosition.x = crtc_info->x - primary.left;
1514 mode->dmPosition.y = crtc_info->y - primary.top;
1515 ret = TRUE;
1517 done:
1518 if (ret && mode_ptr)
1520 memcpy( &mode_ptr->mode, mode, sizeof(*mode) );
1521 mode_ptr->mode.dmSize = sizeof(*mode);
1522 mode_ptr->mode.dmDriverExtra = 0;
1523 mode_ptr->loaded = TRUE;
1525 pthread_mutex_unlock( &xrandr_mutex );
1526 if (crtc_info)
1527 pXRRFreeCrtcInfo( crtc_info );
1528 if (output_info)
1529 pXRRFreeOutputInfo( output_info );
1530 if (screen_resources)
1531 pXRRFreeScreenResources( screen_resources );
1532 return ret;
1535 static LONG xrandr14_set_current_mode( x11drv_settings_id id, const DEVMODEW *mode )
1537 unsigned int screen_width, screen_height;
1538 RROutput output = (RROutput)id.id, *outputs;
1539 XRRScreenResources *screen_resources;
1540 XRROutputInfo *output_info = NULL;
1541 XRRCrtcInfo *crtc_info = NULL;
1542 LONG ret = DISP_CHANGE_FAILED;
1543 Rotation rotation;
1544 INT output_count;
1545 RRCrtc crtc = 0;
1546 Status status;
1547 RRMode rrmode;
1549 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
1550 WARN("Cannot change screen color depth from %ubits to %ubits!\n",
1551 screen_bpp, (int)mode->dmBitsPerPel);
1553 screen_resources = xrandr_get_screen_resources();
1554 if (!screen_resources)
1555 return ret;
1557 XGrabServer( gdi_display );
1559 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1560 if (!output_info || output_info->connection != RR_Connected)
1561 goto done;
1563 if (is_detached_mode(mode))
1565 /* Already detached */
1566 if (!output_info->crtc)
1568 ret = DISP_CHANGE_SUCCESSFUL;
1569 goto done;
1572 /* Execute detach operation */
1573 status = pXRRSetCrtcConfig( gdi_display, screen_resources, output_info->crtc,
1574 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0 );
1575 if (status == RRSetConfigSuccess)
1577 get_screen_size( screen_resources, &screen_width, &screen_height );
1578 set_screen_size( screen_width, screen_height );
1579 ret = DISP_CHANGE_SUCCESSFUL;
1581 goto done;
1584 /* Attached */
1585 if (output_info->crtc)
1587 crtc = output_info->crtc;
1589 /* Detached, need to find a free CRTC */
1590 else
1592 if (!(crtc = get_output_free_crtc( screen_resources, output_info )))
1593 goto done;
1596 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1597 if (!crtc_info)
1598 goto done;
1600 assert( mode->dmDriverExtra == sizeof(RRMode) );
1601 memcpy( &rrmode, (BYTE *)mode + sizeof(*mode), sizeof(rrmode) );
1603 if (crtc_info->noutput)
1605 outputs = crtc_info->outputs;
1606 output_count = crtc_info->noutput;
1608 else
1610 outputs = &output;
1611 output_count = 1;
1613 rotation = get_rotation( mode->dmDisplayOrientation );
1615 /* According to the RandR spec, the entire CRTC must fit inside the screen.
1616 * Since we use the union of all enabled CRTCs to determine the necessary
1617 * screen size, this might involve shrinking the screen, so we must disable
1618 * the CRTC in question first. */
1619 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime, 0, 0, None,
1620 RR_Rotate_0, NULL, 0 );
1621 if (status != RRSetConfigSuccess)
1622 goto done;
1624 get_screen_size( screen_resources, &screen_width, &screen_height );
1625 screen_width = max( screen_width, mode->dmPosition.x + mode->dmPelsWidth );
1626 screen_height = max( screen_height, mode->dmPosition.y + mode->dmPelsHeight );
1627 set_screen_size( screen_width, screen_height );
1629 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
1630 mode->dmPosition.x, mode->dmPosition.y, rrmode,
1631 rotation, outputs, output_count );
1632 if (status == RRSetConfigSuccess)
1633 ret = DISP_CHANGE_SUCCESSFUL;
1635 done:
1636 XUngrabServer( gdi_display );
1637 XFlush( gdi_display );
1638 if (crtc_info)
1639 pXRRFreeCrtcInfo( crtc_info );
1640 if (output_info)
1641 pXRRFreeOutputInfo( output_info );
1642 pXRRFreeScreenResources( screen_resources );
1643 xrandr14_invalidate_current_mode_cache();
1644 return ret;
1647 #endif
1649 void X11DRV_XRandR_Init(void)
1651 struct x11drv_display_device_handler display_handler;
1652 struct x11drv_settings_handler settings_handler;
1653 int event_base, error_base, minor, ret;
1654 static int major;
1655 Bool ok;
1657 if (major) return; /* already initialized? */
1658 if (!usexrandr) return; /* disabled in config */
1659 if (is_virtual_desktop()) return;
1660 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
1662 /* see if Xrandr is available */
1663 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
1664 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
1665 ok = pXRRQueryVersion( gdi_display, &major, &minor );
1666 if (X11DRV_check_error() || !ok) return;
1668 TRACE("Found XRandR %d.%d.\n", major, minor);
1670 settings_handler.name = "XRandR 1.0";
1671 settings_handler.priority = 200;
1672 settings_handler.get_id = xrandr10_get_id;
1673 settings_handler.get_modes = xrandr10_get_modes;
1674 settings_handler.free_modes = xrandr10_free_modes;
1675 settings_handler.get_current_mode = xrandr10_get_current_mode;
1676 settings_handler.set_current_mode = xrandr10_set_current_mode;
1677 X11DRV_Settings_SetHandler( &settings_handler );
1679 #ifdef HAVE_XRRGETPROVIDERRESOURCES
1680 if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))
1682 XRRScreenResources *screen_resources;
1683 XRROutputInfo *output_info;
1684 BOOL found_output = FALSE;
1685 INT i;
1687 screen_resources = xrandr_get_screen_resources();
1688 if (!screen_resources)
1689 return;
1691 for (i = 0; i < screen_resources->noutput; ++i)
1693 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1694 if (!output_info)
1695 continue;
1697 if (output_info->connection == RR_Connected)
1699 pXRRFreeOutputInfo( output_info );
1700 found_output = TRUE;
1701 break;
1704 pXRRFreeOutputInfo( output_info );
1706 pXRRFreeScreenResources( screen_resources );
1708 if (!found_output)
1710 WARN("No connected outputs found.\n");
1711 return;
1714 display_handler.name = "XRandR 1.4";
1715 display_handler.priority = 200;
1716 display_handler.get_gpus = xrandr14_get_gpus;
1717 display_handler.get_adapters = xrandr14_get_adapters;
1718 display_handler.get_monitors = xrandr14_get_monitors;
1719 display_handler.free_gpus = xrandr14_free_gpus;
1720 display_handler.free_adapters = xrandr14_free_adapters;
1721 display_handler.free_monitors = xrandr14_free_monitors;
1722 display_handler.register_event_handlers = xrandr14_register_event_handlers;
1723 X11DRV_DisplayDevices_SetHandler( &display_handler );
1725 if (is_broken_driver())
1726 return;
1728 settings_handler.name = "XRandR 1.4";
1729 settings_handler.priority = 300;
1730 settings_handler.get_id = xrandr14_get_id;
1731 settings_handler.get_modes = xrandr14_get_modes;
1732 settings_handler.free_modes = xrandr14_free_modes;
1733 settings_handler.get_current_mode = xrandr14_get_current_mode;
1734 settings_handler.set_current_mode = xrandr14_set_current_mode;
1735 X11DRV_Settings_SetHandler( &settings_handler );
1737 #endif
1740 #else /* SONAME_LIBXRANDR */
1742 void X11DRV_XRandR_Init(void)
1744 TRACE("XRandR support not compiled in.\n");
1747 #endif /* SONAME_LIBXRANDR */