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