winemac.drv: Add adapter initialization functions.

Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com>
Signed-off-by: Ken Thomases <ken@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zhiyi Zhang 2019-08-29 16:11:39 -05:00 committed by Alexandre Julliard
parent 0699089f0e
commit 039a7715f3
3 changed files with 241 additions and 7 deletions

View file

@ -26,6 +26,8 @@
#endif
#include "macdrv_cocoa.h"
static uint64_t dedicated_gpu_id;
static uint64_t integrated_gpu_id;
/***********************************************************************
* convert_display_rect
@ -291,6 +293,7 @@ static int macdrv_get_gpus_from_metal(struct macdrv_gpu** new_gpus, int* count)
/* Hide the integrated GPU if the system default device is a dedicated GPU */
if (!primary_device.isLowPower)
{
dedicated_gpu_id = primary_gpu.id;
hide_integrated = TRUE;
}
@ -301,6 +304,7 @@ static int macdrv_get_gpus_from_metal(struct macdrv_gpu** new_gpus, int* count)
if (hide_integrated && devices[i].isLowPower)
{
integrated_gpu_id = gpus[gpu_count].id;
continue;
}
@ -406,6 +410,7 @@ static int macdrv_get_gpus_from_iokit(struct macdrv_gpu** new_gpus, int* count)
* Assuming integrated GPU vendor is Intel for now */
if (gpus[i].vendor_id == 0x8086)
{
integrated_gpu_id = gpus[i].id;
integrated_index = i;
}
@ -428,6 +433,7 @@ static int macdrv_get_gpus_from_iokit(struct macdrv_gpu** new_gpus, int* count)
else if (primary_index == gpu_count - 1)
primary_index = integrated_index;
dedicated_gpu_id = gpus[primary_index].id;
gpu_count--;
}
}
@ -460,6 +466,9 @@ static int macdrv_get_gpus_from_iokit(struct macdrv_gpu** new_gpus, int* count)
*/
int macdrv_get_gpus(struct macdrv_gpu** new_gpus, int* count)
{
integrated_gpu_id = 0;
dedicated_gpu_id = 0;
if (!macdrv_get_gpus_from_metal(new_gpus, count))
return 0;
else
@ -476,3 +485,93 @@ void macdrv_free_gpus(struct macdrv_gpu* gpus)
if (gpus)
free(gpus);
}
/***********************************************************************
* macdrv_get_adapters
*
* Get a list of adapters under gpu_id. The first adapter is primary if GPU is primary.
* Call macdrv_free_adapters() when you are done using the data.
*
* Returns non-zero value on failure with parameters unchanged and zero on success.
*/
int macdrv_get_adapters(uint64_t gpu_id, struct macdrv_adapter** new_adapters, int* count)
{
CGDirectDisplayID display_ids[16];
uint32_t display_id_count;
struct macdrv_adapter* adapters;
struct macdrv_gpu gpu;
int primary_index = 0;
int adapter_count = 0;
int ret = -1;
uint32_t i;
if (CGGetOnlineDisplayList(sizeof(display_ids) / sizeof(display_ids[0]), display_ids, &display_id_count)
!= kCGErrorSuccess)
return -1;
if (!display_id_count)
{
*new_adapters = NULL;
*count = 0;
return 0;
}
/* Actual adapter count may be less */
adapters = calloc(display_id_count, sizeof(*adapters));
if (!adapters)
return -1;
for (i = 0; i < display_id_count; i++)
{
/* Mirrored displays are under the same adapter with primary display, so they doesn't increase adapter count */
if (CGDisplayMirrorsDisplay(display_ids[i]) != kCGNullDirectDisplay)
continue;
if (macdrv_get_gpu_info_from_display_id(&gpu, display_ids[i]))
goto done;
if (gpu.id == gpu_id || (gpu_id == dedicated_gpu_id && gpu.id == integrated_gpu_id))
{
adapters[adapter_count].id = display_ids[i];
if (CGDisplayIsMain(display_ids[i]))
{
adapters[adapter_count].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
primary_index = adapter_count;
}
if (CGDisplayIsActive(display_ids[i]))
adapters[adapter_count].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
adapter_count++;
}
}
/* Make sure the first adapter is primary if the GPU is primary */
if (primary_index)
{
struct macdrv_adapter tmp;
tmp = adapters[0];
adapters[0] = adapters[primary_index];
adapters[primary_index] = tmp;
}
*new_adapters = adapters;
*count = adapter_count;
ret = 0;
done:
if (ret)
macdrv_free_adapters(adapters);
return ret;
}
/***********************************************************************
* macdrv_free_adapters
*
* Frees an adapter list allocated from macdrv_get_adapters()
*/
void macdrv_free_adapters(struct macdrv_adapter* adapters)
{
if (adapters)
free(adapters);
}

