gpu_control_list.cc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gpu/config/gpu_control_list.h"
  5. #include <utility>
  6. #include "base/json/values_util.h"
  7. #include "base/logging.h"
  8. #include "base/notreached.h"
  9. #include "base/numerics/safe_conversions.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/strings/string_split.h"
  12. #include "base/strings/string_util.h"
  13. #include "base/strings/stringprintf.h"
  14. #include "base/system/sys_info.h"
  15. #include "base/values.h"
  16. #include "build/build_config.h"
  17. #include "components/crash/core/common/crash_key.h"
  18. #include "gpu/config/gpu_util.h"
  19. #include "third_party/re2/src/re2/re2.h"
  20. namespace gpu {
  21. namespace {
  22. // Break a version string into segments. Return true if each segment is
  23. // a valid number, and not all segment is 0.
  24. bool ProcessVersionString(const std::string& version_string,
  25. char splitter,
  26. std::vector<std::string>* version) {
  27. DCHECK(version);
  28. *version = base::SplitString(
  29. version_string, std::string(1, splitter),
  30. base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  31. if (version->size() == 0)
  32. return false;
  33. // If the splitter is '-', we assume it's a date with format "mm-dd-yyyy";
  34. // we split it into the order of "yyyy", "mm", "dd".
  35. if (splitter == '-') {
  36. std::string year = version->back();
  37. for (size_t i = version->size() - 1; i > 0; --i) {
  38. (*version)[i] = (*version)[i - 1];
  39. }
  40. (*version)[0] = year;
  41. }
  42. bool all_zero = true;
  43. for (size_t i = 0; i < version->size(); ++i) {
  44. unsigned num = 0;
  45. if (!base::StringToUint((*version)[i], &num)) {
  46. version->resize(i);
  47. break;
  48. }
  49. if (num)
  50. all_zero = false;
  51. }
  52. return !all_zero;
  53. }
  54. // Compare two number strings using numerical ordering.
  55. // Return 0 if number = number_ref,
  56. // 1 if number > number_ref,
  57. // -1 if number < number_ref.
  58. int CompareNumericalNumberStrings(
  59. const std::string& number, const std::string& number_ref) {
  60. unsigned value1 = 0;
  61. unsigned value2 = 0;
  62. bool valid = base::StringToUint(number, &value1);
  63. DCHECK(valid);
  64. valid = base::StringToUint(number_ref, &value2);
  65. DCHECK(valid);
  66. if (value1 == value2)
  67. return 0;
  68. if (value1 > value2)
  69. return 1;
  70. return -1;
  71. }
  72. // Compare two number strings using lexical ordering.
  73. // Return 0 if number = number_ref,
  74. // 1 if number > number_ref,
  75. // -1 if number < number_ref.
  76. // We only compare as many digits as number_ref contains.
  77. // If number_ref is xxx, it's considered as xxx*
  78. // For example: CompareLexicalNumberStrings("121", "12") returns 0,
  79. // CompareLexicalNumberStrings("12", "121") returns -1.
  80. int CompareLexicalNumberStrings(
  81. const std::string& number, const std::string& number_ref) {
  82. for (size_t i = 0; i < number_ref.length(); ++i) {
  83. unsigned value1 = 0;
  84. if (i < number.length())
  85. value1 = number[i] - '0';
  86. unsigned value2 = number_ref[i] - '0';
  87. if (value1 > value2)
  88. return 1;
  89. if (value1 < value2)
  90. return -1;
  91. }
  92. return 0;
  93. }
  94. // A mismatch is identified only if both |input| and |pattern| are not empty.
  95. bool StringMismatch(const std::string& input, const std::string& pattern) {
  96. if (input.empty() || pattern.empty())
  97. return false;
  98. static crash_reporter::CrashKeyString<128> crash_key(
  99. "StringMismatch::pattern");
  100. crash_reporter::ScopedCrashKeyString scoped_crash_key(&crash_key, pattern);
  101. return !RE2::FullMatch(input, pattern);
  102. }
  103. bool StringMismatch(const std::string& input, const char* pattern) {
  104. if (!pattern)
  105. return false;
  106. std::string pattern_string(pattern);
  107. return StringMismatch(input, pattern_string);
  108. }
  109. bool ProcessANGLEGLRenderer(const std::string& gl_renderer,
  110. std::string* vendor,
  111. std::string* renderer,
  112. std::string* version) {
  113. constexpr char kANGLEPrefix[] = "ANGLE (";
  114. if (!base::StartsWith(gl_renderer, kANGLEPrefix))
  115. return false;
  116. std::vector<std::string> segments;
  117. // ANGLE GL_RENDERER string:
  118. // ANGLE (vendor,renderer,version)
  119. size_t len = gl_renderer.size();
  120. std::string vendor_renderer_version =
  121. gl_renderer.substr(sizeof(kANGLEPrefix) - 1, len - sizeof(kANGLEPrefix));
  122. segments = base::SplitString(vendor_renderer_version, ",",
  123. base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  124. if (segments.size() != 3) {
  125. LOG(DFATAL) << "Cannot parse ANGLE GL_RENDERER: " << gl_renderer;
  126. return false;
  127. }
  128. // Check ANGLE backend.
  129. // It could be `OpenGL, D3D, Vulkan, etc`
  130. if (!base::StartsWith(segments[2], "OpenGL")) {
  131. return false;
  132. }
  133. if (vendor)
  134. *vendor = segments[0];
  135. if (renderer)
  136. *renderer = segments[1];
  137. if (version)
  138. *version = segments[2];
  139. return true;
  140. }
  141. } // namespace
  142. bool GpuControlList::Version::Contains(const std::string& version_string,
  143. char splitter) const {
  144. if (op == kUnknown)
  145. return false;
  146. if (op == kAny)
  147. return true;
  148. std::vector<std::string> version;
  149. if (!ProcessVersionString(version_string, splitter, &version))
  150. return false;
  151. std::vector<std::string> ref_version1, ref_version2;
  152. bool valid = ProcessVersionString(value1, '.', &ref_version1);
  153. DCHECK(valid);
  154. if (op == kBetween) {
  155. valid = ProcessVersionString(value2, '.', &ref_version2);
  156. DCHECK(valid);
  157. }
  158. if (schema == kVersionSchemaIntelDriver) {
  159. // Intel graphics driver version schema should only be specified on Windows.
  160. // https://www.intel.com/content/www/us/en/support/articles/000005654/graphics-drivers.html
  161. // If either of the two versions doesn't match the Intel driver version
  162. // schema, they should not be compared.
  163. if (version.size() != 4 || ref_version1.size() != 4)
  164. return false;
  165. if (op == kBetween && ref_version2.size() != 4) {
  166. return false;
  167. }
  168. for (size_t ii = 0; ii < 2; ++ii) {
  169. version.erase(version.begin());
  170. ref_version1.erase(ref_version1.begin());
  171. if (op == kBetween)
  172. ref_version2.erase(ref_version2.begin());
  173. }
  174. } else if (schema == kVersionSchemaNvidiaDriver) {
  175. // The driver version we get from the os is "XX.XX.XXXA.BBCC", while the
  176. // workaround is of the form "ABB.CC". Drop the first two stanzas from the
  177. // detected version, erase all but the last character of the third, and move
  178. // "B" to the previous stanza.
  179. if (version.size() != 4)
  180. return false;
  181. // Remember that the detected version might not have leading zeros, so we
  182. // have to be a bit careful. [2] is of the form "001A", where A > 0, so we
  183. // just care that there's at least one digit. However, if there's less than
  184. // that, the splitter stops anyway on that stanza, and the check for four
  185. // stanzas will fail instead.
  186. version.erase(version.begin(), version.begin() + 2);
  187. version[0].erase(0, version[0].length() - 1);
  188. // The last stanza may be missing leading zeros, so handle them.
  189. if (version[1].length() < 3) {
  190. // Two or more removed leading zeros, so BB are both zero.
  191. version[0] += "00";
  192. } else if (version[1].length() < 4) {
  193. // One removed leading zero. BB is 0[1-9].
  194. version[0] += "0" + version[1].substr(0, 1);
  195. version[1].erase(0, 1);
  196. } else {
  197. // No leading zeros.
  198. version[0] += version[1].substr(0, 2);
  199. version[1].erase(0, 2);
  200. }
  201. }
  202. int relation = Version::Compare(version, ref_version1, style);
  203. switch (op) {
  204. case kEQ:
  205. return (relation == 0);
  206. case kLT:
  207. return (relation < 0);
  208. case kLE:
  209. return (relation <= 0);
  210. case kGT:
  211. return (relation > 0);
  212. case kGE:
  213. return (relation >= 0);
  214. case kBetween:
  215. if (relation < 0)
  216. return false;
  217. return Version::Compare(version, ref_version2, style) <= 0;
  218. default:
  219. NOTREACHED();
  220. return false;
  221. }
  222. }
  223. // static
  224. int GpuControlList::Version::Compare(
  225. const std::vector<std::string>& version,
  226. const std::vector<std::string>& version_ref,
  227. VersionStyle version_style) {
  228. DCHECK(version.size() > 0 && version_ref.size() > 0);
  229. DCHECK(version_style != kVersionStyleUnknown);
  230. for (size_t i = 0; i < version_ref.size(); ++i) {
  231. if (i >= version.size())
  232. return 0;
  233. int ret = 0;
  234. // We assume both versions are checked by ProcessVersionString().
  235. if (i > 0 && version_style == kVersionStyleLexical)
  236. ret = CompareLexicalNumberStrings(version[i], version_ref[i]);
  237. else
  238. ret = CompareNumericalNumberStrings(version[i], version_ref[i]);
  239. if (ret != 0)
  240. return ret;
  241. }
  242. return 0;
  243. }
  244. bool GpuControlList::More::GLVersionInfoMismatch(
  245. const std::string& gl_version_string) const {
  246. if (gl_version_string.empty())
  247. return false;
  248. if (!gl_version.IsSpecified() && gl_type == kGLTypeNone)
  249. return false;
  250. std::vector<std::string> segments = base::SplitString(
  251. gl_version_string, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  252. std::string number;
  253. GLType target_gl_type = kGLTypeNone;
  254. if (segments.size() > 2 &&
  255. segments[0] == "OpenGL" && segments[1] == "ES") {
  256. bool full_match = RE2::FullMatch(segments[2], "([\\d.]+).*", &number);
  257. DCHECK(full_match);
  258. target_gl_type = kGLTypeGLES;
  259. if (segments.size() > 3 &&
  260. base::StartsWith(segments[3], "(ANGLE",
  261. base::CompareCase::INSENSITIVE_ASCII)) {
  262. target_gl_type = kGLTypeANGLE;
  263. }
  264. } else {
  265. number = segments[0];
  266. target_gl_type = kGLTypeGL;
  267. }
  268. GLType entry_gl_type = gl_type;
  269. if (entry_gl_type == kGLTypeNone && gl_version.IsSpecified()) {
  270. entry_gl_type = GetDefaultGLType();
  271. }
  272. if (entry_gl_type != kGLTypeNone && entry_gl_type != target_gl_type) {
  273. return true;
  274. }
  275. if (gl_version.IsSpecified() && !gl_version.Contains(number)) {
  276. return true;
  277. }
  278. return false;
  279. }
  280. // static
  281. GpuControlList::GLType GpuControlList::More::GetDefaultGLType() {
  282. #if BUILDFLAG(IS_CHROMEOS)
  283. return kGLTypeGL;
  284. #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_OPENBSD)
  285. return kGLTypeGL;
  286. #elif BUILDFLAG(IS_MAC)
  287. return kGLTypeGL;
  288. #elif BUILDFLAG(IS_WIN)
  289. return kGLTypeANGLE;
  290. #elif BUILDFLAG(IS_ANDROID)
  291. return kGLTypeGLES;
  292. #else
  293. return kGLTypeNone;
  294. #endif
  295. }
  296. void GpuControlList::Entry::LogControlListMatch(
  297. const std::string& control_list_logging_name) const {
  298. static const char kControlListMatchMessage[] =
  299. "Control list match for rule #%u in %s.";
  300. VLOG(1) << base::StringPrintf(kControlListMatchMessage, id,
  301. control_list_logging_name.c_str());
  302. }
  303. bool GpuControlList::DriverInfo::Contains(
  304. const std::vector<GPUInfo::GPUDevice>& gpus) const {
  305. for (auto& gpu : gpus) {
  306. if (StringMismatch(gpu.driver_vendor, driver_vendor))
  307. continue;
  308. if (driver_version.IsSpecified() && !gpu.driver_version.empty() &&
  309. !driver_version.Contains(gpu.driver_version)) {
  310. continue;
  311. }
  312. return true;
  313. }
  314. return false;
  315. }
  316. bool GpuControlList::GLStrings::Contains(const GPUInfo& gpu_info) const {
  317. if (StringMismatch(gpu_info.gl_extensions, gl_extensions))
  318. return false;
  319. std::string vendor;
  320. std::string renderer;
  321. std::string version;
  322. bool is_angle_gl = ProcessANGLEGLRenderer(gpu_info.gl_renderer, &vendor,
  323. &renderer, &version);
  324. if (StringMismatch(is_angle_gl ? vendor : gpu_info.gl_vendor, gl_vendor)) {
  325. return false;
  326. }
  327. if (StringMismatch(is_angle_gl ? renderer : gpu_info.gl_renderer,
  328. gl_renderer)) {
  329. return false;
  330. }
  331. if (StringMismatch(is_angle_gl ? version : gpu_info.gl_version, gl_version)) {
  332. return false;
  333. }
  334. return true;
  335. }
  336. bool GpuControlList::MachineModelInfo::Contains(const GPUInfo& gpu_info) const {
  337. if (machine_model_name_size > 0) {
  338. if (gpu_info.machine_model_name.empty())
  339. return false;
  340. bool found_match = false;
  341. for (size_t ii = 0; ii < machine_model_name_size; ++ii) {
  342. if (RE2::FullMatch(gpu_info.machine_model_name,
  343. machine_model_names[ii])) {
  344. found_match = true;
  345. break;
  346. }
  347. }
  348. if (!found_match)
  349. return false;
  350. }
  351. if (machine_model_version.IsSpecified() &&
  352. (gpu_info.machine_model_version.empty() ||
  353. !machine_model_version.Contains(gpu_info.machine_model_version))) {
  354. return false;
  355. }
  356. return true;
  357. }
  358. bool GpuControlList::More::Contains(const GPUInfo& gpu_info) const {
  359. std::string gl_version_string;
  360. bool is_angle_gl = ProcessANGLEGLRenderer(gpu_info.gl_renderer, nullptr,
  361. nullptr, &gl_version_string);
  362. if (GLVersionInfoMismatch(is_angle_gl ? gl_version_string
  363. : gpu_info.gl_version)) {
  364. return false;
  365. }
  366. if (gl_reset_notification_strategy != 0 &&
  367. gl_reset_notification_strategy !=
  368. gpu_info.gl_reset_notification_strategy) {
  369. return false;
  370. }
  371. if (gpu_count.IsSpecified()) {
  372. size_t count = gpu_info.secondary_gpus.size() + 1;
  373. if (!gpu_count.Contains(std::to_string(count))) {
  374. return false;
  375. }
  376. }
  377. if (direct_rendering_version.IsSpecified() &&
  378. !direct_rendering_version.Contains(gpu_info.direct_rendering_version)) {
  379. return false;
  380. }
  381. if (in_process_gpu && !gpu_info.in_process_gpu) {
  382. return false;
  383. }
  384. if (pixel_shader_version.IsSpecified() &&
  385. !pixel_shader_version.Contains(gpu_info.pixel_shader_version)) {
  386. return false;
  387. }
  388. switch (hardware_overlay) {
  389. case kDontCare:
  390. break;
  391. case kSupported:
  392. #if BUILDFLAG(IS_WIN)
  393. if (!gpu_info.overlay_info.supports_overlays)
  394. return false;
  395. #endif // BUILDFLAG(IS_WIN)
  396. break;
  397. case kUnsupported:
  398. #if BUILDFLAG(IS_WIN)
  399. if (gpu_info.overlay_info.supports_overlays)
  400. return false;
  401. #endif // BUILDFLAG(IS_WIN)
  402. break;
  403. }
  404. if ((subpixel_font_rendering == kUnsupported &&
  405. gpu_info.subpixel_font_rendering) ||
  406. (subpixel_font_rendering == kSupported &&
  407. !gpu_info.subpixel_font_rendering)) {
  408. return false;
  409. }
  410. return true;
  411. }
  412. bool GpuControlList::Conditions::Contains(OsType target_os_type,
  413. const std::string& target_os_version,
  414. const GPUInfo& gpu_info) const {
  415. DCHECK(target_os_type != kOsAny);
  416. if (os_type != kOsAny) {
  417. if (os_type != target_os_type)
  418. return false;
  419. if (os_version.IsSpecified() && !os_version.Contains(target_os_version))
  420. return false;
  421. }
  422. std::vector<GPUInfo::GPUDevice> candidates;
  423. switch (multi_gpu_category) {
  424. case kMultiGpuCategoryPrimary:
  425. candidates.push_back(gpu_info.gpu);
  426. break;
  427. case kMultiGpuCategorySecondary:
  428. candidates = gpu_info.secondary_gpus;
  429. break;
  430. case kMultiGpuCategoryAny:
  431. candidates = gpu_info.secondary_gpus;
  432. candidates.push_back(gpu_info.gpu);
  433. break;
  434. case kMultiGpuCategoryActive:
  435. case kMultiGpuCategoryNone:
  436. // If gpu category is not specified, default to the active gpu.
  437. if (gpu_info.gpu.active || gpu_info.secondary_gpus.empty())
  438. candidates.push_back(gpu_info.gpu);
  439. for (auto& gpu : gpu_info.secondary_gpus) {
  440. if (gpu.active)
  441. candidates.push_back(gpu);
  442. }
  443. if (candidates.empty())
  444. candidates.push_back(gpu_info.gpu);
  445. }
  446. if (vendor_id != 0 || intel_gpu_series_list_size > 0 ||
  447. intel_gpu_generation.IsSpecified()) {
  448. bool found = false;
  449. if (intel_gpu_series_list_size > 0) {
  450. for (size_t ii = 0; !found && ii < candidates.size(); ++ii) {
  451. IntelGpuSeriesType candidate_series = GetIntelGpuSeriesType(
  452. candidates[ii].vendor_id, candidates[ii].device_id);
  453. if (candidate_series == IntelGpuSeriesType::kUnknown)
  454. continue;
  455. for (size_t jj = 0; jj < intel_gpu_series_list_size; ++jj) {
  456. if (candidate_series == intel_gpu_series_list[jj]) {
  457. found = true;
  458. break;
  459. }
  460. }
  461. }
  462. } else if (intel_gpu_generation.IsSpecified()) {
  463. for (auto& candidate : candidates) {
  464. std::string candidate_generation =
  465. GetIntelGpuGeneration(candidate.vendor_id, candidate.device_id);
  466. if (candidate_generation.empty())
  467. continue;
  468. if (intel_gpu_generation.Contains(candidate_generation)) {
  469. found = true;
  470. break;
  471. }
  472. }
  473. } else {
  474. if (device_size == 0) {
  475. for (auto& candidate : candidates) {
  476. if (vendor_id == candidate.vendor_id) {
  477. found = true;
  478. break;
  479. }
  480. }
  481. } else {
  482. for (size_t ii = 0; !found && ii < device_size; ++ii) {
  483. uint32_t device_id = devices[ii].device_id;
  484. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
  485. uint32_t revision = devices[ii].revision;
  486. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
  487. for (auto& candidate : candidates) {
  488. if (vendor_id != candidate.vendor_id ||
  489. device_id != candidate.device_id)
  490. continue;
  491. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
  492. if (revision && revision != candidate.revision)
  493. continue;
  494. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
  495. found = true;
  496. break;
  497. }
  498. }
  499. }
  500. }
  501. if (!found)
  502. return false;
  503. }
  504. switch (multi_gpu_style) {
  505. case kMultiGpuStyleOptimus:
  506. if (!gpu_info.optimus)
  507. return false;
  508. break;
  509. case kMultiGpuStyleAMDSwitchable:
  510. if (!gpu_info.amd_switchable)
  511. return false;
  512. break;
  513. case kMultiGpuStyleAMDSwitchableDiscrete:
  514. if (!gpu_info.amd_switchable)
  515. return false;
  516. // The discrete GPU is always the primary GPU.
  517. // This is guaranteed by GpuInfoCollector.
  518. if (!gpu_info.gpu.active)
  519. return false;
  520. break;
  521. case kMultiGpuStyleAMDSwitchableIntegrated:
  522. if (!gpu_info.amd_switchable)
  523. return false;
  524. // Assume the integrated GPU is the first in the secondary GPU list.
  525. if (gpu_info.secondary_gpus.size() == 0 ||
  526. !gpu_info.secondary_gpus[0].active)
  527. return false;
  528. break;
  529. case kMultiGpuStyleNone:
  530. break;
  531. }
  532. if (driver_info) {
  533. // We don't have a reliable way to check driver version without
  534. // also checking for vendor.
  535. DCHECK(vendor_id != 0 || candidates.size() < 2);
  536. // Remove candidate GPUs made by different vendors.
  537. auto behind_last =
  538. std::remove_if(candidates.begin(), candidates.end(),
  539. [vendor_id = vendor_id](const GPUInfo::GPUDevice& gpu) {
  540. return (vendor_id && vendor_id != gpu.vendor_id);
  541. });
  542. candidates.erase(behind_last, candidates.end());
  543. if (!driver_info->Contains(candidates))
  544. return false;
  545. }
  546. if (gl_strings && !gl_strings->Contains(gpu_info)) {
  547. return false;
  548. }
  549. if (machine_model_info && !machine_model_info->Contains(gpu_info)) {
  550. return false;
  551. }
  552. if (more && !more->Contains(gpu_info)) {
  553. return false;
  554. }
  555. return true;
  556. }
  557. bool GpuControlList::Entry::Contains(OsType target_os_type,
  558. const std::string& target_os_version,
  559. const GPUInfo& gpu_info) const {
  560. static crash_reporter::CrashKeyString<8> crash_key(
  561. "GpuControlList::Entry::id");
  562. crash_reporter::ScopedCrashKeyString scoped_crash_key(
  563. &crash_key, base::StringPrintf("%d", id));
  564. if (!conditions.Contains(target_os_type, target_os_version, gpu_info)) {
  565. return false;
  566. }
  567. for (size_t ii = 0; ii < exception_size; ++ii) {
  568. if (exceptions[ii].Contains(target_os_type, target_os_version, gpu_info) &&
  569. !exceptions[ii].NeedsMoreInfo(gpu_info)) {
  570. return false;
  571. }
  572. }
  573. return true;
  574. }
  575. bool GpuControlList::Entry::AppliesToTestGroup(
  576. uint32_t target_test_group) const {
  577. // If an entry specifies non-zero test group, then the entry only applies
  578. // if that test group is enabled (as specified in |target_test_group|).
  579. if (conditions.more && conditions.more->test_group)
  580. return conditions.more->test_group == target_test_group;
  581. return true;
  582. }
  583. bool GpuControlList::Conditions::NeedsMoreInfo(const GPUInfo& gpu_info) const {
  584. // We only check for missing info that might be collected with a gl context.
  585. // If certain info is missing due to some error, say, we fail to collect
  586. // vendor_id/device_id, then even if we launch GPU process and create a gl
  587. // context, we won't gather such missing info, so we still return false.
  588. const GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
  589. if (driver_info) {
  590. if (driver_info->driver_vendor && active_gpu.driver_vendor.empty()) {
  591. return true;
  592. }
  593. if (driver_info->driver_version.IsSpecified() &&
  594. active_gpu.driver_version.empty()) {
  595. return true;
  596. }
  597. }
  598. if (((more && more->gl_version.IsSpecified()) ||
  599. (gl_strings && gl_strings->gl_version)) &&
  600. gpu_info.gl_version.empty()) {
  601. return true;
  602. }
  603. if (gl_strings && gl_strings->gl_vendor && gpu_info.gl_vendor.empty())
  604. return true;
  605. if (gl_strings && gl_strings->gl_renderer && gpu_info.gl_renderer.empty())
  606. return true;
  607. if (more && more->pixel_shader_version.IsSpecified() &&
  608. gpu_info.pixel_shader_version.empty()) {
  609. return true;
  610. }
  611. return false;
  612. }
  613. bool GpuControlList::Entry::NeedsMoreInfo(const GPUInfo& gpu_info,
  614. bool consider_exceptions) const {
  615. if (conditions.NeedsMoreInfo(gpu_info))
  616. return true;
  617. if (consider_exceptions) {
  618. for (size_t ii = 0; ii < exception_size; ++ii) {
  619. if (exceptions[ii].NeedsMoreInfo(gpu_info))
  620. return true;
  621. }
  622. }
  623. return false;
  624. }
  625. base::Value::List GpuControlList::Entry::GetFeatureNames(
  626. const FeatureMap& feature_map) const {
  627. base::Value::List feature_names;
  628. for (size_t ii = 0; ii < feature_size; ++ii) {
  629. auto iter = feature_map.find(features[ii]);
  630. DCHECK(iter != feature_map.end());
  631. feature_names.Append(iter->second);
  632. }
  633. for (size_t ii = 0; ii < disabled_extension_size; ++ii) {
  634. std::string name =
  635. base::StringPrintf("disable(%s)", disabled_extensions[ii]);
  636. feature_names.Append(name);
  637. }
  638. return feature_names;
  639. }
  640. GpuControlList::GpuControlList(const GpuControlListData& data)
  641. : entry_count_(data.entry_count),
  642. entries_(data.entries),
  643. max_entry_id_(0),
  644. needs_more_info_(false),
  645. control_list_logging_enabled_(false) {
  646. DCHECK_LT(0u, entry_count_);
  647. // Assume the newly last added entry has the largest ID.
  648. max_entry_id_ = entries_[entry_count_ - 1].id;
  649. }
  650. GpuControlList::~GpuControlList() = default;
  651. std::set<int32_t> GpuControlList::MakeDecision(GpuControlList::OsType os,
  652. const std::string& os_version,
  653. const GPUInfo& gpu_info) {
  654. return MakeDecision(os, os_version, gpu_info, 0);
  655. }
  656. std::set<int32_t> GpuControlList::MakeDecision(GpuControlList::OsType os,
  657. const std::string& os_version,
  658. const GPUInfo& gpu_info,
  659. uint32_t target_test_group) {
  660. active_entries_.clear();
  661. std::set<int> features;
  662. needs_more_info_ = false;
  663. // Has all features permanently in the list without any possibility of
  664. // removal in the future (subset of "features" set).
  665. std::set<int32_t> permanent_features;
  666. // Has all features absent from "features" set that could potentially be
  667. // included later with more information.
  668. std::set<int32_t> potential_features;
  669. if (os == kOsAny)
  670. os = GetOsType();
  671. std::string processed_os_version = os_version;
  672. if (processed_os_version.empty())
  673. processed_os_version = base::SysInfo::OperatingSystemVersion();
  674. // Get rid of the non numbers because later processing expects a valid
  675. // version string in the format of "a.b.c".
  676. size_t pos = processed_os_version.find_first_not_of("0123456789.");
  677. if (pos != std::string::npos)
  678. processed_os_version = processed_os_version.substr(0, pos);
  679. for (size_t ii = 0; ii < entry_count_; ++ii) {
  680. const Entry& entry = entries_[ii];
  681. DCHECK_NE(0u, entry.id);
  682. if (!entry.AppliesToTestGroup(target_test_group))
  683. continue;
  684. if (entry.Contains(os, processed_os_version, gpu_info)) {
  685. bool needs_more_info_main = entry.NeedsMoreInfo(gpu_info, false);
  686. bool needs_more_info_exception = entry.NeedsMoreInfo(gpu_info, true);
  687. if (control_list_logging_enabled_)
  688. entry.LogControlListMatch(control_list_logging_name_);
  689. // Only look at main entry info when deciding what to add to "features"
  690. // set. If we don't have enough info for an exception, it's safer if we
  691. // just ignore the exception and assume the exception doesn't apply.
  692. for (size_t jj = 0; jj < entry.feature_size; ++jj) {
  693. int32_t feature = entry.features[jj];
  694. if (needs_more_info_main) {
  695. if (!features.count(feature))
  696. potential_features.insert(feature);
  697. } else {
  698. features.insert(feature);
  699. potential_features.erase(feature);
  700. if (!needs_more_info_exception)
  701. permanent_features.insert(feature);
  702. }
  703. }
  704. if (!needs_more_info_main)
  705. active_entries_.push_back(base::checked_cast<uint32_t>(ii));
  706. }
  707. }
  708. needs_more_info_ = permanent_features.size() < features.size() ||
  709. !potential_features.empty();
  710. return features;
  711. }
  712. const std::vector<uint32_t>& GpuControlList::GetActiveEntries() const {
  713. return active_entries_;
  714. }
  715. std::vector<uint32_t> GpuControlList::GetEntryIDsFromIndices(
  716. const std::vector<uint32_t>& entry_indices) const {
  717. std::vector<uint32_t> ids;
  718. for (auto index : entry_indices) {
  719. DCHECK_LT(index, entry_count_);
  720. ids.push_back(entries_[index].id);
  721. }
  722. return ids;
  723. }
  724. std::vector<std::string> GpuControlList::GetDisabledExtensions() {
  725. std::set<std::string> disabled_extensions;
  726. for (auto index : active_entries_) {
  727. DCHECK_LT(index, entry_count_);
  728. const Entry& entry = entries_[index];
  729. for (size_t ii = 0; ii < entry.disabled_extension_size; ++ii) {
  730. disabled_extensions.insert(entry.disabled_extensions[ii]);
  731. }
  732. }
  733. return std::vector<std::string>(disabled_extensions.begin(),
  734. disabled_extensions.end());
  735. }
  736. std::vector<std::string> GpuControlList::GetDisabledWebGLExtensions() {
  737. std::set<std::string> disabled_webgl_extensions;
  738. for (auto index : active_entries_) {
  739. DCHECK_LT(index, entry_count_);
  740. const Entry& entry = entries_[index];
  741. for (size_t ii = 0; ii < entry.disabled_webgl_extension_size; ++ii) {
  742. disabled_webgl_extensions.insert(entry.disabled_webgl_extensions[ii]);
  743. }
  744. }
  745. return std::vector<std::string>(disabled_webgl_extensions.begin(),
  746. disabled_webgl_extensions.end());
  747. }
  748. void GpuControlList::GetReasons(base::Value::List& problem_list,
  749. const std::string& tag,
  750. const std::vector<uint32_t>& entries) const {
  751. for (auto index : entries) {
  752. DCHECK_LT(index, entry_count_);
  753. const Entry& entry = entries_[index];
  754. base::Value::Dict problem;
  755. problem.Set("description", entry.description);
  756. base::Value::List cr_bugs;
  757. for (size_t jj = 0; jj < entry.cr_bug_size; ++jj)
  758. cr_bugs.Append(
  759. base::Int64ToValue(static_cast<int64_t>(entry.cr_bugs[jj])));
  760. problem.Set("crBugs", std::move(cr_bugs));
  761. base::Value::List features = entry.GetFeatureNames(feature_map_);
  762. problem.Set("affectedGpuSettings", std::move(features));
  763. DCHECK(tag == "workarounds" || tag == "disabledFeatures");
  764. problem.Set("tag", tag);
  765. problem_list.Append(std::move(problem));
  766. }
  767. }
  768. size_t GpuControlList::num_entries() const {
  769. return entry_count_;
  770. }
  771. uint32_t GpuControlList::max_entry_id() const {
  772. return max_entry_id_;
  773. }
  774. // static
  775. GpuControlList::OsType GpuControlList::GetOsType() {
  776. #if BUILDFLAG(IS_CHROMEOS)
  777. return kOsChromeOS;
  778. #elif BUILDFLAG(IS_WIN)
  779. return kOsWin;
  780. #elif BUILDFLAG(IS_ANDROID)
  781. return kOsAndroid;
  782. #elif BUILDFLAG(IS_FUCHSIA)
  783. return kOsFuchsia;
  784. #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_OPENBSD)
  785. return kOsLinux;
  786. #elif BUILDFLAG(IS_MAC)
  787. return kOsMacosx;
  788. #else
  789. return kOsAny;
  790. #endif
  791. }
  792. void GpuControlList::AddSupportedFeature(
  793. const std::string& feature_name, int feature_id) {
  794. feature_map_[feature_id] = feature_name;
  795. }
  796. // static
  797. bool GpuControlList::AreEntryIndicesValid(
  798. const std::vector<uint32_t>& entry_indices,
  799. size_t total_entries) {
  800. for (auto index : entry_indices) {
  801. if (index >= total_entries)
  802. return false;
  803. }
  804. return true;
  805. }
  806. } // namespace gpu