| #!/usr/bin/python3 |
| # |
| # Copyright 2021 The ANGLE Project Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| # |
| # gen_extensions.py: |
| # Generates files from supported extensions data. |
| # NOTE: don't run this script directly. Run scripts/run_code_generation.py. |
| |
| import json |
| import os |
| import re |
| import sys |
| |
| d = os.path.dirname |
| THIS_DIR = d(os.path.abspath(__file__)) |
| ANGLE_SRC_DIR = d(d(THIS_DIR)) |
| SCRIPTS_DIR = os.path.join(ANGLE_SRC_DIR, 'scripts') |
| sys.path.insert(0, SCRIPTS_DIR) |
| |
| import registry_xml |
| |
| _MD_GLES_GPU_CONFIGS = [ |
| 'NVIDIA 1660 Win10', |
| 'Intel 630 Win10', |
| 'NVIDIA 1660 Linux', |
| 'Intel 630 Linux', |
| 'SwiftShader Win10', |
| 'Pixel 4 Android 11', |
| 'Pixel 6 Android 13', |
| ] |
| |
| _MD_GLES1_GPU_CONFIGS = [ |
| 'SwiftShader Win10', |
| ] |
| |
| _GLES_EXTENSIONS_TEMPLATE = """\ |
| // GENERATED FILE - DO NOT EDIT. |
| // Generated by {script_name} using data from {data_source_name} |
| // |
| // Copyright 2021 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // {filename}: GLES extension information. |
| |
| #ifndef LIBANGLE_GLES_EXTENSIONS_AUTOGEN_H_ |
| #define LIBANGLE_GLES_EXTENSIONS_AUTOGEN_H_ |
| |
| namespace gl |
| {{ |
| class TextureCapsMap; |
| |
| struct Extensions |
| {{ |
| Extensions(); |
| Extensions(const Extensions &other); |
| |
| Extensions &operator=(const Extensions &other); |
| |
| // Generate a vector of supported extension strings |
| std::vector<std::string> getStrings() const; |
| |
| // Set all texture related extension support based on the supported textures. |
| // Determines support for: |
| // GL_OES_packed_depth_stencil |
| // GL_OES_rgb8_rgba8 |
| // GL_EXT_texture_format_BGRA8888 |
| // GL_EXT_color_buffer_half_float, |
| // GL_OES_texture_half_float, GL_OES_texture_half_float_linear |
| // GL_OES_texture_float, GL_OES_texture_float_linear |
| // GL_EXT_texture_rg |
| // GL_EXT_texture_type_2_10_10_10_REV |
| // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, |
| // GL_ANGLE_texture_compression_dxt5 |
| // GL_KHR_texture_compression_astc_ldr, GL_OES_texture_compression_astc. |
| // NOTE: GL_KHR_texture_compression_astc_hdr must be enabled separately. Support for the |
| // HDR profile cannot be determined from the format enums alone. |
| // GL_OES_compressed_ETC1_RGB8_texture |
| // GL_EXT_sRGB |
| // GL_ANGLE_depth_texture, GL_OES_depth32 |
| // GL_EXT_color_buffer_float |
| // GL_EXT_texture_norm16 |
| // GL_EXT_texture_compression_bptc |
| // GL_EXT_texture_compression_rgtc |
| void setTextureExtensionSupport(const TextureCapsMap &textureCaps); |
| |
| // Helper functions |
| {helper_functions} |
| |
| // GLES 2.0+ extensions |
| // -------------------- |
| |
| {gles_extensions} |
| // ANGLE unofficial extensions |
| // --------------------------- |
| |
| {angle_extensions} |
| // GLES 1.0 and 1.1 extensions |
| // --------------------------- |
| |
| {gles1_extensions}}}; |
| }} // namespace gl |
| |
| #endif // LIBANGLE_GLES_EXTENSIONS_AUTOGEN_H_ |
| """ |
| |
| _EXT_MEMBER_TEMPLATE = """\ |
| // {full_name} |
| bool {name_camel_case}{vendor} = false; |
| """ |
| |
| _HELPER_TEMPLATE = """ bool {ext_name}Any() const {{ return ({expression}); }}""" |
| |
| _GLES_EXT_STRINGS_TEMPLATE = """\ |
| // GENERATED FILE - DO NOT EDIT. |
| // Generated by {script_name} using data from {data_source_name} |
| // |
| // Copyright 2021 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // {filename}: GLES extension strings information. |
| |
| #include "anglebase/no_destructor.h" |
| #include "libANGLE/Caps.h" |
| |
| namespace gl |
| {{ |
| const ExtensionInfoMap &GetExtensionInfoMap() |
| {{ |
| auto buildExtensionInfoMap = []() {{ |
| auto enableableExtension = [](ExtensionBool member) {{ |
| ExtensionInfo info; |
| info.Requestable = true; |
| info.ExtensionsMember = member; |
| return info; |
| }}; |
| |
| auto enableableDisablableExtension = [&](ExtensionBool member) {{ |
| ExtensionInfo info = enableableExtension(member); |
| info.Disablable = true; |
| return info; |
| }}; |
| |
| auto esOnlyExtension = [](ExtensionBool member) {{ |
| ExtensionInfo info; |
| info.ExtensionsMember = member; |
| return info; |
| }}; |
| |
| // clang-format off |
| ExtensionInfoMap map; |
| |
| // GLES 2.0 extension strings |
| // -------------------------- |
| {gles_strings} |
| |
| // ANGLE unofficial extension strings |
| // ---------------------------------- |
| {angle_strings} |
| |
| // GLES 1.0 and 1.1 extension strings |
| // ---------------------------------- |
| {gles1_strings} |
| // clang-format on |
| |
| #if defined(ANGLE_ENABLE_ASSERTS) |
| // Verify all extension strings start with GL_ |
| for (const auto &extension : map) |
| {{ |
| ASSERT(extension.first.rfind("GL_", 0) == 0); |
| }} |
| #endif |
| |
| return map; |
| }}; |
| |
| static const angle::base::NoDestructor<ExtensionInfoMap> extensionInfo(buildExtensionInfoMap()); |
| return *extensionInfo; |
| }} |
| }} // namespace gl |
| """ |
| |
| _EXT_STRING_TEMPLATE = """\ |
| map["{full_name}"] = {mode}Extension(&Extensions::{name_camel_case}{vendor});""" |
| |
| ESONLY = 'esOnly' |
| REQUESTABLE = 'enableable' |
| TOGGLEABLE = 'enableableDisablable' |
| |
| _MARKDOWN_TEMPLATE = """\ |
| # ANGLE Supported Extensions |
| |
| This is a list of all extensions currently supported by ANGLE's front-end, and |
| support listed for some of the tested targets for ANGLE's Vulkan back-end. To |
| produce a list of all supported extensions in the Vulkan back-end, run |
| `angle_end2end_tests` with `--gtest_filter EGLPrintEGLinfoTest.PrintGLInfo/ES*_Vulkan`. |
| |
| Specifications for GLES extensions can be found in the [Khronos OpenGL ES API |
| Registry](http://www.khronos.org/registry/gles/) |
| |
| Specifications for EGL extensions can be found in the [Khronos EGL API |
| Registry](http://www.khronos.org/registry/egl/) |
| |
| Specifications for ANGLE-specific extensions can be found in the [ANGLE |
| extension registry](../extensions) |
| |
| This list is automatically generated by [`{script_name}`](../src/libANGLE/gen_extensions.py) |
| using data from {data_source_name}. |
| |
| ## GLES 2.0, 3.0, 3.1 and 3.2 extension support |
| |
| *Note: some data is sampled from older drivers, so might not represent the latest driver support.* |
| |
| {gles_md_table_header} |
| {gles_md_exts} |
| |
| ## ANGLE unofficial extension support |
| |
| *Note: some ANGLE extensions are currently missing specifications.* |
| |
| {angle_md_table_header} |
| {angle_md_exts} |
| |
| ## GLES 1.0 and 1.1 extension support |
| |
| {gles1_md_table_header} |
| {gles1_md_exts} |
| |
| ## EGL extension support |
| |
| Currently EGL extensions are not automatically tracked by our scripting. For a |
| list of supported EGL extensions in ANGLE's front-end see |
| [`src/libANGLE/Caps.h`](../src/libANGLE/Caps.h). |
| |
| ## Configuration information |
| |
| {md_gpu_info} |
| ## How to update supported extension data |
| |
| Supported extension data is stored in the ANGLE repo as JSON files in |
| [`scripts/extension_data`](../scripts/extension_data). The JSON data is |
| sourced from public ANGLE test runs. Look for `angle_end2end_tests` in a bot |
| run: [example link](https://ci.chromium.org/ui/p/angle/builders/ci/win-test/520/overview). |
| Search for "`angle_end2end_tests`", then click on the "cas output" and find |
| `GLinfo_ES3_2_Vulkan.json` or `GLinfo_ES3_1_Vulkan_SwiftShader.json` for |
| SwiftShader. |
| |
| All data except for GLES 1 is automatically updated using |
| the [`update_extension_data.py`](../scripts/update_extension_data.py) script. |
| To use it first authenticate to the `bb` and `luci-go` tools by running `bb |
| auth-login` and `./tools/luci-go/swarming login`. Then run the script and |
| re-run [code generation][CodeGen]. |
| |
| The GLES 1 data is currently manually updated. Find the relevant |
| file from the task output (see above) and overwrite the correspoding file. |
| Re-run [code generation][CodeGen] and create a CL as per our normal process. |
| |
| To add a new configuration, first retrieve the JSON data, modify |
| [`gen_extensions.py`](../src/libANGLE/gen_extensions.py) as necessary, then |
| run [`scripts/run_code_generation.py`][CodeGen] to refresh generated files. |
| Also update `update_extension_data.py` as necessary. |
| |
| [CodeGen]: ../scripts/run_code_generation.py |
| """ |
| |
| _MD_TABLE_HEADER_TEMPLATE = """\ |
| | Extension Name | {configs} | |
| | -------------- | {dashes} |""" |
| |
| _MD_CONFIG_INFO_TEMPLATE = """\ |
| {config}: |
| |
| * `GL_RENDERER` is `{Renderer}` |
| * `GL_VENDOR` is `{Vendor}` |
| * `GL_VERSION` is `{Version}` |
| * Data updated {DateRecorded} |
| """ |
| |
| _MD_GLES_EXT_LINK_TEMPLATE = """[{full_name}](https://khronos.org/registry/OpenGL/extensions/{vendor}/{vendor}_{link}.txt)""" |
| _MD_ANGLE_EXT_LINK_TEMPLATE = """[{full_name}](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/{vendor}_{link}.txt)""" |
| |
| # Some extensions are defined in documents that have different names. |
| _LINK_OVERRIDES = { |
| 'GL_ANGLE_shader_pixel_local_storage_coherent': 'shader_pixel_local_storage', |
| 'GL_EXT_memory_object_fd': 'external_objects_fd', |
| 'GL_EXT_semaphore_fd': 'external_objects_fd', |
| } |
| |
| |
| def get_camel_case(name_with_underscores): |
| """ To follow ANGLE naming for member variables, we convert the canonical extension: |
| 0. Delete the API and vendor prefix. |
| 1. Capitalize letters after underscores. |
| 2. Delete underscores. |
| 3. Add back the vendor prefix to the end. """ |
| words = name_with_underscores.split('_') |
| words = [words[0]] + [(word[0].upper() + word[1:]) for word in words[1:]] |
| return ''.join(words) |
| |
| |
| def break_down_ext(ext, expr, mode): |
| """ This splits an extension name like GL_EXT_buffer_storage into string components. """ |
| m = expr.match(ext) |
| return { |
| 'full_name': ext, |
| 'api_prefix': m.group(1), |
| 'vendor': m.group(2), |
| 'name_with_underscores': m.group(3), |
| 'name_camel_case': get_camel_case(m.group(3)), |
| 'mode': mode, |
| 'link': _LINK_OVERRIDES.get(ext, m.group(3)), |
| } |
| |
| |
| def break_down_exts(exts, expr, mode): |
| return [break_down_ext(ext, expr, mode) for ext in exts] |
| |
| |
| def format_exts(ext_infos): |
| return '\n'.join([_EXT_MEMBER_TEMPLATE.format(**ext_info) for ext_info in ext_infos]) |
| |
| |
| def format_helper_function(ext_name, vendors): |
| return _HELPER_TEMPLATE.format( |
| ext_name=ext_name, |
| expression=' || '.join(['%s%s' % (ext_name, vendor) for vendor in vendors]), |
| ) |
| |
| |
| def format_ext_strings(ext_infos): |
| return '\n'.join([_EXT_STRING_TEMPLATE.format(**ext_info) for ext_info in ext_infos]) |
| |
| |
| def write_file(fname, template, format_args): |
| with open(fname, 'w') as f: |
| formatted = template.format(**format_args) |
| f.write(formatted) |
| f.close() |
| |
| |
| def sort_by_ext_name(ext_infos): |
| return sorted(ext_infos, key=lambda e: e['name_camel_case'].lower()) |
| |
| |
| def get_ext_support(ext_name, gpu_data): |
| |
| def s(ext, support): |
| SUPPORT_SYM = '✔' |
| NOSUPPORT_SYM = '' |
| return SUPPORT_SYM if ext in support['Extensions'] else NOSUPPORT_SYM |
| |
| return ' | '.join([s(ext_name, support) for support in gpu_data]) |
| |
| |
| def get_md_table_header(md_gpu_configs): |
| configs = ' | '.join(md_gpu_configs) |
| dashes = ' | '.join([(':%s:' % ('-' * (len(config) - 2))) for config in md_gpu_configs]) |
| return _MD_TABLE_HEADER_TEMPLATE.format(configs=configs, dashes=dashes) |
| |
| |
| def format_md_gpu_info(gpu_data): |
| return _MD_CONFIG_INFO_TEMPLATE.format(**gpu_data) |
| |
| |
| def format_md_link(ext_info, link_template): |
| return link_template.format(**ext_info) |
| |
| |
| def format_md_ext(ext_info, gpu_json_data, link_template): |
| return '| %s | %s |' % (format_md_link( |
| ext_info, link_template), get_ext_support(ext_info['full_name'], gpu_json_data)) |
| |
| |
| def format_md_exts(ext_infos, gpu_json_data, link_template): |
| return '\n'.join( |
| [format_md_ext(ext_info, gpu_json_data, link_template) for ext_info in ext_infos]) |
| |
| |
| def main(): |
| # auto_script parameters. |
| data_source_name = 'registry_xml.py and gl.xml' |
| gles_h_output_name = 'gles_extensions_autogen.h' |
| gles_cpp_output_name = 'gles_extensions_autogen.cpp' |
| md_output_name = '../../doc/ExtensionSupport.md' |
| ext_jsons = [ |
| '../../scripts/extension_data/%s.json' % s.lower().replace(' ', '_') |
| for s in _MD_GLES_GPU_CONFIGS |
| ] |
| gles1_ext_jsons = [ |
| '../../scripts/extension_data/%s_gles1.json' % s.lower().replace(' ', '_') |
| for s in _MD_GLES1_GPU_CONFIGS |
| ] |
| if len(sys.argv) > 1: |
| inputs = ['../../scripts/%s' % xml_input for xml_input in registry_xml.xml_inputs |
| ] + ext_jsons + gles1_ext_jsons |
| outputs = [gles_h_output_name, gles_cpp_output_name, md_output_name] |
| if sys.argv[1] == 'inputs': |
| print(','.join(inputs)) |
| elif sys.argv[1] == 'outputs': |
| print(','.join(outputs)) |
| else: |
| print('Invalid script parameters.') |
| return 1 |
| return 0 |
| |
| expr = re.compile(r'^([A-Z]+)_([A-Z]+)_(\w+)$') |
| |
| angle_ext_infos = ( |
| break_down_exts(registry_xml.angle_requestable_extensions, expr, REQUESTABLE) + |
| break_down_exts(registry_xml.angle_es_only_extensions, expr, ESONLY) + |
| break_down_exts(registry_xml.angle_toggleable_extensions, expr, TOGGLEABLE)) |
| |
| angle_ext_infos = sort_by_ext_name(angle_ext_infos) |
| |
| gles_ext_infos = ( |
| break_down_exts(registry_xml.gles_requestable_extensions, expr, REQUESTABLE) + |
| break_down_exts(registry_xml.gles_es_only_extensions, expr, ESONLY)) |
| |
| gles_ext_infos = sort_by_ext_name(gles_ext_infos) |
| |
| gles1_ext_infos = break_down_exts(registry_xml.gles1_extensions, expr, REQUESTABLE) |
| |
| gles1_ext_infos = sort_by_ext_name(gles1_ext_infos) |
| |
| ext_infos = angle_ext_infos + gles_ext_infos + gles1_ext_infos |
| |
| ext_name_to_vendors = {} |
| for info in ext_infos: |
| ext_name = info['name_camel_case'] |
| if ext_name in ext_name_to_vendors: |
| ext_name_to_vendors[ext_name] += [info['vendor']] |
| else: |
| ext_name_to_vendors[ext_name] = [info['vendor']] |
| |
| helper_function_data = [] |
| for (ext_name, vendors) in sorted(ext_name_to_vendors.items()): |
| if len(vendors) > 1: |
| helper_function_data += [format_helper_function(ext_name, vendors)] |
| |
| helper_functions = '\n'.join(helper_function_data) |
| |
| gles_gpu_data = [] |
| for (gpu_config, ext_json) in zip(_MD_GLES_GPU_CONFIGS, ext_jsons): |
| with open(ext_json) as f: |
| config_support = json.loads(f.read()) |
| config_support['config'] = gpu_config |
| gles_gpu_data.append(config_support) |
| |
| gles1_gpu_data = [] |
| for (gpu_config, ext_json) in zip(_MD_GLES1_GPU_CONFIGS, gles1_ext_jsons): |
| with open(ext_json) as f: |
| config_support = json.loads(f.read()) |
| config_support['config'] = gpu_config |
| gles1_gpu_data.append(config_support) |
| |
| gles_md_exts = format_md_exts(gles_ext_infos, gles_gpu_data, _MD_GLES_EXT_LINK_TEMPLATE) |
| angle_md_exts = format_md_exts(angle_ext_infos, gles_gpu_data, _MD_ANGLE_EXT_LINK_TEMPLATE) |
| gles1_md_exts = format_md_exts(gles1_ext_infos, gles1_gpu_data, _MD_GLES_EXT_LINK_TEMPLATE) |
| md_gpu_info = [format_md_gpu_info(gpu_data) for gpu_data in gles_gpu_data] |
| |
| format_args = { |
| 'script_name': os.path.basename(__file__), |
| 'data_source_name': os.path.basename(data_source_name), |
| 'filename': gles_h_output_name, |
| 'gles_extensions': format_exts(gles_ext_infos), |
| 'angle_extensions': format_exts(angle_ext_infos), |
| 'gles1_extensions': format_exts(gles1_ext_infos), |
| 'helper_functions': helper_functions, |
| 'angle_strings': format_ext_strings(angle_ext_infos), |
| 'gles_strings': format_ext_strings(gles_ext_infos), |
| 'gles1_strings': format_ext_strings(gles1_ext_infos), |
| 'gles_md_table_header': get_md_table_header(_MD_GLES_GPU_CONFIGS), |
| 'gles_md_exts': gles_md_exts, |
| 'angle_md_table_header': get_md_table_header(_MD_GLES_GPU_CONFIGS), |
| 'angle_md_exts': angle_md_exts, |
| 'gles1_md_table_header': get_md_table_header(_MD_GLES1_GPU_CONFIGS), |
| 'gles1_md_exts': gles1_md_exts, |
| 'md_gpu_info': '\n'.join(md_gpu_info), |
| } |
| |
| write_file(gles_h_output_name, _GLES_EXTENSIONS_TEMPLATE, format_args) |
| write_file(gles_cpp_output_name, _GLES_EXT_STRINGS_TEMPLATE, format_args) |
| write_file(md_output_name, _MARKDOWN_TEMPLATE, format_args) |
| |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |