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