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