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