2 * MACDRV display settings
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #define WIN32_NO_STATUS
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(display
);
40 struct display_mode_descriptor
48 CFStringRef pixel_encoding
;
52 BOOL CDECL
macdrv_EnumDisplaySettingsEx(LPCWSTR devname
, DWORD mode
, LPDEVMODEW devmode
, DWORD flags
);
54 DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID
, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
55 DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID
, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1);
56 DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID
, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2);
58 /* Wine specific monitor properties */
59 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS
, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
60 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR
, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3);
61 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCWORK
, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 4);
62 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_ADAPTERNAME
, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 5);
64 static const char initial_mode_key
[] = "Initial Display Mode";
65 static const WCHAR pixelencodingW
[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
66 static const WCHAR driver_date_dataW
[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
67 static const WCHAR driver_descW
[] = {'D','r','i','v','e','r','D','e','s','c',0};
68 static const WCHAR displayW
[] = {'D','I','S','P','L','A','Y',0};
69 static const WCHAR pciW
[] = {'P','C','I',0};
70 static const WCHAR video_idW
[] = {'V','i','d','e','o','I','D',0};
71 static const WCHAR symbolic_link_valueW
[]= {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
72 static const WCHAR gpu_idW
[] = {'G','P','U','I','D',0};
73 static const WCHAR monitor_id_fmtW
[] = {'M','o','n','i','t','o','r','I','D','%','d',0};
74 static const WCHAR adapter_prefixW
[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'};
75 static const WCHAR adapter_name_fmtW
[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','%','d',0};
76 static const WCHAR state_flagsW
[] = {'S','t','a','t','e','F','l','a','g','s',0};
77 static const WCHAR guid_fmtW
[] = {
78 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
79 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
80 static const WCHAR gpu_instance_fmtW
[] = {
82 'V','E','N','_','%','0','4','X','&',
83 'D','E','V','_','%','0','4','X','&',
84 'S','U','B','S','Y','S','_','%','0','8','X','&',
85 'R','E','V','_','%','0','2','X','\\',
87 static const WCHAR gpu_hardware_id_fmtW
[] = {
89 'V','E','N','_','%','0','4','X','&',
90 'D','E','V','_','%','0','4','X','&',
91 'S','U','B','S','Y','S','_','0','0','0','0','0','0','0','0','&',
92 'R','E','V','_','0','0',0};
93 static const WCHAR video_keyW
[] = {
94 'H','A','R','D','W','A','R','E','\\',
95 'D','E','V','I','C','E','M','A','P','\\',
96 'V','I','D','E','O',0};
97 static const WCHAR adapter_key_fmtW
[] = {
98 'S','y','s','t','e','m','\\',
99 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
100 'C','o','n','t','r','o','l','\\',
101 'V','i','d','e','o','\\',
104 static const WCHAR device_video_fmtW
[] = {
105 '\\','D','e','v','i','c','e','\\',
106 'V','i','d','e','o','%','d',0};
107 static const WCHAR machine_prefixW
[] = {
108 '\\','R','e','g','i','s','t','r','y','\\',
109 'M','a','c','h','i','n','e','\\',0};
110 static const WCHAR nt_classW
[] = {
111 '\\','R','e','g','i','s','t','r','y','\\',
112 'M','a','c','h','i','n','e','\\',
113 'S','y','s','t','e','m','\\',
114 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
115 'C','o','n','t','r','o','l','\\',
116 'C','l','a','s','s','\\',0};
117 static const WCHAR monitor_instance_fmtW
[] = {
118 'D','I','S','P','L','A','Y','\\',
119 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r','\\',
120 '%','0','4','X','&','%','0','4','X',0};
121 static const WCHAR monitor_hardware_idW
[] = {
122 'M','O','N','I','T','O','R','\\',
123 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
126 static CFArrayRef modes
;
127 static BOOL modes_has_8bpp
, modes_has_16bpp
;
128 static int default_mode_bpp
;
129 static CRITICAL_SECTION modes_section
;
130 static CRITICAL_SECTION_DEBUG critsect_debug
=
132 0, 0, &modes_section
,
133 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
134 0, 0, { (DWORD_PTR
)(__FILE__
": modes_section") }
136 static CRITICAL_SECTION modes_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
138 static BOOL inited_original_display_mode
;
140 static HANDLE
get_display_device_init_mutex(void)
142 static const WCHAR init_mutexW
[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
143 HANDLE mutex
= CreateMutexW(NULL
, FALSE
, init_mutexW
);
145 WaitForSingleObject(mutex
, INFINITE
);
149 static void release_display_device_init_mutex(HANDLE mutex
)
155 static BOOL
get_display_device_reg_key(const WCHAR
*device_name
, WCHAR
*key
, unsigned len
)
157 WCHAR value_name
[MAX_PATH
], buffer
[MAX_PATH
], *end_ptr
;
158 DWORD adapter_index
, size
;
160 /* Device name has to be \\.\DISPLAY%d */
161 if (strncmpiW(device_name
, adapter_prefixW
, ARRAY_SIZE(adapter_prefixW
)))
164 /* Parse \\.\DISPLAY* */
165 adapter_index
= strtolW(device_name
+ ARRAY_SIZE(adapter_prefixW
), &end_ptr
, 10) - 1;
169 /* Open \Device\Video* in HKLM\HARDWARE\DEVICEMAP\VIDEO\ */
170 sprintfW(value_name
, device_video_fmtW
, adapter_index
);
171 size
= sizeof(buffer
);
172 if (RegGetValueW(HKEY_LOCAL_MACHINE
, video_keyW
, value_name
, RRF_RT_REG_SZ
, NULL
, buffer
, &size
))
175 if (len
< lstrlenW(buffer
+ 18) + 1)
178 /* Skip \Registry\Machine\ prefix */
179 lstrcpyW(key
, buffer
+ 18);
180 TRACE("display device %s registry settings key %s.\n", wine_dbgstr_w(device_name
), wine_dbgstr_w(key
));
185 static BOOL
read_registry_settings(const WCHAR
*device_name
, DEVMODEW
*dm
)
187 WCHAR wine_mac_reg_key
[MAX_PATH
];
195 mutex
= get_display_device_init_mutex();
196 if (!get_display_device_reg_key(device_name
, wine_mac_reg_key
, ARRAY_SIZE(wine_mac_reg_key
)))
198 release_display_device_init_mutex(mutex
);
202 if (RegOpenKeyExW(HKEY_CURRENT_CONFIG
, wine_mac_reg_key
, 0, KEY_READ
, &hkey
))
204 release_display_device_init_mutex(mutex
);
208 #define query_value(name, data) \
209 size = sizeof(DWORD); \
210 if (RegQueryValueExA(hkey, name, 0, &type, (LPBYTE)(data), &size) || \
211 type != REG_DWORD || size != sizeof(DWORD)) \
214 query_value("DefaultSettings.BitsPerPel", &dm
->dmBitsPerPel
);
215 dm
->dmFields
|= DM_BITSPERPEL
;
216 query_value("DefaultSettings.XResolution", &dm
->dmPelsWidth
);
217 dm
->dmFields
|= DM_PELSWIDTH
;
218 query_value("DefaultSettings.YResolution", &dm
->dmPelsHeight
);
219 dm
->dmFields
|= DM_PELSHEIGHT
;
220 query_value("DefaultSettings.VRefresh", &dm
->dmDisplayFrequency
);
221 dm
->dmFields
|= DM_DISPLAYFREQUENCY
;
222 query_value("DefaultSettings.Flags", &dm
->dmDisplayFlags
);
223 dm
->dmFields
|= DM_DISPLAYFLAGS
;
224 query_value("DefaultSettings.XPanning", &dm
->dmPosition
.x
);
225 query_value("DefaultSettings.YPanning", &dm
->dmPosition
.y
);
226 dm
->dmFields
|= DM_POSITION
;
227 query_value("DefaultSettings.Orientation", &dm
->dmDisplayOrientation
);
228 dm
->dmFields
|= DM_DISPLAYORIENTATION
;
229 query_value("DefaultSettings.FixedOutput", &dm
->dmDisplayFixedOutput
);
234 release_display_device_init_mutex(mutex
);
239 static BOOL
write_registry_settings(const WCHAR
*device_name
, const DEVMODEW
*dm
)
241 WCHAR wine_mac_reg_key
[MAX_PATH
];
246 mutex
= get_display_device_init_mutex();
247 if (!get_display_device_reg_key(device_name
, wine_mac_reg_key
, ARRAY_SIZE(wine_mac_reg_key
)))
249 release_display_device_init_mutex(mutex
);
253 if (RegCreateKeyExW(HKEY_CURRENT_CONFIG
, wine_mac_reg_key
, 0, NULL
,
254 REG_OPTION_VOLATILE
, KEY_WRITE
, NULL
, &hkey
, NULL
))
256 release_display_device_init_mutex(mutex
);
260 #define set_value(name, data) \
261 if (RegSetValueExA(hkey, name, 0, REG_DWORD, (const BYTE*)(data), sizeof(DWORD))) \
264 set_value("DefaultSettings.BitsPerPel", &dm
->dmBitsPerPel
);
265 set_value("DefaultSettings.XResolution", &dm
->dmPelsWidth
);
266 set_value("DefaultSettings.YResolution", &dm
->dmPelsHeight
);
267 set_value("DefaultSettings.VRefresh", &dm
->dmDisplayFrequency
);
268 set_value("DefaultSettings.Flags", &dm
->dmDisplayFlags
);
269 set_value("DefaultSettings.XPanning", &dm
->dmPosition
.x
);
270 set_value("DefaultSettings.YPanning", &dm
->dmPosition
.y
);
271 set_value("DefaultSettings.Orientation", &dm
->dmDisplayOrientation
);
272 set_value("DefaultSettings.FixedOutput", &dm
->dmDisplayFixedOutput
);
277 release_display_device_init_mutex(mutex
);
282 static BOOL
write_display_settings(HKEY parent_hkey
, CGDirectDisplayID displayID
)
285 char display_key_name
[19];
287 CGDisplayModeRef display_mode
;
289 CFStringRef pixel_encoding
;
293 snprintf(display_key_name
, sizeof(display_key_name
), "Display 0x%08x", CGDisplayUnitNumber(displayID
));
294 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode\Display 0xnnnnnnnn */
295 if (RegCreateKeyExA(parent_hkey
, display_key_name
, 0, NULL
,
296 REG_OPTION_VOLATILE
, KEY_WRITE
, NULL
, &display_hkey
, NULL
))
299 display_mode
= CGDisplayCopyDisplayMode(displayID
);
303 val
= CGDisplayModeGetWidth(display_mode
);
304 if (RegSetValueExA(display_hkey
, "Width", 0, REG_DWORD
, (const BYTE
*)&val
, sizeof(val
)))
306 val
= CGDisplayModeGetHeight(display_mode
);
307 if (RegSetValueExA(display_hkey
, "Height", 0, REG_DWORD
, (const BYTE
*)&val
, sizeof(val
)))
309 val
= CGDisplayModeGetRefreshRate(display_mode
) * 100;
310 if (RegSetValueExA(display_hkey
, "RefreshRateTimes100", 0, REG_DWORD
, (const BYTE
*)&val
, sizeof(val
)))
312 val
= CGDisplayModeGetIOFlags(display_mode
);
313 if (RegSetValueExA(display_hkey
, "IOFlags", 0, REG_DWORD
, (const BYTE
*)&val
, sizeof(val
)))
316 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
317 if (&CGDisplayModeGetPixelWidth
!= NULL
&& &CGDisplayModeGetPixelHeight
!= NULL
)
319 val
= CGDisplayModeGetPixelWidth(display_mode
);
320 if (RegSetValueExA(display_hkey
, "PixelWidth", 0, REG_DWORD
, (const BYTE
*)&val
, sizeof(val
)))
322 val
= CGDisplayModeGetPixelHeight(display_mode
);
323 if (RegSetValueExA(display_hkey
, "PixelHeight", 0, REG_DWORD
, (const BYTE
*)&val
, sizeof(val
)))
328 pixel_encoding
= CGDisplayModeCopyPixelEncoding(display_mode
);
329 len
= CFStringGetLength(pixel_encoding
);
330 buf
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
331 CFStringGetCharacters(pixel_encoding
, CFRangeMake(0, len
), (UniChar
*)buf
);
333 CFRelease(pixel_encoding
);
334 if (RegSetValueExW(display_hkey
, pixelencodingW
, 0, REG_SZ
, (const BYTE
*)buf
, (len
+ 1) * sizeof(WCHAR
)))
340 HeapFree(GetProcessHeap(), 0, buf
);
341 if (display_mode
) CGDisplayModeRelease(display_mode
);
342 RegCloseKey(display_hkey
);
344 RegDeleteKeyA(parent_hkey
, display_key_name
);
349 static void init_original_display_mode(void)
351 BOOL success
= FALSE
;
352 HKEY mac_driver_hkey
, parent_hkey
;
354 struct macdrv_display
*displays
= NULL
;
357 if (inited_original_display_mode
)
360 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver */
361 if (RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Mac Driver", 0, NULL
,
362 0, KEY_ALL_ACCESS
, NULL
, &mac_driver_hkey
, NULL
))
365 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode */
366 if (RegCreateKeyExA(mac_driver_hkey
, initial_mode_key
, 0, NULL
,
367 REG_OPTION_VOLATILE
, KEY_WRITE
, NULL
, &parent_hkey
, &disposition
))
373 /* If we didn't create a new key, then it already existed. Something already stored
374 the initial display mode since Wine was started. We don't want to overwrite it. */
375 if (disposition
!= REG_CREATED_NEW_KEY
)
378 if (macdrv_get_displays(&displays
, &num_displays
))
381 for (i
= 0; i
< num_displays
; i
++)
383 if (!write_display_settings(parent_hkey
, displays
[i
].displayID
))
391 macdrv_free_displays(displays
);
392 RegCloseKey(parent_hkey
);
393 if (!success
&& parent_hkey
)
394 RegDeleteTreeA(mac_driver_hkey
, initial_mode_key
);
395 RegCloseKey(mac_driver_hkey
);
397 inited_original_display_mode
= TRUE
;
401 static BOOL
read_dword(HKEY hkey
, const char* name
, DWORD
* val
)
403 DWORD type
, size
= sizeof(*val
);
404 if (RegQueryValueExA(hkey
, name
, 0, &type
, (BYTE
*)val
, &size
) || type
!= REG_DWORD
|| size
!= sizeof(*val
))
410 static void free_display_mode_descriptor(struct display_mode_descriptor
* desc
)
414 if (desc
->pixel_encoding
)
415 CFRelease(desc
->pixel_encoding
);
416 HeapFree(GetProcessHeap(), 0, desc
);
421 static struct display_mode_descriptor
* create_original_display_mode_descriptor(CGDirectDisplayID displayID
)
423 static const char display_key_format
[] = "Software\\Wine\\Mac Driver\\Initial Display Mode\\Display 0x%08x";
424 struct display_mode_descriptor
* ret
= NULL
;
425 struct display_mode_descriptor
* desc
;
426 char display_key
[sizeof(display_key_format
) + 10];
430 WCHAR
* pixel_encoding
= NULL
, *end
;
432 init_original_display_mode();
434 snprintf(display_key
, sizeof(display_key
), display_key_format
, CGDisplayUnitNumber(displayID
));
435 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode\Display 0xnnnnnnnn */
436 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, display_key
, 0, KEY_READ
, &hkey
))
439 desc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*desc
));
440 desc
->pixel_encoding
= NULL
;
442 if (!read_dword(hkey
, "Width", &desc
->width
) ||
443 !read_dword(hkey
, "Height", &desc
->height
) ||
444 !read_dword(hkey
, "RefreshRateTimes100", &refresh100
) ||
445 !read_dword(hkey
, "IOFlags", &desc
->io_flags
))
448 desc
->refresh
= refresh100
/ 100.0;
452 if (!read_dword(hkey
, "PixelWidth", &desc
->pixel_width
) ||
453 !read_dword(hkey
, "PixelHeight", &desc
->pixel_height
))
455 desc
->pixel_width
= desc
->width
;
456 desc
->pixel_height
= desc
->height
;
460 if (RegQueryValueExW(hkey
, pixelencodingW
, 0, &type
, NULL
, &size
) || type
!= REG_SZ
)
462 pixel_encoding
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
463 if (RegQueryValueExW(hkey
, pixelencodingW
, 0, &type
, (BYTE
*)pixel_encoding
, &size
) || type
!= REG_SZ
)
465 if ((end
= memchrW(pixel_encoding
, 0, size
)))
466 size
= end
- pixel_encoding
;
467 desc
->pixel_encoding
= CFStringCreateWithCharacters(NULL
, (const UniChar
*)pixel_encoding
, size
);
473 free_display_mode_descriptor(desc
);
474 HeapFree(GetProcessHeap(), 0, pixel_encoding
);
480 static BOOL
display_mode_matches_descriptor(CGDisplayModeRef mode
, const struct display_mode_descriptor
* desc
)
484 CFStringRef mode_pixel_encoding
;
489 if (CGDisplayModeGetWidth(mode
) != desc
->width
||
490 CGDisplayModeGetHeight(mode
) != desc
->height
)
493 mode_io_flags
= CGDisplayModeGetIOFlags(mode
);
494 if ((desc
->io_flags
^ mode_io_flags
) & (kDisplayModeValidFlag
| kDisplayModeSafeFlag
| kDisplayModeStretchedFlag
|
495 kDisplayModeInterlacedFlag
| kDisplayModeTelevisionFlag
))
498 mode_refresh
= CGDisplayModeGetRefreshRate(mode
);
501 if (fabs(desc
->refresh
- mode_refresh
) > 0.1)
504 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
505 if (&CGDisplayModeGetPixelWidth
!= NULL
&& &CGDisplayModeGetPixelHeight
!= NULL
)
507 if (CGDisplayModeGetPixelWidth(mode
) != desc
->pixel_width
||
508 CGDisplayModeGetPixelHeight(mode
) != desc
->pixel_height
)
513 if (CGDisplayModeGetWidth(mode
) != desc
->pixel_width
||
514 CGDisplayModeGetHeight(mode
) != desc
->pixel_height
)
517 mode_pixel_encoding
= CGDisplayModeCopyPixelEncoding(mode
);
518 if (!CFEqual(mode_pixel_encoding
, desc
->pixel_encoding
))
520 CFRelease(mode_pixel_encoding
);
523 CFRelease(mode_pixel_encoding
);
529 static int display_mode_bits_per_pixel(CGDisplayModeRef display_mode
)
531 CFStringRef pixel_encoding
;
532 int bits_per_pixel
= 0;
534 pixel_encoding
= CGDisplayModeCopyPixelEncoding(display_mode
);
537 if (CFEqual(pixel_encoding
, CFSTR(kIO32BitFloatPixels
)))
538 bits_per_pixel
= 128;
539 else if (CFEqual(pixel_encoding
, CFSTR(kIO16BitFloatPixels
)))
541 else if (CFEqual(pixel_encoding
, CFSTR(kIO64BitDirectPixels
)))
543 else if (CFEqual(pixel_encoding
, CFSTR(kIO30BitDirectPixels
)))
545 else if (CFEqual(pixel_encoding
, CFSTR(IO32BitDirectPixels
)))
547 else if (CFEqual(pixel_encoding
, CFSTR(IO16BitDirectPixels
)))
549 else if (CFEqual(pixel_encoding
, CFSTR(IO8BitIndexedPixels
)))
551 else if (CFEqual(pixel_encoding
, CFSTR(IO4BitIndexedPixels
)))
553 else if (CFEqual(pixel_encoding
, CFSTR(IO2BitIndexedPixels
)))
555 else if (CFEqual(pixel_encoding
, CFSTR(IO1BitIndexedPixels
)))
558 CFRelease(pixel_encoding
);
561 return bits_per_pixel
;
565 static int get_default_bpp(void)
569 EnterCriticalSection(&modes_section
);
571 if (!default_mode_bpp
)
573 CGDisplayModeRef mode
= CGDisplayCopyDisplayMode(kCGDirectMainDisplay
);
576 default_mode_bpp
= display_mode_bits_per_pixel(mode
);
580 if (!default_mode_bpp
)
581 default_mode_bpp
= 32;
584 ret
= default_mode_bpp
;
586 LeaveCriticalSection(&modes_section
);
588 TRACE(" -> %d\n", ret
);
593 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
594 static CFDictionaryRef
create_mode_dict(CGDisplayModeRef display_mode
, BOOL is_original
)
597 SInt32 io_flags
= CGDisplayModeGetIOFlags(display_mode
);
598 SInt64 width
= CGDisplayModeGetWidth(display_mode
);
599 SInt64 height
= CGDisplayModeGetHeight(display_mode
);
600 double refresh_rate
= CGDisplayModeGetRefreshRate(display_mode
);
601 CFStringRef pixel_encoding
= CGDisplayModeCopyPixelEncoding(display_mode
);
602 CFNumberRef cf_io_flags
, cf_width
, cf_height
, cf_refresh
;
604 if (retina_enabled
&& is_original
)
610 io_flags
&= kDisplayModeValidFlag
| kDisplayModeSafeFlag
| kDisplayModeInterlacedFlag
|
611 kDisplayModeStretchedFlag
| kDisplayModeTelevisionFlag
;
612 cf_io_flags
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &io_flags
);
613 cf_width
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &width
);
614 cf_height
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &height
);
615 cf_refresh
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &refresh_rate
);
618 static const CFStringRef keys
[] = {
622 CFSTR("pixel_encoding"),
623 CFSTR("refresh_rate"),
625 const void* values
[ARRAY_SIZE(keys
)] = {
633 ret
= CFDictionaryCreate(NULL
, (const void**)keys
, (const void**)values
, ARRAY_SIZE(keys
),
634 &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
637 CFRelease(pixel_encoding
);
638 CFRelease(cf_io_flags
);
640 CFRelease(cf_height
);
641 CFRelease(cf_refresh
);
648 /***********************************************************************
651 * Wrapper around CGDisplayCopyAllDisplayModes() to include additional
652 * modes on Retina-capable systems, but filter those which would confuse
653 * Windows apps (basically duplicates at different DPIs).
655 * For example, some Retina Macs support a 1920x1200 mode, but it's not
656 * returned from CGDisplayCopyAllDisplayModes() without special options.
657 * This is especially bad if that's the user's default mode, since then
658 * no "available" mode matches the initial settings.
660 static CFArrayRef
copy_display_modes(CGDirectDisplayID display
)
662 CFArrayRef modes
= NULL
;
664 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
665 if (&CGDisplayModeGetPixelWidth
!= NULL
&& &CGDisplayModeGetPixelHeight
!= NULL
)
667 CFDictionaryRef options
;
668 struct display_mode_descriptor
* desc
;
669 CFMutableDictionaryRef modes_by_size
;
671 CGDisplayModeRef
* mode_array
;
673 options
= CFDictionaryCreate(NULL
, (const void**)&kCGDisplayShowDuplicateLowResolutionModes
,
674 (const void**)&kCFBooleanTrue
, 1, &kCFTypeDictionaryKeyCallBacks
,
675 &kCFTypeDictionaryValueCallBacks
);
677 modes
= CGDisplayCopyAllDisplayModes(display
, options
);
683 desc
= create_original_display_mode_descriptor(display
);
685 modes_by_size
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
686 count
= CFArrayGetCount(modes
);
687 for (i
= 0; i
< count
; i
++)
690 CGDisplayModeRef new_mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
691 BOOL new_is_original
= display_mode_matches_descriptor(new_mode
, desc
);
692 CFDictionaryRef key
= create_mode_dict(new_mode
, new_is_original
);
694 /* If a given mode is the user's default, then always list it in preference to any similar
695 modes that may exist. */
700 CFStringRef pixel_encoding
= CGDisplayModeCopyPixelEncoding(new_mode
);
701 CGDisplayModeRef old_mode
;
705 BOOL bpp30
= CFEqual(pixel_encoding
, CFSTR(kIO30BitDirectPixels
));
706 CFRelease(pixel_encoding
);
709 /* This is an odd pixel encoding. It seems it's only returned
710 when using kCGDisplayShowDuplicateLowResolutionModes. It's
711 32bpp in terms of the actual raster layout, but it's 10
712 bits per component. I think that no Windows program is
713 likely to need it and they will probably be confused by it.
720 old_mode
= (CGDisplayModeRef
)CFDictionaryGetValue(modes_by_size
, key
);
723 BOOL old_is_original
= display_mode_matches_descriptor(old_mode
, desc
);
729 /* Otherwise, prefer a mode whose pixel size equals its point size over one which
731 size_t width_points
= CGDisplayModeGetWidth(new_mode
);
732 size_t height_points
= CGDisplayModeGetHeight(new_mode
);
733 size_t new_width_pixels
= CGDisplayModeGetPixelWidth(new_mode
);
734 size_t new_height_pixels
= CGDisplayModeGetPixelHeight(new_mode
);
735 size_t old_width_pixels
= CGDisplayModeGetPixelWidth(old_mode
);
736 size_t old_height_pixels
= CGDisplayModeGetPixelHeight(old_mode
);
737 BOOL new_size_same
= (new_width_pixels
== width_points
&& new_height_pixels
== height_points
);
738 BOOL old_size_same
= (old_width_pixels
== width_points
&& old_height_pixels
== height_points
);
740 if (new_size_same
&& !old_size_same
)
742 else if (!new_size_same
&& old_size_same
)
746 /* Otherwise, prefer the mode with the smaller pixel size. */
747 if (old_width_pixels
< new_width_pixels
|| old_height_pixels
< new_height_pixels
)
755 CFDictionarySetValue(modes_by_size
, key
, new_mode
);
760 free_display_mode_descriptor(desc
);
763 count
= CFDictionaryGetCount(modes_by_size
);
764 mode_array
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(mode_array
[0]));
765 CFDictionaryGetKeysAndValues(modes_by_size
, NULL
, (const void **)mode_array
);
766 modes
= CFArrayCreate(NULL
, (const void **)mode_array
, count
, &kCFTypeArrayCallBacks
);
767 HeapFree(GetProcessHeap(), 0, mode_array
);
768 CFRelease(modes_by_size
);
772 modes
= CGDisplayCopyAllDisplayModes(display
, NULL
);
778 void check_retina_status(void)
782 struct display_mode_descriptor
* desc
= create_original_display_mode_descriptor(kCGDirectMainDisplay
);
783 CGDisplayModeRef mode
= CGDisplayCopyDisplayMode(kCGDirectMainDisplay
);
784 BOOL new_value
= display_mode_matches_descriptor(mode
, desc
);
786 CGDisplayModeRelease(mode
);
787 free_display_mode_descriptor(desc
);
789 if (new_value
!= retina_on
)
790 macdrv_set_cocoa_retina_mode(new_value
);
794 static BOOL
get_primary_adapter(WCHAR
*name
)
800 for (i
= 0; EnumDisplayDevicesW(NULL
, i
, &dd
, 0); ++i
)
802 if (dd
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
)
804 lstrcpyW(name
, dd
.DeviceName
);
812 static BOOL
is_detached_mode(const DEVMODEW
*mode
)
814 return mode
->dmFields
& DM_POSITION
&&
815 mode
->dmFields
& DM_PELSWIDTH
&&
816 mode
->dmFields
& DM_PELSHEIGHT
&&
817 mode
->dmPelsWidth
== 0 &&
818 mode
->dmPelsHeight
== 0;
821 /***********************************************************************
822 * ChangeDisplaySettingsEx (MACDRV.@)
825 LONG CDECL
macdrv_ChangeDisplaySettingsEx(LPCWSTR devname
, LPDEVMODEW devmode
,
826 HWND hwnd
, DWORD flags
, LPVOID lpvoid
)
828 WCHAR primary_adapter
[CCHDEVICENAME
];
829 LONG ret
= DISP_CHANGE_BADMODE
;
830 DEVMODEW default_mode
;
832 struct macdrv_display
*displays
;
834 CFArrayRef display_modes
;
835 struct display_mode_descriptor
* desc
;
836 CFIndex count
, i
, safe
, best
;
837 CGDisplayModeRef best_display_mode
;
838 uint32_t best_io_flags
;
839 BOOL best_is_original
;
841 TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname
), devmode
, hwnd
, flags
, lpvoid
);
843 init_original_display_mode();
845 if (!get_primary_adapter(primary_adapter
))
846 return DISP_CHANGE_FAILED
;
848 if (!devname
&& !devmode
)
850 memset(&default_mode
, 0, sizeof(default_mode
));
851 default_mode
.dmSize
= sizeof(default_mode
);
852 if (!EnumDisplaySettingsExW(primary_adapter
, ENUM_REGISTRY_SETTINGS
, &default_mode
, 0))
854 ERR("Default mode not found for %s!\n", wine_dbgstr_w(primary_adapter
));
855 return DISP_CHANGE_BADMODE
;
858 devname
= primary_adapter
;
859 devmode
= &default_mode
;
862 if (is_detached_mode(devmode
))
864 FIXME("Detaching adapters is currently unsupported.\n");
865 return DISP_CHANGE_SUCCESSFUL
;
868 if (macdrv_get_displays(&displays
, &num_displays
))
869 return DISP_CHANGE_FAILED
;
871 display_modes
= copy_display_modes(displays
[0].displayID
);
874 macdrv_free_displays(displays
);
875 return DISP_CHANGE_FAILED
;
878 bpp
= get_default_bpp();
879 if ((devmode
->dmFields
& DM_BITSPERPEL
) && devmode
->dmBitsPerPel
!= bpp
)
880 TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp
, devmode
->dmBitsPerPel
);
882 TRACE("looking for %dx%dx%dbpp @%d Hz",
883 (devmode
->dmFields
& DM_PELSWIDTH
? devmode
->dmPelsWidth
: 0),
884 (devmode
->dmFields
& DM_PELSHEIGHT
? devmode
->dmPelsHeight
: 0),
886 (devmode
->dmFields
& DM_DISPLAYFREQUENCY
? devmode
->dmDisplayFrequency
: 0));
887 if (devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)
888 TRACE(" %sstretched", devmode
->dmDisplayFixedOutput
== DMDFO_STRETCH
? "" : "un");
889 if (devmode
->dmFields
& DM_DISPLAYFLAGS
)
890 TRACE(" %sinterlaced", devmode
->dmDisplayFlags
& DM_INTERLACED
? "" : "non-");
893 desc
= create_original_display_mode_descriptor(displays
[0].displayID
);
896 best_display_mode
= NULL
;
897 count
= CFArrayGetCount(display_modes
);
898 for (i
= 0; i
< count
; i
++)
900 CGDisplayModeRef display_mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(display_modes
, i
);
901 BOOL is_original
= display_mode_matches_descriptor(display_mode
, desc
);
902 uint32_t io_flags
= CGDisplayModeGetIOFlags(display_mode
);
903 int mode_bpp
= display_mode_bits_per_pixel(display_mode
);
904 size_t width
= CGDisplayModeGetWidth(display_mode
);
905 size_t height
= CGDisplayModeGetHeight(display_mode
);
907 if (is_original
&& retina_enabled
)
913 if (!(io_flags
& kDisplayModeValidFlag
) || !(io_flags
& kDisplayModeSafeFlag
))
921 if (devmode
->dmFields
& DM_PELSWIDTH
)
923 if (devmode
->dmPelsWidth
!= width
)
926 if (devmode
->dmFields
& DM_PELSHEIGHT
)
928 if (devmode
->dmPelsHeight
!= height
)
931 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) &&
932 devmode
->dmDisplayFrequency
!= 0 &&
933 devmode
->dmDisplayFrequency
!= 1)
935 double refresh_rate
= CGDisplayModeGetRefreshRate(display_mode
);
938 if (devmode
->dmDisplayFrequency
!= (DWORD
)refresh_rate
)
941 if (devmode
->dmFields
& DM_DISPLAYFLAGS
)
943 if (!(devmode
->dmDisplayFlags
& DM_INTERLACED
) != !(io_flags
& kDisplayModeInterlacedFlag
))
946 else if (best_display_mode
)
948 if (io_flags
& kDisplayModeInterlacedFlag
&& !(best_io_flags
& kDisplayModeInterlacedFlag
))
950 else if (!(io_flags
& kDisplayModeInterlacedFlag
) && best_io_flags
& kDisplayModeInterlacedFlag
)
953 if (devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)
955 if (!(devmode
->dmDisplayFixedOutput
== DMDFO_STRETCH
) != !(io_flags
& kDisplayModeStretchedFlag
))
958 else if (best_display_mode
)
960 if (io_flags
& kDisplayModeStretchedFlag
&& !(best_io_flags
& kDisplayModeStretchedFlag
))
962 else if (!(io_flags
& kDisplayModeStretchedFlag
) && best_io_flags
& kDisplayModeStretchedFlag
)
966 if (best_display_mode
)
970 best_display_mode
= display_mode
;
972 best_io_flags
= io_flags
;
973 best_is_original
= is_original
;
976 if (best_display_mode
)
978 /* we have a valid mode */
979 TRACE("Requested display settings match mode %ld\n", best
);
981 if ((flags
& CDS_UPDATEREGISTRY
) && !write_registry_settings(devname
, devmode
))
983 WARN("Failed to update registry\n");
984 ret
= DISP_CHANGE_NOTUPDATED
;
986 else if (flags
& (CDS_TEST
| CDS_NORESET
))
987 ret
= DISP_CHANGE_SUCCESSFUL
;
988 else if (lstrcmpiW(primary_adapter
, devname
))
990 FIXME("Changing non-primary adapter settings is currently unsupported.\n");
991 ret
= DISP_CHANGE_SUCCESSFUL
;
993 else if (macdrv_set_display_mode(&displays
[0], best_display_mode
))
995 int mode_bpp
= display_mode_bits_per_pixel(best_display_mode
);
996 size_t width
= CGDisplayModeGetWidth(best_display_mode
);
997 size_t height
= CGDisplayModeGetHeight(best_display_mode
);
999 macdrv_init_display_devices(TRUE
);
1001 if (best_is_original
&& retina_enabled
)
1007 SendMessageW(GetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT
, mode_bpp
,
1008 MAKELPARAM(width
, height
));
1009 ret
= DISP_CHANGE_SUCCESSFUL
;
1013 WARN("Failed to set display mode\n");
1014 ret
= DISP_CHANGE_FAILED
;
1019 /* no valid modes found */
1020 ERR("No matching mode found %ux%ux%d @%u!\n", devmode
->dmPelsWidth
, devmode
->dmPelsHeight
,
1021 bpp
, devmode
->dmDisplayFrequency
);
1024 free_display_mode_descriptor(desc
);
1025 CFRelease(display_modes
);
1026 macdrv_free_displays(displays
);
1031 /***********************************************************************
1032 * EnumDisplaySettingsEx (MACDRV.@)
1035 BOOL CDECL
macdrv_EnumDisplaySettingsEx(LPCWSTR devname
, DWORD mode
,
1036 LPDEVMODEW devmode
, DWORD flags
)
1038 static const WCHAR dev_name
[CCHDEVICENAME
] =
1039 { 'W','i','n','e',' ','M','a','c',' ','d','r','i','v','e','r',0 };
1040 struct macdrv_display
*displays
= NULL
;
1042 CGDisplayModeRef display_mode
;
1043 int display_mode_bpp
;
1044 BOOL synthesized
= FALSE
;
1048 TRACE("%s, %u, %p + %hu, %08x\n", debugstr_w(devname
), mode
, devmode
, devmode
->dmSize
, flags
);
1050 init_original_display_mode();
1052 memcpy(devmode
->dmDeviceName
, dev_name
, sizeof(dev_name
));
1053 devmode
->dmSpecVersion
= DM_SPECVERSION
;
1054 devmode
->dmDriverVersion
= DM_SPECVERSION
;
1055 devmode
->dmSize
= FIELD_OFFSET(DEVMODEW
, dmICMMethod
);
1056 devmode
->dmDriverExtra
= 0;
1057 memset(&devmode
->dmFields
, 0, devmode
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmFields
));
1059 if (mode
== ENUM_REGISTRY_SETTINGS
)
1061 TRACE("mode %d (registry) -- getting default mode\n", mode
);
1062 return read_registry_settings(devname
, devmode
);
1065 if (macdrv_get_displays(&displays
, &num_displays
))
1068 if (mode
== ENUM_CURRENT_SETTINGS
)
1070 TRACE("mode %d (current) -- getting current mode\n", mode
);
1071 display_mode
= CGDisplayCopyDisplayMode(displays
[0].displayID
);
1072 display_mode_bpp
= display_mode_bits_per_pixel(display_mode
);
1078 EnterCriticalSection(&modes_section
);
1080 if (mode
== 0 || !modes
)
1082 if (modes
) CFRelease(modes
);
1083 modes
= copy_display_modes(displays
[0].displayID
);
1084 modes_has_8bpp
= modes_has_16bpp
= FALSE
;
1088 count
= CFArrayGetCount(modes
);
1089 for (i
= 0; i
< count
&& !(modes_has_8bpp
&& modes_has_16bpp
); i
++)
1091 CGDisplayModeRef mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
1092 int bpp
= display_mode_bits_per_pixel(mode
);
1094 modes_has_8bpp
= TRUE
;
1096 modes_has_16bpp
= TRUE
;
1101 display_mode
= NULL
;
1104 int default_bpp
= get_default_bpp();
1105 DWORD seen_modes
= 0;
1107 count
= CFArrayGetCount(modes
);
1108 for (i
= 0; i
< count
; i
++)
1110 CGDisplayModeRef candidate
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
1112 io_flags
= CGDisplayModeGetIOFlags(candidate
);
1113 if (!(flags
& EDS_RAWMODE
) &&
1114 (!(io_flags
& kDisplayModeValidFlag
) || !(io_flags
& kDisplayModeSafeFlag
)))
1118 if (seen_modes
> mode
)
1120 display_mode
= (CGDisplayModeRef
)CFRetain(candidate
);
1121 display_mode_bpp
= display_mode_bits_per_pixel(display_mode
);
1125 /* We only synthesize modes from those having the default bpp. */
1126 if (display_mode_bits_per_pixel(candidate
) != default_bpp
)
1129 if (!modes_has_8bpp
)
1132 if (seen_modes
> mode
)
1134 display_mode
= (CGDisplayModeRef
)CFRetain(candidate
);
1135 display_mode_bpp
= 8;
1141 if (!modes_has_16bpp
)
1144 if (seen_modes
> mode
)
1146 display_mode
= (CGDisplayModeRef
)CFRetain(candidate
);
1147 display_mode_bpp
= 16;
1155 LeaveCriticalSection(&modes_section
);
1161 /* We currently only report modes for the primary display, so it's at (0, 0). */
1162 devmode
->dmPosition
.x
= 0;
1163 devmode
->dmPosition
.y
= 0;
1164 devmode
->dmFields
|= DM_POSITION
;
1166 rotation
= CGDisplayRotation(displays
[0].displayID
);
1167 devmode
->dmDisplayOrientation
= ((int)((rotation
/ 90) + 0.5)) % 4;
1168 devmode
->dmFields
|= DM_DISPLAYORIENTATION
;
1170 io_flags
= CGDisplayModeGetIOFlags(display_mode
);
1171 if (io_flags
& kDisplayModeStretchedFlag
)
1172 devmode
->dmDisplayFixedOutput
= DMDFO_STRETCH
;
1174 devmode
->dmDisplayFixedOutput
= DMDFO_CENTER
;
1175 devmode
->dmFields
|= DM_DISPLAYFIXEDOUTPUT
;
1177 devmode
->dmBitsPerPel
= display_mode_bpp
;
1178 if (devmode
->dmBitsPerPel
)
1179 devmode
->dmFields
|= DM_BITSPERPEL
;
1181 devmode
->dmPelsWidth
= CGDisplayModeGetWidth(display_mode
);
1182 devmode
->dmPelsHeight
= CGDisplayModeGetHeight(display_mode
);
1185 struct display_mode_descriptor
* desc
= create_original_display_mode_descriptor(displays
[0].displayID
);
1186 if (display_mode_matches_descriptor(display_mode
, desc
))
1188 devmode
->dmPelsWidth
*= 2;
1189 devmode
->dmPelsHeight
*= 2;
1191 free_display_mode_descriptor(desc
);
1193 devmode
->dmFields
|= DM_PELSWIDTH
| DM_PELSHEIGHT
;
1195 devmode
->dmDisplayFlags
= 0;
1196 if (io_flags
& kDisplayModeInterlacedFlag
)
1197 devmode
->dmDisplayFlags
|= DM_INTERLACED
;
1198 devmode
->dmFields
|= DM_DISPLAYFLAGS
;
1200 devmode
->dmDisplayFrequency
= CGDisplayModeGetRefreshRate(display_mode
);
1201 if (!devmode
->dmDisplayFrequency
)
1202 devmode
->dmDisplayFrequency
= 60;
1203 devmode
->dmFields
|= DM_DISPLAYFREQUENCY
;
1205 CFRelease(display_mode
);
1206 macdrv_free_displays(displays
);
1208 TRACE("mode %d -- %dx%dx%dbpp @%d Hz", mode
,
1209 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, devmode
->dmBitsPerPel
,
1210 devmode
->dmDisplayFrequency
);
1211 if (devmode
->dmDisplayOrientation
)
1212 TRACE(" rotated %u degrees", devmode
->dmDisplayOrientation
* 90);
1213 if (devmode
->dmDisplayFixedOutput
== DMDFO_STRETCH
)
1214 TRACE(" stretched");
1215 if (devmode
->dmDisplayFlags
& DM_INTERLACED
)
1216 TRACE(" interlaced");
1218 TRACE(" (synthesized)");
1224 TRACE("mode %d -- not present\n", mode
);
1225 if (displays
) macdrv_free_displays(displays
);
1226 SetLastError(ERROR_NO_MORE_FILES
);
1231 /***********************************************************************
1232 * GetDeviceGammaRamp (MACDRV.@)
1234 BOOL CDECL
macdrv_GetDeviceGammaRamp(PHYSDEV dev
, LPVOID ramp
)
1237 DDGAMMARAMP
*r
= ramp
;
1238 struct macdrv_display
*displays
;
1240 uint32_t mac_entries
;
1241 int win_entries
= ARRAY_SIZE(r
->red
);
1242 CGGammaValue
*red
, *green
, *blue
;
1246 TRACE("dev %p ramp %p\n", dev
, ramp
);
1248 if (macdrv_get_displays(&displays
, &num_displays
))
1250 WARN("failed to get Mac displays\n");
1254 mac_entries
= CGDisplayGammaTableCapacity(displays
[0].displayID
);
1255 red
= HeapAlloc(GetProcessHeap(), 0, mac_entries
* sizeof(red
[0]) * 3);
1258 green
= red
+ mac_entries
;
1259 blue
= green
+ mac_entries
;
1261 err
= CGGetDisplayTransferByTable(displays
[0].displayID
, mac_entries
, red
, green
,
1262 blue
, &mac_entries
);
1263 if (err
!= kCGErrorSuccess
)
1265 WARN("failed to get Mac gamma table: %d\n", err
);
1269 if (mac_entries
== win_entries
)
1271 for (win_entry
= 0; win_entry
< win_entries
; win_entry
++)
1273 r
->red
[win_entry
] = red
[win_entry
] * 65535 + 0.5;
1274 r
->green
[win_entry
] = green
[win_entry
] * 65535 + 0.5;
1275 r
->blue
[win_entry
] = blue
[win_entry
] * 65535 + 0.5;
1280 for (win_entry
= 0; win_entry
< win_entries
; win_entry
++)
1282 double mac_pos
= win_entry
* (mac_entries
- 1) / (double)(win_entries
- 1);
1283 int mac_entry
= mac_pos
;
1284 double red_value
, green_value
, blue_value
;
1286 if (mac_entry
== mac_entries
- 1)
1288 red_value
= red
[mac_entry
];
1289 green_value
= green
[mac_entry
];
1290 blue_value
= blue
[mac_entry
];
1294 double distance
= mac_pos
- mac_entry
;
1296 red_value
= red
[mac_entry
] * (1 - distance
) + red
[mac_entry
+ 1] * distance
;
1297 green_value
= green
[mac_entry
] * (1 - distance
) + green
[mac_entry
+ 1] * distance
;
1298 blue_value
= blue
[mac_entry
] * (1 - distance
) + blue
[mac_entry
+ 1] * distance
;
1301 r
->red
[win_entry
] = red_value
* 65535 + 0.5;
1302 r
->green
[win_entry
] = green_value
* 65535 + 0.5;
1303 r
->blue
[win_entry
] = blue_value
* 65535 + 0.5;
1310 HeapFree(GetProcessHeap(), 0, red
);
1311 macdrv_free_displays(displays
);
1315 /***********************************************************************
1316 * SetDeviceGammaRamp (MACDRV.@)
1318 BOOL CDECL
macdrv_SetDeviceGammaRamp(PHYSDEV dev
, LPVOID ramp
)
1320 DDGAMMARAMP
*r
= ramp
;
1321 struct macdrv_display
*displays
;
1323 int win_entries
= ARRAY_SIZE(r
->red
);
1324 CGGammaValue
*red
, *green
, *blue
;
1326 CGError err
= kCGErrorFailure
;
1328 TRACE("dev %p ramp %p\n", dev
, ramp
);
1330 if (!allow_set_gamma
)
1332 TRACE("disallowed by registry setting\n");
1336 if (macdrv_get_displays(&displays
, &num_displays
))
1338 WARN("failed to get Mac displays\n");
1342 red
= HeapAlloc(GetProcessHeap(), 0, win_entries
* sizeof(red
[0]) * 3);
1345 green
= red
+ win_entries
;
1346 blue
= green
+ win_entries
;
1348 for (i
= 0; i
< win_entries
; i
++)
1350 red
[i
] = r
->red
[i
] / 65535.0;
1351 green
[i
] = r
->green
[i
] / 65535.0;
1352 blue
[i
] = r
->blue
[i
] / 65535.0;
1355 err
= CGSetDisplayTransferByTable(displays
[0].displayID
, win_entries
, red
, green
, blue
);
1356 if (err
!= kCGErrorSuccess
)
1357 WARN("failed to set display gamma table: %d\n", err
);
1360 HeapFree(GetProcessHeap(), 0, red
);
1361 macdrv_free_displays(displays
);
1362 return (err
== kCGErrorSuccess
);
1365 /***********************************************************************
1366 * init_registry_display_settings
1368 * Initialize registry display settings when new display devices are added.
1370 static void init_registry_display_settings(void)
1372 DEVMODEW dm
= {.dmSize
= sizeof(dm
)};
1373 DISPLAY_DEVICEW dd
= {sizeof(dd
)};
1377 while (EnumDisplayDevicesW(NULL
, i
++, &dd
, 0))
1379 /* Skip if the device already has registry display settings */
1380 if (EnumDisplaySettingsExW(dd
.DeviceName
, ENUM_REGISTRY_SETTINGS
, &dm
, 0))
1383 if (!EnumDisplaySettingsExW(dd
.DeviceName
, ENUM_CURRENT_SETTINGS
, &dm
, 0))
1385 ERR("Failed to query current display settings for %s.\n", wine_dbgstr_w(dd
.DeviceName
));
1389 TRACE("Device %s current display mode %ux%u %ubits %uHz at %d,%d.\n",
1390 wine_dbgstr_w(dd
.DeviceName
), dm
.dmPelsWidth
, dm
.dmPelsHeight
, dm
.dmBitsPerPel
,
1391 dm
.dmDisplayFrequency
, dm
.dmPosition
.x
, dm
.dmPosition
.y
);
1393 ret
= ChangeDisplaySettingsExW(dd
.DeviceName
, &dm
, NULL
,
1394 CDS_GLOBAL
| CDS_NORESET
| CDS_UPDATEREGISTRY
, NULL
);
1395 if (ret
!= DISP_CHANGE_SUCCESSFUL
)
1396 ERR("Failed to save registry display settings for %s, returned %d.\n",
1397 wine_dbgstr_w(dd
.DeviceName
), ret
);
1401 /***********************************************************************
1402 * macdrv_displays_changed
1404 * Handler for DISPLAYS_CHANGED events.
1406 void macdrv_displays_changed(const macdrv_event
*event
)
1408 HWND hwnd
= GetDesktopWindow();
1410 /* A system display change will get delivered to all GUI-attached threads,
1411 so the desktop-window-owning thread will get it and all others should
1412 ignore it. A synthesized display change event due to activation
1413 will only get delivered to the activated process. So, it needs to
1414 process it (by sending it to the desktop window). */
1415 if (event
->displays_changed
.activating
||
1416 GetWindowThreadProcessId(hwnd
, NULL
) == GetCurrentThreadId())
1418 CGDirectDisplayID mainDisplay
= CGMainDisplayID();
1419 CGDisplayModeRef mode
= CGDisplayCopyDisplayMode(mainDisplay
);
1420 size_t width
= CGDisplayModeGetWidth(mode
);
1421 size_t height
= CGDisplayModeGetHeight(mode
);
1422 int mode_bpp
= display_mode_bits_per_pixel(mode
);
1423 struct display_mode_descriptor
* desc
= create_original_display_mode_descriptor(mainDisplay
);
1424 BOOL is_original
= display_mode_matches_descriptor(mode
, desc
);
1426 free_display_mode_descriptor(desc
);
1427 CGDisplayModeRelease(mode
);
1429 macdrv_init_display_devices(TRUE
);
1430 init_registry_display_settings();
1432 if (is_original
&& retina_enabled
)
1438 SendMessageW(hwnd
, WM_MACDRV_UPDATE_DESKTOP_RECT
, mode_bpp
,
1439 MAKELPARAM(width
, height
));
1443 /***********************************************************************
1446 * Initialize a GPU instance.
1447 * Return its GUID string in guid_string, driver value in driver parameter and LUID in gpu_luid.
1449 * Return FALSE on failure and TRUE on success.
1451 static BOOL
macdrv_init_gpu(HDEVINFO devinfo
, const struct macdrv_gpu
*gpu
, int gpu_index
, WCHAR
*guid_string
,
1452 WCHAR
*driver
, LUID
*gpu_luid
)
1454 static const BOOL present
= TRUE
;
1455 SP_DEVINFO_DATA device_data
= {sizeof(device_data
)};
1456 WCHAR instanceW
[MAX_PATH
];
1457 DEVPROPTYPE property_type
;
1458 WCHAR nameW
[MAX_PATH
];
1459 WCHAR bufferW
[1024];
1468 sprintfW(instanceW
, gpu_instance_fmtW
, gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
, gpu_index
);
1469 MultiByteToWideChar(CP_UTF8
, 0, gpu
->name
, -1, nameW
, ARRAY_SIZE(nameW
));
1470 if (!SetupDiOpenDeviceInfoW(devinfo
, instanceW
, NULL
, 0, &device_data
))
1472 SetupDiCreateDeviceInfoW(devinfo
, instanceW
, &GUID_DEVCLASS_DISPLAY
, nameW
, NULL
, 0, &device_data
);
1473 if (!SetupDiRegisterDeviceInfo(devinfo
, &device_data
, 0, NULL
, NULL
, NULL
))
1477 /* Write HardwareID registry property, REG_MULTI_SZ */
1478 written
= sprintfW(bufferW
, gpu_hardware_id_fmtW
, gpu
->vendor_id
, gpu
->device_id
);
1479 bufferW
[written
+ 1] = 0;
1480 if (!SetupDiSetDeviceRegistryPropertyW(devinfo
, &device_data
, SPDRP_HARDWAREID
, (const BYTE
*)bufferW
,
1481 (written
+ 2) * sizeof(WCHAR
)))
1484 /* Write DEVPKEY_Device_IsPresent property */
1485 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &DEVPKEY_Device_IsPresent
, DEVPROP_TYPE_BOOLEAN
,
1486 (const BYTE
*)&present
, sizeof(present
), 0))
1489 /* Write DEVPROPKEY_GPU_LUID property */
1490 if (!SetupDiGetDevicePropertyW(devinfo
, &device_data
, &DEVPROPKEY_GPU_LUID
, &property_type
,
1491 (BYTE
*)&luid
, sizeof(luid
), NULL
, 0))
1493 if (!AllocateLocallyUniqueId(&luid
))
1496 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &DEVPROPKEY_GPU_LUID
,
1497 DEVPROP_TYPE_UINT64
, (const BYTE
*)&luid
, sizeof(luid
), 0))
1501 TRACE("GPU id:0x%s name:%s LUID:%08x:%08x.\n", wine_dbgstr_longlong(gpu
->id
), gpu
->name
,
1502 luid
.HighPart
, luid
.LowPart
);
1505 * This is where HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} links to */
1506 hkey
= SetupDiCreateDevRegKeyW(devinfo
, &device_data
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, NULL
, NULL
);
1508 /* Write DriverDesc value */
1509 if (RegSetValueExW(hkey
, driver_descW
, 0, REG_SZ
, (const BYTE
*)nameW
, (lstrlenW(nameW
) + 1) * sizeof(WCHAR
)))
1511 /* Write DriverDateData value, using current time as driver date, needed by Evoland */
1512 GetSystemTimeAsFileTime(&filetime
);
1513 if (RegSetValueExW(hkey
, driver_date_dataW
, 0, REG_BINARY
, (BYTE
*)&filetime
, sizeof(filetime
)))
1517 /* Retrieve driver value for adapters */
1518 if (!SetupDiGetDeviceRegistryPropertyW(devinfo
, &device_data
, SPDRP_DRIVER
, NULL
, (BYTE
*)bufferW
, sizeof(bufferW
),
1521 lstrcpyW(driver
, nt_classW
);
1522 lstrcatW(driver
, bufferW
);
1524 /* Write GUID in VideoID in .../instance/Device Parameters, reuse the GUID if it's existent */
1525 hkey
= SetupDiCreateDevRegKeyW(devinfo
, &device_data
, DICS_FLAG_GLOBAL
, 0, DIREG_DEV
, NULL
, NULL
);
1527 size
= sizeof(bufferW
);
1528 if (RegQueryValueExW(hkey
, video_idW
, 0, NULL
, (BYTE
*)bufferW
, &size
))
1531 sprintfW(bufferW
, guid_fmtW
, guid
.Data1
, guid
.Data2
, guid
.Data3
, guid
.Data4
[0], guid
.Data4
[1], guid
.Data4
[2],
1532 guid
.Data4
[3], guid
.Data4
[4], guid
.Data4
[5], guid
.Data4
[6], guid
.Data4
[7]);
1533 if (RegSetValueExW(hkey
, video_idW
, 0, REG_SZ
, (const BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
)))
1536 lstrcpyW(guid_string
, bufferW
);
1542 ERR("Failed to initialize GPU\n");
1546 /***********************************************************************
1547 * macdrv_init_adapter
1549 * Initialize an adapter.
1551 * Return FALSE on failure and TRUE on success.
1553 static BOOL
macdrv_init_adapter(HKEY video_hkey
, int video_index
, int gpu_index
, int adapter_index
, int monitor_count
,
1554 const struct macdrv_gpu
*gpu
, const WCHAR
*guid_string
, const WCHAR
*gpu_driver
,
1555 const struct macdrv_adapter
*adapter
)
1557 WCHAR adapter_keyW
[MAX_PATH
];
1558 WCHAR key_nameW
[MAX_PATH
];
1559 WCHAR bufferW
[1024];
1565 sprintfW(key_nameW
, device_video_fmtW
, video_index
);
1566 lstrcpyW(bufferW
, machine_prefixW
);
1567 sprintfW(adapter_keyW
, adapter_key_fmtW
, guid_string
, adapter_index
);
1568 lstrcatW(bufferW
, adapter_keyW
);
1570 /* Write value of \Device\Video? (adapter key) in HKLM\HARDWARE\DEVICEMAP\VIDEO\ */
1571 if (RegSetValueExW(video_hkey
, key_nameW
, 0, REG_SZ
, (const BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
)))
1574 /* Create HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} link to GPU driver */
1575 ls
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, adapter_keyW
, 0, NULL
, REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
1576 KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1577 if (ls
== ERROR_ALREADY_EXISTS
)
1578 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, adapter_keyW
, 0, NULL
, REG_OPTION_VOLATILE
| REG_OPTION_OPEN_LINK
,
1579 KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1580 if (RegSetValueExW(hkey
, symbolic_link_valueW
, 0, REG_LINK
, (const BYTE
*)gpu_driver
,
1581 lstrlenW(gpu_driver
) * sizeof(WCHAR
)))
1587 * Following information is Wine specific, it doesn't really exist on Windows. It is used so that we can
1588 * implement EnumDisplayDevices etc by querying registry only. This information is most likely reported by the
1589 * device driver on Windows */
1590 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, adapter_keyW
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_WRITE
, NULL
, &hkey
, NULL
);
1592 /* Write GPU instance path so that we can find the GPU instance via adapters quickly. Another way is trying to match
1593 * them via the GUID in Device Parameters/VideoID, but it would require enumerating all GPU instances */
1594 sprintfW(bufferW
, gpu_instance_fmtW
, gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
, gpu_index
);
1595 if (RegSetValueExW(hkey
, gpu_idW
, 0, REG_SZ
, (const BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
)))
1598 /* Write all monitor instance paths under this adapter */
1599 for (i
= 0; i
< monitor_count
; i
++)
1601 sprintfW(key_nameW
, monitor_id_fmtW
, i
);
1602 sprintfW(bufferW
, monitor_instance_fmtW
, video_index
, i
);
1603 if (RegSetValueExW(hkey
, key_nameW
, 0, REG_SZ
, (const BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
)))
1607 /* Write StateFlags */
1608 if (RegSetValueExW(hkey
, state_flagsW
, 0, REG_DWORD
, (const BYTE
*)&adapter
->state_flags
,
1609 sizeof(adapter
->state_flags
)))
1616 ERR("Failed to initialize adapter\n");
1620 /***********************************************************************
1621 * macdrv_init_monitor
1623 * Initialize an monitor.
1625 * Return FALSE on failure and TRUE on success.
1627 static BOOL
macdrv_init_monitor(HDEVINFO devinfo
, const struct macdrv_monitor
*monitor
, int monitor_index
,
1628 int video_index
, const LUID
*gpu_luid
, UINT output_id
)
1630 SP_DEVINFO_DATA device_data
= {sizeof(SP_DEVINFO_DATA
)};
1631 WCHAR nameW
[MAX_PATH
];
1632 WCHAR bufferW
[MAX_PATH
];
1637 /* Create GUID_DEVCLASS_MONITOR instance */
1638 sprintfW(bufferW
, monitor_instance_fmtW
, video_index
, monitor_index
);
1639 MultiByteToWideChar(CP_UTF8
, 0, monitor
->name
, -1, nameW
, ARRAY_SIZE(nameW
));
1640 SetupDiCreateDeviceInfoW(devinfo
, bufferW
, &GUID_DEVCLASS_MONITOR
, nameW
, NULL
, 0, &device_data
);
1641 if (!SetupDiRegisterDeviceInfo(devinfo
, &device_data
, 0, NULL
, NULL
, NULL
))
1644 /* Write HardwareID registry property */
1645 if (!SetupDiSetDeviceRegistryPropertyW(devinfo
, &device_data
, SPDRP_HARDWAREID
,
1646 (const BYTE
*)monitor_hardware_idW
, sizeof(monitor_hardware_idW
)))
1649 /* Write DEVPROPKEY_MONITOR_GPU_LUID */
1650 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &DEVPROPKEY_MONITOR_GPU_LUID
,
1651 DEVPROP_TYPE_INT64
, (const BYTE
*)gpu_luid
, sizeof(*gpu_luid
), 0))
1654 /* Write DEVPROPKEY_MONITOR_OUTPUT_ID */
1655 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &DEVPROPKEY_MONITOR_OUTPUT_ID
,
1656 DEVPROP_TYPE_UINT32
, (const BYTE
*)&output_id
, sizeof(output_id
), 0))
1659 /* Create driver key */
1660 hkey
= SetupDiCreateDevRegKeyW(devinfo
, &device_data
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, NULL
, NULL
);
1664 * Following properties are Wine specific, see comments in macdrv_init_adapter for details */
1666 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS
, DEVPROP_TYPE_UINT32
,
1667 (const BYTE
*)&monitor
->state_flags
, sizeof(monitor
->state_flags
), 0))
1670 rect
= rect_from_cgrect(monitor
->rc_monitor
);
1671 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &WINE_DEVPROPKEY_MONITOR_RCMONITOR
, DEVPROP_TYPE_BINARY
,
1672 (const BYTE
*)&rect
, sizeof(rect
), 0))
1675 rect
= rect_from_cgrect(monitor
->rc_work
);
1676 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &WINE_DEVPROPKEY_MONITOR_RCWORK
, DEVPROP_TYPE_BINARY
,
1677 (const BYTE
*)&rect
, sizeof(rect
), 0))
1680 sprintfW(bufferW
, adapter_name_fmtW
, video_index
+ 1);
1681 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME
, DEVPROP_TYPE_STRING
,
1682 (const BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
), 0))
1688 ERR("Failed to initialize monitor\n");
1692 static void prepare_devices(HKEY video_hkey
)
1694 static const BOOL not_present
= FALSE
;
1695 SP_DEVINFO_DATA device_data
= {sizeof(device_data
)};
1699 /* Remove all monitors */
1700 devinfo
= SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR
, displayW
, NULL
, 0);
1701 while (SetupDiEnumDeviceInfo(devinfo
, i
++, &device_data
))
1703 if (!SetupDiRemoveDevice(devinfo
, &device_data
))
1704 ERR("Failed to remove monitor\n");
1706 SetupDiDestroyDeviceInfoList(devinfo
);
1708 /* Clean up old adapter keys for reinitialization */
1709 RegDeleteTreeW(video_hkey
, NULL
);
1712 * Currently SetupDiGetClassDevsW with DIGCF_PRESENT is unsupported, So we need to clean up not present devices in
1713 * case application uses SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
1714 * of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain
1715 * the same GUID for the same GPU. */
1717 devinfo
= SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY
, pciW
, NULL
, 0);
1718 while (SetupDiEnumDeviceInfo(devinfo
, i
++, &device_data
))
1720 if (!SetupDiSetDevicePropertyW(devinfo
, &device_data
, &DEVPKEY_Device_IsPresent
, DEVPROP_TYPE_BOOLEAN
,
1721 (const BYTE
*)¬_present
, sizeof(not_present
), 0))
1722 ERR("Failed to set GPU present property\n");
1724 SetupDiDestroyDeviceInfoList(devinfo
);
1727 static void cleanup_devices(void)
1729 SP_DEVINFO_DATA device_data
= {sizeof(device_data
)};
1735 devinfo
= SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY
, pciW
, NULL
, 0);
1736 while (SetupDiEnumDeviceInfo(devinfo
, i
++, &device_data
))
1739 SetupDiGetDevicePropertyW(devinfo
, &device_data
, &DEVPKEY_Device_IsPresent
, &type
, (BYTE
*)&present
,
1740 sizeof(present
), NULL
, 0);
1741 if (!present
&& !SetupDiRemoveDevice(devinfo
, &device_data
))
1742 ERR("Failed to remove GPU\n");
1744 SetupDiDestroyDeviceInfoList(devinfo
);
1747 /***********************************************************************
1748 * macdrv_init_display_devices
1750 * Initialize display device registry data.
1752 void macdrv_init_display_devices(BOOL force
)
1755 struct macdrv_gpu
*gpus
= NULL
;
1756 struct macdrv_adapter
*adapters
= NULL
;
1757 struct macdrv_monitor
*monitors
= NULL
;
1758 INT gpu_count
, adapter_count
, monitor_count
;
1759 INT gpu
, adapter
, monitor
;
1760 HDEVINFO gpu_devinfo
= NULL
, monitor_devinfo
= NULL
;
1761 HKEY video_hkey
= NULL
;
1762 INT video_index
= 0;
1763 DWORD disposition
= 0;
1765 WCHAR driverW
[1024];
1769 mutex
= get_display_device_init_mutex();
1771 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE
, video_keyW
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &video_hkey
,
1774 ERR("Failed to create video device key\n");
1778 /* Avoid unnecessary reinit */
1779 if (!force
&& disposition
!= REG_CREATED_NEW_KEY
)
1784 prepare_devices(video_hkey
);
1786 gpu_devinfo
= SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY
, NULL
);
1787 monitor_devinfo
= SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR
, NULL
);
1789 /* Initialize GPUs */
1790 if (macdrv_get_gpus(&gpus
, &gpu_count
))
1792 TRACE("GPU count: %d\n", gpu_count
);
1794 ERR("No GPUs detected\n");
1796 for (gpu
= 0; gpu
< gpu_count
; gpu
++)
1798 if (!macdrv_init_gpu(gpu_devinfo
, &gpus
[gpu
], gpu
, guidW
, driverW
, &gpu_luid
))
1801 /* Initialize adapters */
1802 if (macdrv_get_adapters(gpus
[gpu
].id
, &adapters
, &adapter_count
))
1804 TRACE("GPU: %#llx %s, adapter count: %d\n", gpus
[gpu
].id
, gpus
[gpu
].name
, adapter_count
);
1806 for (adapter
= 0; adapter
< adapter_count
; adapter
++)
1808 if (macdrv_get_monitors(adapters
[adapter
].id
, &monitors
, &monitor_count
))
1810 TRACE("adapter: %#x, monitor count: %d\n", adapters
[adapter
].id
, monitor_count
);
1812 if (!macdrv_init_adapter(video_hkey
, video_index
, gpu
, adapter
, monitor_count
, &gpus
[gpu
], guidW
, driverW
,
1813 &adapters
[adapter
]))
1816 /* Initialize monitors */
1817 for (monitor
= 0; monitor
< monitor_count
; monitor
++)
1819 TRACE("monitor: %#x %s\n", monitor
, monitors
[monitor
].name
);
1820 if (!macdrv_init_monitor(monitor_devinfo
, &monitors
[monitor
], monitor
, video_index
, &gpu_luid
, output_id
++))
1824 macdrv_free_monitors(monitors
);
1829 macdrv_free_adapters(adapters
);
1835 SetupDiDestroyDeviceInfoList(monitor_devinfo
);
1836 SetupDiDestroyDeviceInfoList(gpu_devinfo
);
1837 RegCloseKey(video_hkey
);
1839 release_display_device_init_mutex(mutex
);
1841 macdrv_free_gpus(gpus
);
1842 macdrv_free_adapters(adapters
);
1843 macdrv_free_monitors(monitors
);