[PATCH 2/6] winemac.drv: Add GPU initialization functions.

Zhiyi Zhang zzhang at codeweavers.com
Thu Jul 4 08:22:22 CDT 2019


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/winemac.drv/Makefile.in     |   2 +-
 dlls/winemac.drv/cocoa_display.m | 378 +++++++++++++++++++++++++++++++++++++++
 dlls/winemac.drv/display.c       | 200 +++++++++++++++++++++
 dlls/winemac.drv/macdrv.h        |   1 +
 dlls/winemac.drv/macdrv_cocoa.h  |  17 ++
 5 files changed, 597 insertions(+), 1 deletion(-)

diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in
index 3ffb7d666c..c6ae9733bd 100644
--- a/dlls/winemac.drv/Makefile.in
+++ b/dlls/winemac.drv/Makefile.in
@@ -1,5 +1,5 @@
 MODULE    = winemac.drv
-IMPORTS   = uuid user32 gdi32 advapi32
+IMPORTS   = uuid setupapi rpcrt4 user32 gdi32 advapi32
 DELAYIMPORTS = ole32 shell32 imm32
 EXTRALIBS = -framework AppKit -framework Carbon -framework Security -framework OpenGL -framework IOKit -framework CoreVideo $(METAL_LIBS)
 
diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m
index 93a0fbca35..82c9e3fcc3 100644
--- a/dlls/winemac.drv/cocoa_display.m
+++ b/dlls/winemac.drv/cocoa_display.m
@@ -18,7 +18,12 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+
 #import <AppKit/AppKit.h>
+#ifdef HAVE_METAL_METAL_H
+#import <Metal/Metal.h>
+#endif
 #include "macdrv_cocoa.h"
 
 
@@ -103,3 +108,376 @@ void macdrv_free_displays(struct macdrv_display* displays)
 {
     free(displays);
 }
