• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = '&#x2714;'
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