1 // Copyright 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "host-common/opengl/NativeGpuInfo.h"
16
17 #include "host-common/opengl/macTouchOpenGL.h"
18
19 #include <CoreGraphics/CGDirectDisplay.h>
20 #include <IOKit/graphics/IOGraphicsLib.h>
21 #include <IOKit/IOTypes.h>
22 #include <IOKit/IOKitLib.h>
23
24 #include <string>
25 #include <vector>
26
27 #include <stdio.h>
28
29 typedef std::pair<uint32_t, uint32_t> GpuVendorDeviceId;
30 typedef std::vector<GpuVendorDeviceId> GpuVendorDeviceIdList;
31
32 // Based on code from:
33 // https://chromium.googlesource.com/chromium/src/gpu/+/e626016b34c63b7ff51bf9a6c20b37bcc18150c4/config/gpu_info_collector_mac.mm
34 // https://github.com/glfw/glfw/blob/e0a6772e5e4c672179fc69a90bcda3369792ed1f/src/cocoa_monitor.m
35
36 // GetEntryProperty():
37 // Return 0 if we couldn't find the property.
38 // The property values we use should not be 0, so it's OK to use 0 as failure.
GetEntryProperty(io_registry_entry_t entry,CFStringRef property_name)39 uint32_t GetEntryProperty(io_registry_entry_t entry, CFStringRef property_name) {
40 CFDataRef ref(
41 static_cast<CFDataRef>(IORegistryEntrySearchCFProperty(
42 entry,
43 kIOServicePlane,
44 property_name,
45 kCFAllocatorDefault,
46 kIORegistryIterateRecursively | kIORegistryIterateParents)));
47
48 if (!ref)
49 return 0;
50
51 uint32_t value = 0;
52 const uint32_t* value_pointer =
53 reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(ref));
54
55 if (value_pointer != NULL)
56 value = *value_pointer;
57
58 CFRelease(ref);
59 return value;
60 }
61
GetGPUInfoMac()62 static auto GetGPUInfoMac() {
63
64 GpuVendorDeviceIdList res;
65
66 io_iterator_t iter;
67 io_service_t serv = 0;
68
69 CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect");
70 kern_return_t err = IOServiceGetMatchingServices(kIOMasterPortDefault,
71 matching,
72 &iter);
73
74 if (err) return res;
75
76 while ((serv = IOIteratorNext(iter)) != 0) {
77 uint32_t vendor_id = GetEntryProperty(serv, CFSTR("vendor-id"));
78 if (vendor_id) {
79 uint32_t device_id = GetEntryProperty(serv, CFSTR("device-id"));
80 if (device_id) {
81 res.push_back(std::make_pair(vendor_id, device_id));
82 }
83 }
84 }
85
86 return res;
87 }
88
getGpuInfoListNative(GpuInfoList * out)89 void getGpuInfoListNative(GpuInfoList* out) {
90 // This call initializes a pixel format,
91 // which should update the IOKit stuff to the
92 // correct GPU that will actually be used
93 // while the emulator is running.
94 macTouchOpenGL();
95
96 auto gpulist = GetGPUInfoMac();
97
98 char vendoridbuf[64] = {};
99 char deviceidbuf[64] = {};
100
101 for (const auto& elt : gpulist) {
102 snprintf(vendoridbuf, sizeof(vendoridbuf), "%04x", elt.first);
103 snprintf(deviceidbuf, sizeof(deviceidbuf), "%04x", elt.second);
104 out->infos.emplace_back(
105 std::string(vendoridbuf), // make -> vendorid
106 std::string(deviceidbuf), // model -> deviceid
107 std::string(deviceidbuf), // device_id -> deviceid
108 "", "", "" // revision, version, renderer blank
109 );
110 }
111 }
112
113 // macOS: Disable Vulkan for now unless on M1.
isVulkanSafeToUseNative()114 bool isVulkanSafeToUseNative() {
115 #ifdef __aarch64__
116 return true;
117 #else
118 return false;
119 #endif
120 }