• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
2#
3# Copyright 2019 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_gl_enum_utils.py:
8#   Generates GLenum value to string mapping for ANGLE
9#   NOTE: don't run this script directly. Run scripts/run_code_generation.py.
10
11import sys
12import os
13
14import registry_xml
15
16template_gl_enums_header = """// GENERATED FILE - DO NOT EDIT.
17// Generated by {script_name} using data from {data_source_name}.
18//
19// Copyright 2019 The ANGLE Project Authors. All rights reserved.
20// Use of this source code is governed by a BSD-style license that can be
21// found in the LICENSE file.
22//
23// gl_enum_utils_autogen.h:
24//   mapping of GLenum value to string.
25
26# ifndef LIBANGLE_GL_ENUM_UTILS_AUTOGEN_H_
27# define LIBANGLE_GL_ENUM_UTILS_AUTOGEN_H_
28
29namespace gl
30{{
31enum class GLenumGroup
32{{
33    {gl_enum_groups}
34}};
35}}  // namespace gl
36
37# endif  // LIBANGLE_GL_ENUM_UTILS_AUTOGEN_H_
38"""
39
40template_gl_enums_source = """// GENERATED FILE - DO NOT EDIT.
41// Generated by {script_name} using data from {data_source_name}.
42//
43// Copyright 2019 The ANGLE Project Authors. All rights reserved.
44// Use of this source code is governed by a BSD-style license that can be
45// found in the LICENSE file.
46//
47// gl_enum_utils_autogen.cpp:
48//   mapping of GLenum value to string.
49
50#include "libANGLE/capture/gl_enum_utils_autogen.h"
51
52#include "libANGLE/capture/gl_enum_utils.h"
53
54namespace gl
55{{
56namespace
57{{
58const char *UnknownGLenumToString(unsigned int value)
59{{
60    constexpr size_t kBufferSize = 64;
61    static thread_local char sBuffer[kBufferSize];
62    snprintf(sBuffer, kBufferSize, "0x%04X", value);
63    return sBuffer;
64}}
65}}  // anonymous namespace
66
67const char *GLenumToString(GLenumGroup enumGroup, unsigned int value)
68{{
69    switch (enumGroup)
70    {{
71        {gl_enums_value_to_string_table}
72        default:
73            return UnknownGLenumToString(value);
74    }}
75}}
76}}  // namespace gl
77
78"""
79
80template_enum_group_case = """case GLenumGroup::{group_name}: {{
81    switch (value) {{
82        {inner_group_cases}
83        default:
84            return UnknownGLenumToString(value);
85    }}
86}}
87"""
88
89template_enum_value_to_string_case = """case {value}: return {name};"""
90
91exclude_gl_enums = {
92    'GL_NO_ERROR', 'GL_TIMEOUT_IGNORED', 'GL_INVALID_INDEX', 'GL_VERSION_ES_CL_1_0',
93    'GL_VERSION_ES_CM_1_1', 'GL_VERSION_ES_CL_1_1'
94}
95exclude_gl_enum_groups = {'SpecialNumbers'}
96
97
98def dump_value_to_string_mapping(gl_enum_in_groups, exporting_enums):
99    exporting_groups = list()
100    for group_name, inner_mapping in gl_enum_in_groups.items():
101        string_value_pairs = list(filter(lambda x: x[0] in exporting_enums, inner_mapping.items()))
102        if not string_value_pairs:
103            continue
104
105        # sort according values
106        string_value_pairs.sort(key=lambda x: (x[1], x[0]))
107
108        # remove all duplicate values from the pairs list
109        # some value may have more than one GLenum mapped to them, such as:
110        #     GL_DRAW_FRAMEBUFFER_BINDING and GL_FRAMEBUFFER_BINDING
111        #     GL_BLEND_EQUATION_RGB and GL_BLEND_EQUATION
112        # it is safe to output either one of them, for simplity here just
113        # choose the shorter one which comes first in the sorted list
114        exporting_string_value_pairs = list()
115        for index, pair in enumerate(string_value_pairs):
116            if index == 0 or pair[1] != string_value_pairs[index - 1][1]:
117                exporting_string_value_pairs.append(pair)
118
119        inner_code_block = "\n".join([
120            template_enum_value_to_string_case.format(
121                value='0x%X' % value,
122                name='"%s"' % name,
123            ) for name, value in exporting_string_value_pairs
124        ])
125
126        exporting_groups.append((group_name, inner_code_block))
127
128    return "\n".join([
129        template_enum_group_case.format(
130            group_name=group_name,
131            inner_group_cases=inner_code_block,
132        ) for group_name, inner_code_block in sorted(exporting_groups, key=lambda x: x[0])
133    ])
134
135
136def main(header_output_path, source_output_path):
137    xml = registry_xml.RegistryXML('gl.xml', 'gl_angle_ext.xml')
138
139    # build a map from GLenum name to its value
140    all_gl_enums = dict()
141    for enums_node in xml.root.findall('enums'):
142        for enum in enums_node.findall('enum'):
143            name = enum.attrib['name']
144            value = int(enum.attrib['value'], base=16)
145            all_gl_enums[name] = value
146
147    # Parse groups of GLenums to build a {group, name} -> value mapping.
148    gl_enum_in_groups = dict()
149    enums_has_group = set()
150    for enums_group_node in xml.root.findall('groups/group'):
151        group_name = enums_group_node.attrib['name']
152        if group_name in exclude_gl_enum_groups:
153            continue
154
155        if group_name not in gl_enum_in_groups:
156            gl_enum_in_groups[group_name] = dict()
157
158        for enum_node in enums_group_node.findall('enum'):
159            enum_name = enum_node.attrib['name']
160            enums_has_group.add(enum_name)
161            gl_enum_in_groups[group_name][enum_name] = all_gl_enums[enum_name]
162
163    # Find relevant GLenums according to enabled APIs and extensions.
164    exporting_enums = set()
165    # export all the apis
166    xpath = "./feature[@api='gles2']/require/enum"
167    for enum_tag in xml.root.findall(xpath):
168        enum_name = enum_tag.attrib['name']
169        if enum_name not in exclude_gl_enums:
170            exporting_enums.add(enum_name)
171
172    for extension in registry_xml.supported_extensions:
173        xpath = "./extensions/extension[@name='%s']/require/enum" % extension
174        for enum_tag in xml.root.findall(xpath):
175            enum_name = enum_tag.attrib['name']
176            if enum_name not in exclude_gl_enums:
177                exporting_enums.add(enum_name)
178
179    # For enums that do not have a group, add them to a default group
180    default_group_name = registry_xml.default_enum_group_name
181    gl_enum_in_groups[default_group_name] = dict()
182    default_group = gl_enum_in_groups[default_group_name]
183    for enum_name in exporting_enums:
184        if enum_name not in enums_has_group:
185            default_group[enum_name] = all_gl_enums[enum_name]
186
187    # Write GLenum groups into the header file.
188    header_content = template_gl_enums_header.format(
189        script_name=os.path.basename(sys.argv[0]),
190        data_source_name="gl.xml and gl_angle_ext.xml",
191        gl_enum_groups=',\n'.join(sorted(gl_enum_in_groups.keys())))
192
193    header_output_path = registry_xml.script_relative(header_output_path)
194    with open(header_output_path, 'w') as f:
195        f.write(header_content)
196
197    # Write mapping to source file
198    gl_enums_value_to_string_table = dump_value_to_string_mapping(gl_enum_in_groups,
199                                                                  exporting_enums)
200    source_content = template_gl_enums_source.format(
201        script_name=os.path.basename(sys.argv[0]),
202        data_source_name="gl.xml and gl_angle_ext.xml",
203        gl_enums_value_to_string_table=gl_enums_value_to_string_table,
204    )
205
206    source_output_path = registry_xml.script_relative(source_output_path)
207    with open(source_output_path, 'w') as f:
208        f.write(source_content)
209
210    return 0
211
212
213if __name__ == '__main__':
214    inputs = [
215        'gl.xml',
216        'gl_angle_ext.xml',
217        'registry_xml.py',
218    ]
219
220    gl_enum_utils_autogen_base_path = '../src/libANGLE/capture/gl_enum_utils_autogen'
221    outputs = [
222        gl_enum_utils_autogen_base_path + '.h',
223        gl_enum_utils_autogen_base_path + '.cpp',
224    ]
225
226    if len(sys.argv) > 1:
227        if sys.argv[1] == 'inputs':
228            print(','.join(inputs))
229        elif sys.argv[1] == 'outputs':
230            print(','.join(outputs))
231    else:
232        sys.exit(
233            main(
234                registry_xml.script_relative(outputs[0]),
235                registry_xml.script_relative(outputs[1])))
236