1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // feature_support_util.cpp: Helps client APIs make decisions based on rules
8 // data files. For example, the Android EGL loader uses this library to
9 // determine whether to use ANGLE or a native GLES driver.
10
11 #include "feature_support_util.h"
12 #include <json/json.h>
13 #include <string.h>
14 #include "common/platform.h"
15 #if defined(ANGLE_PLATFORM_ANDROID)
16 # include <android/log.h>
17 # include <unistd.h>
18 #endif
19 #include <fstream>
20 #include <list>
21 #include "../gpu_info_util/SystemInfo.h"
22
23 namespace angle
24 {
25
26 #if defined(ANGLE_PLATFORM_ANDROID)
27 // Define ANGLE_FEATURE_UTIL_LOG_VERBOSE if you want VERBOSE to output
28 // ANGLE_FEATURE_UTIL_LOG_VERBOSE is automatically defined when is_debug = true
29
30 # define ERR(...) __android_log_print(ANDROID_LOG_ERROR, "ANGLE", __VA_ARGS__)
31 # define WARN(...) __android_log_print(ANDROID_LOG_WARN, "ANGLE", __VA_ARGS__)
32 # define INFO(...) __android_log_print(ANDROID_LOG_INFO, "ANGLE", __VA_ARGS__)
33 # define DEBUG(...) __android_log_print(ANDROID_LOG_DEBUG, "ANGLE", __VA_ARGS__)
34 # ifdef ANGLE_FEATURE_UTIL_LOG_VERBOSE
35 # define VERBOSE(...) __android_log_print(ANDROID_LOG_VERBOSE, "ANGLE", __VA_ARGS__)
36 # else
37 # define VERBOSE(...) ((void)0)
38 # endif
39 #else // defined(ANDROID)
40 # define ERR(...) printf(__VA_ARGS__)
41 # define WARN(...) printf(__VA_ARGS__)
42 # define INFO(...) printf(__VA_ARGS__)
43 # define DEBUG(...) printf(__VA_ARGS__)
44 # define VERBOSE(...) printf(__VA_ARGS__)
45 #endif // defined(ANDROID)
46
47 // JSON values are generally composed of either:
48 // - Objects, which are a set of comma-separated string:value pairs (note the recursive nature)
49 // - Arrays, which are a set of comma-separated values.
50 // We'll call the string in a string:value pair the "identifier". These identifiers are defined
51 // below, as follows:
52
53 // The JSON identifier for the top-level set of rules. This is an object, the value of which is an
54 // array of rules. The rules will be processed in order. If a rule matches, the rule's version of
55 // the answer (true or false) becomes the new answer. After all rules are processed, the
56 // most-recent answer is the final answer.
57 constexpr char kJsonRules[] = "Rules";
58 // The JSON identifier for a given rule. A rule is an object, the first string:value pair is this
59 // identifier (i.e. "Rule") as the string and the value is a user-firendly description of the rule:
60 constexpr char kJsonRule[] = "Rule";
61 // Within a rule, the JSON identifier for the answer--whether or not to use ANGLE. The value is a
62 // boolean (i.e. true or false).
63 constexpr char kJsonUseANGLE[] = "UseANGLE";
64
65 // Within a rule, the JSON identifier for describing one or more applications. The value is an
66 // array of objects, each object of which can specify attributes of an application.
67 constexpr char kJsonApplications[] = "Applications";
68 // Within an object that describes the attributes of an application, the JSON identifier for the
69 // name of the application (e.g. "com.google.maps"). The value is a string. If any other
70 // attributes will be specified, this must be the first attribute specified in the object.
71 constexpr char kJsonAppName[] = "AppName";
72
73 // Within a rule, the JSON identifier for describing one or more devices. The value is an
74 // array of objects, each object of which can specify attributes of a device.
75 constexpr char kJsonDevices[] = "Devices";
76 // Within an object that describes the attributes of a device, the JSON identifier for the
77 // manufacturer of the device. The value is a string. If any other non-GPU attributes will be
78 // specified, this must be the first attribute specified in the object.
79 constexpr char kJsonManufacturer[] = "Manufacturer";
80 // Within an object that describes the attributes of a device, the JSON identifier for the
81 // model of the device. The value is a string.
82 constexpr char kJsonModel[] = "Model";
83
84 // Within an object that describes the attributes of a device, the JSON identifier for describing
85 // one or more GPUs/drivers used in the device. The value is an
86 // array of objects, each object of which can specify attributes of a GPU and its driver.
87 constexpr char kJsonGPUs[] = "GPUs";
88 // Within an object that describes the attributes of a GPU and driver, the JSON identifier for the
89 // vendor of the device/driver. The value is a string. If any other attributes will be specified,
90 // this must be the first attribute specified in the object.
91 constexpr char kJsonVendor[] = "Vendor";
92 // Within an object that describes the attributes of a GPU and driver, the JSON identifier for the
93 // deviceId of the device. The value is an unsigned integer. If the driver version will be
94 // specified, this must preceded the version attributes specified in the object.
95 constexpr char kJsonDeviceId[] = "DeviceId";
96
97 // Within an object that describes the attributes of either an application or a GPU, the JSON
98 // identifier for the major version of that application or GPU driver. The value is a positive
99 // integer number. Not specifying a major version implies a wildcard for all values of a version.
100 constexpr char kJsonVerMajor[] = "VerMajor";
101 // Within an object that describes the attributes of either an application or a GPU, the JSON
102 // identifier for the minor version of that application or GPU driver. The value is a positive
103 // integer number. In order to specify a minor version, it must be specified immediately after the
104 // major number associated with it. Not specifying a minor version implies a wildcard for the
105 // minor, subminor, and patch values of a version.
106 constexpr char kJsonVerMinor[] = "VerMinor";
107 // Within an object that describes the attributes of either an application or a GPU, the JSON
108 // identifier for the subminor version of that application or GPU driver. The value is a positive
109 // integer number. In order to specify a subminor version, it must be specified immediately after
110 // the minor number associated with it. Not specifying a subminor version implies a wildcard for
111 // the subminor and patch values of a version.
112 constexpr char kJsonVerSubMinor[] = "VerSubMinor";
113 // Within an object that describes the attributes of either an application or a GPU, the JSON
114 // identifier for the patch version of that application or GPU driver. The value is a positive
115 // integer number. In order to specify a patch version, it must be specified immediately after the
116 // subminor number associated with it. Not specifying a patch version implies a wildcard for the
117 // patch value of a version.
118 constexpr char kJsonVerPatch[] = "VerPatch";
119
120 // This encapsulates a std::string. The default constructor (not given a string) assumes that this
121 // is a wildcard (i.e. will match all other StringPart objects).
122 class StringPart
123 {
124 public:
StringPart()125 StringPart() : mPart(""), mWildcard(true) {}
StringPart(const std::string part)126 StringPart(const std::string part) : mPart(part), mWildcard(false) {}
~StringPart()127 ~StringPart() {}
match(const StringPart & toCheck) const128 bool match(const StringPart &toCheck) const
129 {
130 return (mWildcard || toCheck.mWildcard || (toCheck.mPart == mPart));
131 }
132
133 public:
134 std::string mPart;
135 bool mWildcard;
136 };
137
138 // This encapsulates a 32-bit unsigned integer. The default constructor (not given a number)
139 // assumes that this is a wildcard (i.e. will match all other IntegerPart objects).
140 class IntegerPart
141 {
142 public:
IntegerPart()143 IntegerPart() : mPart(0), mWildcard(true) {}
IntegerPart(uint32_t part)144 IntegerPart(uint32_t part) : mPart(part), mWildcard(false) {}
~IntegerPart()145 ~IntegerPart() {}
match(const IntegerPart & toCheck) const146 bool match(const IntegerPart &toCheck) const
147 {
148 return (mWildcard || toCheck.mWildcard || (toCheck.mPart == mPart));
149 }
150
151 public:
152 uint32_t mPart;
153 bool mWildcard;
154 };
155
156 // This encapsulates a list of other classes, each of which will have a match() and logItem()
157 // method. The common constructor (given a type, but not any list items) assumes that this is
158 // a wildcard (i.e. will match all other ListOf<t> objects).
159 template <class T>
160 class ListOf
161 {
162 public:
ListOf(const std::string listType)163 ListOf(const std::string listType) : mWildcard(true), mListType(listType) {}
~ListOf()164 ~ListOf() { mList.clear(); }
addItem(const T & toAdd)165 void addItem(const T &toAdd)
166 {
167 mList.push_back(toAdd);
168 mWildcard = false;
169 }
match(const T & toCheck) const170 bool match(const T &toCheck) const
171 {
172 VERBOSE("\t\t Within ListOf<%s> match: wildcards are %s and %s,\n", mListType.c_str(),
173 mWildcard ? "true" : "false", toCheck.mWildcard ? "true" : "false");
174 if (mWildcard || toCheck.mWildcard)
175 {
176 return true;
177 }
178 for (const T &it : mList)
179 {
180 VERBOSE("\t\t Within ListOf<%s> match: calling match on sub-item is %s,\n",
181 mListType.c_str(), it.match(toCheck) ? "true" : "false");
182 if (it.match(toCheck))
183 {
184 return true;
185 }
186 }
187 return false;
188 }
match(const ListOf<T> & toCheck) const189 bool match(const ListOf<T> &toCheck) const
190 {
191 VERBOSE("\t\t Within ListOf<%s> match: wildcards are %s and %s,\n", mListType.c_str(),
192 mWildcard ? "true" : "false", toCheck.mWildcard ? "true" : "false");
193 if (mWildcard || toCheck.mWildcard)
194 {
195 return true;
196 }
197 // If we make it to here, both this and toCheck have at least one item in their mList
198 for (const T &it : toCheck.mList)
199 {
200 if (match(it))
201 {
202 return true;
203 }
204 }
205 return false;
206 }
logListOf(const std::string prefix,const std::string name) const207 void logListOf(const std::string prefix, const std::string name) const
208 {
209 if (mWildcard)
210 {
211 VERBOSE("%sListOf%s is wildcarded to always match", prefix.c_str(), name.c_str());
212 }
213 else
214 {
215 VERBOSE("%sListOf%s has %d item(s):", prefix.c_str(), name.c_str(),
216 static_cast<int>(mList.size()));
217 for (auto &it : mList)
218 {
219 it.logItem();
220 }
221 }
222 }
223
224 bool mWildcard;
225
226 private:
227 std::string mListType;
228 std::vector<T> mList;
229 };
230
231 // This encapsulates up-to four 32-bit unsigned integers, that represent a potentially-complex
232 // version number. The default constructor (not given any numbers) assumes that this is a wildcard
233 // (i.e. will match all other Version objects). Each part of a Version is stored in an IntegerPart
234 // class, and so may be wildcarded as well.
235 class Version
236 {
237 public:
Version(uint32_t major,uint32_t minor,uint32_t subminor,uint32_t patch)238 Version(uint32_t major, uint32_t minor, uint32_t subminor, uint32_t patch)
239 : mMajor(major), mMinor(minor), mSubminor(subminor), mPatch(patch), mWildcard(false)
240 {}
Version(uint32_t major,uint32_t minor,uint32_t subminor)241 Version(uint32_t major, uint32_t minor, uint32_t subminor)
242 : mMajor(major), mMinor(minor), mSubminor(subminor), mWildcard(false)
243 {}
Version(uint32_t major,uint32_t minor)244 Version(uint32_t major, uint32_t minor) : mMajor(major), mMinor(minor), mWildcard(false) {}
Version(uint32_t major)245 Version(uint32_t major) : mMajor(major), mWildcard(false) {}
Version()246 Version() : mWildcard(true) {}
Version(const Version & toCopy)247 Version(const Version &toCopy)
248 : mMajor(toCopy.mMajor),
249 mMinor(toCopy.mMinor),
250 mSubminor(toCopy.mSubminor),
251 mPatch(toCopy.mPatch),
252 mWildcard(toCopy.mWildcard)
253 {}
~Version()254 ~Version() {}
255
CreateVersionFromJson(const Json::Value & jObject)256 static Version *CreateVersionFromJson(const Json::Value &jObject)
257 {
258 Version *version = nullptr;
259 // A major version must be provided before a minor, and so on:
260 if (jObject.isMember(kJsonVerMajor) && jObject[kJsonVerMajor].isInt())
261 {
262 int major = jObject[kJsonVerMajor].asInt();
263 if (jObject.isMember(kJsonVerMinor) && jObject[kJsonVerMinor].isInt())
264 {
265 int minor = jObject[kJsonVerMinor].asInt();
266 if (jObject.isMember(kJsonVerSubMinor) && jObject[kJsonVerSubMinor].isInt())
267 {
268 int subMinor = jObject[kJsonVerSubMinor].asInt();
269 if (jObject.isMember(kJsonVerPatch) && jObject[kJsonVerPatch].isInt())
270 {
271 int patch = jObject[kJsonVerPatch].asInt();
272 version = new Version(major, minor, subMinor, patch);
273 }
274 else
275 {
276 version = new Version(major, minor, subMinor);
277 }
278 }
279 else
280 {
281 version = new Version(major, minor);
282 }
283 }
284 else
285 {
286 version = new Version(major);
287 }
288 }
289 return version;
290 }
291
match(const Version & toCheck) const292 bool match(const Version &toCheck) const
293 {
294 VERBOSE("\t\t\t Within Version %d,%d,%d,%d match(%d,%d,%d,%d): wildcards are %s and %s,\n",
295 mMajor.mPart, mMinor.mPart, mSubminor.mPart, mPatch.mPart, toCheck.mMajor.mPart,
296 toCheck.mMinor.mPart, toCheck.mSubminor.mPart, toCheck.mPatch.mPart,
297 mWildcard ? "true" : "false", toCheck.mWildcard ? "true" : "false");
298 if (!(mWildcard || toCheck.mWildcard))
299 {
300 VERBOSE("\t\t\t mMajor match is %s, mMinor is %s, mSubminor is %s, mPatch is %s\n",
301 mMajor.match(toCheck.mMajor) ? "true" : "false",
302 mMinor.match(toCheck.mMinor) ? "true" : "false",
303 mSubminor.match(toCheck.mSubminor) ? "true" : "false",
304 mPatch.match(toCheck.mPatch) ? "true" : "false");
305 }
306 return (mWildcard || toCheck.mWildcard ||
307 (mMajor.match(toCheck.mMajor) && mMinor.match(toCheck.mMinor) &&
308 mSubminor.match(toCheck.mSubminor) && mPatch.match(toCheck.mPatch)));
309 }
getString() const310 std::string getString() const
311 {
312 if (mWildcard)
313 {
314 return "*";
315 }
316 else
317 {
318 char ret[100];
319 // Must at least have a major version:
320 if (!mMinor.mWildcard)
321 {
322 if (!mSubminor.mWildcard)
323 {
324 if (!mPatch.mWildcard)
325 {
326 snprintf(ret, 100, "%d.%d.%d.%d", mMajor.mPart, mMinor.mPart,
327 mSubminor.mPart, mPatch.mPart);
328 }
329 else
330 {
331 snprintf(ret, 100, "%d.%d.%d.*", mMajor.mPart, mMinor.mPart,
332 mSubminor.mPart);
333 }
334 }
335 else
336 {
337 snprintf(ret, 100, "%d.%d.*", mMajor.mPart, mMinor.mPart);
338 }
339 }
340 else
341 {
342 snprintf(ret, 100, "%d.*", mMajor.mPart);
343 }
344 std::string retString = ret;
345 return retString;
346 }
347 }
348
349 public:
350 IntegerPart mMajor;
351 IntegerPart mMinor;
352 IntegerPart mSubminor;
353 IntegerPart mPatch;
354 bool mWildcard;
355 };
356
357 // This encapsulates an application, and potentially the application's Version. The default
358 // constructor (not given any values) assumes that this is a wildcard (i.e. will match all
359 // other Application objects). Each part of an Application is stored in a class that may
360 // also be wildcarded.
361 class Application
362 {
363 public:
Application(const std::string name,const Version & version)364 Application(const std::string name, const Version &version)
365 : mName(name), mVersion(version), mWildcard(false)
366 {}
Application(const std::string name)367 Application(const std::string name) : mName(name), mVersion(), mWildcard(false) {}
Application()368 Application() : mName(), mVersion(), mWildcard(true) {}
~Application()369 ~Application() {}
370
CreateApplicationFromJson(const Json::Value & jObject)371 static Application *CreateApplicationFromJson(const Json::Value &jObject)
372 {
373 Application *application = nullptr;
374
375 // If an application is listed, the application's name is required:
376 std::string appName = jObject[kJsonAppName].asString();
377
378 // The application's version is optional:
379 Version *version = Version::CreateVersionFromJson(jObject);
380 if (version)
381 {
382 application = new Application(appName, *version);
383 delete version;
384 }
385 else
386 {
387 application = new Application(appName);
388 }
389 return application;
390 }
391
match(const Application & toCheck) const392 bool match(const Application &toCheck) const
393 {
394 return (mWildcard || toCheck.mWildcard ||
395 (toCheck.mName.match(mName) && toCheck.mVersion.match(mVersion)));
396 }
logItem() const397 void logItem() const
398 {
399 if (mWildcard)
400 {
401 VERBOSE(" Wildcard (i.e. will match all applications)");
402 }
403 else if (!mVersion.mWildcard)
404 {
405 VERBOSE(" Application \"%s\" (version: %s)", mName.mPart.c_str(),
406 mVersion.getString().c_str());
407 }
408 else
409 {
410 VERBOSE(" Application \"%s\"", mName.mPart.c_str());
411 }
412 }
413
414 public:
415 StringPart mName;
416 Version mVersion;
417 bool mWildcard;
418 };
419
420 // This encapsulates a GPU and its driver. The default constructor (not given any values) assumes
421 // that this is a wildcard (i.e. will match all other GPU objects). Each part of a GPU is stored
422 // in a class that may also be wildcarded.
423 class GPU
424 {
425 public:
GPU(const std::string vendor,uint32_t deviceId,const Version & version)426 GPU(const std::string vendor, uint32_t deviceId, const Version &version)
427 : mVendor(vendor), mDeviceId(IntegerPart(deviceId)), mVersion(version), mWildcard(false)
428 {}
GPU(const std::string vendor,uint32_t deviceId)429 GPU(const std::string vendor, uint32_t deviceId)
430 : mVendor(vendor), mDeviceId(IntegerPart(deviceId)), mVersion(), mWildcard(false)
431 {}
GPU(const std::string vendor)432 GPU(const std::string vendor) : mVendor(vendor), mDeviceId(), mVersion(), mWildcard(false) {}
GPU()433 GPU() : mVendor(), mDeviceId(), mVersion(), mWildcard(true) {}
match(const GPU & toCheck) const434 bool match(const GPU &toCheck) const
435 {
436 VERBOSE("\t\t Within GPU match: wildcards are %s and %s,\n", mWildcard ? "true" : "false",
437 toCheck.mWildcard ? "true" : "false");
438 VERBOSE("\t\t mVendor = \"%s\" and toCheck.mVendor = \"%s\"\n", mVendor.mPart.c_str(),
439 toCheck.mVendor.mPart.c_str());
440 VERBOSE("\t\t mDeviceId = %d and toCheck.mDeviceId = %d\n", mDeviceId.mPart,
441 toCheck.mDeviceId.mPart);
442 VERBOSE("\t\t mVendor match is %s, mDeviceId is %s, mVersion is %s\n",
443 toCheck.mVendor.match(mVendor) ? "true" : "false",
444 toCheck.mDeviceId.match(mDeviceId) ? "true" : "false",
445 toCheck.mVersion.match(mVersion) ? "true" : "false");
446 return (mWildcard || toCheck.mWildcard ||
447 (toCheck.mVendor.match(mVendor) && toCheck.mDeviceId.match(mDeviceId) &&
448 toCheck.mVersion.match(mVersion)));
449 }
~GPU()450 ~GPU() {}
451
CreateGpuFromJson(const Json::Value & jObject)452 static GPU *CreateGpuFromJson(const Json::Value &jObject)
453 {
454 GPU *gpu = nullptr;
455
456 // If a GPU is listed, the vendor name is required:
457 if (jObject.isMember(kJsonVendor) && jObject[kJsonVendor].isString())
458 {
459 std::string vendor = jObject[kJsonVendor].asString();
460 // If a version is given, the deviceId is required:
461 if (jObject.isMember(kJsonDeviceId) && jObject[kJsonDeviceId].isUInt())
462 {
463 uint32_t deviceId = jObject[kJsonDeviceId].asUInt();
464 Version *version = Version::CreateVersionFromJson(jObject);
465 if (version)
466 {
467 gpu = new GPU(vendor, deviceId, *version);
468 delete version;
469 }
470 else
471 {
472 gpu = new GPU(vendor, deviceId);
473 }
474 }
475 else
476 {
477 gpu = new GPU(vendor);
478 }
479 }
480 else
481 {
482 WARN("Asked to parse a GPU, but no vendor found");
483 }
484
485 return gpu;
486 }
487
logItem() const488 void logItem() const
489 {
490 if (mWildcard)
491 {
492 VERBOSE(" Wildcard (i.e. will match all GPUs)");
493 }
494 else
495 {
496 if (!mDeviceId.mWildcard)
497 {
498 if (!mVersion.mWildcard)
499 {
500 VERBOSE("\t GPU vendor: %s, deviceId: 0x%x, version: %s",
501 mVendor.mPart.c_str(), mDeviceId.mPart, mVersion.getString().c_str());
502 }
503 else
504 {
505 VERBOSE("\t GPU vendor: %s, deviceId: 0x%x", mVendor.mPart.c_str(),
506 mDeviceId.mPart);
507 }
508 }
509 else
510 {
511 VERBOSE("\t GPU vendor: %s", mVendor.mPart.c_str());
512 }
513 }
514 }
515
516 public:
517 StringPart mVendor;
518 IntegerPart mDeviceId;
519 Version mVersion;
520 bool mWildcard;
521 };
522
523 // This encapsulates a device, and potentially the device's model and/or a list of GPUs/drivers
524 // associated with the Device. The default constructor (not given any values) assumes that this is
525 // a wildcard (i.e. will match all other Device objects). Each part of a Device is stored in a
526 // class that may also be wildcarded.
527 class Device
528 {
529 public:
Device(const std::string manufacturer,const std::string model)530 Device(const std::string manufacturer, const std::string model)
531 : mManufacturer(manufacturer), mModel(model), mGpuList("GPU"), mWildcard(false)
532 {}
Device(const std::string manufacturer)533 Device(const std::string manufacturer)
534 : mManufacturer(manufacturer), mModel(), mGpuList("GPU"), mWildcard(false)
535 {}
Device()536 Device() : mManufacturer(), mModel(), mGpuList("GPU"), mWildcard(true) {}
~Device()537 ~Device() {}
538
CreateDeviceFromJson(const Json::Value & jObject)539 static Device *CreateDeviceFromJson(const Json::Value &jObject)
540 {
541 Device *device = nullptr;
542 if (jObject.isMember(kJsonManufacturer) && jObject[kJsonManufacturer].isString())
543 {
544 std::string manufacturerName = jObject[kJsonManufacturer].asString();
545 // We don't let a model be specified without also specifying an Manufacturer:
546 if (jObject.isMember(kJsonModel) && jObject[kJsonModel].isString())
547 {
548 std::string model = jObject[kJsonModel].asString();
549 device = new Device(manufacturerName, model);
550 }
551 else
552 {
553 device = new Device(manufacturerName);
554 }
555 }
556 else
557 {
558 // This case is not treated as an error because a rule may wish to only call out one or
559 // more GPUs, but not any specific Manufacturer (e.g. for any manufacturer's device
560 // that uses a GPU from Vendor-A, with DeviceID-Foo, and with driver version 1.2.3.4):
561 device = new Device();
562 }
563 return device;
564 }
565
addGPU(const GPU & gpu)566 void addGPU(const GPU &gpu) { mGpuList.addItem(gpu); }
match(const Device & toCheck) const567 bool match(const Device &toCheck) const
568 {
569 VERBOSE("\t Within Device match: wildcards are %s and %s,\n", mWildcard ? "true" : "false",
570 toCheck.mWildcard ? "true" : "false");
571 if (!(mWildcard || toCheck.mWildcard))
572 {
573 VERBOSE("\t Manufacturer match is %s, model is %s\n",
574 toCheck.mManufacturer.match(mManufacturer) ? "true" : "false",
575 toCheck.mModel.match(mModel) ? "true" : "false");
576 }
577 VERBOSE("\t Need to check ListOf<GPU>\n");
578 return ((mWildcard || toCheck.mWildcard ||
579 // The wildcards can override the Manufacturer/Model check, but not the GPU check
580 (toCheck.mManufacturer.match(mManufacturer) && toCheck.mModel.match(mModel))) &&
581 mGpuList.match(toCheck.mGpuList));
582 }
logItem() const583 void logItem() const
584 {
585 if (mWildcard)
586 {
587 if (mGpuList.mWildcard)
588 {
589 VERBOSE(" Wildcard (i.e. will match all devices)");
590 return;
591 }
592 else
593 {
594 VERBOSE(
595 " Device with any manufacturer and model"
596 ", and with the following GPUs:");
597 }
598 }
599 else
600 {
601 if (!mModel.mWildcard)
602 {
603 VERBOSE(
604 " Device manufacturer: \"%s\" and model \"%s\""
605 ", and with the following GPUs:",
606 mManufacturer.mPart.c_str(), mModel.mPart.c_str());
607 }
608 else
609 {
610 VERBOSE(
611 " Device manufacturer: \"%s\""
612 ", and with the following GPUs:",
613 mManufacturer.mPart.c_str());
614 }
615 }
616 mGpuList.logListOf(" ", "GPUs");
617 }
618
619 public:
620 StringPart mManufacturer;
621 StringPart mModel;
622 ListOf<GPU> mGpuList;
623 bool mWildcard;
624 };
625
626 // This encapsulates a particular scenario to check against the rules. A Scenario is similar to a
627 // Rule, except that a Rule has an answer and potentially many wildcards, and a Scenario is the
628 // fully-specified combination of an Application and a Device that is proposed to be run with
629 // ANGLE. It is compared with the list of Rules.
630 class Scenario
631 {
632 public:
Scenario(const char * appName,const char * deviceMfr,const char * deviceModel)633 Scenario(const char *appName, const char *deviceMfr, const char *deviceModel)
634 : mApplication(Application(appName)), mDevice(Device(deviceMfr, deviceModel))
635 {}
~Scenario()636 ~Scenario() {}
logScenario()637 void logScenario()
638 {
639 VERBOSE(" Scenario to compare against the rules");
640 VERBOSE(" Application:");
641 mApplication.logItem();
642 VERBOSE(" Device:");
643 mDevice.logItem();
644 }
645
646 public:
647 Application mApplication;
648 Device mDevice;
649 };
650
651 // This encapsulates a Rule that provides an answer based on whether a particular Scenario matches
652 // the Rule. A Rule always has an answer, but can potentially wildcard every item in it (i.e.
653 // match every scenario).
654 class Rule
655 {
656 public:
Rule(const std::string description,bool useANGLE)657 Rule(const std::string description, bool useANGLE)
658 : mDescription(description),
659 mAppList("Application"),
660 mDevList("Device"),
661 mUseANGLE(useANGLE)
662 {}
~Rule()663 ~Rule() {}
addApp(const Application & app)664 void addApp(const Application &app) { mAppList.addItem(app); }
addDevice(const Device & dev)665 void addDevice(const Device &dev) { mDevList.addItem(dev); }
match(const Scenario & toCheck) const666 bool match(const Scenario &toCheck) const
667 {
668 VERBOSE(" Within \"%s\" Rule: application match is %s and device match is %s\n",
669 mDescription.c_str(), mAppList.match(toCheck.mApplication) ? "true" : "false",
670 mDevList.match(toCheck.mDevice) ? "true" : "false");
671 return (mAppList.match(toCheck.mApplication) && mDevList.match(toCheck.mDevice));
672 }
getUseANGLE() const673 bool getUseANGLE() const { return mUseANGLE; }
logRule() const674 void logRule() const
675 {
676 VERBOSE(" Rule: \"%s\" %s ANGLE", mDescription.c_str(),
677 mUseANGLE ? "enables" : "disables");
678 mAppList.logListOf(" ", "Applications");
679 mDevList.logListOf(" ", "Devices");
680 }
681
682 std::string mDescription;
683 ListOf<Application> mAppList;
684 ListOf<Device> mDevList;
685 bool mUseANGLE;
686 };
687
688 // This encapsulates a list of Rules that Scenarios are matched against. A Scenario is compared
689 // with each Rule, in order. Any time a Scenario matches a Rule, the current answer is overridden
690 // with the answer of the matched Rule.
691 class RuleList
692 {
693 public:
RuleList()694 RuleList() {}
~RuleList()695 ~RuleList() { mRuleList.clear(); }
696
ReadRulesFromJsonString(const std::string jsonFileContents)697 static RuleList *ReadRulesFromJsonString(const std::string jsonFileContents)
698 {
699 RuleList *rules = new RuleList;
700
701 // Open the file and start parsing it:
702 Json::Reader jReader;
703 Json::Value jTopLevelObject;
704 jReader.parse(jsonFileContents, jTopLevelObject);
705 Json::Value jRules = jTopLevelObject[kJsonRules];
706 for (unsigned int ruleIndex = 0; ruleIndex < jRules.size(); ruleIndex++)
707 {
708 Json::Value jRule = jRules[ruleIndex];
709 std::string ruleDescription = jRule[kJsonRule].asString();
710 bool useANGLE = jRule[kJsonUseANGLE].asBool();
711 Rule *newRule = new Rule(ruleDescription, useANGLE);
712
713 Json::Value jApps = jRule[kJsonApplications];
714 for (unsigned int appIndex = 0; appIndex < jApps.size(); appIndex++)
715 {
716 Json::Value jApp = jApps[appIndex];
717 Application *newApp = Application::CreateApplicationFromJson(jApp);
718 newRule->addApp(*newApp);
719 delete newApp;
720 }
721
722 Json::Value jDevs = jRule[kJsonDevices];
723 for (unsigned int deviceIndex = 0; deviceIndex < jDevs.size(); deviceIndex++)
724 {
725 Json::Value jDev = jDevs[deviceIndex];
726 Device *newDev = Device::CreateDeviceFromJson(jDev);
727
728 Json::Value jGPUs = jDev[kJsonGPUs];
729 for (unsigned int gpuIndex = 0; gpuIndex < jGPUs.size(); gpuIndex++)
730 {
731 Json::Value jGPU = jGPUs[gpuIndex];
732 GPU *newGPU = GPU::CreateGpuFromJson(jGPU);
733 if (newGPU)
734 {
735 newDev->addGPU(*newGPU);
736 delete newGPU;
737 }
738 }
739 newRule->addDevice(*newDev);
740 delete newDev;
741 }
742
743 rules->addRule(*newRule);
744 delete newRule;
745 }
746
747 // Make sure there is at least one, default rule. If not, add it here:
748 if (rules->mRuleList.size() == 0)
749 {
750 Rule defaultRule("Default Rule", false);
751 rules->addRule(defaultRule);
752 }
753 return rules;
754 }
755
addRule(const Rule & rule)756 void addRule(const Rule &rule) { mRuleList.push_back(rule); }
getUseANGLE(const Scenario & toCheck)757 bool getUseANGLE(const Scenario &toCheck)
758 {
759 // Initialize useANGLE to the system-wide default (that should be set in the default
760 // rule, but just in case, set it here too):
761 bool useANGLE = false;
762 VERBOSE("Checking scenario against %d ANGLE-for-Android rules:",
763 static_cast<int>(mRuleList.size()));
764
765 for (const Rule &rule : mRuleList)
766 {
767 VERBOSE(" Checking Rule: \"%s\" (to see whether there's a match)",
768 rule.mDescription.c_str());
769 if (rule.match(toCheck))
770 {
771 VERBOSE(" -> Rule matches. Setting useANGLE to %s",
772 rule.getUseANGLE() ? "true" : "false");
773 useANGLE = rule.getUseANGLE();
774 }
775 else
776 {
777 VERBOSE(" -> Rule doesn't match.");
778 }
779 }
780
781 return useANGLE;
782 }
logRules()783 void logRules()
784 {
785 VERBOSE("Showing %d ANGLE-for-Android rules:", static_cast<int>(mRuleList.size()));
786 for (const Rule &rule : mRuleList)
787 {
788 rule.logRule();
789 }
790 }
791
792 public:
793 std::vector<Rule> mRuleList;
794 };
795
796 } // namespace angle
797
798 extern "C" {
799
800 using namespace angle;
801
802 // This function is part of the version-2 API:
ANGLEGetFeatureSupportUtilAPIVersion(unsigned int * versionToUse)803 ANGLE_EXPORT bool ANGLEGetFeatureSupportUtilAPIVersion(unsigned int *versionToUse)
804 {
805 if (!versionToUse || (*versionToUse < kFeatureVersion_LowestSupported))
806 {
807 // The versionToUse is either nullptr or is less than the lowest version supported, which
808 // is an error.
809 return false;
810 }
811 if (*versionToUse > kFeatureVersion_HighestSupported)
812 {
813 // The versionToUse is greater than the highest version supported; change it to the
814 // highest version supported (caller will decide if it can use that version).
815 *versionToUse = kFeatureVersion_HighestSupported;
816 }
817 return true;
818 }
819
820 // This function is part of the version-2 API:
ANGLEAndroidParseRulesString(const char * rulesString,RulesHandle * rulesHandle,int * rulesVersion)821 ANGLE_EXPORT bool ANGLEAndroidParseRulesString(const char *rulesString,
822 RulesHandle *rulesHandle,
823 int *rulesVersion)
824 {
825 if (!rulesString || !rulesHandle || !rulesVersion)
826 {
827 return false;
828 }
829
830 std::string rulesFileContents = rulesString;
831 RuleList *rules = RuleList::ReadRulesFromJsonString(rulesFileContents);
832 rules->logRules();
833
834 *rulesHandle = rules;
835 *rulesVersion = 0;
836 return true;
837 }
838
839 // This function is part of the version-2 API:
ANGLEGetSystemInfo(SystemInfoHandle * systemInfoHandle)840 ANGLE_EXPORT bool ANGLEGetSystemInfo(SystemInfoHandle *systemInfoHandle)
841 {
842 if (!systemInfoHandle)
843 {
844 return false;
845 }
846
847 // TODO (http://anglebug.com/3036): Restore the real code
848 angle::SystemInfo *systemInfo = new angle::SystemInfo;
849 systemInfo->gpus.resize(1);
850 GPUDeviceInfo &gpu = systemInfo->gpus[0];
851 gpu.vendorId = 0xFEFEFEFE;
852 gpu.deviceId = 0xFEEEFEEE;
853 gpu.driverVendor = "Foo";
854 gpu.driverVersion = "1.2.3.4";
855
856 *systemInfoHandle = systemInfo;
857 return true;
858 }
859
860 // This function is part of the version-2 API:
ANGLEAddDeviceInfoToSystemInfo(const char * deviceMfr,const char * deviceModel,SystemInfoHandle systemInfoHandle)861 ANGLE_EXPORT bool ANGLEAddDeviceInfoToSystemInfo(const char *deviceMfr,
862 const char *deviceModel,
863 SystemInfoHandle systemInfoHandle)
864 {
865 angle::SystemInfo *systemInfo = static_cast<angle::SystemInfo *>(systemInfoHandle);
866 if (!deviceMfr || !deviceModel || !systemInfo)
867 {
868 return false;
869 }
870
871 systemInfo->machineManufacturer = deviceMfr;
872 systemInfo->machineModelName = deviceModel;
873 return true;
874 }
875
876 // This function is part of the version-2 API:
ANGLEShouldBeUsedForApplication(const RulesHandle rulesHandle,int rulesVersion,const SystemInfoHandle systemInfoHandle,const char * appName)877 ANGLE_EXPORT bool ANGLEShouldBeUsedForApplication(const RulesHandle rulesHandle,
878 int rulesVersion,
879 const SystemInfoHandle systemInfoHandle,
880 const char *appName)
881 {
882 RuleList *rules = static_cast<RuleList *>(rulesHandle);
883 angle::SystemInfo *systemInfo = static_cast<angle::SystemInfo *>(systemInfoHandle);
884 if (!rules || !systemInfo || !appName || (systemInfo->gpus.size() != 1))
885 {
886 return false;
887 }
888
889 Scenario scenario(appName, systemInfo->machineManufacturer.c_str(),
890 systemInfo->machineModelName.c_str());
891 Version gpuDriverVersion(systemInfo->gpus[0].detailedDriverVersion.major,
892 systemInfo->gpus[0].detailedDriverVersion.minor,
893 systemInfo->gpus[0].detailedDriverVersion.subMinor,
894 systemInfo->gpus[0].detailedDriverVersion.patch);
895 GPU gpuDriver(systemInfo->gpus[0].driverVendor, systemInfo->gpus[0].deviceId, gpuDriverVersion);
896 scenario.mDevice.addGPU(gpuDriver);
897 scenario.logScenario();
898
899 bool rtn = rules->getUseANGLE(scenario);
900 VERBOSE("Application \"%s\" should %s ANGLE", appName, rtn ? "use" : "NOT use");
901
902 return rtn;
903 }
904
905 // This function is part of the version-2 API:
ANGLEFreeRulesHandle(const RulesHandle rulesHandle)906 ANGLE_EXPORT void ANGLEFreeRulesHandle(const RulesHandle rulesHandle)
907 {
908 RuleList *rules = static_cast<RuleList *>(rulesHandle);
909 if (rules)
910 {
911 delete rules;
912 }
913 }
914
915 // This function is part of the version-2 API:
ANGLEFreeSystemInfoHandle(const SystemInfoHandle systemInfoHandle)916 ANGLE_EXPORT void ANGLEFreeSystemInfoHandle(const SystemInfoHandle systemInfoHandle)
917 {
918 angle::SystemInfo *systemInfo = static_cast<angle::SystemInfo *>(systemInfoHandle);
919 if (systemInfo)
920 {
921 delete systemInfo;
922 }
923 }
924
925 } // extern "C"
926