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-clang-x64-rel/8183/overview). 233Search for "`angle_end2end_tests`", then click on the "cas output" and find 234`GLinfo_ES3_2_Vulkan.json`. 235 236The Pixel 4 and GLES 3 NVIDIA and Intel data is automatically updated using 237the [`update_extension_data.py`](../scripts/update_extension_data.py) script. 238To use it first authenticate to the `bb` and `luci-go` tools by running `bb 239auth-login` and `./tools/luci-go/swarming login`. Then run the script and 240re-run [code generation][CodeGen]. 241 242The GLES 1 and SwiftShader data is currently manually updated. Find the relevant 243file from the task output (see above) and overwrite the correspoding file. 244Re-run [code generation][CodeGen] and create a CL as per our normal process. 245 246To add a new configuration, first retrieve the JSON data, modify 247[`gen_extensions.py`](../src/libANGLE/gen_extensions.py) as necessary, then 248run [`scripts/run_code_generation.py`][CodeGen] to refresh generated files. 249 250[CodeGen]: ../scripts/run_code_generation.py 251""" 252 253_MD_GLES_GPU_CONFIGS = [ 254 'NVIDIA P400 Win10', 255 'Intel 630 Win10', 256 'NVIDIA P400 Linux', 257 'Intel 630 Linux', 258 'SwiftShader Win10', 259 'Pixel 4 Android 11', 260] 261 262_MD_GLES1_GPU_CONFIGS = [ 263 'SwiftShader Win10', 264] 265 266_MD_TABLE_HEADER_TEMPLATE = """\ 267| Extension Name | {configs} | 268| -------------- | {dashes} |""" 269 270_MD_CONFIG_INFO_TEMPLATE = """\ 271{config}: 272 273 * `GL_RENDERER` is `{Renderer}` 274 * `GL_VENDOR` is `{Vendor}` 275 * `GL_VERSION` is `{Version}` 276 * Data updated {DateRecorded} 277""" 278 279_MD_GLES_EXT_LINK_TEMPLATE = """[{full_name}](https://khronos.org/registry/OpenGL/extensions/{vendor}/{vendor}_{link}.txt)""" 280_MD_ANGLE_EXT_LINK_TEMPLATE = """[{full_name}](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/{vendor}_{link}.txt)""" 281 282# Some extensions are defined in documents that have different names. 283_LINK_OVERRIDES = { 284 'GL_EXT_memory_object_fd': 'external_objects_fd', 285 'GL_EXT_semaphore_fd': 'external_objects_fd', 286} 287 288 289def get_camel_case(name_with_underscores): 290 """ To follow ANGLE naming for member variables, we convert the canonical extension: 291 0. Delete the API and vendor prefix. 292 1. Capitalize letters after underscores. 293 2. Delete underscores. 294 3. Add back the vendor prefix to the end. """ 295 words = name_with_underscores.split('_') 296 words = [words[0]] + [(word[0].upper() + word[1:]) for word in words[1:]] 297 return ''.join(words) 298 299 300def break_down_ext(ext, expr, mode): 301 """ This splits an extension name like GL_EXT_buffer_storage into string components. """ 302 m = expr.match(ext) 303 return { 304 'full_name': ext, 305 'api_prefix': m.group(1), 306 'vendor': m.group(2), 307 'name_with_underscores': m.group(3), 308 'name_camel_case': get_camel_case(m.group(3)), 309 'mode': mode, 310 'link': _LINK_OVERRIDES.get(ext, m.group(3)), 311 } 312 313 314def break_down_exts(exts, expr, mode): 315 return [break_down_ext(ext, expr, mode) for ext in exts] 316 317 318def format_exts(ext_infos): 319 return '\n'.join([_EXT_MEMBER_TEMPLATE.format(**ext_info) for ext_info in ext_infos]) 320 321 322def format_helper_function(ext_name, vendors): 323 return _HELPER_TEMPLATE.format( 324 ext_name=ext_name, 325 expression=' || '.join(['%s%s' % (ext_name, vendor) for vendor in vendors]), 326 ) 327 328 329def format_ext_strings(ext_infos): 330 return '\n'.join([_EXT_STRING_TEMPLATE.format(**ext_info) for ext_info in ext_infos]) 331 332 333def write_file(fname, template, format_args): 334 with open(fname, 'w') as f: 335 formatted = template.format(**format_args) 336 f.write(formatted) 337 f.close() 338 339 340def sort_by_ext_name(ext_infos): 341 return sorted(ext_infos, key=lambda e: e['name_camel_case'].lower()) 342 343 344def get_ext_support(ext_name, gpu_data): 345 346 def s(ext, support): 347 CHECKMARK = '✔' 348 CROSS = '❌' 349 return CHECKMARK if ext in support['Extensions'] else CROSS 350 351 return ' | '.join([s(ext_name, support) for support in gpu_data]) 352 353 354def get_md_table_header(md_gpu_configs): 355 configs = ' | '.join(md_gpu_configs) 356 dashes = ' | '.join([(':%s:' % ('-' * (len(config) - 2))) for config in md_gpu_configs]) 357 return _MD_TABLE_HEADER_TEMPLATE.format(configs=configs, dashes=dashes) 358 359 360def format_md_gpu_info(gpu_data): 361 return _MD_CONFIG_INFO_TEMPLATE.format(**gpu_data) 362 363 364def format_md_link(ext_info, link_template): 365 return link_template.format(**ext_info) 366 367 368def format_md_ext(ext_info, gpu_json_data, link_template): 369 return '| %s | %s |' % (format_md_link( 370 ext_info, link_template), get_ext_support(ext_info['full_name'], gpu_json_data)) 371 372 373def format_md_exts(ext_infos, gpu_json_data, link_template): 374 return '\n'.join( 375 [format_md_ext(ext_info, gpu_json_data, link_template) for ext_info in ext_infos]) 376 377 378def main(): 379 # auto_script parameters. 380 data_source_name = 'registry_xml.py and gl.xml' 381 gles_h_output_name = 'gles_extensions_autogen.h' 382 gles_cpp_output_name = 'gles_extensions_autogen.cpp' 383 md_output_name = '../../doc/ExtensionSupport.md' 384 ext_jsons = [ 385 '../../scripts/extension_data/%s.json' % s.lower().replace(' ', '_') 386 for s in _MD_GLES_GPU_CONFIGS 387 ] 388 gles1_ext_jsons = [ 389 '../../scripts/extension_data/%s_gles1.json' % s.lower().replace(' ', '_') 390 for s in _MD_GLES1_GPU_CONFIGS 391 ] 392 if len(sys.argv) > 1: 393 inputs = ['../../scripts/%s' % xml_input for xml_input in registry_xml.xml_inputs 394 ] + ext_jsons + gles1_ext_jsons 395 outputs = [gles_h_output_name, gles_cpp_output_name, md_output_name] 396 if sys.argv[1] == 'inputs': 397 print(','.join(inputs)) 398 elif sys.argv[1] == 'outputs': 399 print(','.join(outputs)) 400 else: 401 print('Invalid script parameters.') 402 return 1 403 return 0 404 405 expr = re.compile(r'^([A-Z]+)_([A-Z]+)_(\w+)$') 406 407 angle_ext_infos = ( 408 break_down_exts(registry_xml.angle_requestable_extensions, expr, REQUESTABLE) + 409 break_down_exts(registry_xml.angle_es_only_extensions, expr, ESONLY) + 410 break_down_exts(registry_xml.angle_toggleable_extensions, expr, TOGGLEABLE)) 411 412 angle_ext_infos = sort_by_ext_name(angle_ext_infos) 413 414 gles_ext_infos = ( 415 break_down_exts(registry_xml.gles_requestable_extensions, expr, REQUESTABLE) + 416 break_down_exts(registry_xml.gles_es_only_extensions, expr, ESONLY)) 417 418 gles_ext_infos = sort_by_ext_name(gles_ext_infos) 419 420 gles1_ext_infos = break_down_exts(registry_xml.gles1_extensions, expr, REQUESTABLE) 421 422 gles1_ext_infos = sort_by_ext_name(gles1_ext_infos) 423 424 ext_infos = angle_ext_infos + gles_ext_infos + gles1_ext_infos 425 426 ext_name_to_vendors = {} 427 for info in ext_infos: 428 ext_name = info['name_camel_case'] 429 if ext_name in ext_name_to_vendors: 430 ext_name_to_vendors[ext_name] += [info['vendor']] 431 else: 432 ext_name_to_vendors[ext_name] = [info['vendor']] 433 434 helper_function_data = [] 435 for (ext_name, vendors) in sorted(ext_name_to_vendors.items()): 436 if len(vendors) > 1: 437 helper_function_data += [format_helper_function(ext_name, vendors)] 438 439 helper_functions = '\n'.join(helper_function_data) 440 441 gles_gpu_data = [] 442 for (gpu_config, ext_json) in zip(_MD_GLES_GPU_CONFIGS, ext_jsons): 443 with open(ext_json) as f: 444 config_support = json.loads(f.read()) 445 config_support['config'] = gpu_config 446 gles_gpu_data.append(config_support) 447 448 gles1_gpu_data = [] 449 for (gpu_config, ext_json) in zip(_MD_GLES1_GPU_CONFIGS, gles1_ext_jsons): 450 with open(ext_json) as f: 451 config_support = json.loads(f.read()) 452 config_support['config'] = gpu_config 453 gles1_gpu_data.append(config_support) 454 455 gles_md_exts = format_md_exts(gles_ext_infos, gles_gpu_data, _MD_GLES_EXT_LINK_TEMPLATE) 456 angle_md_exts = format_md_exts(angle_ext_infos, gles_gpu_data, _MD_ANGLE_EXT_LINK_TEMPLATE) 457 gles1_md_exts = format_md_exts(gles1_ext_infos, gles1_gpu_data, _MD_GLES_EXT_LINK_TEMPLATE) 458 md_gpu_info = [format_md_gpu_info(gpu_data) for gpu_data in gles_gpu_data] 459 460 format_args = { 461 'script_name': os.path.basename(__file__), 462 'data_source_name': os.path.basename(data_source_name), 463 'filename': gles_h_output_name, 464 'gles_extensions': format_exts(gles_ext_infos), 465 'angle_extensions': format_exts(angle_ext_infos), 466 'gles1_extensions': format_exts(gles1_ext_infos), 467 'helper_functions': helper_functions, 468 'angle_strings': format_ext_strings(angle_ext_infos), 469 'gles_strings': format_ext_strings(gles_ext_infos), 470 'gles1_strings': format_ext_strings(gles1_ext_infos), 471 'gles_md_table_header': get_md_table_header(_MD_GLES_GPU_CONFIGS), 472 'gles_md_exts': gles_md_exts, 473 'angle_md_table_header': get_md_table_header(_MD_GLES_GPU_CONFIGS), 474 'angle_md_exts': angle_md_exts, 475 'gles1_md_table_header': get_md_table_header(_MD_GLES1_GPU_CONFIGS), 476 'gles1_md_exts': gles1_md_exts, 477 'md_gpu_info': '\n'.join(md_gpu_info), 478 } 479 480 write_file(gles_h_output_name, _GLES_EXTENSIONS_TEMPLATE, format_args) 481 write_file(gles_cpp_output_name, _GLES_EXT_STRINGS_TEMPLATE, format_args) 482 write_file(md_output_name, _MARKDOWN_TEMPLATE, format_args) 483 484 return 0 485 486 487if __name__ == '__main__': 488 sys.exit(main()) 489