Hash :
db08edce
Author :
Date :
2019-09-24T08:42:39
Reduce logging in feature_support_util. The very verbose logging was making the unit test output too much. Disable verbose logging by default. Bug: angleproject:3162 Change-Id: I1b675877c314573749c9808684bab0c60f7d6127 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1821937 Reviewed-by: Ian Elliott <ianelliott@google.com> Commit-Queue: Jamie Madill <jmadill@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 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
//
// 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 <list>
#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() : mPart(""), mWildcard(true) {}
StringPart(const std::string part) : mPart(part), mWildcard(false) {}
~StringPart() {}
bool match(const StringPart &toCheck) const
{
return (mWildcard || toCheck.mWildcard || (toCheck.mPart == mPart));
}
public:
std::string mPart;
bool mWildcard;
};
// 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() : mPart(0), mWildcard(true) {}
IntegerPart(uint32_t part) : mPart(part), mWildcard(false) {}
~IntegerPart() {}
bool match(const IntegerPart &toCheck) const
{
return (mWildcard || toCheck.mWildcard || (toCheck.mPart == mPart));
}
public:
uint32_t mPart;
bool mWildcard;
};
// 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:
ListOf(const std::string listType) : mWildcard(true), mListType(listType) {}
~ListOf() { mList.clear(); }
void addItem(const T &toAdd)
{
mList.push_back(toAdd);
mWildcard = false;
}
bool match(const T &toCheck) const
{
VERBOSE("\t\t Within ListOf<%s> match: wildcards are %s and %s,\n", mListType.c_str(),
mWildcard ? "true" : "false", toCheck.mWildcard ? "true" : "false");
if (mWildcard || toCheck.mWildcard)
{
return true;
}
for (const T &it : mList)
{
VERBOSE("\t\t Within ListOf<%s> match: calling match on sub-item is %s,\n",
mListType.c_str(), it.match(toCheck) ? "true" : "false");
if (it.match(toCheck))
{
return true;
}
}
return false;
}
bool match(const ListOf<T> &toCheck) const
{
VERBOSE("\t\t Within ListOf<%s> match: wildcards are %s and %s,\n", mListType.c_str(),
mWildcard ? "true" : "false", toCheck.mWildcard ? "true" : "false");
if (mWildcard || toCheck.mWildcard)
{
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))
{
return true;
}
}
return false;
}
void logListOf(const std::string prefix, const std::string name) const
{
if (mWildcard)
{
VERBOSE("%sListOf%s is wildcarded to always match", prefix.c_str(), name.c_str());
}
else
{
VERBOSE("%sListOf%s has %d item(s):", 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), mWildcard(false)
{}
Version(uint32_t major, uint32_t minor, uint32_t subminor)
: mMajor(major), mMinor(minor), mSubminor(subminor), mWildcard(false)
{}
Version(uint32_t major, uint32_t minor) : mMajor(major), mMinor(minor), mWildcard(false) {}
Version(uint32_t major) : mMajor(major), mWildcard(false) {}
Version() : mWildcard(true) {}
Version(const Version &toCopy)
: mMajor(toCopy.mMajor),
mMinor(toCopy.mMinor),
mSubminor(toCopy.mSubminor),
mPatch(toCopy.mPatch),
mWildcard(toCopy.mWildcard)
{}
~Version() {}
static Version *CreateVersionFromJson(const Json::Value &jObject)
{
Version *version = nullptr;
// A major version must be provided before a minor, and so on:
if (jObject.isMember(kJsonVerMajor) && jObject[kJsonVerMajor].isInt())
{
int major = jObject[kJsonVerMajor].asInt();
if (jObject.isMember(kJsonVerMinor) && jObject[kJsonVerMinor].isInt())
{
int minor = jObject[kJsonVerMinor].asInt();
if (jObject.isMember(kJsonVerSubMinor) && jObject[kJsonVerSubMinor].isInt())
{
int subMinor = jObject[kJsonVerSubMinor].asInt();
if (jObject.isMember(kJsonVerPatch) && jObject[kJsonVerPatch].isInt())
{
int patch = jObject[kJsonVerPatch].asInt();
version = new Version(major, minor, subMinor, patch);
}
else
{
version = new Version(major, minor, subMinor);
}
}
else
{
version = new Version(major, minor);
}
}
else
{
version = new Version(major);
}
}
return version;
}
bool match(const Version &toCheck) const
{
VERBOSE("\t\t\t Within Version %d,%d,%d,%d match(%d,%d,%d,%d): wildcards are %s and %s,\n",
mMajor.mPart, mMinor.mPart, mSubminor.mPart, mPatch.mPart, toCheck.mMajor.mPart,
toCheck.mMinor.mPart, toCheck.mSubminor.mPart, toCheck.mPatch.mPart,
mWildcard ? "true" : "false", toCheck.mWildcard ? "true" : "false");
if (!(mWildcard || toCheck.mWildcard))
{
VERBOSE("\t\t\t mMajor match is %s, mMinor is %s, mSubminor is %s, mPatch is %s\n",
mMajor.match(toCheck.mMajor) ? "true" : "false",
mMinor.match(toCheck.mMinor) ? "true" : "false",
mSubminor.match(toCheck.mSubminor) ? "true" : "false",
mPatch.match(toCheck.mPatch) ? "true" : "false");
}
return (mWildcard || toCheck.mWildcard ||
(mMajor.match(toCheck.mMajor) && mMinor.match(toCheck.mMinor) &&
mSubminor.match(toCheck.mSubminor) && mPatch.match(toCheck.mPatch)));
}
std::string getString() const
{
if (mWildcard)
{
return "*";
}
else
{
char ret[100];
// Must at least have a major version:
if (!mMinor.mWildcard)
{
if (!mSubminor.mWildcard)
{
if (!mPatch.mWildcard)
{
snprintf(ret, 100, "%d.%d.%d.%d", mMajor.mPart, mMinor.mPart,
mSubminor.mPart, mPatch.mPart);
}
else
{
snprintf(ret, 100, "%d.%d.%d.*", mMajor.mPart, mMinor.mPart,
mSubminor.mPart);
}
}
else
{
snprintf(ret, 100, "%d.%d.*", mMajor.mPart, mMinor.mPart);
}
}
else
{
snprintf(ret, 100, "%d.*", mMajor.mPart);
}
std::string retString = ret;
return retString;
}
}
public:
IntegerPart mMajor;
IntegerPart mMinor;
IntegerPart mSubminor;
IntegerPart mPatch;
bool mWildcard;
};
// 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(const std::string name, const Version &version)
: mName(name), mVersion(version), mWildcard(false)
{}
Application(const std::string name) : mName(name), mVersion(), mWildcard(false) {}
Application() : mName(), mVersion(), mWildcard(true) {}
~Application() {}
static Application *CreateApplicationFromJson(const Json::Value &jObject)
{
Application *application = nullptr;
// If an application is listed, the application's name is required:
std::string appName = jObject[kJsonAppName].asString();
// The application's version is optional:
Version *version = Version::CreateVersionFromJson(jObject);
if (version)
{
application = new Application(appName, *version);
delete version;
}
else
{
application = new Application(appName);
}
return application;
}
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)");
}
else if (!mVersion.mWildcard)
{
VERBOSE(" Application \"%s\" (version: %s)", mName.mPart.c_str(),
mVersion.getString().c_str());
}
else
{
VERBOSE(" Application \"%s\"", mName.mPart.c_str());
}
}
public:
StringPart mName;
Version mVersion;
bool mWildcard;
};
// 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(const std::string vendor, uint32_t deviceId, const Version &version)
: mVendor(vendor), mDeviceId(IntegerPart(deviceId)), mVersion(version), mWildcard(false)
{}
GPU(const std::string vendor, uint32_t deviceId)
: mVendor(vendor), mDeviceId(IntegerPart(deviceId)), mVersion(), mWildcard(false)
{}
GPU(const std::string vendor) : mVendor(vendor), mDeviceId(), mVersion(), mWildcard(false) {}
GPU() : mVendor(), mDeviceId(), mVersion(), mWildcard(true) {}
bool match(const GPU &toCheck) const
{
VERBOSE("\t\t Within GPU match: wildcards are %s and %s,\n", mWildcard ? "true" : "false",
toCheck.mWildcard ? "true" : "false");
VERBOSE("\t\t mVendor = \"%s\" and toCheck.mVendor = \"%s\"\n", mVendor.mPart.c_str(),
toCheck.mVendor.mPart.c_str());
VERBOSE("\t\t mDeviceId = %d and toCheck.mDeviceId = %d\n", mDeviceId.mPart,
toCheck.mDeviceId.mPart);
VERBOSE("\t\t mVendor match is %s, mDeviceId is %s, mVersion is %s\n",
toCheck.mVendor.match(mVendor) ? "true" : "false",
toCheck.mDeviceId.match(mDeviceId) ? "true" : "false",
toCheck.mVersion.match(mVersion) ? "true" : "false");
return (mWildcard || toCheck.mWildcard ||
(toCheck.mVendor.match(mVendor) && toCheck.mDeviceId.match(mDeviceId) &&
toCheck.mVersion.match(mVersion)));
}
~GPU() {}
static GPU *CreateGpuFromJson(const Json::Value &jObject)
{
GPU *gpu = nullptr;
// If a GPU is listed, the vendor name is required:
if (jObject.isMember(kJsonVendor) && jObject[kJsonVendor].isString())
{
std::string vendor = jObject[kJsonVendor].asString();
// If a version is given, the deviceId is required:
if (jObject.isMember(kJsonDeviceId) && jObject[kJsonDeviceId].isUInt())
{
uint32_t deviceId = jObject[kJsonDeviceId].asUInt();
Version *version = Version::CreateVersionFromJson(jObject);
if (version)
{
gpu = new GPU(vendor, deviceId, *version);
delete version;
}
else
{
gpu = new GPU(vendor, deviceId);
}
}
else
{
gpu = new GPU(vendor);
}
}
else
{
WARN("Asked to parse a GPU, but no vendor found");
}
return gpu;
}
void logItem() const
{
if (mWildcard)
{
VERBOSE(" Wildcard (i.e. will match all GPUs)");
}
else
{
if (!mDeviceId.mWildcard)
{
if (!mVersion.mWildcard)
{
VERBOSE("\t GPU vendor: %s, deviceId: 0x%x, version: %s",
mVendor.mPart.c_str(), mDeviceId.mPart, mVersion.getString().c_str());
}
else
{
VERBOSE("\t GPU vendor: %s, deviceId: 0x%x", mVendor.mPart.c_str(),
mDeviceId.mPart);
}
}
else
{
VERBOSE("\t GPU vendor: %s", mVendor.mPart.c_str());
}
}
}
public:
StringPart mVendor;
IntegerPart mDeviceId;
Version mVersion;
bool mWildcard;
};
// 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(const std::string manufacturer, const std::string model)
: mManufacturer(manufacturer), mModel(model), mGpuList("GPU"), mWildcard(false)
{}
Device(const std::string manufacturer)
: mManufacturer(manufacturer), mModel(), mGpuList("GPU"), mWildcard(false)
{}
Device() : mManufacturer(), mModel(), mGpuList("GPU"), mWildcard(true) {}
~Device() {}
static Device *CreateDeviceFromJson(const Json::Value &jObject)
{
Device *device = nullptr;
if (jObject.isMember(kJsonManufacturer) && jObject[kJsonManufacturer].isString())
{
std::string manufacturerName = jObject[kJsonManufacturer].asString();
// We don't let a model be specified without also specifying an Manufacturer:
if (jObject.isMember(kJsonModel) && jObject[kJsonModel].isString())
{
std::string model = jObject[kJsonModel].asString();
device = new Device(manufacturerName, model);
}
else
{
device = new Device(manufacturerName);
}
}
else
{
// 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):
device = new Device();
}
return device;
}
void addGPU(const GPU &gpu) { mGpuList.addItem(gpu); }
bool match(const Device &toCheck) const
{
VERBOSE("\t Within Device match: wildcards are %s and %s,\n", mWildcard ? "true" : "false",
toCheck.mWildcard ? "true" : "false");
if (!(mWildcard || toCheck.mWildcard))
{
VERBOSE("\t Manufacturer match is %s, model is %s\n",
toCheck.mManufacturer.match(mManufacturer) ? "true" : "false",
toCheck.mModel.match(mModel) ? "true" : "false");
}
VERBOSE("\t Need to check ListOf<GPU>\n");
return ((mWildcard || toCheck.mWildcard ||
// The wildcards can override the Manufacturer/Model check, but not the GPU check
(toCheck.mManufacturer.match(mManufacturer) && toCheck.mModel.match(mModel))) &&
mGpuList.match(toCheck.mGpuList));
}
void logItem() const
{
if (mWildcard)
{
if (mGpuList.mWildcard)
{
VERBOSE(" Wildcard (i.e. will match all devices)");
return;
}
else
{
VERBOSE(
" Device with any manufacturer and model"
", and with the following GPUs:");
}
}
else
{
if (!mModel.mWildcard)
{
VERBOSE(
" Device manufacturer: \"%s\" and model \"%s\""
", and with the following GPUs:",
mManufacturer.mPart.c_str(), mModel.mPart.c_str());
}
else
{
VERBOSE(
" Device manufacturer: \"%s\""
", and with the following GPUs:",
mManufacturer.mPart.c_str());
}
}
mGpuList.logListOf(" ", "GPUs");
}
public:
StringPart mManufacturer;
StringPart mModel;
ListOf<GPU> mGpuList;
bool mWildcard;
};
// 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(appName)), mDevice(Device(deviceMfr, deviceModel))
{}
~Scenario() {}
void logScenario()
{
VERBOSE(" Scenario to compare against the rules");
VERBOSE(" Application:");
mApplication.logItem();
VERBOSE(" Device:");
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() {}
void addApp(const Application &app) { mAppList.addItem(app); }
void addDevice(const Device &dev) { mDevList.addItem(dev); }
bool match(const Scenario &toCheck) const
{
VERBOSE(" Within \"%s\" Rule: application match is %s and device match is %s\n",
mDescription.c_str(), mAppList.match(toCheck.mApplication) ? "true" : "false",
mDevList.match(toCheck.mDevice) ? "true" : "false");
return (mAppList.match(toCheck.mApplication) && mDevList.match(toCheck.mDevice));
}
bool getUseANGLE() const { return mUseANGLE; }
void logRule() const
{
VERBOSE(" Rule: \"%s\" %s ANGLE", 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::Reader jReader;
Json::Value jTopLevelObject;
jReader.parse(jsonFileContents, jTopLevelObject);
Json::Value jRules = jTopLevelObject[kJsonRules];
for (unsigned int ruleIndex = 0; ruleIndex < jRules.size(); ruleIndex++)
{
Json::Value jRule = jRules[ruleIndex];
std::string ruleDescription = jRule[kJsonRule].asString();
bool useANGLE = jRule[kJsonUseANGLE].asBool();
Rule *newRule = new Rule(ruleDescription, useANGLE);
Json::Value jApps = jRule[kJsonApplications];
for (unsigned int appIndex = 0; appIndex < jApps.size(); appIndex++)
{
Json::Value jApp = jApps[appIndex];
Application *newApp = Application::CreateApplicationFromJson(jApp);
newRule->addApp(*newApp);
delete newApp;
}
Json::Value jDevs = jRule[kJsonDevices];
for (unsigned int deviceIndex = 0; deviceIndex < jDevs.size(); deviceIndex++)
{
Json::Value jDev = jDevs[deviceIndex];
Device *newDev = Device::CreateDeviceFromJson(jDev);
Json::Value jGPUs = jDev[kJsonGPUs];
for (unsigned int gpuIndex = 0; gpuIndex < jGPUs.size(); gpuIndex++)
{
Json::Value jGPU = jGPUs[gpuIndex];
GPU *newGPU = GPU::CreateGpuFromJson(jGPU);
if (newGPU)
{
newDev->addGPU(*newGPU);
delete newGPU;
}
}
newRule->addDevice(*newDev);
delete newDev;
}
rules->addRule(*newRule);
delete newRule;
}
// Make sure there is at least one, default rule. If not, add it here:
if (rules->mRuleList.size() == 0)
{
Rule defaultRule("Default Rule", false);
rules->addRule(defaultRule);
}
return rules;
}
void addRule(const Rule &rule) { mRuleList.push_back(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:",
static_cast<int>(mRuleList.size()));
for (const Rule &rule : mRuleList)
{
VERBOSE(" Checking Rule: \"%s\" (to see whether there's a match)",
rule.mDescription.c_str());
if (rule.match(toCheck))
{
VERBOSE(" -> Rule matches. Setting useANGLE to %s",
rule.getUseANGLE() ? "true" : "false");
useANGLE = rule.getUseANGLE();
}
else
{
VERBOSE(" -> Rule doesn't match.");
}
}
return useANGLE;
}
void logRules()
{
VERBOSE("Showing %d ANGLE-for-Android rules:", 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);
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/3036): 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, gpuDriverVersion);
scenario.mDevice.addGPU(gpuDriver);
scenario.logScenario();
bool rtn = rules->getUseANGLE(scenario);
VERBOSE("Application \"%s\" should %s ANGLE", 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"