1 // Copyright 2020 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 "gpuinfo.h"
16
17 #include "base/ArraySize.h"
18 #include "base/System.h"
19 #include "base/FunctorThread.h"
20 #include "gpuinfo.h"
21 #include "NativeGpuInfo.h"
22
23 #include <assert.h>
24 #include <inttypes.h>
25 #include <sstream>
26 #include <utility>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 using android::base::arraySize;
32 using android::base::FunctorThread;
33
34 // Try to switch to NVIDIA on Optimus systems,
35 // and AMD GPU on AmdPowerXpress.
36 // See http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf
37 // and https://community.amd.com/thread/169965
38 // These variables need to be visible from the final emulator executable
39 // as exported symbols.
40 #ifdef _WIN32
41 #define FLAG_EXPORT __declspec(dllexport)
42 #else
43 #define FLAG_EXPORT __attribute__ ((visibility ("default")))
44 #endif
45
46 extern "C" {
47
48 FLAG_EXPORT int NvOptimusEnablement = 0x00000001;
49 FLAG_EXPORT int AmdPowerXpressRequestHighPerformance = 0x00000001;
50
51 } // extern "C"
52
53 #undef FLAG_EXPORT
54
55
addDll(std::string dll_str)56 void GpuInfo::addDll(std::string dll_str) {
57 dlls.push_back(std::move(dll_str));
58 }
59
addGpu()60 void GpuInfoList::addGpu() {
61 infos.push_back(GpuInfo());
62 }
currGpu()63 GpuInfo& GpuInfoList::currGpu() {
64 if (infos.empty()) { addGpu(); }
65 return infos.back();
66 }
67
dump() const68 std::string GpuInfoList::dump() const {
69 std::stringstream ss;
70 for (unsigned int i = 0; i < infos.size(); i++) {
71 ss << "GPU #" << i + 1 << std::endl;
72
73 if (!infos[i].make.empty()) {
74 ss << " Make: " << infos[i].make << std::endl;
75 }
76 if (!infos[i].model.empty()) {
77 ss << " Model: " << infos[i].model << std::endl;
78 }
79 if (!infos[i].device_id.empty()) {
80 ss << " Device ID: " << infos[i].device_id << std::endl;
81 }
82 if (!infos[i].revision_id.empty()) {
83 ss << " Revision ID: " << infos[i].revision_id << std::endl;
84 }
85 if (!infos[i].version.empty()) {
86 ss << " Driver version: " << infos[i].version << std::endl;
87 }
88 if (!infos[i].renderer.empty()) {
89 ss << " Renderer: " << infos[i].renderer << std::endl;
90 }
91 }
92 return ss.str();
93 }
94
clear()95 void GpuInfoList::clear() {
96 blacklist_status = false;
97 Anglelist_status = false;
98 SyncBlacklist_status = false;
99 VulkanBlacklist_status = false;
100 infos.clear();
101 }
102
gpuinfo_query_list(GpuInfoList * gpulist,const BlacklistEntry * list,int size)103 static bool gpuinfo_query_list(GpuInfoList* gpulist,
104 const BlacklistEntry* list,
105 int size) {
106 for (auto gpuinfo : gpulist->infos) {
107 for (int i = 0; i < size; i++) {
108 auto bl_entry = list[i];
109 const char* bl_make = bl_entry.make;
110 const char* bl_model = bl_entry.model;
111 const char* bl_device_id = bl_entry.device_id;
112 const char* bl_revision_id = bl_entry.revision_id;
113 const char* bl_version = bl_entry.version;
114 const char* bl_renderer = bl_entry.renderer;
115 const char* bl_os = bl_entry.os;
116
117 if (bl_make && (gpuinfo.make != bl_make))
118 continue;
119 if (bl_model && (gpuinfo.model != bl_model))
120 continue;
121 if (bl_device_id && (gpuinfo.device_id != bl_device_id))
122 continue;
123 if (bl_revision_id && (gpuinfo.revision_id != bl_revision_id))
124 continue;
125 if (bl_version && (gpuinfo.revision_id != bl_version))
126 continue;
127 if (bl_renderer && (gpuinfo.renderer.find(bl_renderer) ==
128 std::string::npos))
129 continue;
130 if (bl_os && (gpuinfo.os != bl_os))
131 continue;
132 return true;
133 }
134 }
135 return false;
136 }
137
138 // Actual blacklist starts here.
139 // Most entries imported from Chrome blacklist.
140 static const BlacklistEntry sGpuBlacklist[] = {
141
142 // Make | Model | DeviceID | RevisionID | DriverVersion | Renderer |
143 // OS
144 {nullptr, nullptr, "0x7249", nullptr, nullptr,
145 nullptr, "M"}, // ATI Radeon X1900 on Mac
146 {"8086", nullptr, nullptr, nullptr, nullptr,
147 "Mesa", "L"}, // Linux, Intel, Mesa
148 {"8086", nullptr, nullptr, nullptr, nullptr,
149 "mesa", "L"}, // Linux, Intel, Mesa
150
151 {"8086", nullptr, "27ae", nullptr, nullptr,
152 nullptr, nullptr}, // Intel 945 Chipset
153 {"1002", nullptr, nullptr, nullptr, nullptr, nullptr,
154 "L"}, // Linux, ATI
155
156 {nullptr, nullptr, "0x9583", nullptr, nullptr,
157 nullptr, "M"}, // ATI Radeon HD2600 on Mac
158 {nullptr, nullptr, "0x94c8", nullptr, nullptr,
159 nullptr, "M"}, // ATI Radeon HD2400 on Mac
160
161 {"NVIDIA (0x10de)", nullptr, "0x0324", nullptr, nullptr,
162 nullptr, "M"}, // NVIDIA GeForce FX Go5200 (Mac)
163 {"10DE", "NVIDIA GeForce FX Go5200", nullptr, nullptr, nullptr,
164 nullptr, "W"}, // NVIDIA GeForce FX Go5200 (Win)
165 {"10de", nullptr, "0324", nullptr, nullptr,
166 nullptr, "L"}, // NVIDIA GeForce FX Go5200 (Linux)
167
168 {"10de", nullptr, "029e", nullptr, nullptr,
169 nullptr, "L"}, // NVIDIA Quadro FX 1500 (Linux)
170
171 // Various Quadro FX cards on Linux
172 {"10de", nullptr, "00cd", nullptr, "195.36.24",
173 nullptr, "L"},
174 {"10de", nullptr, "00ce", nullptr, "195.36.24",
175 nullptr, "L"},
176 // Driver version 260.19.6 on Linux
177 {"10de", nullptr, nullptr, nullptr, "260.19.6",
178 nullptr, "L"},
179
180 {"NVIDIA (0x10de)", nullptr, "0x0393", nullptr, nullptr,
181 nullptr, "M"}, // NVIDIA GeForce 7300 GT (Mac)
182
183 // GPUs with < OpenGL 2.1 support
184
185 // Intel Auburn
186 {"8086", nullptr, "7800", nullptr, nullptr, nullptr, nullptr},
187
188 // Intel Portola
189 {"8086", nullptr, "1240", nullptr, nullptr, nullptr, nullptr},
190
191 // Intel Whitney
192 {"8086", nullptr, "7121", nullptr, nullptr, nullptr, nullptr},
193 {"8086", nullptr, "7123", nullptr, nullptr, nullptr, nullptr},
194 {"8086", nullptr, "7125", nullptr, nullptr, nullptr, nullptr},
195
196 // Intel Solano
197 {"8086", nullptr, "1132", nullptr, nullptr, nullptr, nullptr},
198
199 // Intel Brookdale
200 {"8086", nullptr, "2562", nullptr, nullptr, nullptr, nullptr},
201
202 // Intel Almador
203 {"8086", nullptr, "3577", nullptr, nullptr, nullptr, nullptr},
204
205 // Intel Springdale
206 {"8086", nullptr, "2572", nullptr, nullptr, nullptr, nullptr},
207
208 // Intel Montara
209 {"8086", nullptr, "3582", nullptr, nullptr, nullptr, nullptr},
210 {"8086", nullptr, "358e", nullptr, nullptr, nullptr, nullptr},
211
212 // Intel Grantsdale (2.1 desktop / ES 2.0 on Linux supported)
213 {"8086", nullptr, "2582", nullptr, nullptr, nullptr, "W"},
214 {"8086", nullptr, "258a", nullptr, nullptr, nullptr, "W"},
215
216 // Intel Alviso
217 {"8086", nullptr, "2592", nullptr, nullptr, nullptr, "W"},
218
219 // Intel Lakeport
220 {"8086", nullptr, "2772", nullptr, nullptr, nullptr, "W"},
221
222 // Intel Calistoga
223 {"8086", nullptr, "27a2", nullptr, nullptr, nullptr, "W"},
224 {"8086", nullptr, "27ae", nullptr, nullptr, nullptr, "W"},
225
226 // Intel Bearlake
227 {"8086", nullptr, "29c2", nullptr, nullptr, nullptr, "W"},
228 {"8086", nullptr, "29b2", nullptr, nullptr, nullptr, "W"},
229 {"8086", nullptr, "29d2", nullptr, nullptr, nullptr, "W"},
230
231 // Intel Pineview
232 {"8086", nullptr, "a001", nullptr, nullptr, nullptr, "W"},
233 {"8086", nullptr, "a011", nullptr, nullptr, nullptr, "W"},
234
235 // Intel Lakeport
236 {"8086", nullptr, "2972", nullptr, nullptr, nullptr, "W"},
237
238 // Intel Broadwater
239 {"8086", nullptr, "2992", nullptr, nullptr, nullptr, "W"},
240 {"8086", nullptr, "29a2", nullptr, nullptr, nullptr, "W"},
241
242 // Intel Bearlake 2
243 {"8086", nullptr, "2982", nullptr, nullptr, nullptr, "W"},
244
245 // Intel Crestine
246 {"8086", nullptr, "2a02", nullptr, nullptr, nullptr, "W"},
247 {"8086", nullptr, "2a12", nullptr, nullptr, nullptr, "W"},
248
249 // Display-only devices
250
251 // Microsoft Basic Render Driver
252 {"1414", nullptr, "008c", nullptr, nullptr, nullptr, nullptr},
253
254 // Matrix MGA G200eW
255 {"102b", nullptr, "0532", nullptr, nullptr, nullptr, nullptr},
256
257 // VMWare SVGA 3D
258 {"15ad", nullptr, "0405", nullptr, nullptr, nullptr, nullptr},
259
260 // Citrix Display Only Adapter
261 {"5853", nullptr, "1002", nullptr, nullptr, nullptr, nullptr},
262
263 // SeaBIOS Display-Only Device?
264 {"1b36", nullptr, "0100", nullptr, nullptr, nullptr, nullptr},
265
266 // Devices incapable of reliably calling wglMakeCurrent
267 // when switching HDC
268
269 // Intel Eaglelake
270 {"8086", nullptr, "2e42", nullptr, nullptr, nullptr, "W"},
271 {"8086", nullptr, "2e92", nullptr, nullptr, nullptr, "W"},
272 {"8086", nullptr, "2e12", nullptr, nullptr, nullptr, "W"},
273 {"8086", nullptr, "2e32", nullptr, nullptr, nullptr, "W"},
274 {"8086", nullptr, "2e22", nullptr, nullptr, nullptr, "W"},
275
276 // Intel Cantiga
277 {"8086", nullptr, "2a42", nullptr, nullptr, nullptr, "W"},
278
279 // Intel Ironlake
280 {"8086", nullptr, "0042", nullptr, nullptr, nullptr, "W"},
281 {"8086", nullptr, "0046", nullptr, nullptr, nullptr, "W"},
282 };
283
284 // If any blacklist entry matches any gpu, return true.
gpuinfo_query_blacklist(GpuInfoList * gpulist,const BlacklistEntry * list,int size)285 bool gpuinfo_query_blacklist(GpuInfoList* gpulist,
286 const BlacklistEntry* list,
287 int size) {
288 return gpuinfo_query_list(gpulist, list, size);
289 }
290
291 #ifdef _WIN32
292 static const WhitelistEntry sAngleWhitelist[] = {
293 // Make | Model | DeviceID | RevisionID | DriverVersion | Renderer |
294 // OS
295 // HD 3000 on Windows
296 {"8086", nullptr, "0116", nullptr, nullptr,
297 nullptr, "W"},
298 {"8086", nullptr, "0126", nullptr, nullptr,
299 nullptr, "W"},
300 {"8086", nullptr, "0102", nullptr, nullptr,
301 nullptr, "W"},
302 };
303
gpuinfo_query_whitelist(GpuInfoList * gpulist,const WhitelistEntry * list,int size)304 static bool gpuinfo_query_whitelist(GpuInfoList *gpulist,
305 const WhitelistEntry *list,
306 int size) {
307 return gpuinfo_query_list(gpulist, list, size);
308 }
309
310 #endif
311
312 static const BlacklistEntry sSyncBlacklist[] = {
313 // Make | Model | DeviceID | RevisionID | DriverVersion | Renderer |
314 // OS
315 // All NVIDIA Quadro NVS and NVIDIA NVS GPUs on Windows
316 {"10de", nullptr, "06fd", nullptr, nullptr, nullptr, "W"}, // NVS 295
317 {"10de", nullptr, "0a6a", nullptr, nullptr, nullptr, "W"}, // NVS 2100M
318 {"10de", nullptr, "0a6c", nullptr, nullptr, nullptr, "W"}, // NVS 5100M
319 {"10de", nullptr, "0ffd", nullptr, nullptr, nullptr, "W"}, // NVS 510
320 {"10de", nullptr, "1056", nullptr, nullptr, nullptr, "W"}, // NVS 4200M
321 {"10de", nullptr, "10d8", nullptr, nullptr, nullptr, "W"}, // NVS 300
322 {"10de", nullptr, "014a", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 440
323 {"10de", nullptr, "0165", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 285
324 {"10de", nullptr, "017a", nullptr, nullptr, nullptr, "W"}, // Quadro NVS (generic)
325 {"10de", nullptr, "018a", nullptr, nullptr, nullptr, "W"}, // Quadro NVS AGP8X (generic)
326 {"10de", nullptr, "018c", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 50 PCI (generic)
327 {"10de", nullptr, "01db", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 120M
328 {"10de", nullptr, "0245", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 210S / NVIDIA GeForce 6150LE
329 {"10de", nullptr, "032a", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 55/280 PCI
330 {"10de", nullptr, "040c", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 570M / Mobile Quadro FX/NVS video card
331 {"10de", nullptr, "0429", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 135M or Quadro NVS 140M
332 {"10de", nullptr, "042b", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 135M
333 {"10de", nullptr, "042f", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 290
334 {"10de", nullptr, "06ea", nullptr, nullptr, nullptr, "W"}, // quadro nvs 150m
335 {"10de", nullptr, "06eb", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 160M
336 {"10de", nullptr, "06f8", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 420
337 {"10de", nullptr, "06fa", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 450
338 {"10de", nullptr, "0a2c", nullptr, nullptr, nullptr, "W"}, // Quadro NVS 5100M
339 };
340
341 namespace {
342
343 // A set of global variables for GPU information - a single instance of
344 // GpuInfoList and its loading thread.
345 class Globals {
346 DISALLOW_COPY_AND_ASSIGN(Globals);
347
348 public:
Globals()349 Globals()
350 : mAsyncLoadThread([this]() {
351 getGpuInfoListNative(&mGpuInfoList);
352
353 mGpuInfoList.blacklist_status = gpuinfo_query_blacklist(
354 &mGpuInfoList, sGpuBlacklist, arraySize(sGpuBlacklist));
355 #ifdef _WIN32
356 mGpuInfoList.Anglelist_status =
357 gpuinfo_query_whitelist(&mGpuInfoList, sAngleWhitelist,
358 arraySize(sAngleWhitelist));
359 #else
360 mGpuInfoList.Anglelist_status = false;
361 #endif
362 mGpuInfoList.SyncBlacklist_status = gpuinfo_query_blacklist(
363 &mGpuInfoList, sSyncBlacklist, arraySize(sSyncBlacklist));
364
365 mGpuInfoList.VulkanBlacklist_status =
366 !isVulkanSafeToUseNative();
367
368 }) {
369 mAsyncLoadThread.start();
370 }
371
gpuInfoList()372 const GpuInfoList& gpuInfoList() {
373 mAsyncLoadThread.wait();
374 return mGpuInfoList;
375 }
376
377 private:
378 GpuInfoList mGpuInfoList;
379
380 // Separate thread for GPU info querying:
381 //
382 // GPU information querying may take a while, but the implementation is
383 // expected to abort if it's over reasonable limits. That's why we use a
384 // separate thread that's started as soon as possible at startup and then
385 // wait for it synchronoulsy before using the information.
386 //
387 FunctorThread mAsyncLoadThread;
388 };
389
390 } // namespace
391
sGlobals()392 static Globals* sGlobals() {
393 static Globals* g = new Globals;
394 return g;
395 }
396
async_query_host_gpu_start()397 void async_query_host_gpu_start() {
398 sGlobals();
399 }
400
globalGpuInfoList()401 const GpuInfoList& globalGpuInfoList() {
402 return sGlobals()->gpuInfoList();
403 }
404
async_query_host_gpu_blacklisted()405 bool async_query_host_gpu_blacklisted() {
406 return globalGpuInfoList().blacklist_status;
407 }
408
async_query_host_gpu_AngleWhitelisted()409 bool async_query_host_gpu_AngleWhitelisted() {
410 return globalGpuInfoList().Anglelist_status;
411 }
412
async_query_host_gpu_SyncBlacklisted()413 bool async_query_host_gpu_SyncBlacklisted() {
414 return globalGpuInfoList().SyncBlacklist_status;
415 }
416
async_query_host_gpu_VulkanBlacklisted()417 bool async_query_host_gpu_VulkanBlacklisted() {
418 return globalGpuInfoList().VulkanBlacklist_status;
419 }
420
setGpuBlacklistStatus(bool switchedToSoftware)421 void setGpuBlacklistStatus(bool switchedToSoftware) {
422 // We know what we're doing here: GPU list doesn't change after it's fully
423 // loaded.
424 const_cast<GpuInfoList&>(globalGpuInfoList()).blacklist_status =
425 switchedToSoftware;
426 }
427