[PATCH 2/6 v3] winemac.drv: Support GPU initialization via Metal.

Ken Thomases ken at codeweavers.com
Thu Aug 29 16:11:38 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>
---
v3: Check if MTLCopyAllDevices() is available before calling it (for backward
    deployment).

 dlls/winemac.drv/cocoa_display.m | 117 ++++++++++++++++++++++++++++++-
 1 file changed, 116 insertions(+), 1 deletion(-)

diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m
index b8f27309790..68ea89705d2 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"
 
 
@@ -227,6 +232,113 @@ static int macdrv_get_gpu_info_from_entry(struct macdrv_gpu* gpu, io_registry_en
     return ret;
 }
 
+#ifdef HAVE_METAL_METAL_H
+
+/***********************************************************************
+ *              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
+ *
+ * Get a list of GPUs from Metal.
+ *
+ * Returns non-zero value on failure with parameters unchanged and zero on success.
+ */
+static int macdrv_get_gpus_from_metal(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];
+
+    /* Test if Metal is available */
+    if (&MTLCopyAllDevices == NULL)
+        goto done;
+    NSArray<id<MTLDevice>>* devices = [MTLCopyAllDevices() autorelease];
+    if (!devices.count || ![devices[0] respondsToSelector:@selector(registryID)])
+        goto done;
+
+    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 macdrv_get_gpus_from_metal(struct macdrv_gpu** new_gpus, int* count)
+{
+    TRACE("Metal support not compiled in\n");
+    return -1;
+}
+
+#endif
+
 /***********************************************************************
  *              macdrv_get_gpu_info_from_display_id
  *
@@ -348,7 +460,10 @@ 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)
 {
-    return macdrv_get_gpus_from_iokit(new_gpus, count);
+    if (!macdrv_get_gpus_from_metal(new_gpus, count))
+        return 0;
+    else
+        return macdrv_get_gpus_from_iokit(new_gpus, count);
 }
 
 /***********************************************************************
-- 
2.21.0




More information about the wine-devel mailing list