• 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-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 = '&#10004;'
348        CROSS = '&#10060;'
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