opengl32: Correctly interpret glMapBuffer() access in wow64 mapping.
[wine.git] / dlls / winex11.drv / xrandr.c
blob9a27577ba786ddd3b66cb43deb2a72f878edd236
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
31 #include <assert.h>
32 #include <X11/Xlib.h>
33 #ifdef HAVE_X11_EXTENSIONS_XRANDR_H
34 #include <X11/extensions/Xrandr.h>
35 #endif
36 #include <dlfcn.h>
37 #include "x11drv.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
41 #ifdef HAVE_XRRGETPROVIDERRESOURCES
42 WINE_DECLARE_DEBUG_CHANNEL(winediag);
43 #endif
45 #ifdef SONAME_LIBXRANDR
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, BOOL is_primary, x11drv_settings_id *id )
149 /* RandR 1.0 only supports changing the primary adapter settings.
150 * For non-primary adapters, an id is still provided but getting
151 * and changing non-primary adapters' settings will be ignored. */
152 id->id = is_primary ? 1 : 0;
153 return TRUE;
156 static void add_xrandr10_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height,
157 DWORD frequency, SizeID size_id )
159 mode->dmSize = sizeof(*mode);
160 mode->dmDriverExtra = sizeof(SizeID);
161 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
162 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
163 if (frequency)
165 mode->dmFields |= DM_DISPLAYFREQUENCY;
166 mode->dmDisplayFrequency = frequency;
168 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
169 mode->dmBitsPerPel = depth;
170 mode->dmPelsWidth = width;
171 mode->dmPelsHeight = height;
172 mode->u2.dmDisplayFlags = 0;
173 memcpy( (BYTE *)mode + sizeof(*mode), &size_id, sizeof(size_id) );
176 static BOOL xrandr10_get_modes( x11drv_settings_id id, DWORD flags, DEVMODEW **new_modes, UINT *new_mode_count )
178 INT size_idx, depth_idx, rate_idx, mode_idx = 0;
179 INT size_count, rate_count, mode_count = 0;
180 DEVMODEW *modes, *mode;
181 XRRScreenSize *sizes;
182 short *rates;
184 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
185 if (size_count <= 0)
186 return FALSE;
188 for (size_idx = 0; size_idx < size_count; ++size_idx)
190 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
191 if (rate_count)
192 mode_count += rate_count;
193 else
194 ++mode_count;
197 /* Allocate space for reported modes in three depths, and put an SizeID at the end of DEVMODEW as
198 * driver private data */
199 modes = calloc( mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID) );
200 if (!modes)
202 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY );
203 return FALSE;
206 for (size_idx = 0; size_idx < size_count; ++size_idx)
208 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
210 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
211 if (!rate_count)
213 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
214 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
215 sizes[size_idx].height, 0, size_idx );
216 continue;
219 for (rate_idx = 0; rate_idx < rate_count; ++rate_idx)
221 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
222 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
223 sizes[size_idx].height, rates[rate_idx], size_idx );
228 *new_modes = modes;
229 *new_mode_count = mode_idx;
230 return TRUE;
233 static void xrandr10_free_modes( DEVMODEW *modes )
235 free( modes );
238 static BOOL xrandr10_get_current_mode( x11drv_settings_id id, DEVMODEW *mode )
240 XRRScreenConfiguration *screen_config;
241 XRRScreenSize *sizes;
242 Rotation rotation;
243 SizeID size_id;
244 INT size_count;
245 short rate;
247 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
248 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
249 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
250 mode->u2.dmDisplayFlags = 0;
251 mode->u1.s2.dmPosition.x = 0;
252 mode->u1.s2.dmPosition.y = 0;
254 if (id.id != 1)
256 FIXME("Non-primary adapters are unsupported.\n");
257 mode->dmBitsPerPel = 0;
258 mode->dmPelsWidth = 0;
259 mode->dmPelsHeight = 0;
260 mode->dmDisplayFrequency = 0;
261 return TRUE;
264 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
265 if (size_count <= 0)
266 return FALSE;
268 screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) );
269 size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation );
270 rate = pXRRConfigCurrentRate( screen_config );
271 pXRRFreeScreenConfigInfo( screen_config );
273 mode->dmBitsPerPel = screen_bpp;
274 mode->dmPelsWidth = sizes[size_id].width;
275 mode->dmPelsHeight = sizes[size_id].height;
276 mode->dmDisplayFrequency = rate;
277 return TRUE;
280 static LONG xrandr10_set_current_mode( x11drv_settings_id id, const DEVMODEW *mode )
282 XRRScreenConfiguration *screen_config;
283 Rotation rotation;
284 SizeID size_id;
285 Window root;
286 Status stat;
288 if (id.id != 1)
290 FIXME("Non-primary adapters are unsupported.\n");
291 return DISP_CHANGE_SUCCESSFUL;
294 if (is_detached_mode(mode))
296 FIXME("Detaching adapters is unsupported.\n");
297 return DISP_CHANGE_SUCCESSFUL;
300 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
301 WARN("Cannot change screen bit depth from %dbits to %dbits!\n",
302 screen_bpp, (int)mode->dmBitsPerPel);
304 root = DefaultRootWindow( gdi_display );
305 screen_config = pXRRGetScreenInfo( gdi_display, root );
306 pXRRConfigCurrentConfiguration( screen_config, &rotation );
308 assert( mode->dmDriverExtra == sizeof(SizeID) );
309 memcpy( &size_id, (BYTE *)mode + sizeof(*mode), sizeof(size_id) );
311 if (mode->dmFields & DM_DISPLAYFREQUENCY && mode->dmDisplayFrequency)
312 stat = pXRRSetScreenConfigAndRate( gdi_display, screen_config, root, size_id, rotation,
313 mode->dmDisplayFrequency, CurrentTime );
314 else
315 stat = pXRRSetScreenConfig( gdi_display, screen_config, root, size_id, rotation, CurrentTime );
316 pXRRFreeScreenConfigInfo( screen_config );
318 if (stat != RRSetConfigSuccess)
319 return DISP_CHANGE_FAILED;
321 XFlush( gdi_display );
322 return DISP_CHANGE_SUCCESSFUL;
325 #ifdef HAVE_XRRGETPROVIDERRESOURCES
327 static struct current_mode
329 ULONG_PTR id;
330 BOOL loaded;
331 DEVMODEW mode;
332 } *current_modes;
333 static int current_mode_count;
335 static pthread_mutex_t xrandr_mutex = PTHREAD_MUTEX_INITIALIZER;
337 static void xrandr14_invalidate_current_mode_cache(void)
339 pthread_mutex_lock( &xrandr_mutex );
340 free( current_modes);
341 current_modes = NULL;
342 current_mode_count = 0;
343 pthread_mutex_unlock( &xrandr_mutex );
346 static XRRScreenResources *xrandr_get_screen_resources(void)
348 XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window );
349 if (resources && !resources->ncrtc)
351 pXRRFreeScreenResources( resources );
352 resources = pXRRGetScreenResources( gdi_display, root_window );
355 if (!resources)
356 ERR("Failed to get screen resources.\n");
357 return resources;
360 /* Some (304.64, possibly earlier) versions of the NVIDIA driver only
361 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
362 * are only listed through RandR 1.0 / 1.1. This is completely useless,
363 * but NVIDIA considers this a feature, so it's unlikely to change. The
364 * best we can do is to fall back to RandR 1.0 and encourage users to
365 * consider more cooperative driver vendors when we detect such a
366 * configuration. */
367 static BOOL is_broken_driver(void)
369 XRRScreenResources *screen_resources;
370 XRROutputInfo *output_info;
371 XRRModeInfo *first_mode;
372 INT major, event, error;
373 INT output_idx, i, j;
374 BOOL only_one_mode;
376 screen_resources = xrandr_get_screen_resources();
377 if (!screen_resources)
378 return TRUE;
380 /* Check if any output only has one native mode */
381 for (output_idx = 0; output_idx < screen_resources->noutput; ++output_idx)
383 output_info = pXRRGetOutputInfo( gdi_display, screen_resources,
384 screen_resources->outputs[output_idx] );
385 if (!output_info)
386 continue;
388 if (output_info->connection != RR_Connected)
390 pXRRFreeOutputInfo( output_info );
391 continue;
394 first_mode = NULL;
395 only_one_mode = TRUE;
396 for (i = 0; i < output_info->nmode; ++i)
398 for (j = 0; j < screen_resources->nmode; ++j)
400 if (output_info->modes[i] != screen_resources->modes[j].id)
401 continue;
403 if (!first_mode)
405 first_mode = &screen_resources->modes[j];
406 break;
409 if (first_mode->width != screen_resources->modes[j].width ||
410 first_mode->height != screen_resources->modes[j].height)
411 only_one_mode = FALSE;
413 break;
416 if (!only_one_mode)
417 break;
419 pXRRFreeOutputInfo( output_info );
421 if (!only_one_mode)
422 continue;
424 /* Check if it is NVIDIA proprietary driver */
425 if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error ))
427 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
428 "Please consider using the Nouveau driver instead.\n");
429 pXRRFreeScreenResources( screen_resources );
430 return TRUE;
433 pXRRFreeScreenResources( screen_resources );
434 return FALSE;
437 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
439 int min_width = 0, min_height = 0, max_width, max_height;
440 XRRCrtcInfo *crtc_info;
441 int i;
443 pXRRGetScreenSizeRange( gdi_display, root_window, &min_width, &min_height, &max_width, &max_height );
444 *width = min_width;
445 *height = min_height;
447 for (i = 0; i < resources->ncrtc; ++i)
449 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
450 continue;
452 if (crtc_info->mode != None)
454 *width = max(*width, crtc_info->x + crtc_info->width);
455 *height = max(*height, crtc_info->y + crtc_info->height);
458 pXRRFreeCrtcInfo( crtc_info );
462 static unsigned int get_edid( RROutput output, unsigned char **prop )
464 int result, actual_format;
465 unsigned long bytes_after, len;
466 Atom actual_type;
468 result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE,
469 AnyPropertyType, &actual_type, &actual_format, &len,
470 &bytes_after, prop );
472 if (result != Success)
474 WARN("Could not retrieve EDID property for output %#lx.\n", output);
475 *prop = NULL;
476 return 0;
478 return len;
481 static void set_screen_size( int width, int height )
483 int screen = default_visual.screen;
484 int mm_width, mm_height;
486 mm_width = width * DisplayWidthMM( gdi_display, screen ) / DisplayWidth( gdi_display, screen );
487 mm_height = height * DisplayHeightMM( gdi_display, screen ) / DisplayHeight( gdi_display, screen );
488 pXRRSetScreenSize( gdi_display, root_window, width, height, mm_width, mm_height );
491 static unsigned int get_frequency( const XRRModeInfo *mode )
493 unsigned int dots = mode->hTotal * mode->vTotal;
495 if (!dots)
496 return 0;
498 if (mode->modeFlags & RR_DoubleScan)
499 dots *= 2;
500 if (mode->modeFlags & RR_Interlace)
501 dots /= 2;
503 return (mode->dotClock + dots / 2) / dots;
506 static DWORD get_orientation( Rotation rotation )
508 if (rotation & RR_Rotate_270) return DMDO_270;
509 if (rotation & RR_Rotate_180) return DMDO_180;
510 if (rotation & RR_Rotate_90) return DMDO_90;
511 return DMDO_DEFAULT;
514 static DWORD get_orientation_count( Rotation rotations )
516 DWORD count = 0;
518 if (rotations & RR_Rotate_0) ++count;
519 if (rotations & RR_Rotate_90) ++count;
520 if (rotations & RR_Rotate_180) ++count;
521 if (rotations & RR_Rotate_270) ++count;
522 return count;
525 static Rotation get_rotation( DWORD orientation )
527 return (Rotation)(1 << orientation);
530 static RRCrtc get_output_free_crtc( XRRScreenResources *resources, XRROutputInfo *output_info )
532 XRRCrtcInfo *crtc_info;
533 INT crtc_idx;
534 RRCrtc crtc;
536 for (crtc_idx = 0; crtc_idx < output_info->ncrtc; ++crtc_idx)
538 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtcs[crtc_idx] );
539 if (!crtc_info)
540 continue;
542 if (!crtc_info->noutput)
544 crtc = output_info->crtcs[crtc_idx];
545 pXRRFreeCrtcInfo( crtc_info );
546 return crtc;
549 pXRRFreeCrtcInfo( crtc_info );
552 return 0;
555 static RECT get_primary_rect( XRRScreenResources *resources )
557 XRROutputInfo *output_info = NULL;
558 XRRCrtcInfo *crtc_info = NULL;
559 RROutput primary_output;
560 RECT primary_rect = {0};
561 RECT first_rect = {0};
562 INT i;
564 primary_output = pXRRGetOutputPrimary( gdi_display, root_window );
565 if (!primary_output)
566 goto fallback;
568 output_info = pXRRGetOutputInfo( gdi_display, resources, primary_output );
569 if (!output_info || output_info->connection != RR_Connected || !output_info->crtc)
570 goto fallback;
572 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtc );
573 if (!crtc_info || !crtc_info->mode)
574 goto fallback;
576 SetRect( &primary_rect, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
577 pXRRFreeCrtcInfo( crtc_info );
578 pXRRFreeOutputInfo( output_info );
579 return primary_rect;
581 /* Fallback when XRandR primary output is a disconnected output.
582 * Try to find a crtc with (x, y) being (0, 0). If it's found then get the primary rect from that crtc,
583 * otherwise use the first active crtc to get the primary rect */
584 fallback:
585 if (crtc_info)
586 pXRRFreeCrtcInfo( crtc_info );
587 if (output_info)
588 pXRRFreeOutputInfo( output_info );
590 WARN("Primary is set to a disconnected XRandR output.\n");
591 for (i = 0; i < resources->ncrtc; ++i)
593 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
594 if (!crtc_info)
595 continue;
597 if (!crtc_info->mode)
599 pXRRFreeCrtcInfo( crtc_info );
600 continue;
603 if (!crtc_info->x && !crtc_info->y)
605 SetRect( &primary_rect, 0, 0, crtc_info->width, crtc_info->height );
606 pXRRFreeCrtcInfo( crtc_info );
607 break;
610 if (IsRectEmpty( &first_rect ))
611 SetRect( &first_rect, crtc_info->x, crtc_info->y,
612 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
614 pXRRFreeCrtcInfo( crtc_info );
617 return IsRectEmpty( &primary_rect ) ? first_rect : primary_rect;
620 static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
622 return crtc &&
623 crtc->mode &&
624 crtc->x == primary.left &&
625 crtc->y == primary.top &&
626 crtc->x + crtc->width == primary.right &&
627 crtc->y + crtc->height == primary.bottom;
630 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
632 static BOOL get_gpu_properties_from_vulkan( struct gdi_gpu *gpu, const XRRProviderInfo *provider_info,
633 struct gdi_gpu *prev_gpus, int prev_gpu_count )
635 static const char *extensions[] =
637 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
638 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
639 "VK_EXT_acquire_xlib_display",
640 "VK_EXT_direct_mode_display",
641 "VK_KHR_display",
642 VK_KHR_SURFACE_EXTENSION_NAME,
644 const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION );
645 VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
646 PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
647 PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
648 uint32_t device_count, device_idx, output_idx, i;
649 VkPhysicalDevice *vk_physical_devices = NULL;
650 VkPhysicalDeviceProperties2 properties2;
651 VkInstanceCreateInfo create_info;
652 VkPhysicalDeviceIDProperties id;
653 VkInstance vk_instance = NULL;
654 VkDisplayKHR vk_display;
655 DWORD len;
656 BOOL ret = FALSE;
657 VkResult vr;
659 if (!vulkan_funcs)
660 goto done;
662 memset( &create_info, 0, sizeof(create_info) );
663 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
664 create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
665 create_info.ppEnabledExtensionNames = extensions;
667 vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance );
668 if (vr != VK_SUCCESS)
670 WARN("Failed to create a Vulkan instance, vr %d.\n", vr);
671 goto done;
674 #define LOAD_VK_FUNC(f) \
675 if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \
677 WARN("Failed to load " #f ".\n"); \
678 goto done; \
681 LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
682 LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
683 LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
684 #undef LOAD_VK_FUNC
686 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
687 if (vr != VK_SUCCESS || !device_count)
689 WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
690 goto done;
693 if (!(vk_physical_devices = calloc( device_count, sizeof(*vk_physical_devices) )))
694 goto done;
696 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
697 if (vr != VK_SUCCESS)
699 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
700 goto done;
703 TRACE("provider name %s.\n", debugstr_a(provider_info->name));
705 for (device_idx = 0; device_idx < device_count; ++device_idx)
707 for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
709 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
710 vr = pvkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
711 provider_info->outputs[output_idx], &vk_display );
712 XSync( gdi_display, FALSE );
713 if (X11DRV_check_error() || vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
714 continue;
716 memset( &id, 0, sizeof(id) );
717 id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
718 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
719 properties2.pNext = &id;
721 pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
722 for (i = 0; i < prev_gpu_count; ++i)
724 if (!memcmp( &prev_gpus[i].vulkan_uuid, &id.deviceUUID, sizeof(id.deviceUUID) ))
726 WARN( "device UUID %#x:%#x already assigned to GPU %u.\n", *((uint32_t *)id.deviceUUID + 1),
727 *(uint32_t *)id.deviceUUID, i );
728 break;
731 if (i < prev_gpu_count) continue;
733 memcpy( &gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) );
735 /* Ignore Khronos vendor IDs */
736 if (properties2.properties.vendorID < 0x10000)
738 gpu->vendor_id = properties2.properties.vendorID;
739 gpu->device_id = properties2.properties.deviceID;
741 RtlUTF8ToUnicodeN( gpu->name, sizeof(gpu->name), &len, properties2.properties.deviceName,
742 strlen( properties2.properties.deviceName ) + 1 );
743 ret = TRUE;
744 goto done;
748 done:
749 free( vk_physical_devices );
750 if (vk_instance)
751 vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL );
752 return ret;
755 /* Get a list of GPUs reported by XRandR 1.4. Set get_properties to FALSE if GPU properties are
756 * not needed to avoid unnecessary querying */
757 static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_properties )
759 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
760 struct gdi_gpu *gpus = NULL;
761 XRRScreenResources *screen_resources = NULL;
762 XRRProviderResources *provider_resources = NULL;
763 XRRProviderInfo *provider_info = NULL;
764 XRRCrtcInfo *crtc_info = NULL;
765 INT primary_provider = -1;
766 RECT primary_rect;
767 BOOL ret = FALSE;
768 DWORD len;
769 INT i, j;
771 screen_resources = xrandr_get_screen_resources();
772 if (!screen_resources)
773 goto done;
775 provider_resources = pXRRGetProviderResources( gdi_display, root_window );
776 if (!provider_resources)
777 goto done;
779 gpus = calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) );
780 if (!gpus)
781 goto done;
783 /* Some XRandR implementations don't support providers.
784 * In this case, report a fake one to try searching adapters in screen resources */
785 if (!provider_resources->nproviders)
787 WARN("XRandR implementation doesn't report any providers, faking one.\n");
788 lstrcpyW( gpus[0].name, wine_adapterW );
789 *new_gpus = gpus;
790 *count = 1;
791 ret = TRUE;
792 goto done;
795 primary_rect = get_primary_rect( screen_resources );
796 for (i = 0; i < provider_resources->nproviders; ++i)
798 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, provider_resources->providers[i] );
799 if (!provider_info)
800 goto done;
802 /* Find primary provider */
803 for (j = 0; primary_provider == -1 && j < provider_info->ncrtcs; ++j)
805 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, provider_info->crtcs[j] );
806 if (!crtc_info)
807 continue;
809 if (is_crtc_primary( primary_rect, crtc_info ))
811 primary_provider = i;
812 pXRRFreeCrtcInfo( crtc_info );
813 break;
816 pXRRFreeCrtcInfo( crtc_info );
819 gpus[i].id = provider_resources->providers[i];
820 if (get_properties)
822 if (!get_gpu_properties_from_vulkan( &gpus[i], provider_info, gpus, i ))
823 RtlUTF8ToUnicodeN( gpus[i].name, sizeof(gpus[i].name), &len, provider_info->name,
824 strlen( provider_info->name ) + 1 );
825 /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */
827 pXRRFreeProviderInfo( provider_info );
830 /* Make primary GPU the first */
831 if (primary_provider > 0)
833 struct gdi_gpu tmp = gpus[0];
834 gpus[0] = gpus[primary_provider];
835 gpus[primary_provider] = tmp;
838 *new_gpus = gpus;
839 *count = provider_resources->nproviders;
840 ret = TRUE;
841 done:
842 if (provider_resources)
843 pXRRFreeProviderResources( provider_resources );
844 if (screen_resources)
845 pXRRFreeScreenResources( screen_resources );
846 if (!ret)
848 free( gpus );
849 ERR("Failed to get gpus\n");
851 return ret;
854 static BOOL xrandr14_get_gpus( struct gdi_gpu **new_gpus, int *count )
856 return xrandr14_get_gpus2( new_gpus, count, TRUE );
859 static void xrandr14_free_gpus( struct gdi_gpu *gpus )
861 free( gpus );
864 static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_adapters, int *count )
866 struct gdi_adapter *adapters = NULL;
867 XRRScreenResources *screen_resources = NULL;
868 XRRProviderInfo *provider_info = NULL;
869 XRRCrtcInfo *enum_crtc_info, *crtc_info = NULL;
870 XRROutputInfo *enum_output_info, *output_info = NULL;
871 RROutput *outputs;
872 INT crtc_count, output_count;
873 INT primary_adapter = 0;
874 INT adapter_count = 0;
875 BOOL mirrored, detached;
876 RECT primary_rect;
877 BOOL ret = FALSE;
878 INT i, j;
880 screen_resources = xrandr_get_screen_resources();
881 if (!screen_resources)
882 goto done;
884 if (gpu_id)
886 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id );
887 if (!provider_info)
888 goto done;
890 crtc_count = provider_info->ncrtcs;
891 output_count = provider_info->noutputs;
892 outputs = provider_info->outputs;
894 /* Fake provider id, search adapters in screen resources */
895 else
897 crtc_count = screen_resources->ncrtc;
898 output_count = screen_resources->noutput;
899 outputs = screen_resources->outputs;
902 /* Actual adapter count could be less */
903 adapters = calloc( crtc_count, sizeof(*adapters) );
904 if (!adapters)
905 goto done;
907 primary_rect = get_primary_rect( screen_resources );
908 for (i = 0; i < output_count; ++i)
910 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, outputs[i] );
911 if (!output_info)
912 goto done;
914 /* Only connected output are considered as monitors */
915 if (output_info->connection != RR_Connected)
917 pXRRFreeOutputInfo( output_info );
918 output_info = NULL;
919 continue;
922 /* Connected output doesn't mean the output is attached to a crtc */
923 detached = FALSE;
924 if (output_info->crtc)
926 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
927 if (!crtc_info)
928 goto done;
931 if (!output_info->crtc || !crtc_info->mode)
932 detached = TRUE;
934 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
935 mirrored = FALSE;
936 if (!detached)
938 for (j = 0; j < screen_resources->noutput; ++j)
940 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[j] );
941 if (!enum_output_info)
942 continue;
944 if (enum_output_info->connection != RR_Connected || !enum_output_info->crtc)
946 pXRRFreeOutputInfo( enum_output_info );
947 continue;
950 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
951 pXRRFreeOutputInfo( enum_output_info );
952 if (!enum_crtc_info)
953 continue;
955 /* Some outputs may have the same coordinates, aka mirrored. Choose the output with
956 * the lowest value as primary and the rest will then be replicas in a mirroring set */
957 if (crtc_info->x == enum_crtc_info->x &&
958 crtc_info->y == enum_crtc_info->y &&
959 crtc_info->width == enum_crtc_info->width &&
960 crtc_info->height == enum_crtc_info->height &&
961 outputs[i] > screen_resources->outputs[j])
963 mirrored = TRUE;
964 pXRRFreeCrtcInfo( enum_crtc_info );
965 break;
968 pXRRFreeCrtcInfo( enum_crtc_info );
972 if (!mirrored || detached)
974 /* Use RROutput as adapter id. The reason of not using RRCrtc is that we need to detect inactive but
975 * attached monitors */
976 adapters[adapter_count].id = outputs[i];
977 if (!detached)
978 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
979 if (is_crtc_primary( primary_rect, crtc_info ))
981 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
982 primary_adapter = adapter_count;
985 ++adapter_count;
988 pXRRFreeOutputInfo( output_info );
989 output_info = NULL;
990 if (crtc_info)
992 pXRRFreeCrtcInfo( crtc_info );
993 crtc_info = NULL;
997 /* Make primary adapter the first */
998 if (primary_adapter)
1000 struct gdi_adapter tmp = adapters[0];
1001 adapters[0] = adapters[primary_adapter];
1002 adapters[primary_adapter] = tmp;
1005 *new_adapters = adapters;
1006 *count = adapter_count;
1007 ret = TRUE;
1008 done:
1009 if (screen_resources)
1010 pXRRFreeScreenResources( screen_resources );
1011 if (provider_info)
1012 pXRRFreeProviderInfo( provider_info );
1013 if (output_info)
1014 pXRRFreeOutputInfo( output_info );
1015 if (crtc_info)
1016 pXRRFreeCrtcInfo( crtc_info );
1017 if (!ret)
1019 free( adapters );
1020 ERR("Failed to get adapters\n");
1022 return ret;
1025 static void xrandr14_free_adapters( struct gdi_adapter *adapters )
1027 free( adapters );
1030 static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count )
1032 struct gdi_monitor *realloc_monitors, *monitors = NULL;
1033 XRRScreenResources *screen_resources = NULL;
1034 XRROutputInfo *output_info = NULL, *enum_output_info = NULL;
1035 XRRCrtcInfo *crtc_info = NULL, *enum_crtc_info;
1036 INT primary_index = 0, monitor_count = 0, capacity;
1037 RECT primary_rect;
1038 BOOL ret = FALSE;
1039 INT i;
1041 screen_resources = xrandr_get_screen_resources();
1042 if (!screen_resources)
1043 goto done;
1045 /* First start with a 2 monitors, should be enough for most cases */
1046 capacity = 2;
1047 monitors = calloc( capacity, sizeof(*monitors) );
1048 if (!monitors)
1049 goto done;
1051 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, adapter_id );
1052 if (!output_info)
1053 goto done;
1055 if (output_info->crtc)
1057 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1058 if (!crtc_info)
1059 goto done;
1062 /* Inactive but attached monitor, no need to check for mirrored/replica monitors */
1063 if (!output_info->crtc || !crtc_info->mode)
1065 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1066 monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid );
1067 monitor_count = 1;
1069 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
1070 else
1072 primary_rect = get_primary_rect( screen_resources );
1074 for (i = 0; i < screen_resources->noutput; ++i)
1076 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1077 if (!enum_output_info)
1078 goto done;
1080 /* Detached outputs don't count */
1081 if (enum_output_info->connection != RR_Connected)
1083 pXRRFreeOutputInfo( enum_output_info );
1084 enum_output_info = NULL;
1085 continue;
1088 /* Allocate more space if needed */
1089 if (monitor_count >= capacity)
1091 capacity *= 2;
1092 realloc_monitors = realloc( monitors, capacity * sizeof(*monitors) );
1093 if (!realloc_monitors)
1094 goto done;
1095 monitors = realloc_monitors;
1098 if (enum_output_info->crtc)
1100 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
1101 if (!enum_crtc_info)
1102 goto done;
1104 if (enum_crtc_info->x == crtc_info->x &&
1105 enum_crtc_info->y == crtc_info->y &&
1106 enum_crtc_info->width == crtc_info->width &&
1107 enum_crtc_info->height == crtc_info->height)
1109 SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y,
1110 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
1111 monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor );
1113 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1114 if (!IsRectEmpty( &monitors[monitor_count].rc_monitor ))
1115 monitors[monitor_count].state_flags |= DISPLAY_DEVICE_ACTIVE;
1117 if (is_crtc_primary( primary_rect, crtc_info ))
1118 primary_index = monitor_count;
1120 monitors[monitor_count].edid_len = get_edid( screen_resources->outputs[i],
1121 &monitors[monitor_count].edid );
1122 monitor_count++;
1125 pXRRFreeCrtcInfo( enum_crtc_info );
1128 pXRRFreeOutputInfo( enum_output_info );
1129 enum_output_info = NULL;
1132 /* Make sure the first monitor is the primary */
1133 if (primary_index)
1135 struct gdi_monitor tmp = monitors[0];
1136 monitors[0] = monitors[primary_index];
1137 monitors[primary_index] = tmp;
1140 /* Make sure the primary monitor origin is at (0, 0) */
1141 for (i = 0; i < monitor_count; i++)
1143 OffsetRect( &monitors[i].rc_monitor, -primary_rect.left, -primary_rect.top );
1144 OffsetRect( &monitors[i].rc_work, -primary_rect.left, -primary_rect.top );
1148 *new_monitors = monitors;
1149 *count = monitor_count;
1150 ret = TRUE;
1151 done:
1152 if (screen_resources)
1153 pXRRFreeScreenResources( screen_resources );
1154 if (output_info)
1155 pXRRFreeOutputInfo( output_info);
1156 if (crtc_info)
1157 pXRRFreeCrtcInfo( crtc_info );
1158 if (enum_output_info)
1159 pXRRFreeOutputInfo( enum_output_info );
1160 if (!ret)
1162 for (i = 0; i < monitor_count; i++)
1164 if (monitors[i].edid)
1165 XFree( monitors[i].edid );
1167 free( monitors );
1168 ERR("Failed to get monitors\n");
1170 return ret;
1173 static void xrandr14_free_monitors( struct gdi_monitor *monitors, int count )
1175 int i;
1177 for (i = 0; i < count; i++)
1179 if (monitors[i].edid)
1180 XFree( monitors[i].edid );
1182 free( monitors );
1185 static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
1187 RECT rect;
1189 xrandr14_invalidate_current_mode_cache();
1190 if (hwnd == NtUserGetDesktopWindow() && NtUserGetWindowThread( hwnd, NULL ) == GetCurrentThreadId())
1192 X11DRV_DisplayDevices_Init( TRUE );
1193 X11DRV_resize_desktop();
1195 /* Update xinerama monitors for xinerama_get_fullscreen_monitors() */
1196 rect = get_host_primary_monitor_rect();
1197 xinerama_init( rect.right - rect.left, rect.bottom - rect.top );
1198 return FALSE;
1201 static void xrandr14_register_event_handlers(void)
1203 Display *display = thread_init_display();
1204 int event_base, error_base;
1206 if (!pXRRQueryExtension( display, &event_base, &error_base ))
1207 return;
1209 pXRRSelectInput( display, root_window,
1210 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RRProviderChangeNotifyMask );
1211 X11DRV_register_event_handler( event_base + RRNotify_CrtcChange, xrandr14_device_change_handler,
1212 "XRandR CrtcChange" );
1213 X11DRV_register_event_handler( event_base + RRNotify_OutputChange, xrandr14_device_change_handler,
1214 "XRandR OutputChange" );
1215 X11DRV_register_event_handler( event_base + RRNotify_ProviderChange, xrandr14_device_change_handler,
1216 "XRandR ProviderChange" );
1219 /* XRandR 1.4 display settings handler */
1220 static BOOL xrandr14_get_id( const WCHAR *device_name, BOOL is_primary, x11drv_settings_id *id )
1222 struct current_mode *tmp_modes, *new_current_modes = NULL;
1223 INT gpu_count, adapter_count, new_current_mode_count = 0;
1224 INT gpu_idx, adapter_idx, display_idx;
1225 struct gdi_adapter *adapters;
1226 struct gdi_gpu *gpus;
1227 WCHAR *end;
1229 /* Parse \\.\DISPLAY%d */
1230 display_idx = wcstol( device_name + 11, &end, 10 ) - 1;
1231 if (*end)
1232 return FALSE;
1234 /* Update cache */
1235 pthread_mutex_lock( &xrandr_mutex );
1236 if (!current_modes)
1238 if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE ))
1240 pthread_mutex_unlock( &xrandr_mutex );
1241 return FALSE;
1244 for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx)
1246 if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count ))
1247 break;
1249 tmp_modes = realloc( new_current_modes, (new_current_mode_count + adapter_count) * sizeof(*tmp_modes) );
1250 if (!tmp_modes)
1252 xrandr14_free_adapters( adapters );
1253 break;
1255 new_current_modes = tmp_modes;
1257 for (adapter_idx = 0; adapter_idx < adapter_count; ++adapter_idx)
1259 new_current_modes[new_current_mode_count + adapter_idx].id = adapters[adapter_idx].id;
1260 new_current_modes[new_current_mode_count + adapter_idx].loaded = FALSE;
1262 new_current_mode_count += adapter_count;
1263 xrandr14_free_adapters( adapters );
1265 xrandr14_free_gpus( gpus );
1267 if (new_current_modes)
1269 free( current_modes );
1270 current_modes = new_current_modes;
1271 current_mode_count = new_current_mode_count;
1275 if (display_idx >= current_mode_count)
1277 pthread_mutex_unlock( &xrandr_mutex );
1278 return FALSE;
1281 id->id = current_modes[display_idx].id;
1282 pthread_mutex_unlock( &xrandr_mutex );
1283 return TRUE;
1286 static void add_xrandr14_mode( DEVMODEW *mode, XRRModeInfo *info, DWORD depth, DWORD frequency,
1287 DWORD orientation )
1289 mode->dmSize = sizeof(*mode);
1290 mode->dmDriverExtra = sizeof(RRMode);
1291 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
1292 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
1293 if (frequency)
1295 mode->dmFields |= DM_DISPLAYFREQUENCY;
1296 mode->dmDisplayFrequency = frequency;
1298 if (orientation == DMDO_DEFAULT || orientation == DMDO_180)
1300 mode->dmPelsWidth = info->width;
1301 mode->dmPelsHeight = info->height;
1303 else
1305 mode->dmPelsWidth = info->height;
1306 mode->dmPelsHeight = info->width;
1308 mode->u1.s2.dmDisplayOrientation = orientation;
1309 mode->dmBitsPerPel = depth;
1310 mode->u2.dmDisplayFlags = 0;
1311 memcpy( (BYTE *)mode + sizeof(*mode), &info->id, sizeof(info->id) );
1314 static BOOL xrandr14_get_modes( x11drv_settings_id id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count )
1316 DWORD frequency, orientation, orientation_count;
1317 XRRScreenResources *screen_resources;
1318 XRROutputInfo *output_info = NULL;
1319 RROutput output = (RROutput)id.id;
1320 XRRCrtcInfo *crtc_info = NULL;
1321 UINT depth_idx, mode_idx = 0;
1322 XRRModeInfo *mode_info;
1323 DEVMODEW *mode, *modes;
1324 Rotation rotations;
1325 BOOL ret = FALSE;
1326 RRCrtc crtc;
1327 INT i, j;
1329 screen_resources = xrandr_get_screen_resources();
1330 if (!screen_resources)
1331 goto done;
1333 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1334 if (!output_info)
1335 goto done;
1337 if (output_info->connection != RR_Connected)
1339 ret = TRUE;
1340 *new_modes = NULL;
1341 *mode_count = 0;
1342 goto done;
1345 crtc = output_info->crtc;
1346 if (!crtc)
1347 crtc = get_output_free_crtc( screen_resources, output_info );
1348 if (crtc)
1349 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1351 /* If the output is connected to a CRTC, use rotations reported by the CRTC */
1352 if (crtc_info)
1354 if (flags & EDS_ROTATEDMODE)
1356 rotations = crtc_info->rotations;
1358 else
1360 /* According to the RandR spec, RRGetCrtcInfo should set the active rotation to Rotate_0
1361 * when a CRTC is disabled. However, some RandR implementations report 0 in this case */
1362 rotations = (crtc_info->rotation & 0xf) ? crtc_info->rotation : RR_Rotate_0;
1365 /* Not connected to CRTC, assume all rotations are supported */
1366 else
1368 if (flags & EDS_ROTATEDMODE)
1370 rotations = RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270;
1372 else
1374 rotations = RR_Rotate_0;
1377 orientation_count = get_orientation_count( rotations );
1379 /* Allocate space for display modes in different color depths and orientations.
1380 * Store a RRMode at the end of each DEVMODEW as private driver data */
1381 modes = calloc( output_info->nmode * DEPTH_COUNT * orientation_count,
1382 sizeof(*modes) + sizeof(RRMode) );
1383 if (!modes)
1384 goto done;
1386 for (i = 0; i < output_info->nmode; ++i)
1388 for (j = 0; j < screen_resources->nmode; ++j)
1390 if (output_info->modes[i] != screen_resources->modes[j].id)
1391 continue;
1393 mode_info = &screen_resources->modes[j];
1394 frequency = get_frequency( mode_info );
1396 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
1398 for (orientation = DMDO_DEFAULT; orientation <= DMDO_270; ++orientation)
1400 if (!((1 << orientation) & rotations))
1401 continue;
1403 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*modes) + sizeof(RRMode)) * mode_idx);
1404 add_xrandr14_mode( mode, mode_info, depths[depth_idx], frequency, orientation );
1405 ++mode_idx;
1409 break;
1413 ret = TRUE;
1414 *new_modes = modes;
1415 *mode_count = mode_idx;
1416 done:
1417 if (crtc_info)
1418 pXRRFreeCrtcInfo( crtc_info );
1419 if (output_info)
1420 pXRRFreeOutputInfo( output_info );
1421 if (screen_resources)
1422 pXRRFreeScreenResources( screen_resources );
1423 return ret;
1426 static void xrandr14_free_modes( DEVMODEW *modes )
1428 free( modes );
1431 static BOOL xrandr14_get_current_mode( x11drv_settings_id id, DEVMODEW *mode )
1433 struct current_mode *mode_ptr = NULL;
1434 XRRScreenResources *screen_resources;
1435 XRROutputInfo *output_info = NULL;
1436 RROutput output = (RROutput)id.id;
1437 XRRModeInfo *mode_info = NULL;
1438 XRRCrtcInfo *crtc_info = NULL;
1439 BOOL ret = FALSE;
1440 RECT primary;
1441 INT mode_idx;
1443 pthread_mutex_lock( &xrandr_mutex );
1444 for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx)
1446 if (current_modes[mode_idx].id != id.id)
1447 continue;
1449 if (!current_modes[mode_idx].loaded)
1451 mode_ptr = &current_modes[mode_idx];
1452 break;
1455 memcpy( mode, &current_modes[mode_idx].mode, sizeof(*mode) );
1456 pthread_mutex_unlock( &xrandr_mutex );
1457 return TRUE;
1460 screen_resources = xrandr_get_screen_resources();
1461 if (!screen_resources)
1462 goto done;
1464 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1465 if (!output_info)
1466 goto done;
1468 if (output_info->crtc)
1470 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1471 if (!crtc_info)
1472 goto done;
1475 /* Detached */
1476 if (output_info->connection != RR_Connected || !output_info->crtc || !crtc_info->mode)
1478 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1479 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1480 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
1481 mode->dmBitsPerPel = 0;
1482 mode->dmPelsWidth = 0;
1483 mode->dmPelsHeight = 0;
1484 mode->u2.dmDisplayFlags = 0;
1485 mode->dmDisplayFrequency = 0;
1486 mode->u1.s2.dmPosition.x = 0;
1487 mode->u1.s2.dmPosition.y = 0;
1488 ret = TRUE;
1489 goto done;
1492 /* Attached */
1493 for (mode_idx = 0; mode_idx < screen_resources->nmode; ++mode_idx)
1495 if (crtc_info->mode == screen_resources->modes[mode_idx].id)
1497 mode_info = &screen_resources->modes[mode_idx];
1498 break;
1502 if (!mode_info)
1503 goto done;
1505 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
1506 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
1507 mode->u1.s2.dmDisplayOrientation = get_orientation( crtc_info->rotation );
1508 mode->dmBitsPerPel = screen_bpp;
1509 mode->dmPelsWidth = crtc_info->width;
1510 mode->dmPelsHeight = crtc_info->height;
1511 mode->u2.dmDisplayFlags = 0;
1512 mode->dmDisplayFrequency = get_frequency( mode_info );
1513 /* Convert RandR coordinates to virtual screen coordinates */
1514 primary = get_primary_rect( screen_resources );
1515 mode->u1.s2.dmPosition.x = crtc_info->x - primary.left;
1516 mode->u1.s2.dmPosition.y = crtc_info->y - primary.top;
1517 ret = TRUE;
1519 done:
1520 if (ret && mode_ptr)
1522 memcpy( &mode_ptr->mode, mode, sizeof(*mode) );
1523 mode_ptr->mode.dmSize = sizeof(*mode);
1524 mode_ptr->mode.dmDriverExtra = 0;
1525 mode_ptr->loaded = TRUE;
1527 pthread_mutex_unlock( &xrandr_mutex );
1528 if (crtc_info)
1529 pXRRFreeCrtcInfo( crtc_info );
1530 if (output_info)
1531 pXRRFreeOutputInfo( output_info );
1532 if (screen_resources)
1533 pXRRFreeScreenResources( screen_resources );
1534 return ret;
1537 static LONG xrandr14_set_current_mode( x11drv_settings_id id, const DEVMODEW *mode )
1539 unsigned int screen_width, screen_height;
1540 RROutput output = (RROutput)id.id, *outputs;
1541 XRRScreenResources *screen_resources;
1542 XRROutputInfo *output_info = NULL;
1543 XRRCrtcInfo *crtc_info = NULL;
1544 LONG ret = DISP_CHANGE_FAILED;
1545 Rotation rotation;
1546 INT output_count;
1547 RRCrtc crtc = 0;
1548 Status status;
1549 RRMode rrmode;
1551 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
1552 WARN("Cannot change screen color depth from %ubits to %ubits!\n",
1553 screen_bpp, (int)mode->dmBitsPerPel);
1555 screen_resources = xrandr_get_screen_resources();
1556 if (!screen_resources)
1557 return ret;
1559 XGrabServer( gdi_display );
1561 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1562 if (!output_info || output_info->connection != RR_Connected)
1563 goto done;
1565 if (is_detached_mode(mode))
1567 /* Already detached */
1568 if (!output_info->crtc)
1570 ret = DISP_CHANGE_SUCCESSFUL;
1571 goto done;
1574 /* Execute detach operation */
1575 status = pXRRSetCrtcConfig( gdi_display, screen_resources, output_info->crtc,
1576 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0 );
1577 if (status == RRSetConfigSuccess)
1579 get_screen_size( screen_resources, &screen_width, &screen_height );
1580 set_screen_size( screen_width, screen_height );
1581 ret = DISP_CHANGE_SUCCESSFUL;
1583 goto done;
1586 /* Attached */
1587 if (output_info->crtc)
1589 crtc = output_info->crtc;
1591 /* Detached, need to find a free CRTC */
1592 else
1594 if (!(crtc = get_output_free_crtc( screen_resources, output_info )))
1595 goto done;
1598 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1599 if (!crtc_info)
1600 goto done;
1602 assert( mode->dmDriverExtra == sizeof(RRMode) );
1603 memcpy( &rrmode, (BYTE *)mode + sizeof(*mode), sizeof(rrmode) );
1605 if (crtc_info->noutput)
1607 outputs = crtc_info->outputs;
1608 output_count = crtc_info->noutput;
1610 else
1612 outputs = &output;
1613 output_count = 1;
1615 rotation = get_rotation( mode->u1.s2.dmDisplayOrientation );
1617 /* According to the RandR spec, the entire CRTC must fit inside the screen.
1618 * Since we use the union of all enabled CRTCs to determine the necessary
1619 * screen size, this might involve shrinking the screen, so we must disable
1620 * the CRTC in question first. */
1621 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime, 0, 0, None,
1622 RR_Rotate_0, NULL, 0 );
1623 if (status != RRSetConfigSuccess)
1624 goto done;
1626 get_screen_size( screen_resources, &screen_width, &screen_height );
1627 screen_width = max( screen_width, mode->u1.s2.dmPosition.x + mode->dmPelsWidth );
1628 screen_height = max( screen_height, mode->u1.s2.dmPosition.y + mode->dmPelsHeight );
1629 set_screen_size( screen_width, screen_height );
1631 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
1632 mode->u1.s2.dmPosition.x, mode->u1.s2.dmPosition.y, rrmode,
1633 rotation, outputs, output_count );
1634 if (status == RRSetConfigSuccess)
1635 ret = DISP_CHANGE_SUCCESSFUL;
1637 done:
1638 XUngrabServer( gdi_display );
1639 XFlush( gdi_display );
1640 if (crtc_info)
1641 pXRRFreeCrtcInfo( crtc_info );
1642 if (output_info)
1643 pXRRFreeOutputInfo( output_info );
1644 pXRRFreeScreenResources( screen_resources );
1645 xrandr14_invalidate_current_mode_cache();
1646 return ret;
1649 #endif
1651 void X11DRV_XRandR_Init(void)
1653 struct x11drv_display_device_handler display_handler;
1654 struct x11drv_settings_handler settings_handler;
1655 int event_base, error_base, minor, ret;
1656 static int major;
1657 Bool ok;
1659 if (major) return; /* already initialized? */
1660 if (!usexrandr) return; /* disabled in config */
1661 if (is_virtual_desktop()) return;
1662 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
1664 /* see if Xrandr is available */
1665 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
1666 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
1667 ok = pXRRQueryVersion( gdi_display, &major, &minor );
1668 if (X11DRV_check_error() || !ok) return;
1670 TRACE("Found XRandR %d.%d.\n", major, minor);
1672 settings_handler.name = "XRandR 1.0";
1673 settings_handler.priority = 200;
1674 settings_handler.get_id = xrandr10_get_id;
1675 settings_handler.get_modes = xrandr10_get_modes;
1676 settings_handler.free_modes = xrandr10_free_modes;
1677 settings_handler.get_current_mode = xrandr10_get_current_mode;
1678 settings_handler.set_current_mode = xrandr10_set_current_mode;
1679 X11DRV_Settings_SetHandler( &settings_handler );
1681 #ifdef HAVE_XRRGETPROVIDERRESOURCES
1682 if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))
1684 XRRScreenResources *screen_resources;
1685 XRROutputInfo *output_info;
1686 BOOL found_output = FALSE;
1687 INT i;
1689 screen_resources = xrandr_get_screen_resources();
1690 if (!screen_resources)
1691 return;
1693 for (i = 0; i < screen_resources->noutput; ++i)
1695 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1696 if (!output_info)
1697 continue;
1699 if (output_info->connection == RR_Connected)
1701 pXRRFreeOutputInfo( output_info );
1702 found_output = TRUE;
1703 break;
1706 pXRRFreeOutputInfo( output_info );
1708 pXRRFreeScreenResources( screen_resources );
1710 if (!found_output)
1712 WARN("No connected outputs found.\n");
1713 return;
1716 display_handler.name = "XRandR 1.4";
1717 display_handler.priority = 200;
1718 display_handler.get_gpus = xrandr14_get_gpus;
1719 display_handler.get_adapters = xrandr14_get_adapters;
1720 display_handler.get_monitors = xrandr14_get_monitors;
1721 display_handler.free_gpus = xrandr14_free_gpus;
1722 display_handler.free_adapters = xrandr14_free_adapters;
1723 display_handler.free_monitors = xrandr14_free_monitors;
1724 display_handler.register_event_handlers = xrandr14_register_event_handlers;
1725 X11DRV_DisplayDevices_SetHandler( &display_handler );
1727 if (is_broken_driver())
1728 return;
1730 settings_handler.name = "XRandR 1.4";
1731 settings_handler.priority = 300;
1732 settings_handler.get_id = xrandr14_get_id;
1733 settings_handler.get_modes = xrandr14_get_modes;
1734 settings_handler.free_modes = xrandr14_free_modes;
1735 settings_handler.get_current_mode = xrandr14_get_current_mode;
1736 settings_handler.set_current_mode = xrandr14_set_current_mode;
1737 X11DRV_Settings_SetHandler( &settings_handler );
1739 #endif
1742 #else /* SONAME_LIBXRANDR */
1744 void X11DRV_XRandR_Init(void)
1746 TRACE("XRandR support not compiled in.\n");
1749 #endif /* SONAME_LIBXRANDR */