1#!/usr/bin/python3 2# 3# Copyright 2021 The ANGLE Project Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6# 7# gen_extensions.py: 8# Generates files from supported extensions data. 9# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 10 11import json 12import os 13import re 14import sys 15 16d = os.path.dirname 17THIS_DIR = d(os.path.abspath(__file__)) 18ANGLE_SRC_DIR = d(d(THIS_DIR)) 19SCRIPTS_DIR = os.path.join(ANGLE_SRC_DIR, 'scripts') 20sys.path.insert(0, SCRIPTS_DIR) 21 22import registry_xml 23 24_MD_GLES_GPU_CONFIGS = [ 25 'NVIDIA 1660 Win10', 26 'Intel 630 Win10', 27 'NVIDIA 1660 Linux', 28 'Intel 630 Linux', 29 'SwiftShader Win10', 30 'Pixel 4 Android 11', 31 'Pixel 6 Android 13', 32] 33 34_MD_GLES1_GPU_CONFIGS = [ 35 'SwiftShader Win10', 36] 37 38_GLES_EXTENSIONS_TEMPLATE = """\ 39// GENERATED FILE - DO NOT EDIT. 40// Generated by {script_name} using data from {data_source_name} 41// 42// Copyright 2021 The ANGLE Project Authors. All rights reserved. 43// Use of this source code is governed by a BSD-style license that can be 44// found in the LICENSE file. 45// 46// {filename}: GLES extension information. 47 48#ifndef LIBANGLE_GLES_EXTENSIONS_AUTOGEN_H_ 49#define LIBANGLE_GLES_EXTENSIONS_AUTOGEN_H_ 50 51namespace gl 52{{ 53class TextureCapsMap; 54 55struct Extensions 56{{ 57 Extensions(); 58 Extensions(const Extensions &other); 59 60 Extensions &operator=(const Extensions &other); 61 62 // Generate a vector of supported extension strings 63 std::vector<std::string> getStrings() const; 64 65 // Set all texture related extension support based on the supported textures. 66 // Determines support for: 67 // GL_OES_packed_depth_stencil 68 // GL_OES_rgb8_rgba8 69 // GL_EXT_texture_format_BGRA8888 70 // GL_EXT_color_buffer_half_float, 71 // GL_OES_texture_half_float, GL_OES_texture_half_float_linear 72 // GL_OES_texture_float, GL_OES_texture_float_linear 73 // GL_EXT_texture_rg 74 // GL_EXT_texture_type_2_10_10_10_REV 75 // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, 76 // GL_ANGLE_texture_compression_dxt5 77 // GL_KHR_texture_compression_astc_ldr, GL_OES_texture_compression_astc. 78 // NOTE: GL_KHR_texture_compression_astc_hdr must be enabled separately. Support for the 79 // HDR profile cannot be determined from the format enums alone. 80 // GL_OES_compressed_ETC1_RGB8_texture 81 // GL_EXT_sRGB 82 // GL_ANGLE_depth_texture, GL_OES_depth32 83 // GL_EXT_color_buffer_float 84 // GL_EXT_texture_norm16 85 // GL_EXT_texture_compression_bptc 86 // GL_EXT_texture_compression_rgtc 87 void setTextureExtensionSupport(const TextureCapsMap &textureCaps); 88 89 // Helper functions 90{helper_functions} 91 92 // GLES 2.0+ extensions 93 // -------------------- 94 95{gles_extensions} 96 // ANGLE unofficial extensions 97 // --------------------------- 98 99{angle_extensions} 100 // GLES 1.0 and 1.1 extensions 101 // --------------------------- 102 103{gles1_extensions}}}; 104}} // namespace gl 105 106#endif // LIBANGLE_GLES_EXTENSIONS_AUTOGEN_H_ 107""" 108 109_EXT_MEMBER_TEMPLATE = """\ 110 // {full_name} 111 bool {name_camel_case}{vendor} = false; 112""" 113 114_HELPER_TEMPLATE = """ bool {ext_name}Any() const {{ return ({expression}); }}""" 115 116_GLES_EXT_STRINGS_TEMPLATE = """\ 117// GENERATED FILE - DO NOT EDIT. 118// Generated by {script_name} using data from {data_source_name} 119// 120// Copyright 2021 The ANGLE Project Authors. All rights reserved. 121// Use of this source code is governed by a BSD-style license that can be 122// found in the LICENSE file. 123// 124// {filename}: GLES extension strings information. 125 126#include "anglebase/no_destructor.h" 127#include "libANGLE/Caps.h" 128 129namespace gl 130{{ 131const ExtensionInfoMap &GetExtensionInfoMap() 132{{ 133 auto buildExtensionInfoMap = []() {{ 134 auto enableableExtension = [](ExtensionBool member) {{ 135 ExtensionInfo info; 136 info.Requestable = true; 137 info.ExtensionsMember = member; 138 return info; 139 }}; 140 141 auto enableableDisablableExtension = [&](ExtensionBool member) {{ 142 ExtensionInfo info = enableableExtension(member); 143 info.Disablable = true; 144 return info; 145 }}; 146 147 auto esOnlyExtension = [](ExtensionBool member) {{ 148 ExtensionInfo info; 149 info.ExtensionsMember = member; 150 return info; 151 }}; 152 153 // clang-format off 154 ExtensionInfoMap map; 155 156 // GLES 2.0 extension strings 157 // -------------------------- 158{gles_strings} 159 160 // ANGLE unofficial extension strings 161 // ---------------------------------- 162{angle_strings} 163 164 // GLES 1.0 and 1.1 extension strings 165 // ---------------------------------- 166{gles1_strings} 167 // clang-format on 168 169#if defined(ANGLE_ENABLE_ASSERTS) 170 // Verify all extension strings start with GL_ 171 for (const auto &extension : map) 172 {{ 173 ASSERT(extension.first.rfind("GL_", 0) == 0); 174 }} 175#endif 176 177 return map; 178 }}; 179 180 static const angle::base::NoDestructor<ExtensionInfoMap> extensionInfo(buildExtensionInfoMap()); 181 return *extensionInfo; 182}} 183}} // namespace gl 184""" 185 186_EXT_STRING_TEMPLATE = """\ 187 map["{full_name}"] = {mode}Extension(&Extensions::{name_camel_case}{vendor});""" 188 189ESONLY = 'esOnly' 190REQUESTABLE = 'enableable' 191TOGGLEABLE = 'enableableDisablable' 192 193_MARKDOWN_TEMPLATE = """\ 194# ANGLE Supported Extensions 195 196This is a list of all extensions currently supported by ANGLE's front-end, and 197support listed for some of the tested targets for ANGLE's Vulkan back-end. To 198produce a list of all supported extensions in the Vulkan back-end, run 199`angle_end2end_tests` with `--gtest_filter EGLPrintEGLinfoTest.PrintGLInfo/ES*_Vulkan`. 200 201Specifications for GLES extensions can be found in the [Khronos OpenGL ES API 202Registry](http://www.khronos.org/registry/gles/) 203 204Specifications for EGL extensions can be found in the [Khronos EGL API 205Registry](http://www.khronos.org/registry/egl/) 206 207Specifications for ANGLE-specific extensions can be found in the [ANGLE 208extension registry](../extensions) 209 210This list is automatically generated by [`{script_name}`](../src/libANGLE/gen_extensions.py) 211using data from {data_source_name}. 212 213## GLES 2.0, 3.0, 3.1 and 3.2 extension support 214 215*Note: some data is sampled from older drivers, so might not represent the latest driver support.* 216 217{gles_md_table_header} 218{gles_md_exts} 219 220## ANGLE unofficial extension support 221 222*Note: some ANGLE extensions are currently missing specifications.* 223 224{angle_md_table_header} 225{angle_md_exts} 226 227## GLES 1.0 and 1.1 extension support 228 229{gles1_md_table_header} 230{gles1_md_exts} 231 232## EGL extension support 233 234Currently EGL extensions are not automatically tracked by our scripting. For a 235list of supported EGL extensions in ANGLE's front-end see 236[`src/libANGLE/Caps.h`](../src/libANGLE/Caps.h). 237 238## Configuration information 239 240{md_gpu_info} 241## How to update supported extension data 242 243Supported extension data is stored in the ANGLE repo as JSON files in 244[`scripts/extension_data`](../scripts/extension_data). The JSON data is 245sourced from public ANGLE test runs. Look for `angle_end2end_tests` in a bot 246run: [example link](https://ci.chromium.org/ui/p/angle/builders/ci/win-test/520/overview). 247Search for "`angle_end2end_tests`", then click on the "cas output" and find 248`GLinfo_ES3_2_Vulkan.json` or `GLinfo_ES3_1_Vulkan_SwiftShader.json` for 249SwiftShader. 250 251All data except for GLES 1 is automatically updated using 252the [`update_extension_data.py`](../scripts/update_extension_data.py) script. 253To use it first authenticate to the `bb` and `luci-go` tools by running `bb 254auth-login` and `./tools/luci-go/swarming login`. Then run the script and 255re-run [code generation][CodeGen]. 256 257The GLES 1 data is currently manually updated. Find the relevant 258file from the task output (see above) and overwrite the correspoding file. 259Re-run [code generation][CodeGen] and create a CL as per our normal process. 260 261To add a new configuration, first retrieve the JSON data, modify 262[`gen_extensions.py`](../src/libANGLE/gen_extensions.py) as necessary, then 263run [`scripts/run_code_generation.py`][CodeGen] to refresh generated files. 264Also update `update_extension_data.py` as necessary. 265 266[CodeGen]: ../scripts/run_code_generation.py 267""" 268 269_MD_TABLE_HEADER_TEMPLATE = """\ 270| Extension Name | {configs} | 271| -------------- | {dashes} |""" 272 273_MD_CONFIG_INFO_TEMPLATE = """\ 274{config}: 275 276 * `GL_RENDERER` is `{Renderer}` 277 * `GL_VENDOR` is `{Vendor}` 278 * `GL_VERSION` is `{Version}` 279 * Data updated {DateRecorded} 280""" 281 282_MD_GLES_EXT_LINK_TEMPLATE = """[{full_name}](https://khronos.org/registry/OpenGL/extensions/{vendor}/{vendor}_{link}.txt)""" 283_MD_ANGLE_EXT_LINK_TEMPLATE = """[{full_name}](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/{vendor}_{link}.txt)""" 284 285# Some extensions are defined in documents that have different names. 286_LINK_OVERRIDES = { 287 'GL_ANGLE_shader_pixel_local_storage_coherent': 'shader_pixel_local_storage', 288 'GL_EXT_memory_object_fd': 'external_objects_fd', 289 'GL_EXT_semaphore_fd': 'external_objects_fd', 290} 291 292 293def get_camel_case(name_with_underscores): 294 """ To follow ANGLE naming for member variables, we convert the canonical extension: 295 0. Delete the API and vendor prefix. 296 1. Capitalize letters after underscores. 297 2. Delete underscores. 298 3. Add back the vendor prefix to the end. """ 299 words = name_with_underscores.split('_') 300 words = [words[0]] + [(word[0].upper() + word[1:]) for word in words[1:]] 301 return ''.join(words) 302 303 304def break_down_ext(ext, expr, mode): 305 """ This splits an extension name like GL_EXT_buffer_storage into string components. """ 306 m = expr.match(ext) 307 return { 308 'full_name': ext, 309 'api_prefix': m.group(1), 310 'vendor': m.group(2), 311 'name_with_underscores': m.group(3), 312 'name_camel_case': get_camel_case(m.group(3)), 313 'mode': mode, 314 'link': _LINK_OVERRIDES.get(ext, m.group(3)), 315 } 316 317 318def break_down_exts(exts, expr, mode): 319 return [break_down_ext(ext, expr, mode) for ext in exts] 320 321 322def format_exts(ext_infos): 323 return '\n'.join([_EXT_MEMBER_TEMPLATE.format(**ext_info) for ext_info in ext_infos]) 324 325 326def format_helper_function(ext_name, vendors): 327 return _HELPER_TEMPLATE.format( 328 ext_name=ext_name, 329 expression=' || '.join(['%s%s' % (ext_name, vendor) for vendor in vendors]), 330 ) 331 332 333def format_ext_strings(ext_infos): 334 return '\n'.join([_EXT_STRING_TEMPLATE.format(**ext_info) for ext_info in ext_infos]) 335 336 337def write_file(fname, template, format_args): 338 with open(fname, 'w') as f: 339 formatted = template.format(**format_args) 340 f.write(formatted) 341 f.close() 342 343 344def sort_by_ext_name(ext_infos): 345 return sorted(ext_infos, key=lambda e: e['name_camel_case'].lower()) 346 347 348def get_ext_support(ext_name, gpu_data): 349 350 def s(ext, support): 351 SUPPORT_SYM = '✔' 352 NOSUPPORT_SYM = '' 353 return SUPPORT_SYM if ext in support['Extensions'] else NOSUPPORT_SYM 354 355 return ' | '.join([s(ext_name, support) for support in gpu_data]) 356 357 358def get_md_table_header(md_gpu_configs): 359 configs = ' | '.join(md_gpu_configs) 360 dashes = ' | '.join([(':%s:' % ('-' * (len(config) - 2))) for config in md_gpu_configs]) 361 return _MD_TABLE_HEADER_TEMPLATE.format(configs=configs, dashes=dashes) 362 363 364def format_md_gpu_info(gpu_data): 365 return _MD_CONFIG_INFO_TEMPLATE.format(**gpu_data) 366 367 368def format_md_link(ext_info, link_template): 369 return link_template.format(**ext_info) 370 371 372def format_md_ext(ext_info, gpu_json_data, link_template): 373 return '| %s | %s |' % (format_md_link( 374 ext_info, link_template), get_ext_support(ext_info['full_name'], gpu_json_data)) 375 376 377def format_md_exts(ext_infos, gpu_json_data, link_template): 378 return '\n'.join( 379 [format_md_ext(ext_info, gpu_json_data, link_template) for ext_info in ext_infos]) 380 381 382def main(): 383 # auto_script parameters. 384 data_source_name = 'registry_xml.py and gl.xml' 385 gles_h_output_name = 'gles_extensions_autogen.h' 386 gles_cpp_output_name = 'gles_extensions_autogen.cpp' 387 md_output_name = '../../doc/ExtensionSupport.md' 388 ext_jsons = [ 389 '../../scripts/extension_data/%s.json' % s.lower().replace(' ', '_') 390 for s in _MD_GLES_GPU_CONFIGS 391 ] 392 gles1_ext_jsons = [ 393 '../../scripts/extension_data/%s_gles1.json' % s.lower().replace(' ', '_') 394 for s in _MD_GLES1_GPU_CONFIGS 395 ] 396 if len(sys.argv) > 1: 397 inputs = ['../../scripts/%s' % xml_input for xml_input in registry_xml.xml_inputs 398 ] + ext_jsons + gles1_ext_jsons 399 outputs = [gles_h_output_name, gles_cpp_output_name, md_output_name] 400 if sys.argv[1] == 'inputs': 401 print(','.join(inputs)) 402 elif sys.argv[1] == 'outputs': 403 print(','.join(outputs)) 404 else: 405 print('Invalid script parameters.') 406 return 1 407 return 0 408 409 expr = re.compile(r'^([A-Z]+)_([A-Z]+)_(\w+)$') 410 411 angle_ext_infos = ( 412 break_down_exts(registry_xml.angle_requestable_extensions, expr, REQUESTABLE) + 413 break_down_exts(registry_xml.angle_es_only_extensions, expr, ESONLY) + 414 break_down_exts(registry_xml.angle_toggleable_extensions, expr, TOGGLEABLE)) 415 416 angle_ext_infos = sort_by_ext_name(angle_ext_infos) 417 418 gles_ext_infos = ( 419 break_down_exts(registry_xml.gles_requestable_extensions, expr, REQUESTABLE) + 420 break_down_exts(registry_xml.gles_es_only_extensions, expr, ESONLY)) 421 422 gles_ext_infos = sort_by_ext_name(gles_ext_infos) 423 424 gles1_ext_infos = break_down_exts(registry_xml.gles1_extensions, expr, REQUESTABLE) 425 426 gles1_ext_infos = sort_by_ext_name(gles1_ext_infos) 427 428 ext_infos = angle_ext_infos + gles_ext_infos + gles1_ext_infos 429 430 ext_name_to_vendors = {} 431 for info in ext_infos: 432 ext_name = info['name_camel_case'] 433 if ext_name in ext_name_to_vendors: 434 ext_name_to_vendors[ext_name] += [info['vendor']] 435 else: 436 ext_name_to_vendors[ext_name] = [info['vendor']] 437 438 helper_function_data = [] 439 for (ext_name, vendors) in sorted(ext_name_to_vendors.items()): 440 if len(vendors) > 1: 441 helper_function_data += [format_helper_function(ext_name, vendors)] 442 443 helper_functions = '\n'.join(helper_function_data) 444 445 gles_gpu_data = [] 446 for (gpu_config, ext_json) in zip(_MD_GLES_GPU_CONFIGS, ext_jsons): 447 with open(ext_json) as f: 448 config_support = json.loads(f.read()) 449 config_support['config'] = gpu_config 450 gles_gpu_data.append(config_support) 451 452 gles1_gpu_data = [] 453 for (gpu_config, ext_json) in zip(_MD_GLES1_GPU_CONFIGS, gles1_ext_jsons): 454 with open(ext_json) as f: 455 config_support = json.loads(f.read()) 456 config_support['config'] = gpu_config 457 gles1_gpu_data.append(config_support) 458 459 gles_md_exts = format_md_exts(gles_ext_infos, gles_gpu_data, _MD_GLES_EXT_LINK_TEMPLATE) 460 angle_md_exts = format_md_exts(angle_ext_infos, gles_gpu_data, _MD_ANGLE_EXT_LINK_TEMPLATE) 461 gles1_md_exts = format_md_exts(gles1_ext_infos, gles1_gpu_data, _MD_GLES_EXT_LINK_TEMPLATE) 462 md_gpu_info = [format_md_gpu_info(gpu_data) for gpu_data in gles_gpu_data] 463 464 format_args = { 465 'script_name': os.path.basename(__file__), 466 'data_source_name': os.path.basename(data_source_name), 467 'filename': gles_h_output_name, 468 'gles_extensions': format_exts(gles_ext_infos), 469 'angle_extensions': format_exts(angle_ext_infos), 470 'gles1_extensions': format_exts(gles1_ext_infos), 471 'helper_functions': helper_functions, 472 'angle_strings': format_ext_strings(angle_ext_infos), 473 'gles_strings': format_ext_strings(gles_ext_infos), 474 'gles1_strings': format_ext_strings(gles1_ext_infos), 475 'gles_md_table_header': get_md_table_header(_MD_GLES_GPU_CONFIGS), 476 'gles_md_exts': gles_md_exts, 477 'angle_md_table_header': get_md_table_header(_MD_GLES_GPU_CONFIGS), 478 'angle_md_exts': angle_md_exts, 479 'gles1_md_table_header': get_md_table_header(_MD_GLES1_GPU_CONFIGS), 480 'gles1_md_exts': gles1_md_exts, 481 'md_gpu_info': '\n'.join(md_gpu_info), 482 } 483 484 write_file(gles_h_output_name, _GLES_EXTENSIONS_TEMPLATE, format_args) 485 write_file(gles_cpp_output_name, _GLES_EXT_STRINGS_TEMPLATE, format_args) 486 write_file(md_output_name, _MARKDOWN_TEMPLATE, format_args) 487 488 return 0 489 490 491if __name__ == '__main__': 492 sys.exit(main()) 493