1// 2// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6 7// SystemInfo_mac.cpp: implementation of the Mac-specific parts of SystemInfo.h 8 9#include "gpu_info_util/SystemInfo_internal.h" 10 11#import <Cocoa/Cocoa.h> 12#import <IOKit/IOKitLib.h> 13 14namespace angle 15{ 16 17namespace 18{ 19 20std::string GetMachineModel() 21{ 22 io_service_t platformExpert = IOServiceGetMatchingService( 23 kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); 24 25 if (platformExpert == IO_OBJECT_NULL) 26 { 27 return ""; 28 } 29 30 CFDataRef modelData = static_cast<CFDataRef>( 31 IORegistryEntryCreateCFProperty(platformExpert, CFSTR("model"), kCFAllocatorDefault, 0)); 32 if (modelData == nullptr) 33 { 34 IOObjectRelease(platformExpert); 35 return ""; 36 } 37 38 std::string result = reinterpret_cast<const char *>(CFDataGetBytePtr(modelData)); 39 40 IOObjectRelease(platformExpert); 41 CFRelease(modelData); 42 43 return result; 44} 45 46// Extracts one integer property from a registry entry. 47bool GetEntryProperty(io_registry_entry_t entry, CFStringRef name, uint32_t *value) 48{ 49 *value = 0; 50 51 CFDataRef data = static_cast<CFDataRef>( 52 IORegistryEntrySearchCFProperty(entry, kIOServicePlane, name, kCFAllocatorDefault, 53 kIORegistryIterateRecursively | kIORegistryIterateParents)); 54 55 if (data == nullptr) 56 { 57 return false; 58 } 59 60 const uint32_t *valuePtr = reinterpret_cast<const uint32_t *>(CFDataGetBytePtr(data)); 61 62 if (valuePtr == nullptr) 63 { 64 CFRelease(data); 65 return false; 66 } 67 68 *value = *valuePtr; 69 CFRelease(data); 70 return true; 71} 72 73// CGDisplayIOServicePort is deprecated as of macOS 10.9, but has no replacement, see 74// https://crbug.com/650837 75#pragma clang diagnostic push 76#pragma clang diagnostic ignored "-Wdeprecated-declarations" 77 78// Find the info of the current GPU. 79bool GetActiveGPU(VendorID *vendorId, DeviceID *deviceId) 80{ 81 io_registry_entry_t port = CGDisplayIOServicePort(kCGDirectMainDisplay); 82 83 return GetEntryProperty(port, CFSTR("vendor-id"), vendorId) && 84 GetEntryProperty(port, CFSTR("device-id"), deviceId); 85} 86 87#pragma clang diagnostic pop 88 89// Gathers the vendor and device IDs for the PCI GPUs 90bool GetPCIDevices(std::vector<GPUDeviceInfo> *devices) 91{ 92 // matchDictionary will be consumed by IOServiceGetMatchingServices, no need to release it. 93 CFMutableDictionaryRef matchDictionary = IOServiceMatching("IOPCIDevice"); 94 95 io_iterator_t entryIterator; 96 if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchDictionary, &entryIterator) != 97 kIOReturnSuccess) 98 { 99 return false; 100 } 101 102 io_registry_entry_t entry = IO_OBJECT_NULL; 103 104 while ((entry = IOIteratorNext(entryIterator)) != IO_OBJECT_NULL) 105 { 106 constexpr uint32_t kClassCodeDisplayVGA = 0x30000; 107 uint32_t classCode; 108 GPUDeviceInfo info; 109 110 if (GetEntryProperty(entry, CFSTR("class-code"), &classCode) && 111 classCode == kClassCodeDisplayVGA && 112 GetEntryProperty(entry, CFSTR("vendor-id"), &info.vendorId) && 113 GetEntryProperty(entry, CFSTR("device-id"), &info.deviceId)) 114 { 115 devices->push_back(info); 116 } 117 118 IOObjectRelease(entry); 119 } 120 IOObjectRelease(entryIterator); 121 122 return true; 123} 124 125} // anonymous namespace 126 127bool GetSystemInfo(SystemInfo *info) 128{ 129 { 130 int32_t major = 0; 131 int32_t minor = 0; 132 ParseMacMachineModel(GetMachineModel(), &info->machineModelName, &major, &minor); 133 info->machineModelVersion = std::to_string(major) + "." + std::to_string(minor); 134 } 135 136 if (!GetPCIDevices(&(info->gpus))) 137 { 138 return false; 139 } 140 141 if (info->gpus.empty()) 142 { 143 return false; 144 } 145 146 // Find the active GPU 147 { 148 VendorID activeVendor; 149 DeviceID activeDevice; 150 if (!GetActiveGPU(&activeVendor, &activeDevice)) 151 { 152 return false; 153 } 154 155 for (size_t i = 0; i < info->gpus.size(); ++i) 156 { 157 if (info->gpus[i].vendorId == activeVendor && info->gpus[i].deviceId == activeDevice) 158 { 159 info->activeGPUIndex = i; 160 break; 161 } 162 } 163 } 164 165 FindPrimaryGPU(info); 166 167 return true; 168} 169 170} // namespace angle 171