+
+/***********************************************************************
+ *              get_entry_property_uint32
+ *
+ * Get an io registry entry property of type uint32 and store it in value parameter.
+ *
+ * Returns non-zero value on failure.
+ */
+static int get_entry_property_uint32(io_registry_entry_t entry, CFStringRef property_name, uint32_t* value)
+{
+    CFDataRef data = IORegistryEntrySearchCFProperty(entry, kIOServicePlane, property_name, kCFAllocatorDefault, 0);
+    if (!data)
+        return -1;
+
+    if (CFGetTypeID(data) != CFDataGetTypeID() || CFDataGetLength(data) != sizeof(uint32_t))
+    {
+        CFRelease(data);
+        return -1;
+    }
+
+    CFDataGetBytes(data, CFRangeMake(0, sizeof(uint32_t)), (UInt8*)value);
+    CFRelease(data);
+    return 0;
+}
+
+/***********************************************************************
+ *              get_entry_property_string
+ *
+ * Get an io registry entry property of type string and write it in buffer parameter.
+ *
+ * Returns non-zero value on failure.
+ */
+static int get_entry_property_string(io_registry_entry_t entry, CFStringRef property_name, char* buffer,
+                                     size_t buffer_size)
+{
+    size_t length;
+
+    CFDataRef data = IORegistryEntrySearchCFProperty(entry, kIOServicePlane, property_name, kCFAllocatorDefault, 0);
+    if (!data)
+        return -1;
+
+    length = CFDataGetLength(data);
+    if (length + 1 > buffer_size || CFGetTypeID(data) != CFDataGetTypeID())
+    {
+        CFRelease(data);
+        return -1;
+    }
+
+    CFDataGetBytes(data, CFRangeMake(0, length), (UInt8*)buffer);
+    buffer[length] = 0;
+    CFRelease(data);
+    return 0;
+}
+
+/***********************************************************************
+ *              macdrv_get_gpu_info_from_entry
+ *
+ * Starting from entry, search upwards to find the PCI GPU. And get GPU information from the PCI GPU entry.
+ *
+ * Returns non-zero value on failure.
+ */
+static int macdrv_get_gpu_info_from_entry(struct macdrv_gpu* gpu, io_registry_entry_t entry)
+{
+    io_registry_entry_t parent_entry;
+    io_registry_entry_t gpu_entry;
+    kern_return_t result;
+    int ret = -1;
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+    gpu_entry = entry;
+    while (![@"IOPCIDevice" isEqualToString:[(__bridge NSString*)IOObjectCopyClass(gpu_entry) autorelease]])
+    {
+        result = IORegistryEntryGetParentEntry(gpu_entry, kIOServicePlane, &parent_entry);
+        if (gpu_entry != entry)
+            IOObjectRelease(gpu_entry);
+        if (result == kIOReturnSuccess)
+        {
+            gpu_entry = parent_entry;
+        }
+        else
+        {
+            [pool release];
+            return ret;
+        }
+    }
+
+    if (IORegistryEntryGetRegistryEntryID(gpu_entry, &gpu->id) != kIOReturnSuccess)
+        goto done;
+    if (get_entry_property_uint32(gpu_entry, CFSTR("vendor-id"), &gpu->vendor_id))
+        goto done;
+    if (get_entry_property_uint32(gpu_entry, CFSTR("device-id"), &gpu->device_id))
+        goto done;
+    if (get_entry_property_uint32(gpu_entry, CFSTR("subsystem-id"), &gpu->subsys_id))
+        goto done;
+    if (get_entry_property_uint32(gpu_entry, CFSTR("revision-id"), &gpu->revision_id))
+        goto done;
+    if (get_entry_property_string(gpu_entry, CFSTR("model"), gpu->name, sizeof(gpu->name)))
+        goto done;
+
+    ret = 0;
+done:
+    if (gpu_entry != entry)
+        IOObjectRelease(gpu_entry);
+    [pool release];
+    return ret;
+}
+
+#ifdef HAVE_METAL_METAL_H
+
+/***********************************************************************
+ *              is_metal_available
+ *
+ * Returns non-zero value if Metal is available and zero if it's unavailable
+ */
+static int is_metal_available(void)
+{
+    int ret = 0;
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+    NSArray<id<MTLDevice>>* devices = [MTLCopyAllDevices() autorelease];
+    if (devices.count && [devices[0] respondsToSelector:@selector(registryID)])
+        ret = 1;
+
+    [pool release];
+    return ret;
+}
+
+/***********************************************************************
+ *              macdrv_get_gpu_info_from_registry_id
+ *
+ * Get GPU information from a Metal device registry id.
+ *
+ * Returns non-zero value on failure.
+ */
+static int macdrv_get_gpu_info_from_registry_id(struct macdrv_gpu* gpu, uint64_t registry_id)
+{
+    int ret;
+    io_registry_entry_t entry;
+
+    entry = IOServiceGetMatchingService(kIOMasterPortDefault, IORegistryEntryIDMatching(registry_id));
+    ret = macdrv_get_gpu_info_from_entry(gpu, entry);
+    IOObjectRelease(entry);
+    return ret;
+}
+
+/***********************************************************************
+ *              macdrv_get_gpus_from_metal_devices
+ *
+ * Get a list of GPUs from Metal devices.
+ *
+ * Returns non-zero value on failure with parameters unchanged and zero on success.
+ */
+static int macdrv_get_gpus_from_metal_devices(struct macdrv_gpu** new_gpus, int* count)
+{
+    struct macdrv_gpu* gpus = NULL;
+    struct macdrv_gpu primary_gpu;
+    id<MTLDevice> primary_device;
+    BOOL hide_integrated = FALSE;
+    int primary_index = 0, i;
+    int gpu_count = 0;
+    int ret = -1;
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+    NSArray<id<MTLDevice>>* devices = [MTLCopyAllDevices() autorelease];
+    gpus = calloc(devices.count, sizeof(*gpus));
+    if (!gpus)
+        goto done;
+
+    /* Use MTLCreateSystemDefaultDevice instead of CGDirectDisplayCopyCurrentMetalDevice(CGMainDisplayID()) to get
+     * the primary GPU because we need to hide the integrated GPU for an automatic graphic switching pair to avoid apps
+     * using the integrated GPU. This is the behavior of Windows on a Mac. */
+    primary_device = [MTLCreateSystemDefaultDevice() autorelease];
+    if (macdrv_get_gpu_info_from_registry_id(&primary_gpu, primary_device.registryID))
+        goto done;
+
+    /* Hide the integrated GPU if the system default device is a dedicated GPU */
+    if (!primary_device.isLowPower)
+    {
+        hide_integrated = TRUE;
+    }
+
+    for (i = 0; i < devices.count; i++)
+    {
+        if (macdrv_get_gpu_info_from_registry_id(&gpus[gpu_count], devices[i].registryID))
+            goto done;
+
+        if (hide_integrated && devices[i].isLowPower)
+        {
+            continue;
+        }
+
+        if (gpus[gpu_count].id == primary_gpu.id)
+            primary_index = gpu_count;
+
+        gpu_count++;
+    }
+
+    /* Make sure the first GPU is primary */
+    if (primary_index)
+    {
+        struct macdrv_gpu tmp;
+        tmp = gpus[0];
+        gpus[0] = gpus[primary_index];
+        gpus[primary_index] = tmp;
+    }
+
+    *new_gpus = gpus;
+    *count = gpu_count;
+    ret = 0;
+done:
+    if (ret)
+        macdrv_free_gpus(gpus);
+    [pool release];
+    return ret;
+}
+
+#else
+
+static int is_metal_available(void)
+{
+    return 0;
+}
+
+static int macdrv_get_gpus_from_metal_devices(struct macdrv_gpu** new_gpus, int* count)
+{
+    return -1;
+}
+
+#endif
+
+/***********************************************************************
+ *              macdrv_get_gpu_info_from_display_id
+ *
+ * Get GPU information from a display id.
+ * This is a fallback for 32bit build or older Mac OS version where Metal is unavailable.
+ *
+ * Returns non-zero value on failure.
+ */
+static int macdrv_get_gpu_info_from_display_id(struct macdrv_gpu* gpu, CGDirectDisplayID display_id)
+{
+    io_registry_entry_t entry = CGDisplayIOServicePort(display_id);
+    return macdrv_get_gpu_info_from_entry(gpu, entry);
+}
+
+/***********************************************************************
+ *              macdrv_get_gpus_from_displays
+ *
+ * Get a list of GPUs from displays.
+ * This is a fallback for 32bit build or older Mac OS version where Metal is unavailable.
+ *
+ * Returns non-zero value on failure with parameters unchanged and zero on success.
+ */
+static int macdrv_get_gpus_from_displays(struct macdrv_gpu** new_gpus, int* count)
+{
+    CGDirectDisplayID display_ids[16];
+    uint32_t display_id_count;
+    struct macdrv_gpu* gpus;
+    BOOL duplicated;
+    int integrated_index = -1;
+    int primary_index = 0;
+    int gpu_count = 0;
+    int ret = -1;
+    int i, j;
+
+    if (CGGetOnlineDisplayList(sizeof(display_ids) / sizeof(display_ids[0]), display_ids, &display_id_count)
+        != kCGErrorSuccess)
+        return ret;
+
+    if (!display_id_count)
+    {
+        *new_gpus = NULL;
+        *count = 0;
+        return 0;
+    }
+
+    /* Actual GPU count may be less */
+    gpus = calloc(display_id_count, sizeof(*gpus));
+    if (!gpus)
+        return ret;
+
+    for (i = 0; i < display_id_count; i++)
+    {
+        if (macdrv_get_gpu_info_from_display_id(&gpus[gpu_count], display_ids[i]))
+            goto done;
+
+        /* Ignore duplicated GPUs */
+        duplicated = FALSE;
+        for (j = 0; j < gpu_count; j++)
+        {
+            if (gpus[gpu_count].id == gpus[j].id)
+            {
+                duplicated = TRUE;
+                break;
+            }
+        }
+
+        if (duplicated)
+            continue;
+
+        if (display_ids[i] == CGMainDisplayID())
+            primary_index = gpu_count;
+
+        /* FIXME:
+         * Find integrated GPU without Metal support.
+         * Assuming integrated GPU vendor is Intel for now */
+        if (gpus[gpu_count].vendor_id == 0x8086)
+        {
+            integrated_index = gpu_count;
+        }
+
+        gpu_count++;
+    }
+
+    /* If there are more than two GPUs and an Intel card exists,
+     * assume an automatic graphics pair exists and hide the integrated GPU */
+    if (gpu_count > 1 && integrated_index != -1)
+    {
+        if (integrated_index != gpu_count - 1)
+            gpus[integrated_index] = gpus[gpu_count - 1];
+
+        /* FIXME:
+         * Find the dedicated GPU in an automatic graphics switching pair and use that as primary GPU.
+         * Choose the first dedicated GPU as primary */
+        if (primary_index == integrated_index)
+            primary_index = 0;
+
+        gpu_count--;
+    }
+
+    /* Make sure the first GPU is primary */
+    if (primary_index)
+    {
+        struct macdrv_gpu tmp;
+        tmp = gpus[0];
+        gpus[0] = gpus[primary_index];
+        gpus[primary_index] = tmp;
+    }
+
+    *new_gpus = gpus;
+    *count = gpu_count;
+    ret = 0;
+done:
+    if (ret)
+        macdrv_free_gpus(gpus);
+    return ret;
+}
+
+/***********************************************************************
+ *              macdrv_get_gpus
+ *
+ * Get a list of GPUs currently in the system. The first GPU is primary.
+ * Call macdrv_free_gpus() when you are done using the data.
+ *
+ * Returns non-zero value on failure with parameters unchanged and zero on success.
+ */
+int macdrv_get_gpus(struct macdrv_gpu** new_gpus, int* count)
+{
+    if (is_metal_available())
+        return macdrv_get_gpus_from_metal_devices(new_gpus, count);
+    else
+        return macdrv_get_gpus_from_displays(new_gpus, count);
+}
+
+/***********************************************************************
+ *              macdrv_free_gpus
+ *
+ * Frees a GPU list allocated from macdrv_get_gpus()
+ */
+void macdrv_free_gpus(struct macdrv_gpu* gpus)
+{
+    if (gpus)
+        free(gpus);
+}
diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c
index 00ad7738bb..3e7335f5aa 100644
--- a/dlls/winemac.drv/display.c
+++ b/dlls/winemac.drv/display.c
@@ -25,6 +25,13 @@
 #include "winuser.h"
 #include "winreg.h"
 #include "ddrawi.h"
