[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