[PATCH 3/6 resend] winemac.drv: Add adapter initialization functions.

Ken Thomases ken at codeweavers.com
Thu Aug 29 16:11:39 CDT 2019


From: Zhiyi Zhang <zzhang at codeweavers.com>

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
Signed-off-by: Ken Thomases <ken at codeweavers.com>
---
 dlls/winemac.drv/cocoa_display.m |  99 +++++++++++++++++++++++
 dlls/winemac.drv/display.c       | 134 +++++++++++++++++++++++++++++--
 dlls/winemac.drv/macdrv_cocoa.h  |  15 ++++
 3 files changed, 241 insertions(+), 7 deletions(-)

diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m
index 68ea89705d2..284ffe0a535 100644
--- a/dlls/winemac.drv/cocoa_display.m
+++ b/dlls/winemac.drv/cocoa_display.m
@@ -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);
+}
diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c
index 88f8f8f4f33..97ebca22e57 100644
--- a/dlls/winemac.drv/display.c
+++ b/dlls/winemac.drv/display.c
@@ -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);
 }
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index 513746fa0ee..b960e902e3f 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -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 */
-- 
2.21.0




More information about the wine-devel mailing list