From: Zhiyi Zhang Subject: [PATCH 1/7] winemac.drv: Add macdrv_get_gpus() helper. Message-Id: <000dcee0-600e-3263-4ccf-bcb94d9a9aa1@codeweavers.com> Date: Mon, 22 Apr 2019 20:13:02 +0800 Signed-off-by: Zhiyi Zhang --- 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 +#import #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 primary_device; + int primary_index = 0; + int gpu_count; + int i; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSArray>* 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)