dllhost: Add ISurrogate stub implementation.
[wine.git] / dlls / winex11.drv / xrandr.c
blobfb7a4405a1e09e2e5b7b2c26445ee69c9d12624f
1 /*
2 * Wine X11drv Xrandr interface
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2012 Henri Verbeet for CodeWeavers
6 * Copyright 2019 Zhiyi Zhang for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
31 #ifdef HAVE_XRRGETPROVIDERRESOURCES
32 WINE_DECLARE_DEBUG_CHANNEL(winediag);
33 #endif
35 #ifdef SONAME_LIBXRANDR
37 #include <assert.h>
38 #include <X11/Xlib.h>
39 #include <X11/extensions/Xrandr.h>
40 #include <dlfcn.h>
41 #include "x11drv.h"
43 #define VK_NO_PROTOTYPES
44 #define WINE_VK_HOST
46 #include "wine/heap.h"
47 #include "wine/unicode.h"
48 #include "wine/vulkan.h"
49 #include "wine/vulkan_driver.h"
51 static void *xrandr_handle;
53 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
54 MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
55 MAKE_FUNCPTR(XRRConfigCurrentRate)
56 MAKE_FUNCPTR(XRRFreeScreenConfigInfo)
57 MAKE_FUNCPTR(XRRGetScreenInfo)
58 MAKE_FUNCPTR(XRRQueryExtension)
59 MAKE_FUNCPTR(XRRQueryVersion)
60 MAKE_FUNCPTR(XRRRates)
61 MAKE_FUNCPTR(XRRSetScreenConfig)
62 MAKE_FUNCPTR(XRRSetScreenConfigAndRate)
63 MAKE_FUNCPTR(XRRSizes)
65 #ifdef HAVE_XRRGETPROVIDERRESOURCES
66 MAKE_FUNCPTR(XRRFreeCrtcInfo)
67 MAKE_FUNCPTR(XRRFreeOutputInfo)
68 MAKE_FUNCPTR(XRRFreeScreenResources)
69 MAKE_FUNCPTR(XRRGetCrtcInfo)
70 MAKE_FUNCPTR(XRRGetOutputInfo)
71 MAKE_FUNCPTR(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, ULONG_PTR *id )
147 WCHAR primary_adapter[CCHDEVICENAME];
149 if (!get_primary_adapter( primary_adapter ))
150 return FALSE;
152 /* RandR 1.0 only supports changing the primary adapter settings.
153 * For non-primary adapters, an id is still provided but getting
154 * and changing non-primary adapters' settings will be ignored. */
155 *id = !lstrcmpiW( device_name, primary_adapter ) ? 1 : 0;
156 return TRUE;
159 static void add_xrandr10_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height,
160 DWORD frequency, SizeID size_id )
162 mode->dmSize = sizeof(*mode);
163 mode->dmDriverExtra = sizeof(SizeID);
164 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH |
165 DM_PELSHEIGHT | DM_DISPLAYFLAGS;
166 if (frequency)
168 mode->dmFields |= DM_DISPLAYFREQUENCY;
169 mode->dmDisplayFrequency = frequency;
171 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
172 mode->dmBitsPerPel = depth;
173 mode->dmPelsWidth = width;
174 mode->dmPelsHeight = height;
175 mode->u2.dmDisplayFlags = 0;
176 memcpy( (BYTE *)mode + sizeof(*mode), &size_id, sizeof(size_id) );
179 static BOOL xrandr10_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *new_mode_count )
181 INT size_idx, depth_idx, rate_idx, mode_idx = 0;
182 INT size_count, rate_count, mode_count = 0;
183 DEVMODEW *modes, *mode;
184 XRRScreenSize *sizes;
185 short *rates;
187 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
188 if (size_count <= 0)
189 return FALSE;
191 for (size_idx = 0; size_idx < size_count; ++size_idx)
193 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
194 if (rate_count)
195 mode_count += rate_count;
196 else
197 ++mode_count;
200 /* Allocate space for reported modes in three depths, and put an SizeID at the end of DEVMODEW as
201 * driver private data */
202 modes = heap_calloc( mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID) );
203 if (!modes)
205 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
206 return FALSE;
209 for (size_idx = 0; size_idx < size_count; ++size_idx)
211 for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
213 rates = pXRRRates( gdi_display, DefaultScreen( gdi_display ), size_idx, &rate_count );
214 if (!rate_count)
216 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
217 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
218 sizes[size_idx].height, 0, size_idx );
219 continue;
222 for (rate_idx = 0; rate_idx < rate_count; ++rate_idx)
224 mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*mode) + sizeof(SizeID)) * mode_idx++);
225 add_xrandr10_mode( mode, depths[depth_idx], sizes[size_idx].width,
226 sizes[size_idx].height, rates[rate_idx], size_idx );
231 *new_modes = modes;
232 *new_mode_count = mode_idx;
233 return TRUE;
236 static void xrandr10_free_modes( DEVMODEW *modes )
238 heap_free( modes );
241 static BOOL xrandr10_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
243 XRRScreenConfiguration *screen_config;
244 XRRScreenSize *sizes;
245 Rotation rotation;
246 SizeID size_id;
247 INT size_count;
248 short rate;
250 mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
251 DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
252 mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
253 mode->u2.dmDisplayFlags = 0;
254 mode->u1.s2.dmPosition.x = 0;
255 mode->u1.s2.dmPosition.y = 0;
257 if (id != 1)
259 FIXME("Non-primary adapters are unsupported.\n");
260 mode->dmBitsPerPel = 0;
261 mode->dmPelsWidth = 0;
262 mode->dmPelsHeight = 0;
263 mode->dmDisplayFrequency = 0;
264 return TRUE;
267 sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count );
268 if (size_count <= 0)
269 return FALSE;
271 screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) );
272 size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation );
273 rate = pXRRConfigCurrentRate( screen_config );
274 pXRRFreeScreenConfigInfo( screen_config );
276 mode->dmBitsPerPel = screen_bpp;
277 mode->dmPelsWidth = sizes[size_id].width;
278 mode->dmPelsHeight = sizes[size_id].height;
279 mode->dmDisplayFrequency = rate;
280 return TRUE;
283 static LONG xrandr10_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
285 XRRScreenConfiguration *screen_config;
286 Rotation rotation;
287 SizeID size_id;
288 Window root;
289 Status stat;
291 if (id != 1)
293 FIXME("Non-primary adapters are unsupported.\n");
294 return DISP_CHANGE_SUCCESSFUL;
297 if (is_detached_mode(mode))
299 FIXME("Detaching adapters is unsupported.\n");
300 return DISP_CHANGE_SUCCESSFUL;
303 if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
304 WARN("Cannot change screen bit depth from %dbits to %dbits!\n", screen_bpp, mode->dmBitsPerPel);
306 root = DefaultRootWindow( gdi_display );
307 screen_config = pXRRGetScreenInfo( gdi_display, root );
308 pXRRConfigCurrentConfiguration( screen_config, &rotation );
310 assert( mode->dmDriverExtra == sizeof(SizeID) );
311 memcpy( &size_id, (BYTE *)mode + sizeof(*mode), sizeof(size_id) );
313 if (mode->dmFields & DM_DISPLAYFREQUENCY && mode->dmDisplayFrequency)
314 stat = pXRRSetScreenConfigAndRate( gdi_display, screen_config, root, size_id, rotation,
315 mode->dmDisplayFrequency, CurrentTime );
316 else
317 stat = pXRRSetScreenConfig( gdi_display, screen_config, root, size_id, rotation, CurrentTime );
318 pXRRFreeScreenConfigInfo( screen_config );
320 if (stat != RRSetConfigSuccess)
321 return DISP_CHANGE_FAILED;
323 XFlush( gdi_display );
324 return DISP_CHANGE_SUCCESSFUL;
327 #ifdef HAVE_XRRGETPROVIDERRESOURCES
329 static struct current_mode
331 ULONG_PTR id;
332 BOOL loaded;
333 DEVMODEW mode;
334 } *current_modes;
335 static int current_mode_count;
337 static CRITICAL_SECTION current_modes_section;
338 static CRITICAL_SECTION_DEBUG current_modes_critsect_debug =
340 0, 0, &current_modes_section,
341 {&current_modes_critsect_debug.ProcessLocksList, &current_modes_critsect_debug.ProcessLocksList},
342 0, 0, {(DWORD_PTR)(__FILE__ ": current_modes_section")}
344 static CRITICAL_SECTION current_modes_section = {&current_modes_critsect_debug, -1, 0, 0, 0, 0};
346 static void xrandr14_invalidate_current_mode_cache(void)
348 EnterCriticalSection( &current_modes_section );
349 heap_free( current_modes);
350 current_modes = NULL;
351 current_mode_count = 0;
352 LeaveCriticalSection( &current_modes_section );
355 static XRRScreenResources *xrandr_get_screen_resources(void)
357 XRRScreenResources *resources = pXRRGetScreenResourcesCurrent( gdi_display, root_window );
358 if (resources && !resources->ncrtc)
360 pXRRFreeScreenResources( resources );
361 resources = pXRRGetScreenResources( gdi_display, root_window );
364 if (!resources)
365 ERR("Failed to get screen resources.\n");
366 return resources;
369 /* Some (304.64, possibly earlier) versions of the NVIDIA driver only
370 * report a DFP's native mode through RandR 1.2 / 1.3. Standard DMT modes
371 * are only listed through RandR 1.0 / 1.1. This is completely useless,
372 * but NVIDIA considers this a feature, so it's unlikely to change. The
373 * best we can do is to fall back to RandR 1.0 and encourage users to
374 * consider more cooperative driver vendors when we detect such a
375 * configuration. */
376 static BOOL is_broken_driver(void)
378 XRRScreenResources *screen_resources;
379 XRROutputInfo *output_info;
380 XRRModeInfo *first_mode;
381 INT major, event, error;
382 INT output_idx, i, j;
383 BOOL only_one_mode;
385 screen_resources = xrandr_get_screen_resources();
386 if (!screen_resources)
387 return TRUE;
389 /* Check if any output only has one native mode */
390 for (output_idx = 0; output_idx < screen_resources->noutput; ++output_idx)
392 output_info = pXRRGetOutputInfo( gdi_display, screen_resources,
393 screen_resources->outputs[output_idx] );
394 if (!output_info)
395 continue;
397 if (output_info->connection != RR_Connected)
399 pXRRFreeOutputInfo( output_info );
400 continue;
403 first_mode = NULL;
404 only_one_mode = TRUE;
405 for (i = 0; i < output_info->nmode; ++i)
407 for (j = 0; j < screen_resources->nmode; ++j)
409 if (output_info->modes[i] != screen_resources->modes[j].id)
410 continue;
412 if (!first_mode)
414 first_mode = &screen_resources->modes[j];
415 break;
418 if (first_mode->width != screen_resources->modes[j].width ||
419 first_mode->height != screen_resources->modes[j].height)
420 only_one_mode = FALSE;
422 break;
425 if (!only_one_mode)
426 break;
428 pXRRFreeOutputInfo( output_info );
430 if (!only_one_mode)
431 continue;
433 /* Check if it is NVIDIA proprietary driver */
434 if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error ))
436 ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. "
437 "Please consider using the Nouveau driver instead.\n");
438 pXRRFreeScreenResources( screen_resources );
439 return TRUE;
442 pXRRFreeScreenResources( screen_resources );
443 return FALSE;
446 static void get_screen_size( XRRScreenResources *resources, unsigned int *width, unsigned int *height )
448 int min_width = 0, min_height = 0, max_width, max_height;
449 XRRCrtcInfo *crtc_info;
450 int i;
452 pXRRGetScreenSizeRange( gdi_display, root_window, &min_width, &min_height, &max_width, &max_height );
453 *width = min_width;
454 *height = min_height;
456 for (i = 0; i < resources->ncrtc; ++i)
458 if (!(crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] )))
459 continue;
461 if (crtc_info->mode != None)
463 *width = max(*width, crtc_info->x + crtc_info->width);
464 *height = max(*height, crtc_info->y + crtc_info->height);
467 pXRRFreeCrtcInfo( crtc_info );
471 static unsigned int get_edid( RROutput output, unsigned char **prop )
473 int result, actual_format;
474 unsigned long bytes_after, len;
475 Atom actual_type;
477 result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE,
478 AnyPropertyType, &actual_type, &actual_format, &len,
479 &bytes_after, prop );
481 if (result != Success)
483 WARN("Could not retrieve EDID property for output %#lx.\n", output);
484 *prop = NULL;
485 return 0;
487 return len;
490 static void set_screen_size( int width, int height )
492 int screen = default_visual.screen;
493 int mm_width, mm_height;
495 mm_width = width * DisplayWidthMM( gdi_display, screen ) / DisplayWidth( gdi_display, screen );
496 mm_height = height * DisplayHeightMM( gdi_display, screen ) / DisplayHeight( gdi_display, screen );
497 pXRRSetScreenSize( gdi_display, root_window, width, height, mm_width, mm_height );
500 static unsigned int get_frequency( const XRRModeInfo *mode )
502 unsigned int dots = mode->hTotal * mode->vTotal;
504 if (!dots)
505 return 0;
507 if (mode->modeFlags & RR_DoubleScan)
508 dots *= 2;
509 if (mode->modeFlags & RR_Interlace)
510 dots /= 2;
512 return (mode->dotClock + dots / 2) / dots;
515 static DWORD get_orientation( Rotation rotation )
517 if (rotation & RR_Rotate_270) return DMDO_270;
518 if (rotation & RR_Rotate_180) return DMDO_180;
519 if (rotation & RR_Rotate_90) return DMDO_90;
520 return DMDO_DEFAULT;
523 static DWORD get_orientation_count( Rotation rotations )
525 DWORD count = 0;
527 if (rotations & RR_Rotate_0) ++count;
528 if (rotations & RR_Rotate_90) ++count;
529 if (rotations & RR_Rotate_180) ++count;
530 if (rotations & RR_Rotate_270) ++count;
531 return count;
534 static Rotation get_rotation( DWORD orientation )
536 return (Rotation)(1 << orientation);
539 static RRCrtc get_output_free_crtc( XRRScreenResources *resources, XRROutputInfo *output_info )
541 XRRCrtcInfo *crtc_info;
542 INT crtc_idx;
543 RRCrtc crtc;
545 for (crtc_idx = 0; crtc_idx < output_info->ncrtc; ++crtc_idx)
547 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtcs[crtc_idx] );
548 if (!crtc_info)
549 continue;
551 if (!crtc_info->noutput)
553 crtc = output_info->crtcs[crtc_idx];
554 pXRRFreeCrtcInfo( crtc_info );
555 return crtc;
558 pXRRFreeCrtcInfo( crtc_info );
561 return 0;
564 static RECT get_primary_rect( XRRScreenResources *resources )
566 XRROutputInfo *output_info = NULL;
567 XRRCrtcInfo *crtc_info = NULL;
568 RROutput primary_output;
569 RECT primary_rect = {0};
570 RECT first_rect = {0};
571 INT i;
573 primary_output = pXRRGetOutputPrimary( gdi_display, root_window );
574 if (!primary_output)
575 goto fallback;
577 output_info = pXRRGetOutputInfo( gdi_display, resources, primary_output );
578 if (!output_info || output_info->connection != RR_Connected || !output_info->crtc)
579 goto fallback;
581 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, output_info->crtc );
582 if (!crtc_info || !crtc_info->mode)
583 goto fallback;
585 SetRect( &primary_rect, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
586 pXRRFreeCrtcInfo( crtc_info );
587 pXRRFreeOutputInfo( output_info );
588 return primary_rect;
590 /* Fallback when XRandR primary output is a disconnected output.
591 * Try to find a crtc with (x, y) being (0, 0). If it's found then get the primary rect from that crtc,
592 * otherwise use the first active crtc to get the primary rect */
593 fallback:
594 if (crtc_info)
595 pXRRFreeCrtcInfo( crtc_info );
596 if (output_info)
597 pXRRFreeOutputInfo( output_info );
599 WARN("Primary is set to a disconnected XRandR output.\n");
600 for (i = 0; i < resources->ncrtc; ++i)
602 crtc_info = pXRRGetCrtcInfo( gdi_display, resources, resources->crtcs[i] );
603 if (!crtc_info)
604 continue;
606 if (!crtc_info->mode)
608 pXRRFreeCrtcInfo( crtc_info );
609 continue;
612 if (!crtc_info->x && !crtc_info->y)
614 SetRect( &primary_rect, 0, 0, crtc_info->width, crtc_info->height );
615 pXRRFreeCrtcInfo( crtc_info );
616 break;
619 if (IsRectEmpty( &first_rect ))
620 SetRect( &first_rect, crtc_info->x, crtc_info->y,
621 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
623 pXRRFreeCrtcInfo( crtc_info );
626 return IsRectEmpty( &primary_rect ) ? first_rect : primary_rect;
629 static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
631 return crtc &&
632 crtc->mode &&
633 crtc->x == primary.left &&
634 crtc->y == primary.top &&
635 crtc->x + crtc->width == primary.right &&
636 crtc->y + crtc->height == primary.bottom;
639 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
641 static BOOL get_gpu_properties_from_vulkan( struct gdi_gpu *gpu, const XRRProviderInfo *provider_info )
643 static const char *extensions[] =
645 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
646 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
647 "VK_EXT_acquire_xlib_display",
648 "VK_EXT_direct_mode_display",
649 "VK_KHR_display",
650 VK_KHR_SURFACE_EXTENSION_NAME,
652 const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION );
653 VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
654 PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
655 PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
656 uint32_t device_count, device_idx, output_idx;
657 VkPhysicalDevice *vk_physical_devices = NULL;
658 VkPhysicalDeviceProperties2 properties2;
659 VkInstanceCreateInfo create_info;
660 VkPhysicalDeviceIDProperties id;
661 VkInstance vk_instance = NULL;
662 VkDisplayKHR vk_display;
663 BOOL ret = FALSE;
664 VkResult vr;
666 if (!vulkan_funcs)
667 goto done;
669 memset( &create_info, 0, sizeof(create_info) );
670 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
671 create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
672 create_info.ppEnabledExtensionNames = extensions;
674 vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance );
675 if (vr != VK_SUCCESS)
677 WARN("Failed to create a Vulkan instance, vr %d.\n", vr);
678 goto done;
681 #define LOAD_VK_FUNC(f) \
682 if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \
684 WARN("Failed to load " #f ".\n"); \
685 goto done; \
688 LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
689 LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
690 LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
691 #undef LOAD_VK_FUNC
693 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
694 if (vr != VK_SUCCESS || !device_count)
696 WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
697 goto done;
700 if (!(vk_physical_devices = heap_calloc( device_count, sizeof(*vk_physical_devices) )))
701 goto done;
703 vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
704 if (vr != VK_SUCCESS)
706 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
707 goto done;
710 for (device_idx = 0; device_idx < device_count; ++device_idx)
712 for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
714 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
715 vr = pvkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
716 provider_info->outputs[output_idx], &vk_display );
717 XSync( gdi_display, FALSE );
718 if (X11DRV_check_error() || vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
719 continue;
721 memset( &id, 0, sizeof(id) );
722 id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
723 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
724 properties2.pNext = &id;
726 pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
727 memcpy( &gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) );
728 /* Ignore Khronos vendor IDs */
729 if (properties2.properties.vendorID < 0x10000)
731 gpu->vendor_id = properties2.properties.vendorID;
732 gpu->device_id = properties2.properties.deviceID;
734 MultiByteToWideChar( CP_UTF8, 0, properties2.properties.deviceName, -1, gpu->name, ARRAY_SIZE(gpu->name) );
735 ret = TRUE;
736 goto done;
740 done:
741 heap_free( vk_physical_devices );
742 if (vk_instance)
743 vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL );
744 return ret;
747 /* Get a list of GPUs reported by XRandR 1.4. Set get_properties to FALSE if GPU properties are
748 * not needed to avoid unnecessary querying */
749 static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_properties )
751 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
752 struct gdi_gpu *gpus = NULL;
753 XRRScreenResources *screen_resources = NULL;
754 XRRProviderResources *provider_resources = NULL;
755 XRRProviderInfo *provider_info = NULL;
756 XRRCrtcInfo *crtc_info = NULL;
757 INT primary_provider = -1;
758 RECT primary_rect;
759 BOOL ret = FALSE;
760 INT i, j;
762 screen_resources = xrandr_get_screen_resources();
763 if (!screen_resources)
764 goto done;
766 provider_resources = pXRRGetProviderResources( gdi_display, root_window );
767 if (!provider_resources)
768 goto done;
770 gpus = heap_calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) );
771 if (!gpus)
772 goto done;
774 /* Some XRandR implementations don't support providers.
775 * In this case, report a fake one to try searching adapters in screen resources */
776 if (!provider_resources->nproviders)
778 WARN("XRandR implementation doesn't report any providers, faking one.\n");
779 lstrcpyW( gpus[0].name, wine_adapterW );
780 *new_gpus = gpus;
781 *count = 1;
782 ret = TRUE;
783 goto done;
786 primary_rect = get_primary_rect( screen_resources );
787 for (i = 0; i < provider_resources->nproviders; ++i)
789 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, provider_resources->providers[i] );
790 if (!provider_info)
791 goto done;
793 /* Find primary provider */
794 for (j = 0; primary_provider == -1 && j < provider_info->ncrtcs; ++j)
796 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, provider_info->crtcs[j] );
797 if (!crtc_info)
798 continue;
800 if (is_crtc_primary( primary_rect, crtc_info ))
802 primary_provider = i;
803 pXRRFreeCrtcInfo( crtc_info );
804 break;
807 pXRRFreeCrtcInfo( crtc_info );
810 gpus[i].id = provider_resources->providers[i];
811 if (get_properties)
813 if (!get_gpu_properties_from_vulkan( &gpus[i], provider_info ))
814 MultiByteToWideChar( CP_UTF8, 0, provider_info->name, -1, gpus[i].name, ARRAY_SIZE(gpus[i].name) );
815 /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */
817 pXRRFreeProviderInfo( provider_info );
820 /* Make primary GPU the first */
821 if (primary_provider > 0)
823 struct gdi_gpu tmp = gpus[0];
824 gpus[0] = gpus[primary_provider];
825 gpus[primary_provider] = tmp;
828 *new_gpus = gpus;
829 *count = provider_resources->nproviders;
830 ret = TRUE;
831 done:
832 if (provider_resources)
833 pXRRFreeProviderResources( provider_resources );
834 if (screen_resources)
835 pXRRFreeScreenResources( screen_resources );
836 if (!ret)
838 heap_free( gpus );
839 ERR("Failed to get gpus\n");
841 return ret;
844 static BOOL xrandr14_get_gpus( struct gdi_gpu **new_gpus, int *count )
846 return xrandr14_get_gpus2( new_gpus, count, TRUE );
849 static void xrandr14_free_gpus( struct gdi_gpu *gpus )
851 heap_free( gpus );
854 static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_adapters, int *count )
856 struct gdi_adapter *adapters = NULL;
857 XRRScreenResources *screen_resources = NULL;
858 XRRProviderInfo *provider_info = NULL;
859 XRRCrtcInfo *enum_crtc_info, *crtc_info = NULL;
860 XRROutputInfo *enum_output_info, *output_info = NULL;
861 RROutput *outputs;
862 INT crtc_count, output_count;
863 INT primary_adapter = 0;
864 INT adapter_count = 0;
865 BOOL mirrored, detached;
866 RECT primary_rect;
867 BOOL ret = FALSE;
868 INT i, j;
870 screen_resources = xrandr_get_screen_resources();
871 if (!screen_resources)
872 goto done;
874 if (gpu_id)
876 provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id );
877 if (!provider_info)
878 goto done;
880 crtc_count = provider_info->ncrtcs;
881 output_count = provider_info->noutputs;
882 outputs = provider_info->outputs;
884 /* Fake provider id, search adapters in screen resources */
885 else
887 crtc_count = screen_resources->ncrtc;
888 output_count = screen_resources->noutput;
889 outputs = screen_resources->outputs;
892 /* Actual adapter count could be less */
893 adapters = heap_calloc( crtc_count, sizeof(*adapters) );
894 if (!adapters)
895 goto done;
897 primary_rect = get_primary_rect( screen_resources );
898 for (i = 0; i < output_count; ++i)
900 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, outputs[i] );
901 if (!output_info)
902 goto done;
904 /* Only connected output are considered as monitors */
905 if (output_info->connection != RR_Connected)
907 pXRRFreeOutputInfo( output_info );
908 output_info = NULL;
909 continue;
912 /* Connected output doesn't mean the output is attached to a crtc */
913 detached = FALSE;
914 if (output_info->crtc)
916 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
917 if (!crtc_info)
918 goto done;
921 if (!output_info->crtc || !crtc_info->mode)
922 detached = TRUE;
924 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
925 mirrored = FALSE;
926 if (!detached)
928 for (j = 0; j < screen_resources->noutput; ++j)
930 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[j] );
931 if (!enum_output_info)
932 continue;
934 if (enum_output_info->connection != RR_Connected || !enum_output_info->crtc)
936 pXRRFreeOutputInfo( enum_output_info );
937 continue;
940 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
941 pXRRFreeOutputInfo( enum_output_info );
942 if (!enum_crtc_info)
943 continue;
945 /* Some outputs may have the same coordinates, aka mirrored. Choose the output with
946 * the lowest value as primary and the rest will then be replicas in a mirroring set */
947 if (crtc_info->x == enum_crtc_info->x &&
948 crtc_info->y == enum_crtc_info->y &&
949 crtc_info->width == enum_crtc_info->width &&
950 crtc_info->height == enum_crtc_info->height &&
951 outputs[i] > screen_resources->outputs[j])
953 mirrored = TRUE;
954 pXRRFreeCrtcInfo( enum_crtc_info );
955 break;
958 pXRRFreeCrtcInfo( enum_crtc_info );
962 if (!mirrored || detached)
964 /* Use RROutput as adapter id. The reason of not using RRCrtc is that we need to detect inactive but
965 * attached monitors */
966 adapters[adapter_count].id = outputs[i];
967 if (!detached)
968 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
969 if (is_crtc_primary( primary_rect, crtc_info ))
971 adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
972 primary_adapter = adapter_count;
975 ++adapter_count;
978 pXRRFreeOutputInfo( output_info );
979 output_info = NULL;
980 if (crtc_info)
982 pXRRFreeCrtcInfo( crtc_info );
983 crtc_info = NULL;
987 /* Make primary adapter the first */
988 if (primary_adapter)
990 struct gdi_adapter tmp = adapters[0];
991 adapters[0] = adapters[primary_adapter];
992 adapters[primary_adapter] = tmp;
995 *new_adapters = adapters;
996 *count = adapter_count;
997 ret = TRUE;
998 done:
999 if (screen_resources)
1000 pXRRFreeScreenResources( screen_resources );
1001 if (provider_info)
1002 pXRRFreeProviderInfo( provider_info );
1003 if (output_info)
1004 pXRRFreeOutputInfo( output_info );
1005 if (crtc_info)
1006 pXRRFreeCrtcInfo( crtc_info );
1007 if (!ret)
1009 heap_free( adapters );
1010 ERR("Failed to get adapters\n");
1012 return ret;
1015 static void xrandr14_free_adapters( struct gdi_adapter *adapters )
1017 heap_free( adapters );
1020 static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count )
1022 static const WCHAR generic_nonpnp_monitorW[] = {
1023 'G','e','n','e','r','i','c',' ',
1024 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
1025 struct gdi_monitor *realloc_monitors, *monitors = NULL;
1026 XRRScreenResources *screen_resources = NULL;
1027 XRROutputInfo *output_info = NULL, *enum_output_info = NULL;
1028 XRRCrtcInfo *crtc_info = NULL, *enum_crtc_info;
1029 INT primary_index = 0, monitor_count = 0, capacity;
1030 RECT primary_rect;
1031 BOOL ret = FALSE;
1032 INT i;
1034 screen_resources = xrandr_get_screen_resources();
1035 if (!screen_resources)
1036 goto done;
1038 /* First start with a 2 monitors, should be enough for most cases */
1039 capacity = 2;
1040 monitors = heap_calloc( capacity, sizeof(*monitors) );
1041 if (!monitors)
1042 goto done;
1044 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, adapter_id );
1045 if (!output_info)
1046 goto done;
1048 if (output_info->crtc)
1050 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, output_info->crtc );
1051 if (!crtc_info)
1052 goto done;
1055 /* Inactive but attached monitor, no need to check for mirrored/replica monitors */
1056 if (!output_info->crtc || !crtc_info->mode)
1058 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
1059 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1060 monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid );
1061 monitor_count = 1;
1063 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
1064 else
1066 primary_rect = get_primary_rect( screen_resources );
1068 for (i = 0; i < screen_resources->noutput; ++i)
1070 enum_output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1071 if (!enum_output_info)
1072 goto done;
1074 /* Detached outputs don't count */
1075 if (enum_output_info->connection != RR_Connected)
1077 pXRRFreeOutputInfo( enum_output_info );
1078 enum_output_info = NULL;
1079 continue;
1082 /* Allocate more space if needed */
1083 if (monitor_count >= capacity)
1085 capacity *= 2;
1086 realloc_monitors = heap_realloc( monitors, capacity * sizeof(*monitors) );
1087 if (!realloc_monitors)
1088 goto done;
1089 monitors = realloc_monitors;
1092 if (enum_output_info->crtc)
1094 enum_crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, enum_output_info->crtc );
1095 if (!enum_crtc_info)
1096 goto done;
1098 if (enum_crtc_info->x == crtc_info->x &&
1099 enum_crtc_info->y == crtc_info->y &&
1100 enum_crtc_info->width == crtc_info->width &&
1101 enum_crtc_info->height == crtc_info->height)
1103 /* FIXME: Read output EDID property and parse the data to get the correct name */
1104 lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
1106 SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y,
1107 crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height );
1108 monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor );
1110 monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
1111 if (!IsRectEmpty( &monitors[monitor_count].rc_monitor ))
1112 monitors[monitor_count].state_flags |= DISPLAY_DEVICE_ACTIVE;
1114 if (is_crtc_primary( primary_rect, crtc_info ))
1115 primary_index = monitor_count;
1117 monitors[monitor_count].edid_len = get_edid( screen_resources->outputs[i],
1118 &monitors[monitor_count].edid );
1119 monitor_count++;
1122 pXRRFreeCrtcInfo( enum_crtc_info );
1125 pXRRFreeOutputInfo( enum_output_info );
1126 enum_output_info = NULL;
1129 /* Make sure the first monitor is the primary */
1130 if (primary_index)
1132 struct gdi_monitor tmp = monitors[0];
1133 monitors[0] = monitors[primary_index];
1134 monitors[primary_index] = tmp;
1137 /* Make sure the primary monitor origin is at (0, 0) */
1138 for (i = 0; i < monitor_count; i++)
1140 OffsetRect( &monitors[i].rc_monitor, -primary_rect.left, -primary_rect.top );
1141 OffsetRect( &monitors[i].rc_work, -primary_rect.left, -primary_rect.top );
1145 *new_monitors = monitors;
1146 *count = monitor_count;
1147 ret = TRUE;
1148 done:
1149 if (screen_resources)
1150 pXRRFreeScreenResources( screen_resources );
1151 if (output_info)
1152 pXRRFreeOutputInfo( output_info);
1153 if (crtc_info)
1154 pXRRFreeCrtcInfo( crtc_info );
1155 if (enum_output_info)
1156 pXRRFreeOutputInfo( enum_output_info );
1157 if (!ret)
1159 for (i = 0; i < monitor_count; i++)
1161 if (monitors[i].edid)
1162 XFree( monitors[i].edid );
1164 heap_free( monitors );
1165 ERR("Failed to get monitors\n");
1167 return ret;
1170 static void xrandr14_free_monitors( struct gdi_monitor *monitors, int count )
1172 int i;
1174 for (i = 0; i < count; i++)
1176 if (monitors[i].edid)
1177 XFree( monitors[i].edid );
1179 heap_free( monitors );
1182 static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
1184 xrandr14_invalidate_current_mode_cache();
1185 if (hwnd == GetDesktopWindow() && GetWindowThreadProcessId( hwnd, NULL ) == GetCurrentThreadId())
1187 /* Don't send a WM_DISPLAYCHANGE message here because this event may be a result from
1188 * ChangeDisplaySettings(). Otherwise, ChangeDisplaySettings() would send multiple
1189 * WM_DISPLAYCHANGE messages instead of just one */
1190 X11DRV_DisplayDevices_Update( FALSE );
1192 init_registry_display_settings();
1194 return FALSE;
1197 static void xrandr14_register_event_handlers(void)
1199 Display *display = thread_init_display();
1200 int event_base, error_base;
1202 if (!pXRRQueryExtension( display, &event_base, &error_base ))
1203 return;
1205 pXRRSelectInput( display, root_window,
1206 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RRProviderChangeNotifyMask );
1207 X11DRV_register_event_handler( event_base + RRNotify_CrtcChange, xrandr14_device_change_handler,
1208 "XRandR CrtcChange" );
1209 X11DRV_register_event_handler( event_base + RRNotify_OutputChange, xrandr14_device_change_handler,
1210 "XRandR OutputChange" );
1211 X11DRV_register_event_handler( event_base + RRNotify_ProviderChange, xrandr14_device_change_handler,
1212 "XRandR ProviderChange" );
1215 /* XRandR 1.4 display settings handler */
1216 static BOOL xrandr14_get_id( const WCHAR *device_name, ULONG_PTR *id )
1218 struct current_mode *tmp_modes, *new_current_modes = NULL;
1219 INT gpu_count, adapter_count, new_current_mode_count = 0;
1220 INT gpu_idx, adapter_idx, display_idx;
1221 struct gdi_adapter *adapters;
1222 struct gdi_gpu *gpus;
1223 WCHAR *end;
1225 /* Parse \\.\DISPLAY%d */
1226 display_idx = strtolW( device_name + 11, &end, 10 ) - 1;
1227 if (*end)
1228 return FALSE;
1230 /* Update cache */
1231 EnterCriticalSection( &current_modes_section );
1232 if (!current_modes)
1234 if (!xrandr14_get_gpus2( &gpus, &gpu_count, FALSE ))
1236 LeaveCriticalSection( &current_modes_section );
1237 return FALSE;
1240 for (gpu_idx = 0; gpu_idx < gpu_count; ++gpu_idx)
1242 if (!xrandr14_get_adapters( gpus[gpu_idx].id, &adapters, &adapter_count ))
1243 break;
1245 if (!new_current_modes)
1246 tmp_modes = heap_alloc( adapter_count * sizeof(*tmp_modes) );
1247 else
1248 tmp_modes = heap_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 heap_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 LeaveCriticalSection( &current_modes_section );
1278 return FALSE;
1281 *id = current_modes[display_idx].id;
1282 LeaveCriticalSection( &current_modes_section );
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( ULONG_PTR 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;
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 = heap_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 heap_free( modes );
1431 static BOOL xrandr14_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
1433 struct current_mode *mode_ptr = NULL;
1434 XRRScreenResources *screen_resources;
1435 XRROutputInfo *output_info = NULL;
1436 RROutput output = (RROutput)id;
1437 XRRModeInfo *mode_info = NULL;
1438 XRRCrtcInfo *crtc_info = NULL;
1439 BOOL ret = FALSE;
1440 RECT primary;
1441 INT mode_idx;
1443 EnterCriticalSection( &current_modes_section );
1444 for (mode_idx = 0; mode_idx < current_mode_count; ++mode_idx)
1446 if (current_modes[mode_idx].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 LeaveCriticalSection( &current_modes_section );
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 LeaveCriticalSection( &current_modes_section );
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( ULONG_PTR id, DEVMODEW *mode )
1539 unsigned int screen_width, screen_height;
1540 RROutput output = (RROutput)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", screen_bpp, mode->dmBitsPerPel);
1554 screen_resources = xrandr_get_screen_resources();
1555 if (!screen_resources)
1556 return ret;
1558 XGrabServer( gdi_display );
1560 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, output );
1561 if (!output_info || output_info->connection != RR_Connected)
1562 goto done;
1564 if (is_detached_mode(mode))
1566 /* Already detached */
1567 if (!output_info->crtc)
1569 ret = DISP_CHANGE_SUCCESSFUL;
1570 goto done;
1573 /* Execute detach operation */
1574 status = pXRRSetCrtcConfig( gdi_display, screen_resources, output_info->crtc,
1575 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0 );
1576 if (status == RRSetConfigSuccess)
1578 get_screen_size( screen_resources, &screen_width, &screen_height );
1579 set_screen_size( screen_width, screen_height );
1580 ret = DISP_CHANGE_SUCCESSFUL;
1582 goto done;
1585 /* Attached */
1586 if (output_info->crtc)
1588 crtc = output_info->crtc;
1590 /* Detached, need to find a free CRTC */
1591 else
1593 if (!(crtc = get_output_free_crtc( screen_resources, output_info )))
1594 goto done;
1597 crtc_info = pXRRGetCrtcInfo( gdi_display, screen_resources, crtc );
1598 if (!crtc_info)
1599 goto done;
1601 assert( mode->dmDriverExtra == sizeof(RRMode) );
1602 memcpy( &rrmode, (BYTE *)mode + sizeof(*mode), sizeof(rrmode) );
1604 if (crtc_info->noutput)
1606 outputs = crtc_info->outputs;
1607 output_count = crtc_info->noutput;
1609 else
1611 outputs = &output;
1612 output_count = 1;
1614 rotation = get_rotation( mode->u1.s2.dmDisplayOrientation );
1616 /* According to the RandR spec, the entire CRTC must fit inside the screen.
1617 * Since we use the union of all enabled CRTCs to determine the necessary
1618 * screen size, this might involve shrinking the screen, so we must disable
1619 * the CRTC in question first. */
1620 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime, 0, 0, None,
1621 RR_Rotate_0, NULL, 0 );
1622 if (status != RRSetConfigSuccess)
1623 goto done;
1625 get_screen_size( screen_resources, &screen_width, &screen_height );
1626 screen_width = max( screen_width, mode->u1.s2.dmPosition.x + mode->dmPelsWidth );
1627 screen_height = max( screen_height, mode->u1.s2.dmPosition.y + mode->dmPelsHeight );
1628 set_screen_size( screen_width, screen_height );
1630 status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
1631 mode->u1.s2.dmPosition.x, mode->u1.s2.dmPosition.y, rrmode,
1632 rotation, outputs, output_count );
1633 if (status == RRSetConfigSuccess)
1634 ret = DISP_CHANGE_SUCCESSFUL;
1636 done:
1637 XUngrabServer( gdi_display );
1638 XFlush( gdi_display );
1639 if (crtc_info)
1640 pXRRFreeCrtcInfo( crtc_info );
1641 if (output_info)
1642 pXRRFreeOutputInfo( output_info );
1643 pXRRFreeScreenResources( screen_resources );
1644 xrandr14_invalidate_current_mode_cache();
1645 return ret;
1648 #endif
1650 void X11DRV_XRandR_Init(void)
1652 struct x11drv_display_device_handler display_handler;
1653 struct x11drv_settings_handler settings_handler;
1654 int event_base, error_base, minor, ret;
1655 static int major;
1656 Bool ok;
1658 if (major) return; /* already initialized? */
1659 if (!usexrandr) return; /* disabled in config */
1660 if (is_virtual_desktop()) return;
1661 if (!(ret = load_xrandr())) return; /* can't load the Xrandr library */
1663 /* see if Xrandr is available */
1664 if (!pXRRQueryExtension( gdi_display, &event_base, &error_base )) return;
1665 X11DRV_expect_error( gdi_display, XRandRErrorHandler, NULL );
1666 ok = pXRRQueryVersion( gdi_display, &major, &minor );
1667 if (X11DRV_check_error() || !ok) return;
1669 TRACE("Found XRandR %d.%d.\n", major, minor);
1671 settings_handler.name = "XRandR 1.0";
1672 settings_handler.priority = 200;
1673 settings_handler.get_id = xrandr10_get_id;
1674 settings_handler.get_modes = xrandr10_get_modes;
1675 settings_handler.free_modes = xrandr10_free_modes;
1676 settings_handler.get_current_mode = xrandr10_get_current_mode;
1677 settings_handler.set_current_mode = xrandr10_set_current_mode;
1678 X11DRV_Settings_SetHandler( &settings_handler );
1680 #ifdef HAVE_XRRGETPROVIDERRESOURCES
1681 if (ret >= 4 && (major > 1 || (major == 1 && minor >= 4)))
1683 XRRScreenResources *screen_resources;
1684 XRROutputInfo *output_info;
1685 BOOL found_output = FALSE;
1686 INT i;
1688 screen_resources = xrandr_get_screen_resources();
1689 if (!screen_resources)
1690 return;
1692 for (i = 0; i < screen_resources->noutput; ++i)
1694 output_info = pXRRGetOutputInfo( gdi_display, screen_resources, screen_resources->outputs[i] );
1695 if (!output_info)
1696 continue;
1698 if (output_info->connection == RR_Connected)
1700 pXRRFreeOutputInfo( output_info );
1701 found_output = TRUE;
1702 break;
1705 pXRRFreeOutputInfo( output_info );
1707 pXRRFreeScreenResources( screen_resources );
1709 if (!found_output)
1711 WARN("No connected outputs found.\n");
1712 return;
1715 display_handler.name = "XRandR 1.4";
1716 display_handler.priority = 200;
1717 display_handler.get_gpus = xrandr14_get_gpus;
1718 display_handler.get_adapters = xrandr14_get_adapters;
1719 display_handler.get_monitors = xrandr14_get_monitors;
1720 display_handler.free_gpus = xrandr14_free_gpus;
1721 display_handler.free_adapters = xrandr14_free_adapters;
1722 display_handler.free_monitors = xrandr14_free_monitors;
1723 display_handler.register_event_handlers = xrandr14_register_event_handlers;
1724 X11DRV_DisplayDevices_SetHandler( &display_handler );
1726 if (is_broken_driver())
1727 return;
1729 settings_handler.name = "XRandR 1.4";
1730 settings_handler.priority = 300;
1731 settings_handler.get_id = xrandr14_get_id;
1732 settings_handler.get_modes = xrandr14_get_modes;
1733 settings_handler.free_modes = xrandr14_free_modes;
1734 settings_handler.get_current_mode = xrandr14_get_current_mode;
1735 settings_handler.set_current_mode = xrandr14_set_current_mode;
1736 X11DRV_Settings_SetHandler( &settings_handler );
1738 #endif
1741 #else /* SONAME_LIBXRANDR */
1743 void X11DRV_XRandR_Init(void)
1745 TRACE("XRandR support not compiled in.\n");
1748 #endif /* SONAME_LIBXRANDR */