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