+#include "rpc.h"
+#include "initguid.h"
+#include "devguid.h"
+#include "devpkey.h"
+#include "setupapi.h"
+#define WIN32_NO_STATUS
+#include "winternl.h"
 #include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(display);
@@ -47,6 +54,29 @@ BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW
 
 static const char initial_mode_key[] = "Initial Display Mode";
 static const WCHAR pixelencodingW[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
+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 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};
+static const WCHAR gpu_instance_fmtW[] = {
+    'P','C','I','\\',
+    'V','E','N','_','%','0','4','X','&',
+    'D','E','V','_','%','0','4','X','&',
+    'S','U','B','S','Y','S','_','%','0','8','X','&',
+    'R','E','V','_','%','0','2','X','\\',
+    '%','0','8','X',0};
+static const WCHAR gpu_hardware_id_fmtW[] = {
+    'P','C','I','\\',
+    'V','E','N','_','%','0','4','X','&',
+    'D','E','V','_','%','0','4','X','&',
+    'S','U','B','S','Y','S','_','0','0','0','0','0','0','0','0','&',
+    'R','E','V','_','0','0',0};
+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 CFArrayRef modes;
@@ -1397,3 +1427,173 @@ void macdrv_displays_changed(const macdrv_event *event)
                      MAKELPARAM(width, height));
     }
 }
