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