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