1
2# (C) Copyright Zack Rusin 2005. All Rights Reserved.
3# Copyright (C) 2015 Intel Corporation
4# Copyright (C) 2015 Broadcom Corporation
5#
6# Permission is hereby granted, free of charge, to any person obtaining a
7# copy of this software and associated documentation files (the "Software"),
8# to deal in the Software without restriction, including without limitation
9# on the rights to use, copy, modify, merge, publish, distribute, sub
10# license, and/or sell copies of the Software, and to permit persons to whom
11# the Software is furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice (including the next
14# paragraph) shall be included in all copies or substantial portions of the
15# Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
20# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23# IN THE SOFTWARE.
24#
25# Authors:
26#    Zack Rusin <zack@kde.org>
27
28import argparse
29
30import license
31import gl_XML
32import xml.etree.ElementTree as ET
33import sys, getopt
34import re
35
36class PrintGlEnums(gl_XML.gl_print_base):
37
38    def __init__(self):
39        gl_XML.gl_print_base.__init__(self)
40
41        self.name = "gl_enums.py (from Mesa)"
42        self.license = license.bsd_license_template % ( \
43"""Copyright (C) 1999-2005 Brian Paul All Rights Reserved.""", "BRIAN PAUL")
44        # Mapping from enum value to (name, priority) tuples.
45        self.enum_table = {}
46        # Mapping from enum name to value
47        self.string_to_int = {}
48
49
50    def printRealHeader(self):
51        print('#include <stdio.h>')
52        print('#include "main/glheader.h"')
53        print('#include "main/enums.h"')
54        print('#include "main/mtypes.h"')
55        print('')
56        print('typedef struct PACKED {')
57        print('   uint32_t offset;')
58        print('   int n;')
59        print('} enum_elt;')
60        print('')
61        return
62
63    def print_code(self):
64        print("""
65typedef int (*cfunc)(const void *, const void *);
66
67/**
68 * Compare a key enum value to an element in the \c enum_string_table_offsets array.
69 *
70 * \c bsearch always passes the key as the first parameter and the pointer
71 * to the array element as the second parameter.  We can elimiate some
72 * extra work by taking advantage of that fact.
73 *
74 * \param a  Pointer to the desired enum name.
75 * \param b  Pointer into the \c enum_string_table_offsets array.
76 */
77static int compar_nr( const int *a, enum_elt *b )
78{
79   return a[0] - b->n;
80}
81
82
83static char token_tmp[20];
84
85/**
86 * This function always returns a string. If the number is a valid enum, it
87 * returns the enum name. Otherwise, it returns a numeric string.
88 */
89const char *
90_mesa_enum_to_string(int nr)
91{
92   enum_elt *elt;
93
94   elt = bsearch(& nr, enum_string_table_offsets,
95                 ARRAY_SIZE(enum_string_table_offsets),
96                 sizeof(enum_string_table_offsets[0]),
97                 (cfunc) compar_nr);
98
99   if (elt != NULL) {
100      return &enum_string_table[elt->offset];
101   }
102   else {
103      /* this is not re-entrant safe, no big deal here */
104      snprintf(token_tmp, sizeof(token_tmp) - 1, "0x%x", nr);
105      token_tmp[sizeof(token_tmp) - 1] = '\\0';
106      return token_tmp;
107   }
108}
109
110/**
111 * Primitive names
112 */
113static const char *prim_names[PRIM_MAX+3] = {
114   "GL_POINTS",
115   "GL_LINES",
116   "GL_LINE_LOOP",
117   "GL_LINE_STRIP",
118   "GL_TRIANGLES",
119   "GL_TRIANGLE_STRIP",
120   "GL_TRIANGLE_FAN",
121   "GL_QUADS",
122   "GL_QUAD_STRIP",
123   "GL_POLYGON",
124   "GL_LINES_ADJACENCY",
125   "GL_LINE_STRIP_ADJACENCY",
126   "GL_TRIANGLES_ADJACENCY",
127   "GL_TRIANGLE_STRIP_ADJACENCY",
128   "GL_PATCHES",
129   "outside begin/end",
130   "unknown state"
131};
132
133
134/* Get the name of an enum given that it is a primitive type.  Avoids
135 * GL_FALSE/GL_POINTS ambiguity and others.
136 */
137const char *
138_mesa_lookup_prim_by_nr(GLuint nr)
139{
140   if (nr < ARRAY_SIZE(prim_names))
141      return prim_names[nr];
142   else
143      return "invalid mode";
144}
145
146
147""")
148        return
149
150
151    def printBody(self, xml):
152        self.process_enums(xml)
153
154        sorted_enum_values = sorted(self.enum_table.keys())
155        string_offsets = {}
156        i = 0;
157        print('#if defined(__GNUC__)')
158        print('# define LONGSTRING __extension__')
159        print('#else')
160        print('# define LONGSTRING')
161        print('#endif')
162        print('')
163        print('LONGSTRING static const char enum_string_table[] = {')
164        # We express the very long concatenation of enum strings as an array
165        # of characters rather than as a string literal to work-around MSVC's
166        # 65535 character limit.
167        for enum in sorted_enum_values:
168            (name, pri) = self.enum_table[enum]
169            print("  ", end=' ')
170            for ch in name:
171                print("'%c'," % ch, end=' ')
172            print("'\\0',")
173
174            string_offsets[ enum ] = i
175            i += len(name) + 1
176
177        print('};')
178        print('')
179
180
181        print('static const enum_elt enum_string_table_offsets[%u] =' % (len(self.enum_table)))
182        print('{')
183        for enum in sorted_enum_values:
184            (name, pri) = self.enum_table[enum]
185            print('   { %5u, 0x%08X }, /* %s */' % (string_offsets[enum], enum, name))
186        print('};')
187        print('')
188
189        self.print_code()
190        return
191
192    def add_enum_provider(self, name, priority):
193        value = self.string_to_int[name]
194
195        # We don't want the weird GL_SKIP_COMPONENTS1_NV enums.
196        if value < 0:
197            return
198        # We don't want the 64-bit GL_TIMEOUT_IGNORED "enums"
199        if value > 0xffffffff:
200            return
201
202        # We don't want bitfields in the enum-to-string table --
203        # individual bits have so many names, it's pointless.  Note
204        # that we check for power-of-two, since some getters have
205        # "_BITS" in their name, but none have a power-of-two enum
206        # number.
207        if not (value & (value - 1)) and '_BIT' in name:
208            return
209
210        # Also drop the GL_*_ATTRIB_BITS bitmasks.
211        if value == 0xffffffff:
212                return
213
214        if value in self.enum_table:
215            (n, p) = self.enum_table[value]
216            if priority < p:
217                self.enum_table[value] = (name, priority)
218        else:
219            self.enum_table[value] = (name, priority)
220
221    def process_extension(self, extension):
222        if extension.get('name').startswith('GL_ARB_'):
223            extension_prio = 400
224        elif extension.get('name').startswith('GL_EXT_'):
225            extension_prio = 600
226        else:
227            extension_prio = 800
228
229        for enum in extension.findall('require/enum'):
230            self.add_enum_provider(enum.get('name'), extension_prio)
231
232    def process_enums(self, xml):
233        # First, process the XML entries that define the hex values
234        # for all of the enum names.
235        for enum in xml.findall('enums/enum'):
236            name = enum.get('name')
237            value = int(enum.get('value'), base=16)
238
239            # If the same name ever maps to multiple values, that can
240            # confuse us.  GL_ACTIVE_PROGRAM_EXT is OK to lose because
241            # we choose GL_ACTIVE PROGRAM instead.
242            if name in self.string_to_int and name != "GL_ACTIVE_PROGRAM_EXT":
243                print("#error Renumbering {0} from {1} to {2}".format(name, self.string_to_int[name], value))
244
245            self.string_to_int[name] = value
246
247        # Now, process all of the API versions and extensions that
248        # provide enums, so we can decide what name to call any hex
249        # value.
250        for feature in xml.findall('feature'):
251            feature_name = feature.get('name')
252
253            # When an enum gets renamed in a newer version (generally
254            # because of some generalization of the functionality),
255            # prefer the newer name.  Also, prefer desktop GL names to
256            # ES.
257            m = re.match('GL_VERSION_([0-9])_([0-9])', feature_name)
258            if m:
259                feature_prio = 100 - int(m.group(1) + m.group(2))
260            else:
261                m = re.match('GL_ES_VERSION_([0-9])_([0-9])', feature_name)
262                if m:
263                    feature_prio = 200 - int(m.group(1) + m.group(2))
264                else:
265                    feature_prio = 200
266
267            for enum in feature.findall('require/enum'):
268                self.add_enum_provider(enum.get('name'), feature_prio)
269
270        for extension in xml.findall('extensions/extension'):
271            self.process_extension(extension)
272
273
274def _parser():
275    parser = argparse.ArgumentParser()
276    parser.add_argument('-f', '--input_file',
277                        required=True,
278                        help="Choose an xml file to parse.")
279    return parser.parse_args()
280
281
282def main():
283    args = _parser()
284    xml = ET.parse(args.input_file)
285
286    printer = PrintGlEnums()
287    printer.Print(xml)
288
289
290if __name__ == '__main__':
291    main()
292