xref: /aosp_15_r20/external/angle/src/feature_support_util/feature_support_util.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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