1#!/usr/bin/env python
2# Copyright 2017 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Generate data struct from GPU blocklist and driver bug workarounds json."""
7
8import json
9import os
10import platform
11import sys
12import zlib
13from optparse import OptionParser
14from subprocess import call
15
16_LICENSE = """// Copyright (c) 2019 The Chromium Authors. All rights reserved.
17// Use of this source code is governed by a BSD-style license that can be
18// found in the LICENSE file.
19
20"""
21
22_DO_NOT_EDIT_WARNING = """// This file is auto-generated from
23//    gpu/config/process_json.py
24// It's formatted by clang-format using chromium coding style:
25//    clang-format -i -style=chromium filename
26// DO NOT EDIT!
27
28"""
29
30_OS_TYPE_MAP = {
31    'win': 'kOsWin',
32    'macosx': 'kOsMacosx',
33    'android': 'kOsAndroid',
34    'linux': 'kOsLinux',
35    'chromeos': 'kOsChromeOS',
36    '': 'kOsAny',
37  }
38
39INTEL_DRIVER_VERSION_SCHEMA = '''
40The version format of Intel graphics driver is AA.BB.CCC.DDDD.
41DDDD(old schema) or CCC.DDDD(new schema) is the build number. That is,
42indicates the actual driver number. The comparison between old schema
43and new schema is NOT valid. In such a condition the only comparison
44operator that returns true is "not equal".
45
46AA.BB: You are free to specify the real number here, but they are meaningless
47when comparing two version numbers. Usually it's okay to leave it to "0.0".
48
49CCC: It's necessary for new schema. Regarding to old schema, you can speicy
50the real number or any number less than 100 in order to differentiate from
51new schema.
52
53DDDD: It's always meaningful. It must not be "0" under old schema.
54
55Legal: "24.20.100.7000", "0.0.100.7000", "0.0.0.7000", "0.0.100.0"
56Illegal: "24.0.0.0", "24.20.0.0", "0.0.99.0"
57'''
58
59NVIDIA_DRIVER_VERSION_SCHEMA = '''
60The version format used by Nvidia is ABC.DE, where A-E are any digit.  When
61queried by Chrome, it will detect XX.XX.XXXA.BCDE, where 'X' is any digit and
62can be ignored.  Chrome will re-format this to ABC.DE, and compare to the
63version listed here.
64
65So, Chrome might detect 26.21.0014.4575, which would be given here as 445.75 in
66the Nvidia version schema.  The 26.21.001 is ignored.
67'''
68
69
70def check_intel_driver_version(version):
71  ver_list = version.split('.')
72  if len(ver_list) != 4:
73    return False
74  for ver in ver_list:
75    if not ver.isdigit():
76      return False
77  if int(ver_list[2]) < 100 and ver_list[3] == '0':
78    return False
79  return True
80
81def check_nvidia_driver_version(version):
82  ver_list = version.split('.')
83  # Allow "456" to match "456.*", so allow a single-entry list.
84  if len(ver_list) == 0 or len(ver_list) > 2:
85    return False;
86  elif len(ver_list) == 2 and len(ver_list[1]) != 2:
87    return False
88  # Must start with three digits, whether it's "456.*" or "456.78".
89  if len(ver_list[0]) != 3:
90    return False
91  for ver in ver_list:
92    if not ver.isdigit():
93      return False
94  return True
95
96def load_software_rendering_list_features(feature_type_filename):
97  header_file = open(feature_type_filename, 'r')
98  start = False
99  features = []
100  for line in header_file:
101    if line.startswith('enum GpuFeatureType {'):
102      assert not start
103      start = True
104      continue
105    if not start:
106      continue
107    line = line.strip()
108    line = line.split(' ', 1)[0]
109    line = line.split(',', 1)[0]
110    if line.startswith('NUMBER_OF_GPU_FEATURE_TYPES'):
111      assert start
112      start = False
113      break
114    elif line.startswith('GPU_FEATURE_TYPE_'):
115      name = line[len('GPU_FEATURE_TYPE_'):]
116      features.append(name.lower())
117    else:
118      assert False
119  assert not start
120  assert len(features) > 0
121  header_file.close()
122  return features
123
124
125def load_gpu_driver_bug_workarounds(workaround_type_filename):
126  header_file = open(workaround_type_filename, 'r')
127  start = False
128  workaround = None
129  workarounds = []
130  for line in header_file:
131    if line.startswith('#define GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)'):
132      assert not start
133      start = True
134      continue
135    if not start:
136      continue
137    line = line.strip()
138    if line.startswith('GPU_OP('):
139      assert not workaround
140      workaround = line[len('GPU_OP('):]
141      workaround = workaround.split(',', 1)[0].lower()
142      continue
143    if workaround:
144      line = line.split(')', 1)[0]
145      assert line == workaround
146      workarounds.append(line)
147      workaround = None
148      continue
149    start = False
150    break
151  assert not start
152  assert len(workarounds) > 0
153  header_file.close()
154  return workarounds
155
156
157def get_feature_set(features, total_feature_set):
158  assert len(features) > 0
159  feature_set = set([])
160  for feature in features:
161    if feature == 'all':
162      feature_set = set(total_feature_set)
163    elif isinstance(feature, dict):
164      for key in feature:
165        if key == 'exceptions':
166          for exception in feature['exceptions']:
167            assert exception in feature_set
168            feature_set.remove(exception)
169        else:
170          raise KeyError('only exceptions are allowed')
171    else:
172      assert feature in total_feature_set
173      feature_set.add(feature)
174  return feature_set
175
176
177def write_features(feature_set, feature_name_prefix, var_name,
178                   data_helper_file):
179  data_helper_file.write('const int %s[%d] = {\n' %
180                         (var_name, len(feature_set)))
181  for feature in feature_set:
182    data_helper_file.write(feature_name_prefix + feature.upper())
183    data_helper_file.write(',\n')
184  data_helper_file.write('};\n\n')
185
186
187def write_disabled_extension_list(entry_kind, entry_id, data, data_file,
188                                  data_helper_file):
189  if data:
190    var_name = 'k%sForEntry%d' % (entry_kind, entry_id)
191    # define the list
192    data_helper_file.write(
193        'const char* const %s[%d] = {\n' % (var_name, len(data)))
194    for item in data:
195      write_string(item, data_helper_file)
196      data_helper_file.write(',\n')
197    data_helper_file.write('};\n\n')
198    # use the list
199    data_file.write('base::size(%s),  // %s size\n' % (var_name, entry_kind))
200    data_file.write('%s,  // %s\n' % (var_name, entry_kind))
201  else:
202    data_file.write('0,  // %s size\n' % entry_kind)
203    data_file.write('nullptr,  // %s\n' % entry_kind)
204
205
206def write_gl_strings(entry_id, is_exception, exception_id, data,
207                     unique_symbol_id, data_file, data_helper_file):
208  if data:
209    var_name = 'kGLStringsFor%sEntry%d' % (unique_symbol_id, entry_id)
210    if is_exception:
211      var_name += 'Exception' + str(exception_id)
212    # define the GL strings
213    data_helper_file.write('const GpuControlList::GLStrings %s = {\n' %
214                           var_name)
215    for item in data:
216      write_string(item, data_helper_file)
217      data_helper_file.write(',\n')
218    data_helper_file.write('};\n\n')
219    # reference the GL strings
220    data_file.write('&%s,  // GL strings\n' % var_name)
221  else:
222    data_file.write('nullptr,  // GL strings\n')
223
224
225def write_version(version_info, name_tag, data_file):
226  op = ''
227  style = ''
228  schema = ''
229  version1 = ''
230  version2 = ''
231  if version_info:
232    op = version_info['op']
233    if 'style' in version_info:
234      style = version_info['style']
235    if 'schema' in version_info:
236      schema = version_info['schema']
237    version1 = version_info['value']
238    if 'value2' in version_info:
239      version2 = version_info['value2']
240  data_file.write('{')
241  op_map = {
242    '=': 'kEQ',
243    '<': 'kLT',
244    '<=': 'kLE',
245    '>': 'kGT',
246    '>=': 'kGE',
247    'any': 'kAny',
248    'between': 'kBetween',
249    '': 'kUnknown',
250  }
251  assert op in op_map
252  data_file.write('GpuControlList::%s, ' % op_map[op])
253  style_map = {
254    'lexical': 'Lexical',
255    'numerical': 'Numerical',
256    '': 'Numerical',
257  }
258  assert style in style_map
259  data_file.write('GpuControlList::kVersionStyle%s, ' % style_map[style])
260  schema_map = {
261    'common': 'Common',
262    'intel_driver': 'IntelDriver',
263    'nvidia_driver': 'NvidiaDriver',
264    '': 'Common',
265  }
266  assert schema in schema_map
267  data_file.write('GpuControlList::kVersionSchema%s, ' % schema_map[schema])
268  write_string(version1, data_file)
269  data_file.write(', ')
270  write_string(version2, data_file)
271  data_file.write('},  // %s\n' % name_tag)
272
273
274def write_driver_info(entry_id, is_exception, exception_id, driver_vendor,
275                      driver_version, unique_symbol_id,
276                      data_file, data_helper_file):
277  var_name = 'kDriverInfoFor%sEntry%d' % (unique_symbol_id, entry_id)
278  if is_exception:
279    var_name += 'Exception' + str(exception_id)
280  # define the GL strings
281  data_helper_file.write('const GpuControlList::DriverInfo %s = {\n' %
282                         var_name)
283  write_string_value(driver_vendor, 'driver_vendor', data_helper_file)
284  write_version(driver_version, 'driver_version', data_helper_file)
285  data_helper_file.write('};\n\n')
286  # reference the GL strings
287  data_file.write('&%s,  // driver info\n' % var_name)
288
289
290def write_number_list(entry_id, data_type, name_tag, data, is_exception,
291                      exception_id, unique_symbol_id, data_file,
292                      data_helper_file):
293  if data:
294    var_name = 'k%sFor%sEntry%d' % (name_tag, unique_symbol_id, entry_id)
295    if is_exception:
296      var_name += 'Exception' + str(exception_id)
297    # define the list
298    data_helper_file.write('const %s %s[%d] = {\n' %
299                           (data_type, var_name, len(data)))
300    for item in data:
301      data_helper_file.write(str(item))
302      data_helper_file.write(',\n')
303    data_helper_file.write('};\n\n')
304    # reference the list
305    data_file.write('base::size(%s),  // %s size\n' % (var_name, name_tag))
306    data_file.write('%s,  // %s\n' % (var_name, name_tag))
307  else:
308    data_file.write('0,  // %s size\n' % name_tag)
309    data_file.write('nullptr,  // %s\n' % name_tag)
310
311
312def write_string(string, data_file):
313  if string == '':
314    data_file.write('nullptr')
315  else:
316    data_file.write('"%s"' % string.replace('\\', '\\\\'))
317
318
319def write_string_value(string, name_tag, data_file):
320  write_string(string, data_file)
321  data_file.write(',  // %s\n' % name_tag)
322
323
324def write_boolean_value(value, name_tag, data_file):
325  data_file.write('%s,  // %s\n' % (str(value).lower(), name_tag))
326
327
328def write_integer_value(value, name_tag, data_file):
329  data_file.write('%s,  // %s\n' % (str(value), name_tag))
330
331
332def write_device_list(entry_id, device_id, device_revision, is_exception,
333                      exception_id, unique_symbol_id, data_file,
334                      data_helper_file):
335  if device_id:
336    # It's one of the three ways to specify devices:
337    #  1) only specify device IDs
338    #  2) specify one device ID, associated with multiple revisions
339    #  3) specify k device IDs associated with k device revisions.
340    device_size = len(device_id)
341    if device_size == 1 and device_revision and len(device_revision) > 1:
342      device_size = len(device_revision)
343      for ii in range(device_size - 1):
344        device_id.append(device_id[0])
345    if device_revision is None:
346      device_revision = []
347      for ii in range(device_size):
348        device_revision.append('0x0')
349    assert len(device_id) == len(device_revision)
350    var_name = 'kDevicesFor%sEntry%d' % (unique_symbol_id, entry_id)
351    if is_exception:
352      var_name += 'Exception' + str(exception_id)
353    # define the list
354    data_helper_file.write('const GpuControlList::Device %s[%d] = {\n' %
355                           (var_name, len(device_id)))
356    for ii in range(device_size):
357      data_helper_file.write('{%s, %s},\n' %
358                             (device_id[ii], device_revision[ii]))
359    data_helper_file.write('};\n\n')
360    # reference the list
361    data_file.write('base::size(%s),  // Devices size\n' % var_name)
362    data_file.write('%s,  // Devices\n' % var_name)
363  else:
364    assert not device_revision
365    data_file.write('0,  // Devices size\n')
366    data_file.write('nullptr,  // Devices\n')
367
368
369def write_machine_model_info(entry_id, is_exception, exception_id,
370                             machine_model_name, machine_model_version,
371                             data_file, data_helper_file):
372  model_name_var_name = None
373  if machine_model_name:
374    assert isinstance(machine_model_name, list)
375    model_name_var_name = 'kMachineModelNameForEntry' + str(entry_id)
376    if is_exception:
377      model_name_var_name += 'Exception' + str(exception_id)
378    data_helper_file.write('const char* const %s[%d] = {\n' %
379                           (model_name_var_name, len(machine_model_name)))
380    for item in machine_model_name:
381      write_string(item, data_helper_file)
382      data_helper_file.write(',\n')
383    data_helper_file.write('};\n\n')
384  var_name = None
385  if machine_model_name or machine_model_version:
386    var_name = 'kMachineModelInfoForEntry' + str(entry_id)
387    if is_exception:
388      var_name += 'Exception' + str(exception_id)
389    # define machine model info
390    data_helper_file.write(
391      'const GpuControlList::MachineModelInfo %s = {\n' % var_name)
392    if machine_model_name:
393      data_helper_file.write('base::size(%s),  // machine model name size\n' %
394                             model_name_var_name)
395      data_helper_file.write('%s,  // machine model names\n' %
396                             model_name_var_name)
397    else:
398      data_helper_file.write('0,  // machine model name size\n')
399      data_helper_file.write('nullptr,  // machine model names\n')
400    write_version(machine_model_version, 'machine model version',
401                  data_helper_file)
402    data_helper_file.write('};\n\n')
403    # reference the machine model info
404    data_file.write('&%s,  // machine model info\n' % var_name)
405  else:
406    data_file.write('nullptr,  // machine model info\n')
407
408
409def write_os_type(os_type, data_file):
410  assert os_type in _OS_TYPE_MAP
411  data_file.write('GpuControlList::%s,  // os_type\n' % _OS_TYPE_MAP[os_type])
412
413
414def write_multi_gpu_category(multi_gpu_category, data_file):
415  suffix_for_category = {
416    'primary': 'Primary',
417    'secondary': 'Secondary',
418    'active': 'Active',
419    'any': 'Any',
420    '': 'None',
421  }
422  assert multi_gpu_category in suffix_for_category
423  data_file.write(
424    'GpuControlList::kMultiGpuCategory%s,  // multi_gpu_category\n' %
425    suffix_for_category[multi_gpu_category])
426
427
428def write_multi_gpu_style(multi_gpu_style, data_file):
429  suffix_for_style = {
430    'optimus': 'Optimus',
431    'amd_switchable': 'AMDSwitchable',
432    'amd_switchable_discrete': 'AMDSwitchableDiscrete',
433    'amd_switchable_integrated': 'AMDSwitchableIntegrated',
434    '': 'None',
435  }
436  assert multi_gpu_style in suffix_for_style
437  data_file.write(
438    'GpuControlList::kMultiGpuStyle%s,  // multi_gpu_style\n' %
439    suffix_for_style[multi_gpu_style])
440
441
442def write_gl_type(gl_type, data_file):
443  suffix_for_type = {
444    'gl': 'GL',
445    'gles': 'GLES',
446    'angle': 'ANGLE',
447    '': 'None',
448  }
449  assert gl_type in suffix_for_type
450  data_file.write('GpuControlList::kGLType%s,  // gl_type\n' %
451                  suffix_for_type[gl_type])
452
453
454def write_supported_or_not(feature_value, feature_name, data_file):
455  if feature_value is None:
456    feature_value = 'dont_care'
457  suffix_for_value = {
458    'supported': 'Supported',
459    'unsupported': 'Unsupported',
460    'dont_care': 'DontCare',
461  }
462  assert feature_value in suffix_for_value
463  data_file.write('GpuControlList::k%s,  // %s\n' %
464                  (suffix_for_value[feature_value], feature_name))
465
466
467def write_conditions(entry_id, is_exception, exception_id, entry,
468                     unique_symbol_id, data_file, data_helper_file,
469                     _data_exception_file):
470  os_type = ''
471  os_version = None
472  vendor_id = 0
473  device_id = None
474  device_revision = None
475  multi_gpu_category = ''
476  multi_gpu_style = ''
477  intel_gpu_series_list = None
478  intel_gpu_generation = None
479  driver_vendor = ''
480  driver_version = None
481  gl_renderer = ''
482  gl_vendor = ''
483  gl_extensions = ''
484  gl_version_string = ''
485  gl_type = ''
486  gl_version = None
487  pixel_shader_version = None
488  in_process_gpu = False
489  gl_reset_notification_strategy = None
490  direct_rendering_version = ''
491  gpu_count = None
492  hardware_overlay = None
493  test_group = 0
494  machine_model_name = None
495  machine_model_version = None
496  exception_count = 0
497  subpixel_font_rendering = None
498  # process the entry
499  for key in entry:
500    if key == 'id':
501      assert not is_exception
502      assert entry['id'] == entry_id
503      continue
504    elif key == 'description':
505      assert not is_exception
506      continue
507    elif key == 'driver_update_url':
508      assert not is_exception
509      continue
510    elif key == 'features':
511      assert not is_exception
512      continue
513    elif key == 'disabled_extensions':
514      assert not is_exception
515      continue
516    elif key == 'disabled_webgl_extensions':
517      assert not is_exception
518      continue
519    elif key == 'comment':
520      continue
521    elif key == 'webkit_bugs':
522      assert not is_exception
523      continue
524    elif key == 'cr_bugs':
525      assert not is_exception
526      continue
527    elif key == 'os':
528      os_info = entry[key]
529      os_type = os_info['type']
530      if 'version' in os_info:
531        os_version = os_info['version']
532    elif key == 'vendor_id':
533      vendor_id = int(entry[key], 0)
534    elif key == 'device_id':
535      device_id = entry[key]
536    elif key == 'device_revision':
537      device_revision = entry[key]
538    elif key == 'multi_gpu_category':
539      multi_gpu_category = entry[key]
540    elif key == 'multi_gpu_style':
541      multi_gpu_style = entry[key]
542    elif key == 'intel_gpu_series':
543      intel_gpu_series_list = entry[key]
544    elif key == 'intel_gpu_generation':
545      intel_gpu_generation = entry[key]
546    elif key == 'driver_vendor':
547      driver_vendor = entry[key]
548    elif key == 'driver_version':
549      driver_version = entry[key]
550    elif key == 'gl_vendor':
551      gl_vendor = entry[key]
552    elif key == 'gl_renderer':
553      gl_renderer = entry[key]
554    elif key == 'gl_version_string':
555      gl_version_string = entry[key]
556    elif key == 'gl_type':
557      gl_type = entry[key]
558    elif key == 'gl_version':
559      gl_version = entry[key]
560    elif key == 'gl_extensions':
561      gl_extensions = entry[key]
562    elif key == 'pixel_shader_version':
563      pixel_shader_version = entry[key]
564    elif key == 'in_process_gpu':
565      assert entry[key]
566      in_process_gpu = True
567    elif key == 'gl_reset_notification_strategy':
568      gl_reset_notification_strategy = entry[key]
569    elif key == 'direct_rendering_version':
570      direct_rendering_version = entry[key]
571    elif key == 'gpu_count':
572      gpu_count = entry[key]
573    elif key == 'hardware_overlay':
574      hardware_overlay = entry[key]
575    elif key == 'test_group':
576      assert entry[key] > 0
577      test_group = entry[key]
578    elif key == 'machine_model_name':
579      machine_model_name = entry[key]
580    elif key == 'machine_model_version':
581      machine_model_version = entry[key]
582    elif key == 'subpixel_font_rendering':
583      subpixel_font_rendering = entry[key]
584    elif key == 'exceptions':
585      assert not is_exception
586      assert exception_count == 0
587    else:
588      raise ValueError('unknown key: ' + key + ' in entry ' + str(entry))
589  # write out the entry
590  write_os_type(os_type, data_file)
591  write_version(os_version, 'os_version', data_file)
592  data_file.write(format(vendor_id, '#04x'))
593  data_file.write(',  // vendor_id\n')
594  write_device_list(entry_id, device_id, device_revision, is_exception,
595                    exception_id, unique_symbol_id, data_file,
596                    data_helper_file)
597  write_multi_gpu_category(multi_gpu_category, data_file)
598  write_multi_gpu_style(multi_gpu_style, data_file)
599  # group driver info
600  if driver_vendor != '' or driver_version != None:
601    if driver_version and driver_version.get('schema') == 'intel_driver':
602      assert os_type == 'win', 'Intel driver schema is only for Windows'
603      is_intel = (format(vendor_id, '#04x') == '0x8086' or
604                  intel_gpu_series_list or
605                  intel_gpu_generation or
606                  'Intel' in driver_vendor)
607      assert is_intel, 'Intel driver schema is only for Intel GPUs'
608      valid_version = check_intel_driver_version(driver_version['value'])
609      if driver_version.has_key('value2'):
610        valid_version = (valid_version and
611                         check_intel_driver_version(driver_version['value2']))
612      assert valid_version, INTEL_DRIVER_VERSION_SCHEMA
613
614    if driver_version and driver_version.get('schema') == 'nvidia_driver':
615      assert os_type == 'win', 'Nvidia driver schema is only for Windows'
616      is_nvidia = (format(vendor_id, '#04x') == '0x10de')
617      assert is_nvidia, 'Nvidia driver schema is only for Nvidia GPUs'
618      valid_version = check_nvidia_driver_version(driver_version['value'])
619      if driver_version.has_key('value2'):
620        valid_version = (valid_version and
621                         check_nvidia_driver_version(driver_version['value2']))
622      assert valid_version, NVIDIA_DRIVER_VERSION_SCHEMA
623
624    write_driver_info(entry_id, is_exception, exception_id, driver_vendor,
625                      driver_version, unique_symbol_id,
626                      data_file, data_helper_file)
627  else:
628    data_file.write('nullptr,  // driver info\n')
629  # group GL strings
630  gl_strings = None
631  if (gl_vendor != '' or gl_renderer != '' or gl_extensions != '' or
632      gl_version_string != ''):
633    gl_strings = [gl_vendor, gl_renderer, gl_extensions, gl_version_string]
634  write_gl_strings(entry_id, is_exception, exception_id, gl_strings,
635                   unique_symbol_id, data_file, data_helper_file)
636  # group machine model info
637  write_machine_model_info(entry_id, is_exception, exception_id,
638                           machine_model_name, machine_model_version,
639                           data_file, data_helper_file)
640  write_intel_gpu_series_list(entry_id, is_exception, exception_id,
641                              intel_gpu_series_list,
642                              data_file, data_helper_file)
643  write_version(intel_gpu_generation, 'intel_gpu_generation', data_file)
644  # group a bunch of less used conditions
645  if (gl_version != None or pixel_shader_version != None or in_process_gpu or
646      gl_reset_notification_strategy != None or direct_rendering_version != None
647      or gpu_count != None or hardware_overlay != None or test_group != 0 or
648      subpixel_font_rendering != None):
649    write_entry_more_data(entry_id, is_exception, exception_id, gl_type,
650                          gl_version, pixel_shader_version, in_process_gpu,
651                          gl_reset_notification_strategy,
652                          direct_rendering_version, gpu_count, hardware_overlay,
653                          test_group, subpixel_font_rendering,
654                          data_file, data_helper_file)
655  else:
656    data_file.write('nullptr,  // more conditions\n')
657
658
659def write_intel_gpu_series_list(entry_id, is_exception, exception_id,
660                                intel_gpu_series_list,
661                                data_file, data_helper_file):
662  if intel_gpu_series_list:
663    var_name = 'kIntelGpuSeriesForEntry' + str(entry_id)
664    if is_exception:
665      var_name += 'Exception' + str(exception_id)
666    data_helper_file.write('const IntelGpuSeriesType %s[%d] = {\n' %
667                           (var_name, len(intel_gpu_series_list)))
668    intel_gpu_series_map = {
669      'broadwater': 'kBroadwater',
670      'eaglelake': 'kEaglelake',
671      'ironlake': 'kIronlake',
672      'sandybridge': 'kSandybridge',
673      'baytrail': 'kBaytrail',
674      'ivybridge': 'kIvybridge',
675      'haswell': 'kHaswell',
676      'cherrytrail': 'kCherrytrail',
677      'broadwell': 'kBroadwell',
678      'apollolake': 'kApollolake',
679      'skylake': 'kSkylake',
680      'geminilake': 'kGeminilake',
681      'kabylake': 'kKabylake',
682      'coffeelake': 'kCoffeelake',
683      'whiskeylake': 'kWhiskeylake',
684      'cometlake': 'kCometlake',
685      'cannonlake': 'kCannonlake',
686      'icelake': 'kIcelake',
687      'elkhartlake': 'kElkhartlake',
688      'jasperlake': 'kJasperlake',
689      'tigerlake': 'kTigerlake'
690    }
691    for series in intel_gpu_series_list:
692      assert series in intel_gpu_series_map
693      data_helper_file.write('IntelGpuSeriesType::%s,\n' %
694                             intel_gpu_series_map[series])
695    data_helper_file.write('};\n\n')
696
697    data_file.write('base::size(%s),  // intel_gpu_series size\n' % var_name)
698    data_file.write('%s,  // intel_gpu_series\n' % var_name)
699  else:
700    data_file.write('0,  // intel_gpu_series size\n')
701    data_file.write('nullptr,  // intel_gpu_series\n')
702
703
704def write_entry_more_data(entry_id, is_exception, exception_id, gl_type,
705                          gl_version, pixel_shader_version, in_process_gpu,
706                          gl_reset_notification_strategy,
707                          direct_rendering_version, gpu_count, hardware_overlay,
708                          test_group, subpixel_font_rendering, data_file,
709                          data_helper_file):
710  # write more data
711
712  # Generate a unique name for jumbo build which concatenates multiple
713  # translation units into one to speed compilation.
714  basename = os.path.basename(data_helper_file.name)
715  # & 0xffffffff converts to unsigned to keep consistent across Python versions
716  # and platforms as per https://docs.python.org/3/library/zlib.html
717  suffix = '_%s' % (zlib.crc32(basename.encode()) & 0xffffffff)
718  var_name = 'kMoreForEntry' + str(entry_id) + suffix
719  if is_exception:
720    var_name += 'Exception' + str(exception_id)
721  data_helper_file.write('const GpuControlList::More %s = {\n' % var_name)
722  write_gl_type(gl_type, data_helper_file)
723  write_version(gl_version, 'gl_version', data_helper_file)
724  write_version(pixel_shader_version, 'pixel_shader_version', data_helper_file)
725  write_boolean_value(in_process_gpu, 'in_process_gpu', data_helper_file)
726  if not gl_reset_notification_strategy:
727    gl_reset_notification_strategy = '0'
728  data_helper_file.write('%s,  // gl_reset_notification_strategy\n' %
729                         gl_reset_notification_strategy)
730  write_version(direct_rendering_version, 'direct_rendering_version',
731                data_helper_file)
732  write_version(gpu_count, 'gpu_count', data_helper_file)
733  write_supported_or_not(hardware_overlay, 'hardware_overlay', data_helper_file)
734  write_integer_value(test_group, 'test_group', data_helper_file)
735  write_supported_or_not(subpixel_font_rendering, 'subpixel_font_rendering',
736                         data_helper_file)
737  data_helper_file.write('};\n\n')
738  # reference more data in entry
739  data_file.write('&%s,  // more data\n' % var_name)
740
741
742def write_entry(entry, total_feature_set, feature_name_prefix,
743                unique_symbol_id, data_file, data_helper_file,
744                data_exception_file):
745  data_file.write('{\n')
746  # ID
747  entry_id = entry['id']
748  data_file.write('%d,  // id\n' % entry_id)
749  description = entry['description']
750  if 'driver_update_url' in entry:
751    description += (' Please update your graphics driver via this link: ' +
752                    entry['driver_update_url'])
753  data_file.write('"%s",\n' % description);
754  # Features
755  if 'features' in entry:
756    var_name = 'kFeatureListFor%sEntry%d' % (unique_symbol_id, entry_id)
757    features = entry['features']
758    feature_set = get_feature_set(features, total_feature_set)
759    data_file.write('base::size(%s),  // features size\n' % var_name)
760    data_file.write('%s,  // features\n' % var_name)
761    write_features(feature_set, feature_name_prefix, var_name, data_helper_file)
762  else:
763    data_file.write('0,  // feature size\n')
764    data_file.write('nullptr,  // features\n')
765  # Disabled extensions
766  write_disabled_extension_list('DisabledExtensions', entry_id,
767                                entry.get('disabled_extensions', None),
768                                data_file, data_helper_file)
769  # Disabled WebGL extensions
770  write_disabled_extension_list('DisabledWebGLExtensions', entry_id,
771                                entry.get('disabled_webgl_extensions', None),
772                                data_file, data_helper_file)
773  # webkit_bugs are skipped because there is only one entry that has it.
774  # cr_bugs
775  cr_bugs = None
776  if 'cr_bugs' in entry:
777    cr_bugs = entry['cr_bugs']
778  write_number_list(entry_id, 'uint32_t', 'CrBugs', cr_bugs, False, -1,
779                    unique_symbol_id, data_file, data_helper_file)
780  # Conditions
781  data_file.write('{\n')
782  write_conditions(entry_id, False, -1, entry, unique_symbol_id,
783                   data_file, data_helper_file, data_exception_file)
784  data_file.write('},\n')
785  # Exceptions
786  if 'exceptions' in entry:
787    exceptions = entry['exceptions']
788    exception_count = len(exceptions)
789    exception_var = 'kExceptionsForEntry' + str(entry_id)
790    data_exception_file.write('const GpuControlList::Conditions %s[%d] = {\n' %
791                              (exception_var, exception_count))
792    for index in range(exception_count):
793      exception = exceptions[index]
794      if 'device_id' in exception and 'vendor_id' not in exception:
795        assert 'vendor_id' in entry
796        exception['vendor_id'] = entry['vendor_id']
797      data_exception_file.write('{\n')
798      write_conditions(entry_id, True, index, exception, unique_symbol_id,
799                       data_exception_file, data_helper_file, None)
800      data_exception_file.write('},\n')
801    data_exception_file.write('};\n\n')
802    data_file.write('base::size(%s),  // exceptions count\n' % exception_var)
803    data_file.write('%s,  // exceptions\n' % exception_var)
804  else:
805    data_file.write('0,  // exceptions count\n')
806    data_file.write('nullptr,  // exceptions\n')
807  # END
808  data_file.write('},\n')
809
810
811def format_files(generated_files):
812  formatter = "clang-format"
813  if platform.system() == "Windows":
814    formatter += ".bat"
815  for filename in generated_files:
816    call([formatter, "-i", "-style=chromium", filename])
817
818
819def write_header_file_guard(out_file, filename, path, begin):
820  token = (path.upper().replace('/', '_') + '_' +
821           filename.upper().replace('.', '_') + '_')
822  if begin:
823    out_file.write('#ifndef %s\n#define %s\n\n' % (token, token))
824  else:
825    out_file.write('\n#endif  // %s\n' % token)
826
827
828def process_json_file(json_filepath, list_tag,
829                      feature_header_filename, total_features, feature_tag,
830                      output_header_filepath, output_data_filepath,
831                      output_helper_filepath, output_exception_filepath, path,
832                      export_tag, git_format, os_filter, unique_symbol_id):
833  output_header_filename = os.path.basename(output_header_filepath)
834  output_helper_filename = os.path.basename(output_helper_filepath)
835  output_exception_filename = os.path.basename(output_exception_filepath)
836  json_file = open(json_filepath, 'rb')
837  json_data = json.load(json_file)
838  json_file.close()
839  data_file = open(output_data_filepath, 'w')
840  data_file.write(_LICENSE)
841  data_file.write(_DO_NOT_EDIT_WARNING)
842  data_file.write('#include "%s/%s"\n\n' % (path, output_header_filename))
843  data_file.write('#include "%s/%s"\n' % (path, output_helper_filename))
844  data_file.write('#include "%s/%s"\n\n' % (path, output_exception_filename))
845  data_helper_file = open(output_helper_filepath, 'w')
846  data_helper_file.write(_LICENSE)
847  data_helper_file.write(_DO_NOT_EDIT_WARNING)
848  write_header_file_guard(data_helper_file, output_helper_filename, path, True)
849  data_helper_file.write('#include "gpu/config/%s"\n\n' %
850                         feature_header_filename)
851  data_helper_file.write('namespace gpu {\n')
852  data_exception_file = open(output_exception_filepath, 'w')
853  data_exception_file.write(_LICENSE)
854  data_exception_file.write(_DO_NOT_EDIT_WARNING)
855  write_header_file_guard(data_exception_file, output_exception_filename, path,
856                          True)
857  data_exception_file.write('namespace gpu {\n')
858  data_file.write('namespace gpu {\n\n')
859  data_file.write('const GpuControlList::Entry k%sEntries[] = {\n' % list_tag)
860  ids = []
861  entry_count = 0
862  for index in range(len(json_data['entries'])):
863    entry = json_data['entries'][index]
864    entry_id = entry['id']
865    assert entry_id not in ids
866    ids.append(entry_id)
867    if 'os' in entry:
868      os_type = entry['os']['type']
869      # Check for typos in the .json data
870      if os_type not in _OS_TYPE_MAP:
871        raise Exception('Unknown OS type "%s" for entry %d' %
872                        (os_type, entry_id))
873      if os_filter != None and os_type != os_filter:
874        continue
875    entry_count += 1
876    write_entry(entry, total_features, feature_tag, unique_symbol_id,
877                data_file, data_helper_file, data_exception_file)
878  data_file.write('};\n')
879  data_file.write('const size_t k%sEntryCount = %d;\n' %
880                  (list_tag, entry_count))
881  data_file.write('}  // namespace gpu\n')
882  data_file.close()
883  data_helper_file.write('}  // namespace gpu\n')
884  write_header_file_guard(data_helper_file, output_helper_filename, path, False)
885  data_helper_file.close()
886  data_exception_file.write('}  // namespace gpu\n')
887  write_header_file_guard(data_exception_file, output_exception_filename, path,
888                          False)
889  data_exception_file.close()
890  data_header_file = open(output_header_filepath, 'w')
891  data_header_file.write(_LICENSE)
892  data_header_file.write(_DO_NOT_EDIT_WARNING)
893  write_header_file_guard(data_header_file, output_header_filename, path, True)
894  if export_tag == 'CONTENT_EXPORT ':
895    data_header_file.write('#include "content/common/content_export.h"\n')
896  data_header_file.write('#include "gpu/config/gpu_control_list.h"\n\n')
897  data_header_file.write('\n')
898  data_header_file.write('namespace gpu {\n')
899  data_header_file.write('%sextern const size_t k%sEntryCount;\n' %
900                         (export_tag, list_tag))
901  data_header_file.write(
902      '%sextern const GpuControlList::Entry k%sEntries[];\n' %
903      (export_tag, list_tag))
904  data_header_file.write('}  // namespace gpu\n')
905  write_header_file_guard(data_header_file, output_header_filename, path, False)
906  data_header_file.close()
907  if git_format:
908    format_files([output_header_filepath, output_data_filepath,
909                  output_helper_filepath, output_exception_filepath])
910
911
912def process_software_rendering_list(script_dir, output_dir, os_filter):
913  total_features = load_software_rendering_list_features(
914      os.path.join(script_dir, 'gpu_feature_type.h'))
915  process_json_file(
916      os.path.join(script_dir, 'software_rendering_list.json'),
917      'SoftwareRenderingList',
918      'gpu_feature_type.h',
919      total_features,
920      'GPU_FEATURE_TYPE_',
921      os.path.join(output_dir, 'software_rendering_list_autogen.h'),
922      os.path.join(output_dir, 'software_rendering_list_autogen.cc'),
923      os.path.join(output_dir,
924                   'software_rendering_list_arrays_and_structs_autogen.h'),
925      os.path.join(output_dir, 'software_rendering_list_exceptions_autogen.h'),
926      'gpu/config',
927      'GPU_EXPORT ',
928      False,
929      os_filter,
930      'Software')
931
932
933def process_gpu_driver_bug_list(script_dir, output_dir, os_filter):
934  total_features = load_gpu_driver_bug_workarounds(
935      os.path.join(output_dir, 'gpu_driver_bug_workaround_autogen.h'))
936  process_json_file(
937      os.path.join(script_dir, 'gpu_driver_bug_list.json'),
938      'GpuDriverBugList',
939      'gpu_driver_bug_workaround_type.h',
940      total_features,
941      '',
942      os.path.join(output_dir, 'gpu_driver_bug_list_autogen.h'),
943      os.path.join(output_dir, 'gpu_driver_bug_list_autogen.cc'),
944      os.path.join(output_dir,
945                   'gpu_driver_bug_list_arrays_and_structs_autogen.h'),
946      os.path.join(output_dir, 'gpu_driver_bug_list_exceptions_autogen.h'),
947      'gpu/config',
948      'GPU_EXPORT ',
949      False,
950      os_filter,
951      'Workarounds')
952
953
954def process_gpu_control_list_testing(script_dir, output_dir):
955  total_features = ['test_feature_0', 'test_feature_1', 'test_feature_2']
956  process_json_file(
957      os.path.join(script_dir, 'gpu_control_list_testing.json'),
958      'GpuControlListTesting',
959      'gpu_control_list_testing_data.h',
960      total_features,
961      '',
962      os.path.join(output_dir, 'gpu_control_list_testing_autogen.h'),
963      os.path.join(output_dir, 'gpu_control_list_testing_autogen.cc'),
964      os.path.join(output_dir,
965                   'gpu_control_list_testing_arrays_and_structs_autogen.h'),
966      os.path.join(output_dir, 'gpu_control_list_testing_exceptions_autogen.h'),
967      'gpu/config',
968      '',
969      True,
970      None,
971      'GpuControlTesting')
972
973
974def process_gpu_data_manager_testing(script_dir, output_dir):
975  total_features = load_software_rendering_list_features(
976      os.path.join(script_dir, 'gpu_feature_type.h'))
977  process_json_file(
978      os.path.join(output_dir, 'gpu_data_manager_testing.json'),
979      'GpuDataManagerTesting',
980      'gpu_feature_type.h',
981      total_features,
982      'GPU_FEATURE_TYPE_',
983      os.path.join(output_dir, 'gpu_data_manager_testing_autogen.h'),
984      os.path.join(output_dir, 'gpu_data_manager_testing_autogen.cc'),
985      os.path.join(output_dir,
986                   'gpu_data_manager_testing_arrays_and_structs_autogen.h'),
987      os.path.join(output_dir, 'gpu_data_manager_testing_exceptions_autogen.h'),
988      'content/browser/gpu',
989      '',
990      True,
991      None,
992      'GpuManagerTesting')
993
994
995def write_test_entry_enums(input_json_filepath, output_entry_enums_filepath,
996                           path, list_tag):
997  json_file = open(input_json_filepath, 'rb')
998  json_data = json.load(json_file)
999  json_file.close()
1000
1001  output_entry_enums_filename = os.path.basename(output_entry_enums_filepath)
1002  enum_file = open(output_entry_enums_filepath, 'w')
1003  enum_file.write(_LICENSE)
1004  enum_file.write(_DO_NOT_EDIT_WARNING)
1005  write_header_file_guard(enum_file, output_entry_enums_filename, path, True)
1006  enum_file.write('namespace gpu {\n')
1007  enum_file.write('enum %sEntryEnum {\n' % list_tag)
1008  entry_count = len(json_data['entries'])
1009  for index in range(entry_count):
1010    entry = json_data['entries'][index]
1011    entry_id = entry['id']
1012    description = entry['description']
1013    assert(index + 1 == int(entry_id))
1014    description = 'k' + description
1015    description = description.replace('.', '_')
1016    enum_file.write('  %s = %d,\n' % (description, index))
1017  enum_file.write('};\n')
1018  enum_file.write('}  // namespace gpu\n')
1019  write_header_file_guard(enum_file, output_entry_enums_filename, path, False)
1020  enum_file.close()
1021  format_files([output_entry_enums_filepath])
1022
1023
1024def main(argv):
1025  parser = OptionParser()
1026  parser.add_option("--output-dir",
1027                    help="output directory for SoftwareRenderingList and "
1028                    "GpuDriverBugList data files. "
1029                    "If unspecified, these files are not generated.")
1030  parser.add_option("--skip-testing-data", action="store_false",
1031                    dest="generate_testing_data", default=True,
1032                    help="skip testing data generation.")
1033  parser.add_option("--os-filter",
1034                    help="only output entries applied to the specified os.")
1035  (options, _) = parser.parse_args(args=argv)
1036
1037  script_dir = os.path.dirname(os.path.realpath(__file__))
1038
1039  if options.output_dir != None:
1040    process_software_rendering_list(
1041        script_dir, options.output_dir, options.os_filter)
1042    process_gpu_driver_bug_list(
1043        script_dir, options.output_dir, options.os_filter)
1044
1045  if options.generate_testing_data:
1046    # Testing data files are generated by calling the script manually.
1047    process_gpu_control_list_testing(script_dir, script_dir)
1048    write_test_entry_enums(
1049        os.path.join(script_dir, 'gpu_control_list_testing.json'),
1050        os.path.join(script_dir,
1051                     'gpu_control_list_testing_entry_enums_autogen.h'),
1052        'gpu/config',
1053        'GpuControlListTesting')
1054    chrome_root_dir = os.path.abspath(os.path.join(script_dir, '../../'))
1055    gpu_data_manager_dir = os.path.join(chrome_root_dir, 'content/browser/gpu')
1056    process_gpu_data_manager_testing(script_dir, gpu_data_manager_dir)
1057    write_test_entry_enums(
1058        os.path.join(gpu_data_manager_dir, 'gpu_data_manager_testing.json'),
1059        os.path.join(gpu_data_manager_dir,
1060                     'gpu_data_manager_testing_entry_enums_autogen.h'),
1061        'content/browser/gpu',
1062        'GpuDataManagerTesting')
1063
1064
1065if __name__ == '__main__':
1066  sys.exit(main(sys.argv[1:]))
1067