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
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
);
35 #ifdef SONAME_LIBXRANDR
39 #include <X11/extensions/Xrandr.h>
43 #define VK_NO_PROTOTYPES
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
)
87 static int load_xrandr(void)
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
);
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
);
134 if (!r
) TRACE("Unable to load function ptrs from XRandR library\n");
139 static int XRandRErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
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
))
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;
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
;
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
;
187 sizes
= pXRRSizes( gdi_display
, DefaultScreen( gdi_display
), &size_count
);
191 for (size_idx
= 0; size_idx
< size_count
; ++size_idx
)
193 rates
= pXRRRates( gdi_display
, DefaultScreen( gdi_display
), size_idx
, &rate_count
);
195 mode_count
+= rate_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
) );
205 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
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
);
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
);
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
);
232 *new_mode_count
= mode_idx
;
236 static void xrandr10_free_modes( DEVMODEW
*modes
)
241 static BOOL
xrandr10_get_current_mode( ULONG_PTR id
, DEVMODEW
*mode
)
243 XRRScreenConfiguration
*screen_config
;
244 XRRScreenSize
*sizes
;
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;
259 FIXME("Non-primary adapters are unsupported.\n");
260 mode
->dmBitsPerPel
= 0;
261 mode
->dmPelsWidth
= 0;
262 mode
->dmPelsHeight
= 0;
263 mode
->dmDisplayFrequency
= 0;
267 sizes
= pXRRSizes( gdi_display
, DefaultScreen( gdi_display
), &size_count
);
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
;
283 static LONG
xrandr10_set_current_mode( ULONG_PTR id
, DEVMODEW
*mode
)
285 XRRScreenConfiguration
*screen_config
;
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
);
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
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, ¤t_modes_section
,
341 {¤t_modes_critsect_debug
.ProcessLocksList
, ¤t_modes_critsect_debug
.ProcessLocksList
},
342 0, 0, {(DWORD_PTR
)(__FILE__
": current_modes_section")}
344 static CRITICAL_SECTION current_modes_section
= {¤t_modes_critsect_debug
, -1, 0, 0, 0, 0};
346 static void xrandr14_invalidate_current_mode_cache(void)
348 EnterCriticalSection( ¤t_modes_section
);
349 heap_free( current_modes
);
350 current_modes
= NULL
;
351 current_mode_count
= 0;
352 LeaveCriticalSection( ¤t_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
);
365 ERR("Failed to get screen resources.\n");
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
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
;
385 screen_resources
= xrandr_get_screen_resources();
386 if (!screen_resources
)
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
] );
397 if (output_info
->connection
!= RR_Connected
)
399 pXRRFreeOutputInfo( output_info
);
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
)
414 first_mode
= &screen_resources
->modes
[j
];
418 if (first_mode
->width
!= screen_resources
->modes
[j
].width
||
419 first_mode
->height
!= screen_resources
->modes
[j
].height
)
420 only_one_mode
= FALSE
;
428 pXRRFreeOutputInfo( output_info
);
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
);
442 pXRRFreeScreenResources( screen_resources
);
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
;
452 pXRRGetScreenSizeRange( gdi_display
, root_window
, &min_width
, &min_height
, &max_width
, &max_height
);
454 *height
= min_height
;
456 for (i
= 0; i
< resources
->ncrtc
; ++i
)
458 if (!(crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, resources
->crtcs
[i
] )))
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
;
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
);
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
;
507 if (mode
->modeFlags
& RR_DoubleScan
)
509 if (mode
->modeFlags
& RR_Interlace
)
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
;
523 static DWORD
get_orientation_count( Rotation rotations
)
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
;
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
;
545 for (crtc_idx
= 0; crtc_idx
< output_info
->ncrtc
; ++crtc_idx
)
547 crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, output_info
->crtcs
[crtc_idx
] );
551 if (!crtc_info
->noutput
)
553 crtc
= output_info
->crtcs
[crtc_idx
];
554 pXRRFreeCrtcInfo( crtc_info
);
558 pXRRFreeCrtcInfo( crtc_info
);
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};
573 primary_output
= pXRRGetOutputPrimary( gdi_display
, root_window
);
577 output_info
= pXRRGetOutputInfo( gdi_display
, resources
, primary_output
);
578 if (!output_info
|| output_info
->connection
!= RR_Connected
|| !output_info
->crtc
)
581 crtc_info
= pXRRGetCrtcInfo( gdi_display
, resources
, output_info
->crtc
);
582 if (!crtc_info
|| !crtc_info
->mode
)
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
);
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 */
595 pXRRFreeCrtcInfo( crtc_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
] );
606 if (!crtc_info
->mode
)
608 pXRRFreeCrtcInfo( crtc_info
);
612 if (!crtc_info
->x
&& !crtc_info
->y
)
614 SetRect( &primary_rect
, 0, 0, crtc_info
->width
, crtc_info
->height
);
615 pXRRFreeCrtcInfo( crtc_info
);
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
)
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",
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
;
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
);
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"); \
688 LOAD_VK_FUNC(vkEnumeratePhysicalDevices
)
689 LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR
)
690 LOAD_VK_FUNC(vkGetRandROutputDisplayEXT
)
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
);
700 if (!(vk_physical_devices
= heap_calloc( device_count
, sizeof(*vk_physical_devices
) )))
703 vr
= pvkEnumeratePhysicalDevices( vk_instance
, &device_count
, vk_physical_devices
);
704 if (vr
!= VK_SUCCESS
)
706 WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr
);
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
)
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
) );
741 heap_free( vk_physical_devices
);
743 vulkan_funcs
->p_vkDestroyInstance( vk_instance
, NULL
);
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;
762 screen_resources
= xrandr_get_screen_resources();
763 if (!screen_resources
)
766 provider_resources
= pXRRGetProviderResources( gdi_display
, root_window
);
767 if (!provider_resources
)
770 gpus
= heap_calloc( provider_resources
->nproviders
? provider_resources
->nproviders
: 1, sizeof(*gpus
) );
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
);
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
] );
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
] );
800 if (is_crtc_primary( primary_rect
, crtc_info
))
802 primary_provider
= i
;
803 pXRRFreeCrtcInfo( crtc_info
);
807 pXRRFreeCrtcInfo( crtc_info
);
810 gpus
[i
].id
= provider_resources
->providers
[i
];
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
;
829 *count
= provider_resources
->nproviders
;
832 if (provider_resources
)
833 pXRRFreeProviderResources( provider_resources
);
834 if (screen_resources
)
835 pXRRFreeScreenResources( screen_resources
);
839 ERR("Failed to get gpus\n");
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
)
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
;
862 INT crtc_count
, output_count
;
863 INT primary_adapter
= 0;
864 INT adapter_count
= 0;
865 BOOL mirrored
, detached
;
870 screen_resources
= xrandr_get_screen_resources();
871 if (!screen_resources
)
876 provider_info
= pXRRGetProviderInfo( gdi_display
, screen_resources
, gpu_id
);
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 */
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
) );
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
] );
904 /* Only connected output are considered as monitors */
905 if (output_info
->connection
!= RR_Connected
)
907 pXRRFreeOutputInfo( output_info
);
912 /* Connected output doesn't mean the output is attached to a crtc */
914 if (output_info
->crtc
)
916 crtc_info
= pXRRGetCrtcInfo( gdi_display
, screen_resources
, output_info
->crtc
);
921 if (!output_info
->crtc
|| !crtc_info
->mode
)
924 /* Ignore mirroring output replicas because mirrored monitors are under the same adapter */
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
)
934 if (enum_output_info
->connection
!= RR_Connected
|| !enum_output_info
->crtc
)
936 pXRRFreeOutputInfo( enum_output_info
);
940 enum_crtc_info
= pXRRGetCrtcInfo( gdi_display
, screen_resources
, enum_output_info
->crtc
);
941 pXRRFreeOutputInfo( enum_output_info
);
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
])
954 pXRRFreeCrtcInfo( enum_crtc_info
);
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
];
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
;
978 pXRRFreeOutputInfo( output_info
);
982 pXRRFreeCrtcInfo( crtc_info
);
987 /* Make primary adapter the first */
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
;
999 if (screen_resources
)
1000 pXRRFreeScreenResources( screen_resources
);
1002 pXRRFreeProviderInfo( provider_info
);
1004 pXRRFreeOutputInfo( output_info
);
1006 pXRRFreeCrtcInfo( crtc_info
);
1009 heap_free( adapters
);
1010 ERR("Failed to get adapters\n");
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
;
1034 screen_resources
= xrandr_get_screen_resources();
1035 if (!screen_resources
)
1038 /* First start with a 2 monitors, should be enough for most cases */
1040 monitors
= heap_calloc( capacity
, sizeof(*monitors
) );
1044 output_info
= pXRRGetOutputInfo( gdi_display
, screen_resources
, adapter_id
);
1048 if (output_info
->crtc
)
1050 crtc_info
= pXRRGetCrtcInfo( gdi_display
, screen_resources
, output_info
->crtc
);
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
);
1063 /* Active monitors, need to find other monitors with the same coordinates as mirrored */
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
)
1074 /* Detached outputs don't count */
1075 if (enum_output_info
->connection
!= RR_Connected
)
1077 pXRRFreeOutputInfo( enum_output_info
);
1078 enum_output_info
= NULL
;
1082 /* Allocate more space if needed */
1083 if (monitor_count
>= capacity
)
1086 realloc_monitors
= heap_realloc( monitors
, capacity
* sizeof(*monitors
) );
1087 if (!realloc_monitors
)
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
)
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
);
1122 pXRRFreeCrtcInfo( enum_crtc_info
);
1125 pXRRFreeOutputInfo( enum_output_info
);
1126 enum_output_info
= NULL
;
1129 /* Make sure the first monitor is the primary */
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
;
1149 if (screen_resources
)
1150 pXRRFreeScreenResources( screen_resources
);
1152 pXRRFreeOutputInfo( output_info
);
1154 pXRRFreeCrtcInfo( crtc_info
);
1155 if (enum_output_info
)
1156 pXRRFreeOutputInfo( enum_output_info
);
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");
1170 static void xrandr14_free_monitors( struct gdi_monitor
*monitors
, int count
)
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();
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
))
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
;
1225 /* Parse \\.\DISPLAY%d */
1226 display_idx
= strtolW( device_name
+ 11, &end
, 10 ) - 1;
1231 EnterCriticalSection( ¤t_modes_section
);
1234 if (!xrandr14_get_gpus2( &gpus
, &gpu_count
, FALSE
))
1236 LeaveCriticalSection( ¤t_modes_section
);
1240 for (gpu_idx
= 0; gpu_idx
< gpu_count
; ++gpu_idx
)
1242 if (!xrandr14_get_adapters( gpus
[gpu_idx
].id
, &adapters
, &adapter_count
))
1245 if (!new_current_modes
)
1246 tmp_modes
= heap_alloc( adapter_count
* sizeof(*tmp_modes
) );
1248 tmp_modes
= heap_realloc( new_current_modes
, (new_current_mode_count
+ adapter_count
) * sizeof(*tmp_modes
) );
1252 xrandr14_free_adapters( adapters
);
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( ¤t_modes_section
);
1281 *id
= current_modes
[display_idx
].id
;
1282 LeaveCriticalSection( ¤t_modes_section
);
1286 static void add_xrandr14_mode( DEVMODEW
*mode
, XRRModeInfo
*info
, DWORD depth
, DWORD frequency
,
1289 mode
->dmSize
= sizeof(*mode
);
1290 mode
->dmDriverExtra
= sizeof(RRMode
);
1291 mode
->dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
|
1292 DM_PELSHEIGHT
| DM_DISPLAYFLAGS
;
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
;
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
;
1329 screen_resources
= xrandr_get_screen_resources();
1330 if (!screen_resources
)
1333 output_info
= pXRRGetOutputInfo( gdi_display
, screen_resources
, output
);
1337 if (output_info
->connection
!= RR_Connected
)
1345 crtc
= output_info
->crtc
;
1347 crtc
= get_output_free_crtc( screen_resources
, output_info
);
1349 crtc_info
= pXRRGetCrtcInfo( gdi_display
, screen_resources
, crtc
);
1351 /* If the output is connected to a CRTC, use rotations reported by the CRTC */
1354 if (flags
& EDS_ROTATEDMODE
)
1356 rotations
= crtc_info
->rotations
;
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 */
1368 if (flags
& EDS_ROTATEDMODE
)
1370 rotations
= RR_Rotate_0
| RR_Rotate_90
| RR_Rotate_180
| RR_Rotate_270
;
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
) );
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
)
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
))
1403 mode
= (DEVMODEW
*)((BYTE
*)modes
+ (sizeof(*modes
) + sizeof(RRMode
)) * mode_idx
);
1404 add_xrandr14_mode( mode
, mode_info
, depths
[depth_idx
], frequency
, orientation
);
1415 *mode_count
= mode_idx
;
1418 pXRRFreeCrtcInfo( crtc_info
);
1420 pXRRFreeOutputInfo( output_info
);
1421 if (screen_resources
)
1422 pXRRFreeScreenResources( screen_resources
);
1426 static void xrandr14_free_modes( DEVMODEW
*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
;
1443 EnterCriticalSection( ¤t_modes_section
);
1444 for (mode_idx
= 0; mode_idx
< current_mode_count
; ++mode_idx
)
1446 if (current_modes
[mode_idx
].id
!= id
)
1449 if (!current_modes
[mode_idx
].loaded
)
1451 mode_ptr
= ¤t_modes
[mode_idx
];
1455 memcpy( mode
, ¤t_modes
[mode_idx
].mode
, sizeof(*mode
) );
1456 LeaveCriticalSection( ¤t_modes_section
);
1460 screen_resources
= xrandr_get_screen_resources();
1461 if (!screen_resources
)
1464 output_info
= pXRRGetOutputInfo( gdi_display
, screen_resources
, output
);
1468 if (output_info
->crtc
)
1470 crtc_info
= pXRRGetCrtcInfo( gdi_display
, screen_resources
, output_info
->crtc
);
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;
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
];
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
;
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( ¤t_modes_section
);
1529 pXRRFreeCrtcInfo( crtc_info
);
1531 pXRRFreeOutputInfo( output_info
);
1532 if (screen_resources
)
1533 pXRRFreeScreenResources( screen_resources
);
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
;
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
)
1558 XGrabServer( gdi_display
);
1560 output_info
= pXRRGetOutputInfo( gdi_display
, screen_resources
, output
);
1561 if (!output_info
|| output_info
->connection
!= RR_Connected
)
1564 if (is_detached_mode(mode
))
1566 /* Already detached */
1567 if (!output_info
->crtc
)
1569 ret
= DISP_CHANGE_SUCCESSFUL
;
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
;
1586 if (output_info
->crtc
)
1588 crtc
= output_info
->crtc
;
1590 /* Detached, need to find a free CRTC */
1593 if (!(crtc
= get_output_free_crtc( screen_resources
, output_info
)))
1597 crtc_info
= pXRRGetCrtcInfo( gdi_display
, screen_resources
, crtc
);
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
;
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
)
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
;
1637 XUngrabServer( gdi_display
);
1638 XFlush( gdi_display
);
1640 pXRRFreeCrtcInfo( crtc_info
);
1642 pXRRFreeOutputInfo( output_info
);
1643 pXRRFreeScreenResources( screen_resources
);
1644 xrandr14_invalidate_current_mode_cache();
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
;
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
;
1688 screen_resources
= xrandr_get_screen_resources();
1689 if (!screen_resources
)
1692 for (i
= 0; i
< screen_resources
->noutput
; ++i
)
1694 output_info
= pXRRGetOutputInfo( gdi_display
, screen_resources
, screen_resources
->outputs
[i
] );
1698 if (output_info
->connection
== RR_Connected
)
1700 pXRRFreeOutputInfo( output_info
);
1701 found_output
= TRUE
;
1705 pXRRFreeOutputInfo( output_info
);
1707 pXRRFreeScreenResources( screen_resources
);
1711 WARN("No connected outputs found.\n");
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())
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
);
1741 #else /* SONAME_LIBXRANDR */
1743 void X11DRV_XRandR_Init(void)
1745 TRACE("XRandR support not compiled in.\n");
1748 #endif /* SONAME_LIBXRANDR */