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