// // Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SystemInfo_mac.cpp: implementation of the Mac-specific parts of SystemInfo.h #include "gpu_info_util/SystemInfo_internal.h" #import #import namespace angle { namespace { std::string GetMachineModel() { io_service_t platformExpert = IOServiceGetMatchingService( kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); if (platformExpert == IO_OBJECT_NULL) { return ""; } CFDataRef modelData = static_cast( IORegistryEntryCreateCFProperty(platformExpert, CFSTR("model"), kCFAllocatorDefault, 0)); if (modelData == nullptr) { IOObjectRelease(platformExpert); return ""; } std::string result = reinterpret_cast(CFDataGetBytePtr(modelData)); IOObjectRelease(platformExpert); CFRelease(modelData); return result; } // Extracts one integer property from a registry entry. bool GetEntryProperty(io_registry_entry_t entry, CFStringRef name, uint32_t *value) { *value = 0; CFDataRef data = static_cast( IORegistryEntrySearchCFProperty(entry, kIOServicePlane, name, kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents)); if (data == nullptr) { return false; } const uint32_t *valuePtr = reinterpret_cast(CFDataGetBytePtr(data)); if (valuePtr == nullptr) { CFRelease(data); return false; } *value = *valuePtr; CFRelease(data); return true; } // CGDisplayIOServicePort is deprecated as of macOS 10.9, but has no replacement, see // https://crbug.com/650837 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" // Find the info of the current GPU. bool GetActiveGPU(VendorID *vendorId, DeviceID *deviceId) { io_registry_entry_t port = CGDisplayIOServicePort(kCGDirectMainDisplay); return GetEntryProperty(port, CFSTR("vendor-id"), vendorId) && GetEntryProperty(port, CFSTR("device-id"), deviceId); } #pragma clang diagnostic pop // Gathers the vendor and device IDs for the PCI GPUs bool GetPCIDevices(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) { return false; } 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; if (GetEntryProperty(entry, CFSTR("class-code"), &classCode) && classCode == kClassCodeDisplayVGA && GetEntryProperty(entry, CFSTR("vendor-id"), &info.vendorId) && GetEntryProperty(entry, CFSTR("device-id"), &info.deviceId)) { devices->push_back(info); } IOObjectRelease(entry); } IOObjectRelease(entryIterator); return true; } } // anonymous namespace bool GetSystemInfo(SystemInfo *info) { { int32_t major = 0; int32_t minor = 0; ParseMacMachineModel(GetMachineModel(), &info->machineModelName, &major, &minor); info->machineModelVersion = std::to_string(major) + "." + std::to_string(minor); } if (!GetPCIDevices(&(info->gpus))) { return false; } if (info->gpus.empty()) { return false; } // Find the active GPU { VendorID activeVendor; DeviceID activeDevice; if (!GetActiveGPU(&activeVendor, &activeDevice)) { return false; } for (size_t i = 0; i < info->gpus.size(); ++i) { if (info->gpus[i].vendorId == activeVendor && info->gpus[i].deviceId == activeDevice) { info->activeGPUIndex = i; break; } } } FindPrimaryGPU(info); return true; } } // namespace angle