123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872 |
- // Copyright (c) 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "gpu/config/gpu_control_list.h"
- #include <utility>
- #include "base/json/values_util.h"
- #include "base/logging.h"
- #include "base/notreached.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "base/system/sys_info.h"
- #include "base/values.h"
- #include "build/build_config.h"
- #include "components/crash/core/common/crash_key.h"
- #include "gpu/config/gpu_util.h"
- #include "third_party/re2/src/re2/re2.h"
- namespace gpu {
- namespace {
- // Break a version string into segments. Return true if each segment is
- // a valid number, and not all segment is 0.
- bool ProcessVersionString(const std::string& version_string,
- char splitter,
- std::vector<std::string>* version) {
- DCHECK(version);
- *version = base::SplitString(
- version_string, std::string(1, splitter),
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- if (version->size() == 0)
- return false;
- // If the splitter is '-', we assume it's a date with format "mm-dd-yyyy";
- // we split it into the order of "yyyy", "mm", "dd".
- if (splitter == '-') {
- std::string year = version->back();
- for (size_t i = version->size() - 1; i > 0; --i) {
- (*version)[i] = (*version)[i - 1];
- }
- (*version)[0] = year;
- }
- bool all_zero = true;
- for (size_t i = 0; i < version->size(); ++i) {
- unsigned num = 0;
- if (!base::StringToUint((*version)[i], &num)) {
- version->resize(i);
- break;
- }
- if (num)
- all_zero = false;
- }
- return !all_zero;
- }
- // Compare two number strings using numerical ordering.
- // Return 0 if number = number_ref,
- // 1 if number > number_ref,
- // -1 if number < number_ref.
- int CompareNumericalNumberStrings(
- const std::string& number, const std::string& number_ref) {
- unsigned value1 = 0;
- unsigned value2 = 0;
- bool valid = base::StringToUint(number, &value1);
- DCHECK(valid);
- valid = base::StringToUint(number_ref, &value2);
- DCHECK(valid);
- if (value1 == value2)
- return 0;
- if (value1 > value2)
- return 1;
- return -1;
- }
- // Compare two number strings using lexical ordering.
- // Return 0 if number = number_ref,
- // 1 if number > number_ref,
- // -1 if number < number_ref.
- // We only compare as many digits as number_ref contains.
- // If number_ref is xxx, it's considered as xxx*
- // For example: CompareLexicalNumberStrings("121", "12") returns 0,
- // CompareLexicalNumberStrings("12", "121") returns -1.
- int CompareLexicalNumberStrings(
- const std::string& number, const std::string& number_ref) {
- for (size_t i = 0; i < number_ref.length(); ++i) {
- unsigned value1 = 0;
- if (i < number.length())
- value1 = number[i] - '0';
- unsigned value2 = number_ref[i] - '0';
- if (value1 > value2)
- return 1;
- if (value1 < value2)
- return -1;
- }
- return 0;
- }
- // A mismatch is identified only if both |input| and |pattern| are not empty.
- bool StringMismatch(const std::string& input, const std::string& pattern) {
- if (input.empty() || pattern.empty())
- return false;
- static crash_reporter::CrashKeyString<128> crash_key(
- "StringMismatch::pattern");
- crash_reporter::ScopedCrashKeyString scoped_crash_key(&crash_key, pattern);
- return !RE2::FullMatch(input, pattern);
- }
- bool StringMismatch(const std::string& input, const char* pattern) {
- if (!pattern)
- return false;
- std::string pattern_string(pattern);
- return StringMismatch(input, pattern_string);
- }
- bool ProcessANGLEGLRenderer(const std::string& gl_renderer,
- std::string* vendor,
- std::string* renderer,
- std::string* version) {
- constexpr char kANGLEPrefix[] = "ANGLE (";
- if (!base::StartsWith(gl_renderer, kANGLEPrefix))
- return false;
- std::vector<std::string> segments;
- // ANGLE GL_RENDERER string:
- // ANGLE (vendor,renderer,version)
- size_t len = gl_renderer.size();
- std::string vendor_renderer_version =
- gl_renderer.substr(sizeof(kANGLEPrefix) - 1, len - sizeof(kANGLEPrefix));
- segments = base::SplitString(vendor_renderer_version, ",",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- if (segments.size() != 3) {
- LOG(DFATAL) << "Cannot parse ANGLE GL_RENDERER: " << gl_renderer;
- return false;
- }
- // Check ANGLE backend.
- // It could be `OpenGL, D3D, Vulkan, etc`
- if (!base::StartsWith(segments[2], "OpenGL")) {
- return false;
- }
- if (vendor)
- *vendor = segments[0];
- if (renderer)
- *renderer = segments[1];
- if (version)
- *version = segments[2];
- return true;
- }
- } // namespace
- bool GpuControlList::Version::Contains(const std::string& version_string,
- char splitter) const {
- if (op == kUnknown)
- return false;
- if (op == kAny)
- return true;
- std::vector<std::string> version;
- if (!ProcessVersionString(version_string, splitter, &version))
- return false;
- std::vector<std::string> ref_version1, ref_version2;
- bool valid = ProcessVersionString(value1, '.', &ref_version1);
- DCHECK(valid);
- if (op == kBetween) {
- valid = ProcessVersionString(value2, '.', &ref_version2);
- DCHECK(valid);
- }
- if (schema == kVersionSchemaIntelDriver) {
- // Intel graphics driver version schema should only be specified on Windows.
- // https://www.intel.com/content/www/us/en/support/articles/000005654/graphics-drivers.html
- // If either of the two versions doesn't match the Intel driver version
- // schema, they should not be compared.
- if (version.size() != 4 || ref_version1.size() != 4)
- return false;
- if (op == kBetween && ref_version2.size() != 4) {
- return false;
- }
- for (size_t ii = 0; ii < 2; ++ii) {
- version.erase(version.begin());
- ref_version1.erase(ref_version1.begin());
- if (op == kBetween)
- ref_version2.erase(ref_version2.begin());
- }
- } else if (schema == kVersionSchemaNvidiaDriver) {
- // The driver version we get from the os is "XX.XX.XXXA.BBCC", while the
- // workaround is of the form "ABB.CC". Drop the first two stanzas from the
- // detected version, erase all but the last character of the third, and move
- // "B" to the previous stanza.
- if (version.size() != 4)
- return false;
- // Remember that the detected version might not have leading zeros, so we
- // have to be a bit careful. [2] is of the form "001A", where A > 0, so we
- // just care that there's at least one digit. However, if there's less than
- // that, the splitter stops anyway on that stanza, and the check for four
- // stanzas will fail instead.
- version.erase(version.begin(), version.begin() + 2);
- version[0].erase(0, version[0].length() - 1);
- // The last stanza may be missing leading zeros, so handle them.
- if (version[1].length() < 3) {
- // Two or more removed leading zeros, so BB are both zero.
- version[0] += "00";
- } else if (version[1].length() < 4) {
- // One removed leading zero. BB is 0[1-9].
- version[0] += "0" + version[1].substr(0, 1);
- version[1].erase(0, 1);
- } else {
- // No leading zeros.
- version[0] += version[1].substr(0, 2);
- version[1].erase(0, 2);
- }
- }
- int relation = Version::Compare(version, ref_version1, style);
- switch (op) {
- case kEQ:
- return (relation == 0);
- case kLT:
- return (relation < 0);
- case kLE:
- return (relation <= 0);
- case kGT:
- return (relation > 0);
- case kGE:
- return (relation >= 0);
- case kBetween:
- if (relation < 0)
- return false;
- return Version::Compare(version, ref_version2, style) <= 0;
- default:
- NOTREACHED();
- return false;
- }
- }
- // static
- int GpuControlList::Version::Compare(
- const std::vector<std::string>& version,
- const std::vector<std::string>& version_ref,
- VersionStyle version_style) {
- DCHECK(version.size() > 0 && version_ref.size() > 0);
- DCHECK(version_style != kVersionStyleUnknown);
- for (size_t i = 0; i < version_ref.size(); ++i) {
- if (i >= version.size())
- return 0;
- int ret = 0;
- // We assume both versions are checked by ProcessVersionString().
- if (i > 0 && version_style == kVersionStyleLexical)
- ret = CompareLexicalNumberStrings(version[i], version_ref[i]);
- else
- ret = CompareNumericalNumberStrings(version[i], version_ref[i]);
- if (ret != 0)
- return ret;
- }
- return 0;
- }
- bool GpuControlList::More::GLVersionInfoMismatch(
- const std::string& gl_version_string) const {
- if (gl_version_string.empty())
- return false;
- if (!gl_version.IsSpecified() && gl_type == kGLTypeNone)
- return false;
- std::vector<std::string> segments = base::SplitString(
- gl_version_string, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- std::string number;
- GLType target_gl_type = kGLTypeNone;
- if (segments.size() > 2 &&
- segments[0] == "OpenGL" && segments[1] == "ES") {
- bool full_match = RE2::FullMatch(segments[2], "([\\d.]+).*", &number);
- DCHECK(full_match);
- target_gl_type = kGLTypeGLES;
- if (segments.size() > 3 &&
- base::StartsWith(segments[3], "(ANGLE",
- base::CompareCase::INSENSITIVE_ASCII)) {
- target_gl_type = kGLTypeANGLE;
- }
- } else {
- number = segments[0];
- target_gl_type = kGLTypeGL;
- }
- GLType entry_gl_type = gl_type;
- if (entry_gl_type == kGLTypeNone && gl_version.IsSpecified()) {
- entry_gl_type = GetDefaultGLType();
- }
- if (entry_gl_type != kGLTypeNone && entry_gl_type != target_gl_type) {
- return true;
- }
- if (gl_version.IsSpecified() && !gl_version.Contains(number)) {
- return true;
- }
- return false;
- }
- // static
- GpuControlList::GLType GpuControlList::More::GetDefaultGLType() {
- #if BUILDFLAG(IS_CHROMEOS)
- return kGLTypeGL;
- #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_OPENBSD)
- return kGLTypeGL;
- #elif BUILDFLAG(IS_MAC)
- return kGLTypeGL;
- #elif BUILDFLAG(IS_WIN)
- return kGLTypeANGLE;
- #elif BUILDFLAG(IS_ANDROID)
- return kGLTypeGLES;
- #else
- return kGLTypeNone;
- #endif
- }
- void GpuControlList::Entry::LogControlListMatch(
- const std::string& control_list_logging_name) const {
- static const char kControlListMatchMessage[] =
- "Control list match for rule #%u in %s.";
- VLOG(1) << base::StringPrintf(kControlListMatchMessage, id,
- control_list_logging_name.c_str());
- }
- bool GpuControlList::DriverInfo::Contains(
- const std::vector<GPUInfo::GPUDevice>& gpus) const {
- for (auto& gpu : gpus) {
- if (StringMismatch(gpu.driver_vendor, driver_vendor))
- continue;
- if (driver_version.IsSpecified() && !gpu.driver_version.empty() &&
- !driver_version.Contains(gpu.driver_version)) {
- continue;
- }
- return true;
- }
- return false;
- }
- bool GpuControlList::GLStrings::Contains(const GPUInfo& gpu_info) const {
- if (StringMismatch(gpu_info.gl_extensions, gl_extensions))
- return false;
- std::string vendor;
- std::string renderer;
- std::string version;
- bool is_angle_gl = ProcessANGLEGLRenderer(gpu_info.gl_renderer, &vendor,
- &renderer, &version);
- if (StringMismatch(is_angle_gl ? vendor : gpu_info.gl_vendor, gl_vendor)) {
- return false;
- }
- if (StringMismatch(is_angle_gl ? renderer : gpu_info.gl_renderer,
- gl_renderer)) {
- return false;
- }
- if (StringMismatch(is_angle_gl ? version : gpu_info.gl_version, gl_version)) {
- return false;
- }
- return true;
- }
- bool GpuControlList::MachineModelInfo::Contains(const GPUInfo& gpu_info) const {
- if (machine_model_name_size > 0) {
- if (gpu_info.machine_model_name.empty())
- return false;
- bool found_match = false;
- for (size_t ii = 0; ii < machine_model_name_size; ++ii) {
- if (RE2::FullMatch(gpu_info.machine_model_name,
- machine_model_names[ii])) {
- found_match = true;
- break;
- }
- }
- if (!found_match)
- return false;
- }
- if (machine_model_version.IsSpecified() &&
- (gpu_info.machine_model_version.empty() ||
- !machine_model_version.Contains(gpu_info.machine_model_version))) {
- return false;
- }
- return true;
- }
- bool GpuControlList::More::Contains(const GPUInfo& gpu_info) const {
- std::string gl_version_string;
- bool is_angle_gl = ProcessANGLEGLRenderer(gpu_info.gl_renderer, nullptr,
- nullptr, &gl_version_string);
- if (GLVersionInfoMismatch(is_angle_gl ? gl_version_string
- : gpu_info.gl_version)) {
- return false;
- }
- if (gl_reset_notification_strategy != 0 &&
- gl_reset_notification_strategy !=
- gpu_info.gl_reset_notification_strategy) {
- return false;
- }
- if (gpu_count.IsSpecified()) {
- size_t count = gpu_info.secondary_gpus.size() + 1;
- if (!gpu_count.Contains(std::to_string(count))) {
- return false;
- }
- }
- if (direct_rendering_version.IsSpecified() &&
- !direct_rendering_version.Contains(gpu_info.direct_rendering_version)) {
- return false;
- }
- if (in_process_gpu && !gpu_info.in_process_gpu) {
- return false;
- }
- if (pixel_shader_version.IsSpecified() &&
- !pixel_shader_version.Contains(gpu_info.pixel_shader_version)) {
- return false;
- }
- switch (hardware_overlay) {
- case kDontCare:
- break;
- case kSupported:
- #if BUILDFLAG(IS_WIN)
- if (!gpu_info.overlay_info.supports_overlays)
- return false;
- #endif // BUILDFLAG(IS_WIN)
- break;
- case kUnsupported:
- #if BUILDFLAG(IS_WIN)
- if (gpu_info.overlay_info.supports_overlays)
- return false;
- #endif // BUILDFLAG(IS_WIN)
- break;
- }
- if ((subpixel_font_rendering == kUnsupported &&
- gpu_info.subpixel_font_rendering) ||
- (subpixel_font_rendering == kSupported &&
- !gpu_info.subpixel_font_rendering)) {
- return false;
- }
- return true;
- }
- bool GpuControlList::Conditions::Contains(OsType target_os_type,
- const std::string& target_os_version,
- const GPUInfo& gpu_info) const {
- DCHECK(target_os_type != kOsAny);
- if (os_type != kOsAny) {
- if (os_type != target_os_type)
- return false;
- if (os_version.IsSpecified() && !os_version.Contains(target_os_version))
- return false;
- }
- std::vector<GPUInfo::GPUDevice> candidates;
- switch (multi_gpu_category) {
- case kMultiGpuCategoryPrimary:
- candidates.push_back(gpu_info.gpu);
- break;
- case kMultiGpuCategorySecondary:
- candidates = gpu_info.secondary_gpus;
- break;
- case kMultiGpuCategoryAny:
- candidates = gpu_info.secondary_gpus;
- candidates.push_back(gpu_info.gpu);
- break;
- case kMultiGpuCategoryActive:
- case kMultiGpuCategoryNone:
- // If gpu category is not specified, default to the active gpu.
- if (gpu_info.gpu.active || gpu_info.secondary_gpus.empty())
- candidates.push_back(gpu_info.gpu);
- for (auto& gpu : gpu_info.secondary_gpus) {
- if (gpu.active)
- candidates.push_back(gpu);
- }
- if (candidates.empty())
- candidates.push_back(gpu_info.gpu);
- }
- if (vendor_id != 0 || intel_gpu_series_list_size > 0 ||
- intel_gpu_generation.IsSpecified()) {
- bool found = false;
- if (intel_gpu_series_list_size > 0) {
- for (size_t ii = 0; !found && ii < candidates.size(); ++ii) {
- IntelGpuSeriesType candidate_series = GetIntelGpuSeriesType(
- candidates[ii].vendor_id, candidates[ii].device_id);
- if (candidate_series == IntelGpuSeriesType::kUnknown)
- continue;
- for (size_t jj = 0; jj < intel_gpu_series_list_size; ++jj) {
- if (candidate_series == intel_gpu_series_list[jj]) {
- found = true;
- break;
- }
- }
- }
- } else if (intel_gpu_generation.IsSpecified()) {
- for (auto& candidate : candidates) {
- std::string candidate_generation =
- GetIntelGpuGeneration(candidate.vendor_id, candidate.device_id);
- if (candidate_generation.empty())
- continue;
- if (intel_gpu_generation.Contains(candidate_generation)) {
- found = true;
- break;
- }
- }
- } else {
- if (device_size == 0) {
- for (auto& candidate : candidates) {
- if (vendor_id == candidate.vendor_id) {
- found = true;
- break;
- }
- }
- } else {
- for (size_t ii = 0; !found && ii < device_size; ++ii) {
- uint32_t device_id = devices[ii].device_id;
- #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
- uint32_t revision = devices[ii].revision;
- #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
- for (auto& candidate : candidates) {
- if (vendor_id != candidate.vendor_id ||
- device_id != candidate.device_id)
- continue;
- #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
- if (revision && revision != candidate.revision)
- continue;
- #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
- found = true;
- break;
- }
- }
- }
- }
- if (!found)
- return false;
- }
- switch (multi_gpu_style) {
- case kMultiGpuStyleOptimus:
- if (!gpu_info.optimus)
- return false;
- break;
- case kMultiGpuStyleAMDSwitchable:
- if (!gpu_info.amd_switchable)
- return false;
- break;
- case kMultiGpuStyleAMDSwitchableDiscrete:
- if (!gpu_info.amd_switchable)
- return false;
- // The discrete GPU is always the primary GPU.
- // This is guaranteed by GpuInfoCollector.
- if (!gpu_info.gpu.active)
- return false;
- break;
- case kMultiGpuStyleAMDSwitchableIntegrated:
- if (!gpu_info.amd_switchable)
- return false;
- // Assume the integrated GPU is the first in the secondary GPU list.
- if (gpu_info.secondary_gpus.size() == 0 ||
- !gpu_info.secondary_gpus[0].active)
- return false;
- break;
- case kMultiGpuStyleNone:
- break;
- }
- if (driver_info) {
- // We don't have a reliable way to check driver version without
- // also checking for vendor.
- DCHECK(vendor_id != 0 || candidates.size() < 2);
- // Remove candidate GPUs made by different vendors.
- auto behind_last =
- std::remove_if(candidates.begin(), candidates.end(),
- [vendor_id = vendor_id](const GPUInfo::GPUDevice& gpu) {
- return (vendor_id && vendor_id != gpu.vendor_id);
- });
- candidates.erase(behind_last, candidates.end());
- if (!driver_info->Contains(candidates))
- return false;
- }
- if (gl_strings && !gl_strings->Contains(gpu_info)) {
- return false;
- }
- if (machine_model_info && !machine_model_info->Contains(gpu_info)) {
- return false;
- }
- if (more && !more->Contains(gpu_info)) {
- return false;
- }
- return true;
- }
- bool GpuControlList::Entry::Contains(OsType target_os_type,
- const std::string& target_os_version,
- const GPUInfo& gpu_info) const {
- static crash_reporter::CrashKeyString<8> crash_key(
- "GpuControlList::Entry::id");
- crash_reporter::ScopedCrashKeyString scoped_crash_key(
- &crash_key, base::StringPrintf("%d", id));
- if (!conditions.Contains(target_os_type, target_os_version, gpu_info)) {
- return false;
- }
- for (size_t ii = 0; ii < exception_size; ++ii) {
- if (exceptions[ii].Contains(target_os_type, target_os_version, gpu_info) &&
- !exceptions[ii].NeedsMoreInfo(gpu_info)) {
- return false;
- }
- }
- return true;
- }
- bool GpuControlList::Entry::AppliesToTestGroup(
- uint32_t target_test_group) const {
- // If an entry specifies non-zero test group, then the entry only applies
- // if that test group is enabled (as specified in |target_test_group|).
- if (conditions.more && conditions.more->test_group)
- return conditions.more->test_group == target_test_group;
- return true;
- }
- bool GpuControlList::Conditions::NeedsMoreInfo(const GPUInfo& gpu_info) const {
- // We only check for missing info that might be collected with a gl context.
- // If certain info is missing due to some error, say, we fail to collect
- // vendor_id/device_id, then even if we launch GPU process and create a gl
- // context, we won't gather such missing info, so we still return false.
- const GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
- if (driver_info) {
- if (driver_info->driver_vendor && active_gpu.driver_vendor.empty()) {
- return true;
- }
- if (driver_info->driver_version.IsSpecified() &&
- active_gpu.driver_version.empty()) {
- return true;
- }
- }
- if (((more && more->gl_version.IsSpecified()) ||
- (gl_strings && gl_strings->gl_version)) &&
- gpu_info.gl_version.empty()) {
- return true;
- }
- if (gl_strings && gl_strings->gl_vendor && gpu_info.gl_vendor.empty())
- return true;
- if (gl_strings && gl_strings->gl_renderer && gpu_info.gl_renderer.empty())
- return true;
- if (more && more->pixel_shader_version.IsSpecified() &&
- gpu_info.pixel_shader_version.empty()) {
- return true;
- }
- return false;
- }
- bool GpuControlList::Entry::NeedsMoreInfo(const GPUInfo& gpu_info,
- bool consider_exceptions) const {
- if (conditions.NeedsMoreInfo(gpu_info))
- return true;
- if (consider_exceptions) {
- for (size_t ii = 0; ii < exception_size; ++ii) {
- if (exceptions[ii].NeedsMoreInfo(gpu_info))
- return true;
- }
- }
- return false;
- }
- base::Value::List GpuControlList::Entry::GetFeatureNames(
- const FeatureMap& feature_map) const {
- base::Value::List feature_names;
- for (size_t ii = 0; ii < feature_size; ++ii) {
- auto iter = feature_map.find(features[ii]);
- DCHECK(iter != feature_map.end());
- feature_names.Append(iter->second);
- }
- for (size_t ii = 0; ii < disabled_extension_size; ++ii) {
- std::string name =
- base::StringPrintf("disable(%s)", disabled_extensions[ii]);
- feature_names.Append(name);
- }
- return feature_names;
- }
- GpuControlList::GpuControlList(const GpuControlListData& data)
- : entry_count_(data.entry_count),
- entries_(data.entries),
- max_entry_id_(0),
- needs_more_info_(false),
- control_list_logging_enabled_(false) {
- DCHECK_LT(0u, entry_count_);
- // Assume the newly last added entry has the largest ID.
- max_entry_id_ = entries_[entry_count_ - 1].id;
- }
- GpuControlList::~GpuControlList() = default;
- std::set<int32_t> GpuControlList::MakeDecision(GpuControlList::OsType os,
- const std::string& os_version,
- const GPUInfo& gpu_info) {
- return MakeDecision(os, os_version, gpu_info, 0);
- }
- std::set<int32_t> GpuControlList::MakeDecision(GpuControlList::OsType os,
- const std::string& os_version,
- const GPUInfo& gpu_info,
- uint32_t target_test_group) {
- active_entries_.clear();
- std::set<int> features;
- needs_more_info_ = false;
- // Has all features permanently in the list without any possibility of
- // removal in the future (subset of "features" set).
- std::set<int32_t> permanent_features;
- // Has all features absent from "features" set that could potentially be
- // included later with more information.
- std::set<int32_t> potential_features;
- if (os == kOsAny)
- os = GetOsType();
- std::string processed_os_version = os_version;
- if (processed_os_version.empty())
- processed_os_version = base::SysInfo::OperatingSystemVersion();
- // Get rid of the non numbers because later processing expects a valid
- // version string in the format of "a.b.c".
- size_t pos = processed_os_version.find_first_not_of("0123456789.");
- if (pos != std::string::npos)
- processed_os_version = processed_os_version.substr(0, pos);
- for (size_t ii = 0; ii < entry_count_; ++ii) {
- const Entry& entry = entries_[ii];
- DCHECK_NE(0u, entry.id);
- if (!entry.AppliesToTestGroup(target_test_group))
- continue;
- if (entry.Contains(os, processed_os_version, gpu_info)) {
- bool needs_more_info_main = entry.NeedsMoreInfo(gpu_info, false);
- bool needs_more_info_exception = entry.NeedsMoreInfo(gpu_info, true);
- if (control_list_logging_enabled_)
- entry.LogControlListMatch(control_list_logging_name_);
- // Only look at main entry info when deciding what to add to "features"
- // set. If we don't have enough info for an exception, it's safer if we
- // just ignore the exception and assume the exception doesn't apply.
- for (size_t jj = 0; jj < entry.feature_size; ++jj) {
- int32_t feature = entry.features[jj];
- if (needs_more_info_main) {
- if (!features.count(feature))
- potential_features.insert(feature);
- } else {
- features.insert(feature);
- potential_features.erase(feature);
- if (!needs_more_info_exception)
- permanent_features.insert(feature);
- }
- }
- if (!needs_more_info_main)
- active_entries_.push_back(base::checked_cast<uint32_t>(ii));
- }
- }
- needs_more_info_ = permanent_features.size() < features.size() ||
- !potential_features.empty();
- return features;
- }
- const std::vector<uint32_t>& GpuControlList::GetActiveEntries() const {
- return active_entries_;
- }
- std::vector<uint32_t> GpuControlList::GetEntryIDsFromIndices(
- const std::vector<uint32_t>& entry_indices) const {
- std::vector<uint32_t> ids;
- for (auto index : entry_indices) {
- DCHECK_LT(index, entry_count_);
- ids.push_back(entries_[index].id);
- }
- return ids;
- }
- std::vector<std::string> GpuControlList::GetDisabledExtensions() {
- std::set<std::string> disabled_extensions;
- for (auto index : active_entries_) {
- DCHECK_LT(index, entry_count_);
- const Entry& entry = entries_[index];
- for (size_t ii = 0; ii < entry.disabled_extension_size; ++ii) {
- disabled_extensions.insert(entry.disabled_extensions[ii]);
- }
- }
- return std::vector<std::string>(disabled_extensions.begin(),
- disabled_extensions.end());
- }
- std::vector<std::string> GpuControlList::GetDisabledWebGLExtensions() {
- std::set<std::string> disabled_webgl_extensions;
- for (auto index : active_entries_) {
- DCHECK_LT(index, entry_count_);
- const Entry& entry = entries_[index];
- for (size_t ii = 0; ii < entry.disabled_webgl_extension_size; ++ii) {
- disabled_webgl_extensions.insert(entry.disabled_webgl_extensions[ii]);
- }
- }
- return std::vector<std::string>(disabled_webgl_extensions.begin(),
- disabled_webgl_extensions.end());
- }
- void GpuControlList::GetReasons(base::Value::List& problem_list,
- const std::string& tag,
- const std::vector<uint32_t>& entries) const {
- for (auto index : entries) {
- DCHECK_LT(index, entry_count_);
- const Entry& entry = entries_[index];
- base::Value::Dict problem;
- problem.Set("description", entry.description);
- base::Value::List cr_bugs;
- for (size_t jj = 0; jj < entry.cr_bug_size; ++jj)
- cr_bugs.Append(
- base::Int64ToValue(static_cast<int64_t>(entry.cr_bugs[jj])));
- problem.Set("crBugs", std::move(cr_bugs));
- base::Value::List features = entry.GetFeatureNames(feature_map_);
- problem.Set("affectedGpuSettings", std::move(features));
- DCHECK(tag == "workarounds" || tag == "disabledFeatures");
- problem.Set("tag", tag);
- problem_list.Append(std::move(problem));
- }
- }
- size_t GpuControlList::num_entries() const {
- return entry_count_;
- }
- uint32_t GpuControlList::max_entry_id() const {
- return max_entry_id_;
- }
- // static
- GpuControlList::OsType GpuControlList::GetOsType() {
- #if BUILDFLAG(IS_CHROMEOS)
- return kOsChromeOS;
- #elif BUILDFLAG(IS_WIN)
- return kOsWin;
- #elif BUILDFLAG(IS_ANDROID)
- return kOsAndroid;
- #elif BUILDFLAG(IS_FUCHSIA)
- return kOsFuchsia;
- #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_OPENBSD)
- return kOsLinux;
- #elif BUILDFLAG(IS_MAC)
- return kOsMacosx;
- #else
- return kOsAny;
- #endif
- }
- void GpuControlList::AddSupportedFeature(
- const std::string& feature_name, int feature_id) {
- feature_map_[feature_id] = feature_name;
- }
- // static
- bool GpuControlList::AreEntryIndicesValid(
- const std::vector<uint32_t>& entry_indices,
- size_t total_entries) {
- for (auto index : entry_indices) {
- if (index >= total_entries)
- return false;
- }
- return true;
- }
- } // namespace gpu
|