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 blacklist 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
59
60def check_intel_driver_version(version):
61  ver_list = version.split('.')
62  if len(ver_list) != 4:
63    return False
64  for ver in ver_list:
65    if not ver.isdigit():
66      return False
67  if int(ver_list[2]) < 100 and ver_list[3] == '0':
68    return False
69  return True
70
71
72def load_software_rendering_list_features(feature_type_filename):
73  header_file = open(feature_type_filename, 'r')
74  start = False
75  features = []
76  for line in header_file:
77    if line.startswith('enum GpuFeatureType {'):
78      assert not start
79      start = True
80      continue
81    if not start:
82      continue
83    line = line.strip()
84    line = line.split(' ', 1)[0]
85    line = line.split(',', 1)[0]
86    if line.startswith('NUMBER_OF_GPU_FEATURE_TYPES'):
87      assert start
88      start = False
89      break
90    elif line.startswith('GPU_FEATURE_TYPE_'):
91      name = line[len('GPU_FEATURE_TYPE_'):]
92      features.append(name.lower())
93    else:
94      assert False
95  assert not start
96  assert len(features) > 0
97  header_file.close()
98  return features
99
100
101def load_gpu_driver_bug_workarounds(workaround_type_filename):
102  header_file = open(workaround_type_filename, 'r')
103  start = False
104  workaround = None
105  workarounds = []
106  for line in header_file:
107    if line.startswith('#define GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)'):
108      assert not start
109      start = True
110      continue
111    if not start:
112      continue
113    line = line.strip()
114    if line.startswith('GPU_OP('):
115      assert not workaround
116      workaround = line[len('GPU_OP('):]
117      workaround = workaround.split(',', 1)[0].lower()
118      continue
119    if workaround:
120      line = line.split(')', 1)[0]
121      assert line == workaround
122      workarounds.append(line)
123      workaround = None
124      continue
125    start = False
126    break
127  assert not start
128  assert len(workarounds) > 0
129  header_file.close()
130  return workarounds
131
132
133def get_feature_set(features, total_feature_set):
134  assert len(features) > 0
135  feature_set = set([])
136  for feature in features:
137    if feature == 'all':
138      feature_set = set(total_feature_set)
139    elif isinstance(feature, dict):
140      for key in feature:
141        if key == 'exceptions':
142          for exception in feature['exceptions']:
143            assert exception in feature_set
144            feature_set.remove(exception)
145        else:
146          raise KeyError('only exceptions are allowed')
147    else:
148      assert feature in total_feature_set
149      feature_set.add(feature)
150  return feature_set
151
152
153def write_features(feature_set, feature_name_prefix, var_name,
154                   data_helper_file):
155  data_helper_file.write('const int %s[%d] = {\n' %
156                         (var_name, len(feature_set)))
157  for feature in feature_set:
158    data_helper_file.write(feature_name_prefix + feature.upper())
159    data_helper_file.write(',\n')
160  data_helper_file.write('};\n\n')
161
162
163def write_disabled_extension_list(entry_kind, entry_id, data, data_file,
164                                  data_helper_file):
165  if data:
166    var_name = 'k%sForEntry%d' % (entry_kind, entry_id)
167    # define the list
168    data_helper_file.write(
169        'const char* const %s[%d] = {\n' % (var_name, len(data)))
170    for item in data:
171      write_string(item, data_helper_file)
172      data_helper_file.write(',\n')
173    data_helper_file.write('};\n\n')
174    # use the list
175    data_file.write('base::size(%s),  // %s size\n' % (var_name, entry_kind))
176    data_file.write('%s,  // %s\n' % (var_name, entry_kind))
177  else:
178    data_file.write('0,  // %s size\n' % entry_kind)
179    data_file.write('nullptr,  // %s\n' % entry_kind)
180
181
182def write_gl_strings(entry_id, is_exception, exception_id, data,
183                     unique_symbol_id, data_file, data_helper_file):
184  if data:
185    var_name = 'kGLStringsFor%sEntry%d' % (unique_symbol_id, entry_id)
186    if is_exception:
187      var_name += 'Exception' + str(exception_id)
188    # define the GL strings
189    data_helper_file.write('const GpuControlList::GLStrings %s = {\n' %
190                           var_name)
191    for item in data:
192      write_string(item, data_helper_file)
193      data_helper_file.write(',\n')
194    data_helper_file.write('};\n\n')
195    # reference the GL strings
196    data_file.write('&%s,  // GL strings\n' % var_name)
197  else:
198    data_file.write('nullptr,  // GL strings\n')
199
200
201def write_version(version_info, name_tag, data_file):
202  op = ''
203  style = ''
204  version1 = ''
205  version2 = ''
206  if version_info:
207    op = version_info['op']
208    if 'style' in version_info:
209      style = version_info['style']
210    version1 = version_info['value']
211    if 'value2' in version_info:
212      version2 = version_info['value2']
213  data_file.write('{')
214  op_map = {
215    '=': 'kEQ',
216    '<': 'kLT',
217    '<=': 'kLE',
218    '>': 'kGT',
219    '>=': 'kGE',
220    'any': 'kAny',
221    'between': 'kBetween',
222    '': 'kUnknown',
223  }
224  assert op in op_map
225  data_file.write('GpuControlList::%s, ' % op_map[op])
226  style_map = {
227    'lexical': 'Lexical',
228    'numerical': 'Numerical',
229    '': 'Numerical',
230  }
231  assert style in style_map
232  data_file.write('GpuControlList::kVersionStyle%s, ' % style_map[style])
233  write_string(version1, data_file)
234  data_file.write(', ')
235  write_string(version2, data_file)
236  data_file.write('},  // %s\n' % name_tag)
237
238
239def write_driver_info(entry_id, is_exception, exception_id, driver_vendor,
240                      driver_version, unique_symbol_id,
241                      data_file, data_helper_file):
242  var_name = 'kDriverInfoFor%sEntry%d' % (unique_symbol_id, entry_id)
243  if is_exception:
244    var_name += 'Exception' + str(exception_id)
245  # define the GL strings
246  data_helper_file.write('const GpuControlList::DriverInfo %s = {\n' %
247                         var_name)
248  write_string_value(driver_vendor, 'driver_vendor', data_helper_file)
249  write_version(driver_version, 'driver_version', data_helper_file)
250  data_helper_file.write('};\n\n')
251  # reference the GL strings
252  data_file.write('&%s,  // driver info\n' % var_name)
253
254
255def write_number_list(entry_id, data_type, name_tag, data, is_exception,
256                      exception_id, unique_symbol_id, data_file,
257                      data_helper_file):
258  if data:
259    var_name = 'k%sFor%sEntry%d' % (name_tag, unique_symbol_id, entry_id)
260    if is_exception:
261      var_name += 'Exception' + str(exception_id)
262    # define the list
263    data_helper_file.write('const %s %s[%d] = {\n' %
264                           (data_type, var_name, len(data)))
265    for item in data:
266      data_helper_file.write(str(item))
267      data_helper_file.write(',\n')
268    data_helper_file.write('};\n\n')
269    # reference the list
270    data_file.write('base::size(%s),  // %s size\n' % (var_name, name_tag))
271    data_file.write('%s,  // %s\n' % (var_name, name_tag))
272  else:
273    data_file.write('0,  // %s size\n' % name_tag)
274    data_file.write('nullptr,  // %s\n' % name_tag)
275
276
277def write_string(string, data_file):
278  if string == '':
279    data_file.write('nullptr')
280  else:
281    data_file.write('"%s"' % string.replace('\\', '\\\\'))
282
283
284def write_string_value(string, name_tag, data_file):
285  write_string(string, data_file)
286  data_file.write(',  // %s\n' % name_tag)
287
288
289def write_boolean_value(value, name_tag, data_file):
290  data_file.write('%s,  // %s\n' % (str(value).lower(), name_tag))
291
292def write_integer_value(value, name_tag, data_file):
293  data_file.write('%s,  // %s\n' % (str(value), name_tag))
294
295def write_machine_model_info(entry_id, is_exception, exception_id,
296                             machine_model_name, machine_model_version,
297                             data_file, data_helper_file):
298  model_name_var_name = None
299  if machine_model_name:
300    assert isinstance(machine_model_name, list)
301    model_name_var_name = 'kMachineModelNameForEntry' + str(entry_id)
302    if is_exception:
303      model_name_var_name += 'Exception' + str(exception_id)
304    data_helper_file.write('const char* const %s[%d] = {\n' %
305                           (model_name_var_name, len(machine_model_name)))
306    for item in machine_model_name:
307      write_string(item, data_helper_file)
308      data_helper_file.write(',\n')
309    data_helper_file.write('};\n\n')
310  var_name = None
311  if machine_model_name or machine_model_version:
312    var_name = 'kMachineModelInfoForEntry' + str(entry_id)
313    if is_exception:
314      var_name += 'Exception' + str(exception_id)
315    # define machine model info
316    data_helper_file.write(
317      'const GpuControlList::MachineModelInfo %s = {\n' % var_name)
318    if machine_model_name:
319      data_helper_file.write('base::size(%s),  // machine model name size\n' %
320                             model_name_var_name)
321      data_helper_file.write('%s,  // machine model names\n' %
322                             model_name_var_name)
323    else:
324      data_helper_file.write('0,  // machine model name size\n')
325      data_helper_file.write('nullptr,  // machine model names\n')
326    write_version(machine_model_version, 'machine model version',
327                  data_helper_file)
328    data_helper_file.write('};\n\n')
329    # reference the machine model info
330    data_file.write('&%s,  // machine model info\n' % var_name)
331  else:
332    data_file.write('nullptr,  // machine model info\n')
333
334
335def write_os_type(os_type, data_file):
336  assert os_type in _OS_TYPE_MAP
337  data_file.write('GpuControlList::%s,  // os_type\n' % _OS_TYPE_MAP[os_type])
338
339
340def write_multi_gpu_category(multi_gpu_category, data_file):
341  map = {
342    'primary': 'Primary',
343    'secondary': 'Secondary',
344    'active': 'Active',
345    'any': 'Any',
346    '': 'None',
347  }
348  assert multi_gpu_category in map
349  data_file.write(
350    'GpuControlList::kMultiGpuCategory%s,  // multi_gpu_category\n' %
351    map[multi_gpu_category])
352
353
354def write_multi_gpu_style(multi_gpu_style, data_file):
355  map = {
356    'optimus': 'Optimus',
357    'amd_switchable': 'AMDSwitchable',
358    'amd_switchable_discrete': 'AMDSwitchableDiscrete',
359    'amd_switchable_integrated': 'AMDSwitchableIntegrated',
360    '': 'None',
361  }
362  assert multi_gpu_style in map
363  data_file.write(
364    'GpuControlList::kMultiGpuStyle%s,  // multi_gpu_style\n' %
365    map[multi_gpu_style])
366
367
368def write_gl_type(gl_type, data_file):
369  map = {
370    'gl': 'GL',
371    'gles': 'GLES',
372    'angle': 'ANGLE',
373    '': 'None',
374  }
375  assert gl_type in map
376  data_file.write('GpuControlList::kGLType%s,  // gl_type\n' % map[gl_type])
377
378
379def write_supported_or_not(feature_value, feature_name, data_file):
380  if feature_value is None:
381    feature_value = 'dont_care'
382  map = {
383    'supported': 'Supported',
384    'unsupported': 'Unsupported',
385    'dont_care': 'DontCare',
386  }
387  assert feature_value in map
388  data_file.write('GpuControlList::k%s,  // %s\n' %
389                  (map[feature_value], feature_name))
390
391
392def write_conditions(entry_id, is_exception, exception_id, entry,
393                     unique_symbol_id, data_file, data_helper_file,
394                     _data_exception_file):
395  os_type = ''
396  os_version = None
397  vendor_id = 0
398  device_id = None
399  multi_gpu_category = ''
400  multi_gpu_style = ''
401  intel_gpu_series_list = None
402  intel_gpu_generation = None
403  driver_vendor = ''
404  driver_version = None
405  gl_renderer = ''
406  gl_vendor = ''
407  gl_extensions = ''
408  gl_version_string = ''
409  gl_type = ''
410  gl_version = None
411  pixel_shader_version = None
412  in_process_gpu = False
413  gl_reset_notification_strategy = None
414  direct_rendering_version = ''
415  gpu_count = None
416  hardware_overlay = None
417  test_group = 0
418  machine_model_name = None
419  machine_model_version = None
420  exception_count = 0
421  subpixel_font_rendering = None
422  # process the entry
423  for key in entry:
424    if key == 'id':
425      assert not is_exception
426      assert entry['id'] == entry_id
427      continue
428    elif key == 'description':
429      assert not is_exception
430      continue
431    elif key == 'features':
432      assert not is_exception
433      continue
434    elif key == 'disabled_extensions':
435      assert not is_exception
436      continue
437    elif key == 'disabled_webgl_extensions':
438      assert not is_exception
439      continue
440    elif key == 'comment':
441      continue
442    elif key == 'webkit_bugs':
443      assert not is_exception
444      continue
445    elif key == 'cr_bugs':
446      assert not is_exception
447      continue
448    elif key == 'os':
449      os_info = entry[key]
450      os_type = os_info['type']
451      if 'version' in os_info:
452        os_version = os_info['version']
453    elif key == 'vendor_id':
454      vendor_id = int(entry[key], 0)
455    elif key == 'device_id':
456      device_id = entry[key]
457    elif key == 'multi_gpu_category':
458      multi_gpu_category = entry[key]
459    elif key == 'multi_gpu_style':
460      multi_gpu_style = entry[key]
461    elif key == 'intel_gpu_series':
462      intel_gpu_series_list = entry[key]
463    elif key == 'intel_gpu_generation':
464      intel_gpu_generation = entry[key]
465    elif key == 'driver_vendor':
466      driver_vendor = entry[key]
467    elif key == 'driver_version':
468      driver_version = entry[key]
469    elif key == 'gl_vendor':
470      gl_vendor = entry[key]
471    elif key == 'gl_renderer':
472      gl_renderer = entry[key]
473    elif key == 'gl_version_string':
474      gl_version_string = entry[key]
475    elif key == 'gl_type':
476      gl_type = entry[key]
477    elif key == 'gl_version':
478      gl_version = entry[key]
479    elif key == 'gl_extensions':
480      gl_extensions = entry[key]
481    elif key == 'pixel_shader_version':
482      pixel_shader_version = entry[key]
483    elif key == 'in_process_gpu':
484      assert entry[key]
485      in_process_gpu = True
486    elif key == 'gl_reset_notification_strategy':
487      gl_reset_notification_strategy = entry[key]
488    elif key == 'direct_rendering_version':
489      direct_rendering_version = entry[key]
490    elif key == 'gpu_count':
491      gpu_count = entry[key]
492    elif key == 'hardware_overlay':
493      hardware_overlay = entry[key]
494    elif key == 'test_group':
495      assert entry[key] > 0
496      test_group = entry[key]
497    elif key == 'machine_model_name':
498      machine_model_name = entry[key]
499    elif key == 'machine_model_version':
500      machine_model_version = entry[key]
501    elif key == 'subpixel_font_rendering':
502      subpixel_font_rendering = entry[key]
503    elif key == 'exceptions':
504      assert not is_exception
505      assert exception_count == 0
506    else:
507      raise ValueError('unknown key: ' + key + ' in entry ' + str(entry))
508  # write out the entry
509  write_os_type(os_type, data_file)
510  write_version(os_version, 'os_version', data_file)
511  data_file.write(format(vendor_id, '#04x'))
512  data_file.write(',  // vendor_id\n')
513  write_number_list(entry_id, 'uint32_t', 'DeviceIDs', device_id, is_exception,
514                    exception_id, unique_symbol_id, data_file,
515                    data_helper_file)
516  write_multi_gpu_category(multi_gpu_category, data_file)
517  write_multi_gpu_style(multi_gpu_style, data_file)
518  # group driver info
519  if driver_vendor != '' or driver_version != None:
520    if driver_version and os_type == 'win':
521      if (format(vendor_id, '#04x') == '0x8086' or intel_gpu_series_list
522          or intel_gpu_generation or 'Intel' in driver_vendor):
523        if not check_intel_driver_version(driver_version['value']):
524          assert False, INTEL_DRIVER_VERSION_SCHEMA
525        if 'value2' in driver_version:
526          if not check_intel_driver_version(driver_version['value2']):
527            assert False, INTEL_DRIVER_VERSION_SCHEMA
528
529    write_driver_info(entry_id, is_exception, exception_id, driver_vendor,
530                      driver_version, unique_symbol_id,
531                      data_file, data_helper_file)
532  else:
533    data_file.write('nullptr,  // driver info\n')
534  # group GL strings
535  gl_strings = None
536  if (gl_vendor != '' or gl_renderer != '' or gl_extensions != '' or
537      gl_version_string != ''):
538    gl_strings = [gl_vendor, gl_renderer, gl_extensions, gl_version_string]
539  write_gl_strings(entry_id, is_exception, exception_id, gl_strings,
540                   unique_symbol_id, data_file, data_helper_file)
541  # group machine model info
542  write_machine_model_info(entry_id, is_exception, exception_id,
543                           machine_model_name, machine_model_version,
544                           data_file, data_helper_file)
545  write_intel_gpu_series_list(entry_id, is_exception, exception_id,
546                              intel_gpu_series_list,
547                              data_file, data_helper_file)
548  write_version(intel_gpu_generation, 'intel_gpu_generation', data_file)
549  # group a bunch of less used conditions
550  if (gl_version != None or pixel_shader_version != None or in_process_gpu or
551      gl_reset_notification_strategy != None or direct_rendering_version != None
552      or gpu_count != None or hardware_overlay != None or test_group != 0 or
553      subpixel_font_rendering != None):
554    write_entry_more_data(entry_id, is_exception, exception_id, gl_type,
555                          gl_version, pixel_shader_version, in_process_gpu,
556                          gl_reset_notification_strategy,
557                          direct_rendering_version, gpu_count, hardware_overlay,
558                          test_group, subpixel_font_rendering,
559                          data_file, data_helper_file)
560  else:
561    data_file.write('nullptr,  // more conditions\n')
562
563
564def write_intel_gpu_series_list(entry_id, is_exception, exception_id,
565                                intel_gpu_series_list,
566                                data_file, data_helper_file):
567  if intel_gpu_series_list:
568    var_name = 'kIntelGpuSeriesForEntry' + str(entry_id)
569    if is_exception:
570      var_name += 'Exception' + str(exception_id)
571    data_helper_file.write('const IntelGpuSeriesType %s[%d] = {\n' %
572                           (var_name, len(intel_gpu_series_list)))
573    intel_gpu_series_map = {
574      'sandybridge': 'kSandybridge',
575      'baytrail': 'kBaytrail',
576      'ivybridge': 'kIvybridge',
577      'haswell': 'kHaswell',
578      'cherrytrail': 'kCherrytrail',
579      'broadwell': 'kBroadwell',
580      'apollolake': 'kApollolake',
581      'skylake': 'kSkylake',
582      'geminilake': 'kGeminilake',
583      'kabylake': 'kKabylake',
584      'coffeelake': 'kCoffeelake',
585      'whiskeylake': 'kWhiskeylake',
586      'cometlake': 'kCometlake',
587      'cannonlake': 'kCannonlake',
588      'icelake': 'kIcelake'
589    }
590    for series in intel_gpu_series_list:
591      assert series in intel_gpu_series_map
592      data_helper_file.write('IntelGpuSeriesType::%s,\n' %
593                             intel_gpu_series_map[series])
594    data_helper_file.write('};\n\n')
595
596    data_file.write('base::size(%s),  // intel_gpu_series size\n' % var_name)
597    data_file.write('%s,  // intel_gpu_series\n' % var_name)
598  else:
599    data_file.write('0,  // intel_gpu_series size\n')
600    data_file.write('nullptr,  // intel_gpu_series\n')
601
602
603def write_entry_more_data(entry_id, is_exception, exception_id, gl_type,
604                          gl_version, pixel_shader_version, in_process_gpu,
605                          gl_reset_notification_strategy,
606                          direct_rendering_version, gpu_count, hardware_overlay,
607                          test_group, subpixel_font_rendering, data_file,
608                          data_helper_file):
609  # write more data
610
611  # Generate a unique name for jumbo build which concatenates multiple
612  # translation units into one to speed compilation.
613  basename = os.path.basename(data_helper_file.name)
614  # & 0xffffffff converts to unsigned to keep consistent across Python versions
615  # and platforms as per https://docs.python.org/3/library/zlib.html
616  suffix = '_%s' % (zlib.crc32(basename.encode()) & 0xffffffff)
617  var_name = 'kMoreForEntry' + str(entry_id) + suffix
618  if is_exception:
619    var_name += 'Exception' + str(exception_id)
620  data_helper_file.write('const GpuControlList::More %s = {\n' % var_name)
621  write_gl_type(gl_type, data_helper_file)
622  write_version(gl_version, 'gl_version', data_helper_file)
623  write_version(pixel_shader_version, 'pixel_shader_version', data_helper_file)
624  write_boolean_value(in_process_gpu, 'in_process_gpu', data_helper_file)
625  if not gl_reset_notification_strategy:
626    gl_reset_notification_strategy = '0'
627  data_helper_file.write('%s,  // gl_reset_notification_strategy\n' %
628                         gl_reset_notification_strategy)
629  write_version(direct_rendering_version, 'direct_rendering_version',
630                data_helper_file)
631  write_version(gpu_count, 'gpu_count', data_helper_file)
632  write_supported_or_not(hardware_overlay, 'hardware_overlay', data_helper_file)
633  write_integer_value(test_group, 'test_group', data_helper_file)
634  write_supported_or_not(subpixel_font_rendering, 'subpixel_font_rendering',
635                         data_helper_file)
636  data_helper_file.write('};\n\n')
637  # reference more data in entry
638  data_file.write('&%s,  // more data\n' % var_name)
639
640
641def write_entry(entry, total_feature_set, feature_name_prefix,
642                unique_symbol_id, data_file, data_helper_file,
643                data_exception_file):
644  data_file.write('{\n')
645  # ID
646  entry_id = entry['id']
647  data_file.write('%d,  // id\n' % entry_id)
648  data_file.write('"%s",\n' % entry['description']);
649  # Features
650  if 'features' in entry:
651    var_name = 'kFeatureListFor%sEntry%d' % (unique_symbol_id, entry_id)
652    features = entry['features']
653    feature_set = get_feature_set(features, total_feature_set)
654    data_file.write('base::size(%s),  // features size\n' % var_name)
655    data_file.write('%s,  // features\n' % var_name)
656    write_features(feature_set, feature_name_prefix, var_name, data_helper_file)
657  else:
658    data_file.write('0,  // feature size\n')
659    data_file.write('nullptr,  // features\n')
660  # Disabled extensions
661  write_disabled_extension_list('DisabledExtensions', entry_id,
662                                entry.get('disabled_extensions', None),
663                                data_file, data_helper_file)
664  # Disabled WebGL extensions
665  write_disabled_extension_list('DisabledWebGLExtensions', entry_id,
666                                entry.get('disabled_webgl_extensions', None),
667                                data_file, data_helper_file)
668  # webkit_bugs are skipped because there is only one entry that has it.
669  # cr_bugs
670  cr_bugs = None
671  if 'cr_bugs' in entry:
672    cr_bugs = entry['cr_bugs']
673  write_number_list(entry_id, 'uint32_t', 'CrBugs', cr_bugs, False, -1,
674                    unique_symbol_id, data_file, data_helper_file)
675  # Conditions
676  data_file.write('{\n')
677  write_conditions(entry_id, False, -1, entry, unique_symbol_id,
678                   data_file, data_helper_file, data_exception_file)
679  data_file.write('},\n')
680  # Exceptions
681  if 'exceptions' in entry:
682    exceptions = entry['exceptions']
683    exception_count = len(exceptions)
684    exception_var = 'kExceptionsForEntry' + str(entry_id)
685    data_exception_file.write('const GpuControlList::Conditions %s[%d] = {\n' %
686                              (exception_var, exception_count))
687    for index in range(exception_count):
688      exception = exceptions[index]
689      if 'device_id' in exception and 'vendor_id' not in exception:
690        assert 'vendor_id' in entry
691        exception['vendor_id'] = entry['vendor_id']
692      data_exception_file.write('{\n')
693      write_conditions(entry_id, True, index, exception, unique_symbol_id,
694                       data_exception_file, data_helper_file, None)
695      data_exception_file.write('},\n')
696    data_exception_file.write('};\n\n')
697    data_file.write('base::size(%s),  // exceptions count\n' % exception_var)
698    data_file.write('%s,  // exceptions\n' % exception_var)
699  else:
700    data_file.write('0,  // exceptions count\n')
701    data_file.write('nullptr,  // exceptions\n')
702  # END
703  data_file.write('},\n')
704
705
706def format_files(generated_files):
707  formatter = "clang-format"
708  if platform.system() == "Windows":
709    formatter += ".bat"
710  for filename in generated_files:
711    call([formatter, "-i", "-style=chromium", filename])
712
713
714def write_header_file_guard(file, filename, path, begin):
715  token = (path.upper().replace('/', '_') + '_' +
716           filename.upper().replace('.', '_') + '_')
717  if begin:
718    file.write('#ifndef %s\n#define %s\n\n' % (token, token))
719  else:
720    file.write('\n#endif  // %s\n' % token)
721
722
723def process_json_file(json_filepath, list_tag,
724                      feature_header_filename, total_features, feature_tag,
725                      output_header_filepath, output_data_filepath,
726                      output_helper_filepath, output_exception_filepath, path,
727                      export_tag, git_format, os_filter, unique_symbol_id):
728  output_header_filename = os.path.basename(output_header_filepath)
729  output_helper_filename = os.path.basename(output_helper_filepath)
730  output_exception_filename = os.path.basename(output_exception_filepath)
731  json_file = open(json_filepath, 'rb')
732  json_data = json.load(json_file)
733  json_file.close()
734  data_file = open(output_data_filepath, 'w')
735  data_file.write(_LICENSE)
736  data_file.write(_DO_NOT_EDIT_WARNING)
737  data_file.write('#include "%s/%s"\n\n' % (path, output_header_filename))
738  data_file.write('#include "%s/%s"\n' % (path, output_helper_filename))
739  data_file.write('#include "%s/%s"\n\n' % (path, output_exception_filename))
740  data_helper_file = open(output_helper_filepath, 'w')
741  data_helper_file.write(_LICENSE)
742  data_helper_file.write(_DO_NOT_EDIT_WARNING)
743  write_header_file_guard(data_helper_file, output_helper_filename, path, True)
744  data_helper_file.write('#include "gpu/config/%s"\n\n' %
745                         feature_header_filename)
746  data_helper_file.write('namespace gpu {\n')
747  data_exception_file = open(output_exception_filepath, 'w')
748  data_exception_file.write(_LICENSE)
749  data_exception_file.write(_DO_NOT_EDIT_WARNING)
750  write_header_file_guard(data_exception_file, output_exception_filename, path,
751                          True)
752  data_exception_file.write('namespace gpu {\n')
753  data_file.write('namespace gpu {\n\n')
754  data_file.write('const GpuControlList::Entry k%sEntries[] = {\n' % list_tag)
755  ids = []
756  entry_count = 0
757  for index in range(len(json_data['entries'])):
758    entry = json_data['entries'][index]
759    entry_id = entry['id']
760    assert entry_id not in ids
761    ids.append(entry_id)
762    if 'os' in entry:
763      os_type = entry['os']['type']
764      # Check for typos in the .json data
765      if os_type not in _OS_TYPE_MAP:
766        raise Exception('Unknown OS type "%s" for entry %d' %
767                        (os_type, entry_id))
768      if os_filter != None and os_type != os_filter:
769        continue
770    entry_count += 1
771    write_entry(entry, total_features, feature_tag, unique_symbol_id,
772                data_file, data_helper_file, data_exception_file)
773  data_file.write('};\n')
774  data_file.write('const size_t k%sEntryCount = %d;\n' %
775                  (list_tag, entry_count))
776  data_file.write('}  // namespace gpu\n')
777  data_file.close()
778  data_helper_file.write('}  // namespace gpu\n')
779  write_header_file_guard(data_helper_file, output_helper_filename, path, False)
780  data_helper_file.close()
781  data_exception_file.write('}  // namespace gpu\n')
782  write_header_file_guard(data_exception_file, output_exception_filename, path,
783                          False)
784  data_exception_file.close()
785  data_header_file = open(output_header_filepath, 'w')
786  data_header_file.write(_LICENSE)
787  data_header_file.write(_DO_NOT_EDIT_WARNING)
788  write_header_file_guard(data_header_file, output_header_filename, path, True)
789  if export_tag == 'CONTENT_EXPORT ':
790    data_header_file.write('#include "content/common/content_export.h"\n')
791  data_header_file.write('#include "gpu/config/gpu_control_list.h"\n\n')
792  data_header_file.write('\n')
793  data_header_file.write('namespace gpu {\n')
794  data_header_file.write('%sextern const size_t k%sEntryCount;\n' %
795                         (export_tag, list_tag))
796  data_header_file.write(
797      '%sextern const GpuControlList::Entry k%sEntries[];\n' %
798      (export_tag, list_tag))
799  data_header_file.write('}  // namespace gpu\n')
800  write_header_file_guard(data_header_file, output_header_filename, path, False)
801  data_header_file.close()
802  if git_format:
803    format_files([output_header_filepath, output_data_filepath,
804                  output_helper_filepath, output_exception_filepath])
805
806
807def process_software_rendering_list(script_dir, output_dir, os_filter):
808  total_features = load_software_rendering_list_features(
809      os.path.join(script_dir, 'gpu_feature_type.h'))
810  process_json_file(
811      os.path.join(script_dir, 'software_rendering_list.json'),
812      'SoftwareRenderingList',
813      'gpu_feature_type.h',
814      total_features,
815      'GPU_FEATURE_TYPE_',
816      os.path.join(output_dir, 'software_rendering_list_autogen.h'),
817      os.path.join(output_dir, 'software_rendering_list_autogen.cc'),
818      os.path.join(output_dir,
819                   'software_rendering_list_arrays_and_structs_autogen.h'),
820      os.path.join(output_dir, 'software_rendering_list_exceptions_autogen.h'),
821      'gpu/config',
822      'GPU_EXPORT ',
823      False,
824      os_filter,
825      'Software')
826
827
828def process_gpu_driver_bug_list(script_dir, output_dir, os_filter):
829  total_features = load_gpu_driver_bug_workarounds(
830      os.path.join(output_dir, 'gpu_driver_bug_workaround_autogen.h'))
831  process_json_file(
832      os.path.join(script_dir, 'gpu_driver_bug_list.json'),
833      'GpuDriverBugList',
834      'gpu_driver_bug_workaround_type.h',
835      total_features,
836      '',
837      os.path.join(output_dir, 'gpu_driver_bug_list_autogen.h'),
838      os.path.join(output_dir, 'gpu_driver_bug_list_autogen.cc'),
839      os.path.join(output_dir,
840                   'gpu_driver_bug_list_arrays_and_structs_autogen.h'),
841      os.path.join(output_dir, 'gpu_driver_bug_list_exceptions_autogen.h'),
842      'gpu/config',
843      'GPU_EXPORT ',
844      False,
845      os_filter,
846      'Workarounds')
847
848
849def process_gpu_control_list_testing(script_dir, output_dir):
850  total_features = ['test_feature_0', 'test_feature_1', 'test_feature_2']
851  process_json_file(
852      os.path.join(script_dir, 'gpu_control_list_testing.json'),
853      'GpuControlListTesting',
854      'gpu_control_list_testing_data.h',
855      total_features,
856      '',
857      os.path.join(output_dir, 'gpu_control_list_testing_autogen.h'),
858      os.path.join(output_dir, 'gpu_control_list_testing_autogen.cc'),
859      os.path.join(output_dir,
860                   'gpu_control_list_testing_arrays_and_structs_autogen.h'),
861      os.path.join(output_dir, 'gpu_control_list_testing_exceptions_autogen.h'),
862      'gpu/config',
863      '',
864      True,
865      None,
866      'GpuControlTesting')
867
868
869def process_gpu_data_manager_testing(script_dir, output_dir):
870  total_features = load_software_rendering_list_features(
871      os.path.join(script_dir, 'gpu_feature_type.h'))
872  process_json_file(
873      os.path.join(output_dir, 'gpu_data_manager_testing.json'),
874      'GpuDataManagerTesting',
875      'gpu_feature_type.h',
876      total_features,
877      'GPU_FEATURE_TYPE_',
878      os.path.join(output_dir, 'gpu_data_manager_testing_autogen.h'),
879      os.path.join(output_dir, 'gpu_data_manager_testing_autogen.cc'),
880      os.path.join(output_dir,
881                   'gpu_data_manager_testing_arrays_and_structs_autogen.h'),
882      os.path.join(output_dir, 'gpu_data_manager_testing_exceptions_autogen.h'),
883      'content/browser/gpu',
884      '',
885      True,
886      None,
887      'GpuManagerTesting')
888
889
890def write_test_entry_enums(input_json_filepath, output_entry_enums_filepath,
891                           path, list_tag):
892  json_file = open(input_json_filepath, 'rb')
893  json_data = json.load(json_file)
894  json_file.close()
895
896  output_entry_enums_filename = os.path.basename(output_entry_enums_filepath)
897  enum_file = open(output_entry_enums_filepath, 'w')
898  enum_file.write(_LICENSE)
899  enum_file.write(_DO_NOT_EDIT_WARNING)
900  write_header_file_guard(enum_file, output_entry_enums_filename, path, True)
901  enum_file.write('namespace gpu {\n')
902  enum_file.write('enum %sEntryEnum {\n' % list_tag)
903  entry_count = len(json_data['entries'])
904  for index in range(entry_count):
905    entry = json_data['entries'][index]
906    entry_id = entry['id']
907    description = entry['description']
908    assert(index + 1 == int(entry_id))
909    description = 'k' + description
910    description = description.replace('.', '_')
911    enum_file.write('  %s = %d,\n' % (description, index))
912  enum_file.write('};\n')
913  enum_file.write('}  // namespace gpu\n')
914  write_header_file_guard(enum_file, output_entry_enums_filename, path, False)
915  enum_file.close()
916  format_files([output_entry_enums_filepath])
917
918
919def main(argv):
920  parser = OptionParser()
921  parser.add_option("--output-dir",
922                    help="output directory for SoftwareRenderingList and "
923                    "GpuDriverBugList data files. "
924                    "If unspecified, these files are not generated.")
925  parser.add_option("--skip-testing-data", action="store_false",
926                    dest="generate_testing_data", default=True,
927                    help="skip testing data generation.")
928  parser.add_option("--os-filter",
929                    help="only output entries applied to the specified os.")
930  (options, _) = parser.parse_args(args=argv)
931
932  script_dir = os.path.dirname(os.path.realpath(__file__))
933
934  if options.output_dir != None:
935    process_software_rendering_list(
936        script_dir, options.output_dir, options.os_filter)
937    process_gpu_driver_bug_list(
938        script_dir, options.output_dir, options.os_filter)
939
940  if options.generate_testing_data:
941    # Testing data files are generated by calling the script manually.
942    process_gpu_control_list_testing(script_dir, script_dir)
943    write_test_entry_enums(
944        os.path.join(script_dir, 'gpu_control_list_testing.json'),
945        os.path.join(script_dir,
946                     'gpu_control_list_testing_entry_enums_autogen.h'),
947        'gpu/config',
948        'GpuControlListTesting')
949    chrome_root_dir = os.path.abspath(os.path.join(script_dir, '../../'))
950    gpu_data_manager_dir = os.path.join(chrome_root_dir, 'content/browser/gpu')
951    process_gpu_data_manager_testing(script_dir, gpu_data_manager_dir)
952    write_test_entry_enums(
953        os.path.join(gpu_data_manager_dir, 'gpu_data_manager_testing.json'),
954        os.path.join(gpu_data_manager_dir,
955                     'gpu_data_manager_testing_entry_enums_autogen.h'),
956        'content/browser/gpu',
957        'GpuDataManagerTesting')
958
959
960if __name__ == '__main__':
961  sys.exit(main(sys.argv[1:]))
962