[PATCH 1/7] winemac.drv: Add macdrv_get_gpus() helper.

Zhiyi Zhang zzhang at codeweavers.com
Mon Apr 22 07:13:02 CDT 2019


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
Maybe Mac driver would draw more attention :)

 dlls/winemac.drv/cocoa_display.m | 168 +++++++++++++++++++++++++++++++++++++++
 dlls/winemac.drv/macdrv_cocoa.h  |  17 ++++
 2 files changed, 185 insertions(+)

diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m
index 93a0fbca35..569cd32352 100644
--- a/dlls/winemac.drv/cocoa_display.m
+++ b/dlls/winemac.drv/cocoa_display.m
@@ -19,6 +19,7 @@
  */
 
 #import <AppKit/AppKit.h>
+#import <Metal/Metal.h>
 #include "macdrv_cocoa.h"
 
 
@@ -103,3 +104,170 @@ 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.
+ *
+ * Return 0 on failure.
+ */
+static uint32_t get_entry_property_uint32(io_registry_entry_t entry, CFStringRef property_name, uint32_t* value)
+{
+    CFDataRef data = IORegistryEntrySearchCFProperty(entry, kIOServicePlane, property_name, kCFAllocatorDefault,
+                                                     kIORegistryIterateRecursively | kIORegistryIterateParents);
+    if (!data)
+        return 0;
+
+    const uint32_t* bytes = (const uint32_t*)(CFDataGetBytePtr(data));
+    *value = *bytes;
+
+    CFRelease(data);
+    return 1;
+}
+
+/***********************************************************************
+ *              get_entry_property_string
+ *
+ * Get an IO registry entry property of type string and write it in buffer parameter.
+ *
+ * Return the size written into the buffer.
+ */
+static size_t 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,
+                                                     kIORegistryIterateRecursively | kIORegistryIterateParents);
+    if (!data)
+        return 0;
+
+    length = CFDataGetLength(data);
+    if (length > buffer_size)
+        return 0;
+
+    memcpy(buffer, CFDataGetBytePtr(data), length);
+    CFRelease(data);
+    return length;
+}
+
+/***********************************************************************
+ *              macdrv_get_gpu_info_from_entry
+ *
+ * Get GPU information from an IO registry entry.
+ */
+static void macdrv_get_gpu_info_from_entry(struct macdrv_gpu* gpu, io_registry_entry_t entry)
+{
+    get_entry_property_uint32(entry, CFSTR("vendor-id"), &gpu->vendor_id);
+    get_entry_property_uint32(entry, CFSTR("device-id"), &gpu->device_id);
+    get_entry_property_uint32(entry, CFSTR("subsystem-id"), &gpu->subsys_id);
+    get_entry_property_uint32(entry, CFSTR("revision-id"), &gpu->revision_id);
+    get_entry_property_string(entry, CFSTR("model"), gpu->name, sizeof(gpu->name));
+}
+
+/***********************************************************************
+ *              macdrv_get_gpu_info_from_display_id
+ *
+ * Get GPU information from a display id.
+ *
+ * This is a fallback for 32bit build since Metal doesn't support 32bit.
+ * Thus registryID can't be used.
+ */
+void macdrv_get_gpu_info_from_display_id(struct macdrv_gpu* gpu, CGDirectDisplayID display_id)
+{
+    io_registry_entry_t entry = CGDisplayIOServicePort(display_id);
+    macdrv_get_gpu_info_from_entry(gpu, entry);
+}
+
+/***********************************************************************
+ *              macdrv_get_gpu_info_from_registry_id
+ *
+ * Get GPU information from a Metal device registry id.
+ */
+void macdrv_get_gpu_info_from_registry_id(struct macdrv_gpu* gpu, uint64_t registry_id)
+{
+    /* entry is IOGraphicsAccelerator. Parent of the entry is the GPU */
+    io_registry_entry_t entry =
+        IOServiceGetMatchingService(kIOMasterPortDefault, IORegistryEntryIDMatching(registry_id));
+    if (!entry)
+        return;
+
+    io_registry_entry_t parent;
+    if (IORegistryEntryGetParentEntry(entry, kIOServicePlane, &parent) == kIOReturnSuccess)
+    {
+        macdrv_get_gpu_info_from_entry(gpu, entry);
+        IOObjectRelease(parent);
+    }
+    IOObjectRelease(entry);
+}
+
+/***********************************************************************
+ *              macdrv_get_gpus
+ *
+ * Get a list of GPU currently in the system. The first GPU is primary.
+ * Call macdrv_free_gpus() when you are done using the data.
+ *
+ * Return -1 on failure with parameters unchanged.
+ */
+int macdrv_get_gpus(struct macdrv_gpu** new_gpus, int* count)
+{
+    struct macdrv_gpu* gpus;
+    CGDirectDisplayID primary_display;
+    id<MTLDevice> primary_device;
+    int primary_index = 0;
+    int gpu_count;
+    int i;
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+    NSArray<id<MTLDevice>>* devices = MTLCopyAllDevices();
+    gpu_count = devices.count ? devices.count : 1;
+    gpus = calloc(gpu_count, sizeof(*gpus));
+    if (!gpus)
+        return -1;
+
+    primary_display = CGMainDisplayID();
+    primary_device = CGDirectDisplayCopyCurrentMetalDevice(primary_display);
+
+    /* 32bit build. Metal is unsupported. Report only one GPU. Use the primary display to get GPU info */
+    if (!devices.count)
+    {
+        gpus[0].id = 0;
+        macdrv_get_gpu_info_from_display_id(&gpus[0], primary_display);
+    }
+    else
+    {
+        for (i = 0; i < devices.count; i++)
+        {
+            gpus[i].id = devices[i].registryID;
+            macdrv_get_gpu_info_from_registry_id(&gpus[i], gpus[i].id);
+
+            if (gpus[i].id == primary_device.registryID)
+                primary_index = i;
+        }
+
+        /* 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;
+        }
+    }
+
+    [pool release];
+    *new_gpus = gpus;
+    *count = gpu_count;
+    return 0;
+}
+
+/***********************************************************************
+ *              macdrv_free_gpus
+ *
+ * Free a GPU list allocated from macdrv_get_gpus()
+ */
+void macdrv_free_gpus(struct macdrv_gpu* gpus)
+{
+    free(gpus);
+}
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index 6165dc5874..a6d8ec91d4 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
+{
+    /* Metal device registry id. Zero on 32bit build */
+    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