View file

@ -58,6 +58,9 @@ static const WCHAR driver_date_dataW[] = {'D','r','i','v','e','r','D','a','t','e
static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
static const WCHAR pciW[] = {'P','C','I',0};
static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
static const WCHAR symbolic_link_valueW[]= {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
static const WCHAR guid_fmtW[] = {
'{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
'%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
@ -78,6 +81,26 @@ static const WCHAR video_keyW[] = {
'H','A','R','D','W','A','R','E','\\',
'D','E','V','I','C','E','M','A','P','\\',
'V','I','D','E','O',0};
static const WCHAR adapter_key_fmtW[] = {
'S','y','s','t','e','m','\\',
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'C','o','n','t','r','o','l','\\',
'V','i','d','e','o','\\',
'%','s','\\',
'%','0','4','x',0};
static const WCHAR device_video_fmtW[] = {
'\\','D','e','v','i','c','e','\\',
'V','i','d','e','o','%','d',0};
static const WCHAR machine_prefixW[] = {
'\\','R','e','g','i','s','t','r','y','\\',
'M','a','c','h','i','n','e','\\',0};
static const WCHAR nt_classW[] = {
'\\','R','e','g','i','s','t','r','y','\\',
'M','a','c','h','i','n','e','\\',
'S','y','s','t','e','m','\\',
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'C','o','n','t','r','o','l','\\',
'C','l','a','s','s','\\',0};
static CFArrayRef modes;
@ -1432,11 +1455,12 @@ void macdrv_displays_changed(const macdrv_event *event)
/***********************************************************************
* macdrv_init_gpu
*
* Initialize a GPU instance.
* Initialize a GPU instance and return its GUID string in guid_string and driver value in driver parameter.
*
* Return FALSE on failure and TRUE on success.
*/
static BOOL macdrv_init_gpu(HDEVINFO devinfo, const struct macdrv_gpu *gpu, int gpu_index)
static BOOL macdrv_init_gpu(HDEVINFO devinfo, const struct macdrv_gpu *gpu, int gpu_index, WCHAR *guid_string,
WCHAR *driver)
{
static const BOOL present = TRUE;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
@ -1484,6 +1508,13 @@ static BOOL macdrv_init_gpu(HDEVINFO devinfo, const struct macdrv_gpu *gpu, int
goto done;
RegCloseKey(hkey);
/* Retrieve driver value for adapters */
if (!SetupDiGetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW, sizeof(bufferW),
NULL))
goto done;
lstrcpyW(driver, nt_classW);
lstrcatW(driver, bufferW);
/* Write GUID in VideoID in .../instance/Device Parameters, reuse the GUID if it's existent */
hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL);
@ -1496,6 +1527,7 @@ static BOOL macdrv_init_gpu(HDEVINFO devinfo, const struct macdrv_gpu *gpu, int
if (RegSetValueExW(hkey, video_idW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
goto done;
}
lstrcpyW(guid_string, bufferW);
ret = TRUE;
done:
@ -1505,13 +1537,80 @@ done:
return ret;
}
static void prepare_devices(void)
/***********************************************************************
* macdrv_init_adapter
*
* Initialize an adapter.
*
* Return FALSE on failure and TRUE on success.
*/
static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, int adapter_index,
const struct macdrv_gpu *gpu, const WCHAR *guid_string, const WCHAR *gpu_driver,
const struct macdrv_adapter *adapter)
{
WCHAR adapter_keyW[MAX_PATH];
WCHAR key_nameW[MAX_PATH];
WCHAR bufferW[1024];
HKEY hkey = NULL;
BOOL ret = FALSE;
LSTATUS ls;
sprintfW(key_nameW, device_video_fmtW, video_index);
lstrcpyW(bufferW, machine_prefixW);
sprintfW(adapter_keyW, adapter_key_fmtW, guid_string, adapter_index);
lstrcatW(bufferW, adapter_keyW);
/* Write value of \Device\Video? (adapter key) in HKLM\HARDWARE\DEVICEMAP\VIDEO\ */
if (RegSetValueExW(video_hkey, key_nameW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
goto done;
/* Create HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} link to GPU driver */
ls = RegCreateKeyExW(HKEY_LOCAL_MACHINE, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
KEY_ALL_ACCESS, NULL, &hkey, NULL);
if (ls == ERROR_ALREADY_EXISTS)
RegCreateKeyExW(HKEY_LOCAL_MACHINE, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE | REG_OPTION_OPEN_LINK,
KEY_ALL_ACCESS, NULL, &hkey, NULL);
if (RegSetValueExW(hkey, symbolic_link_valueW, 0, REG_LINK, (const BYTE *)gpu_driver,
lstrlenW(gpu_driver) * sizeof(WCHAR)))
goto done;
RegCloseKey(hkey);
hkey = NULL;
/* FIXME:
* Following information is Wine specific, it doesn't really exist on Windows. It is used so that we can
* implement EnumDisplayDevices etc by querying registry only. This information is most likely reported by the
* device driver on Windows */
RegCreateKeyExW(HKEY_CURRENT_CONFIG, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
/* Write GPU instance path so that we can find the GPU instance via adapters quickly. Another way is trying to match
* them via the GUID in Device Paramters/VideoID, but it would required enumrating all GPU instances */
sprintfW(bufferW, gpu_instance_fmtW, gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index);
if (RegSetValueExW(hkey, gpu_idW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
goto done;
/* Write StateFlags */
if (RegSetValueExW(hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&adapter->state_flags,
sizeof(adapter->state_flags)))
goto done;
ret = TRUE;
done:
RegCloseKey(hkey);
if (!ret)
ERR("Failed to initialize adapter\n");
return ret;
}
static void prepare_devices(HKEY video_hkey)
{
static const BOOL not_present = FALSE;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
HDEVINFO devinfo;
DWORD i = 0;
/* Clean up old adapter keys for reinitialization */
RegDeleteTreeW(video_hkey, NULL);
/* FIXME:
* Currently SetupDiGetClassDevsW with DIGCF_PRESENT is unsupported, So we need to clean up not present devices in
* case application uses SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
@ -1557,11 +1656,15 @@ void macdrv_init_display_devices(void)
static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
HANDLE mutex;
struct macdrv_gpu *gpus = NULL;
INT gpu_count;
INT gpu;
struct macdrv_adapter *adapters = NULL;
INT gpu_count, adapter_count;
INT gpu, adapter;
HDEVINFO gpu_devinfo = NULL;
HKEY video_hkey = NULL;
INT video_index = 0;
DWORD disposition = 0;
WCHAR guidW[40];
WCHAR driverW[1024];
mutex = CreateMutexW(NULL, FALSE, init_mutexW);
WaitForSingleObject(mutex, INFINITE);
@ -1579,7 +1682,7 @@ void macdrv_init_display_devices(void)
TRACE("\n");
prepare_devices();
prepare_devices(video_hkey);
gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
@ -1589,8 +1692,24 @@ void macdrv_init_display_devices(void)
for (gpu = 0; gpu < gpu_count; gpu++)
{
if (!macdrv_init_gpu(gpu_devinfo, &gpus[gpu], gpu))
if (!macdrv_init_gpu(gpu_devinfo, &gpus[gpu], gpu, guidW, driverW))
goto done;
/* Initialize adapters */
if (macdrv_get_adapters(gpus[gpu].id, &adapters, &adapter_count))
goto done;
for (adapter = 0; adapter < adapter_count; adapter++)
{
if (!macdrv_init_adapter(video_hkey, video_index, gpu, adapter, &gpus[gpu], guidW, driverW,
&adapters[adapter]))
goto done;
video_index++;
}
macdrv_free_adapters(adapters);
adapters = NULL;
}
done:
@ -1602,4 +1721,5 @@ done:
CloseHandle(mutex);
macdrv_free_gpus(gpus);
macdrv_free_adapters(adapters);
}

View file

@ -258,6 +258,10 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
/* display */
/* Used DISPLAY_DEVICE.StateFlags for adapters */
#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
/* Represent a physical GPU in the PCI slots */
struct macdrv_gpu
{
@ -272,12 +276,23 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
uint32_t revision_id;
};
/* Represent an adapter in EnumDisplayDevices context */
struct macdrv_adapter
{
/* ID to uniquely identify an adapter. Currently it's a CGDirectDisplayID */
uint32_t id;
/* as StateFlags in DISPLAY_DEVICE struct */
uint32_t state_flags;
};
extern int macdrv_get_displays(struct macdrv_display** displays, int* count) DECLSPEC_HIDDEN;
extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN;
extern int macdrv_set_display_mode(const struct macdrv_display* display,
CGDisplayModeRef display_mode) DECLSPEC_HIDDEN;
extern int macdrv_get_gpus(struct macdrv_gpu** gpus, int* count) DECLSPEC_HIDDEN;
extern void macdrv_free_gpus(struct macdrv_gpu* gpus) DECLSPEC_HIDDEN;
extern int macdrv_get_adapters(uint64_t gpu_id, struct macdrv_adapter** adapters, int* count) DECLSPEC_HIDDEN;
extern void macdrv_free_adapters(struct macdrv_adapter* adapters) DECLSPEC_HIDDEN;
/* event */