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