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