From 5dcbac4dc8daee995e9d97e23a0af85abb2d73ca Mon Sep 17 00:00:00 2001 From: Christopher Cameron Date: Tue, 28 Jul 2020 15:26:42 -0700 Subject: [PATCH] macOS/ARM: Allow populating GPU based on AGXAccelerator The existing scheme for populating GPU vendor and device IDs fails on macOS/ARM. If we find no PCI registry entries, look for a AGXAccelerator entry, and (partially) populate that. This is sufficient for Chrome to initialize hardware acceleration. It is unknown how this will interact with multiple GPUs, and this will likely need to be revisited. Bug: chromium:1110421 Change-Id: I08069d7aecf45c83a1d2827cfccc4733c1835994 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2324939 Reviewed-by: Corentin Wallez Reviewed-by: Geoff Lang Reviewed-by: Lingfeng Yang Commit-Queue: ccameron --- src/gpu_info_util/SystemInfo_mac.mm | 80 ++++++++++++++++++----------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/src/gpu_info_util/SystemInfo_mac.mm b/src/gpu_info_util/SystemInfo_mac.mm index 8728d3e770..e37c842df8 100644 --- a/src/gpu_info_util/SystemInfo_mac.mm +++ b/src/gpu_info_util/SystemInfo_mac.mm @@ -118,40 +118,64 @@ bool GetEntryProperty(io_registry_entry_t entry, CFStringRef name, uint32_t *val return true; } -// Gathers the vendor and device IDs for the PCI GPUs -bool GetPCIDevices(std::vector *devices) +// Gathers the vendor and device IDs for GPUs listed in the IORegistry. +void GetIORegistryDevices(std::vector *devices) { - // matchDictionary will be consumed by IOServiceGetMatchingServices, no need to release it. - CFMutableDictionaryRef matchDictionary = IOServiceMatching("IOPCIDevice"); - - io_iterator_t entryIterator; - if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchDictionary, &entryIterator) != - kIOReturnSuccess) + constexpr uint32_t kNumServices = 2; + const char *kServiceNames[kNumServices] = {"IOPCIDevice", "AGXAccelerator"}; + const bool kServiceIsVGA[kNumServices] = {true, false}; + for (uint32_t i = 0; i < kNumServices; ++i) { - return false; - } + // matchDictionary will be consumed by IOServiceGetMatchingServices, no need to release it. + CFMutableDictionaryRef matchDictionary = IOServiceMatching(kServiceNames[i]); - io_registry_entry_t entry = IO_OBJECT_NULL; + io_iterator_t entryIterator; + if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchDictionary, &entryIterator) != + kIOReturnSuccess) + { + continue; + } - while ((entry = IOIteratorNext(entryIterator)) != IO_OBJECT_NULL) - { - constexpr uint32_t kClassCodeDisplayVGA = 0x30000; - uint32_t classCode; - GPUDeviceInfo info; - - if (GetEntryProperty(entry, CFSTR("class-code"), &classCode) && - classCode == kClassCodeDisplayVGA && - GetEntryProperty(entry, CFSTR("vendor-id"), &info.vendorId) && - GetEntryProperty(entry, CFSTR("device-id"), &info.deviceId)) + io_registry_entry_t entry = IO_OBJECT_NULL; + while ((entry = IOIteratorNext(entryIterator)) != IO_OBJECT_NULL) { + constexpr uint32_t kClassCodeDisplayVGA = 0x30000; + uint32_t classCode; + GPUDeviceInfo info; + + // AGXAccelerator entries only provide a vendor ID. + if (!GetEntryProperty(entry, CFSTR("vendor-id"), &info.vendorId)) + { + continue; + } + + if (kServiceIsVGA[i]) + { + if (!GetEntryProperty(entry, CFSTR("class-code"), &classCode)) + { + continue; + } + if (classCode != kClassCodeDisplayVGA) + { + continue; + } + if (!GetEntryProperty(entry, CFSTR("device-id"), &info.deviceId)) + { + continue; + } + } + devices->push_back(info); + IOObjectRelease(entry); } + IOObjectRelease(entryIterator); - IOObjectRelease(entry); + // If any devices have been populated by IOPCIDevice, do not continue to AGXAccelerator. + if (!devices->empty()) + { + break; + } } - IOObjectRelease(entryIterator); - - return true; } void SetActiveGPUIndex(SystemInfo *info) @@ -203,11 +227,7 @@ bool GetSystemInfo(SystemInfo *info) info->machineModelVersion = std::to_string(major) + "." + std::to_string(minor); } - if (!GetPCIDevices(&(info->gpus))) - { - return false; - } - + GetIORegistryDevices(&info->gpus); if (info->gpus.empty()) { return false;