• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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