+
+/***********************************************************************
+ *              macdrv_init_gpu
+ *
+ * Initialize a GPU instance.
+ *
+ * Return FALSE on failure and TRUE on success.
+ */
+static BOOL macdrv_init_gpu(HDEVINFO devinfo, const struct macdrv_gpu *gpu, int gpu_index)
+{
+    static const BOOL present = TRUE;
+    SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+    WCHAR instanceW[MAX_PATH];
+    WCHAR nameW[MAX_PATH];
+    WCHAR bufferW[1024];
+    HKEY hkey = NULL;
+    GUID guid;
+    INT written;
+    DWORD size;
+    BOOL ret = FALSE;
+
+    sprintfW(instanceW, gpu_instance_fmtW, gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index);
+    MultiByteToWideChar(CP_UTF8, 0, gpu->name, -1, nameW, ARRAY_SIZE(nameW));
+    if (!SetupDiOpenDeviceInfoW(devinfo, instanceW, NULL, 0, &device_data))
+    {
+        SetupDiCreateDeviceInfoW(devinfo, instanceW, &GUID_DEVCLASS_DISPLAY, nameW, NULL, 0, &device_data);
+        if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL))
+            goto done;
+    }
+
+    /* Write HardwareID registry property, REG_MULTI_SZ */
+    written = sprintfW(bufferW, gpu_hardware_id_fmtW, gpu->vendor_id, gpu->device_id);
+    bufferW[written + 1] = 0;
+    if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID, (const BYTE *)bufferW,
+                                           (written + 2) * sizeof(WCHAR)))
+        goto done;
+
+    /* Write DEVPKEY_Device_IsPresent property */
+    if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, DEVPROP_TYPE_BOOLEAN,
+                                   (const BYTE *)&present, sizeof(present), 0))
+        goto done;
+
+    /* Open driver key.
+     * This is where HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} links to */
+    hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+
+    /* Write DriverDesc value */
+    if (RegSetValueExW(hkey, driver_descW, 0, REG_SZ, (const BYTE *)nameW, (lstrlenW(nameW) + 1) * sizeof(WCHAR)))
+        goto done;
+    RegCloseKey(hkey);
+
+    /* 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);
+
+    size = sizeof(bufferW);
+    if (RegQueryValueExW(hkey, video_idW, 0, NULL, (BYTE *)bufferW, &size))
+    {
+        UuidCreate(&guid);
+        sprintfW(bufferW, guid_fmtW, guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
+                 guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
+        if (RegSetValueExW(hkey, video_idW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
+            goto done;
+    }
+
+    ret = TRUE;
+done:
+    RegCloseKey(hkey);
+    if (!ret)
+        ERR("Failed to initialize GPU\n");
+    return ret;
+}
+
+static void prepare_devices(void)
+{
+    static const BOOL not_present = FALSE;
+    SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+    HDEVINFO devinfo;
+    DWORD i = 0;
+
+    /* 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
+     * of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain
+     * the same GUID for the same GPU. */
+    devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, pciW, NULL, 0);
+    while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
+    {
+        if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, DEVPROP_TYPE_BOOLEAN,
+                                       (const BYTE *)&not_present, sizeof(not_present), 0))
+            ERR("Failed to set GPU present property\n");
+    }
+    SetupDiDestroyDeviceInfoList(devinfo);
+}
+
+static void cleanup_devices(void)
+{
+    SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+    HDEVINFO devinfo;
+    DWORD type;
+    DWORD i = 0;
+    BOOL present;
+
+    devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, pciW, NULL, 0);
+    while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
+    {
+        present = FALSE;
+        SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, &type, (BYTE *)&present,
+                                  sizeof(present), NULL, 0);
+        if (!present && !SetupDiRemoveDevice(devinfo, &device_data))
+            ERR("Failed to remove GPU\n");
+    }
+    SetupDiDestroyDeviceInfoList(devinfo);
+}
+
+/***********************************************************************
+ *              macdrv_init_display_devices
+ *
+ * Initialize display device registry data.
+ */
+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;
+    HDEVINFO gpu_devinfo = NULL;
+    HKEY video_hkey = NULL;
+    DWORD disposition = 0;
+
+    mutex = CreateMutexW(NULL, FALSE, init_mutexW);
+    WaitForSingleObject(mutex, INFINITE);
+
+    if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, video_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &video_hkey,
+                        &disposition))
+    {
+        ERR("Failed to create video device key\n");
+        goto done;
+    }
+
+    /* Avoid unnecessary reinit */
+    if (disposition != REG_CREATED_NEW_KEY)
+        goto done;
+
+    TRACE("\n");
+
+    prepare_devices();
+
+    gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+
+    /* Initialize GPUs */
+    if (macdrv_get_gpus(&gpus, &gpu_count))
+        goto done;
+
+    for (gpu = 0; gpu < gpu_count; gpu++)
+    {
+        if (!macdrv_init_gpu(gpu_devinfo, &gpus[gpu], gpu))
+            goto done;
+    }
+
+done:
+    cleanup_devices();
+    SetupDiDestroyDeviceInfoList(gpu_devinfo);
+    RegCloseKey(video_hkey);
+
+    ReleaseMutex(mutex);
+    CloseHandle(mutex);
+
+    macdrv_free_gpus(gpus);
+}
diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h
index f948da42c7..064b93a1df 100644
--- a/dlls/winemac.drv/macdrv.h
+++ b/dlls/winemac.drv/macdrv.h
@@ -223,6 +223,7 @@ extern CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP
 extern void macdrv_status_item_mouse_move(const macdrv_event *event) DECLSPEC_HIDDEN;
 
 extern void check_retina_status(void) DECLSPEC_HIDDEN;
+extern void macdrv_init_display_devices(void) DECLSPEC_HIDDEN;
 
 /**************************************************************************
  * Mac IME driver
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index 8ca9b9afa0..513746fa0e 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -257,10 +257,27 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
 
 
 /* display */
+
+/* Represent a physical GPU in the PCI slots */
+struct macdrv_gpu
+{
+    /* PCI GPU io registry entry id */
+    uint64_t id;
+    /* Name, in UTF-8 encoding */
+    char name[128];
+    /* PCI ID */
+    uint32_t vendor_id;
+    uint32_t device_id;
+    uint32_t subsys_id;
+    uint32_t revision_id;
+};
+
 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;
 
 
 /* event */
-- 
2.15.2 (Apple Git-101.1)





More information about the wine-devel mailing list