1848b8605Smrg
2848b8605Smrg# (C) Copyright IBM Corporation 2004, 2005
3848b8605Smrg# All Rights Reserved.
4848b8605Smrg#
5848b8605Smrg# Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg# copy of this software and associated documentation files (the "Software"),
7848b8605Smrg# to deal in the Software without restriction, including without limitation
8848b8605Smrg# on the rights to use, copy, modify, merge, publish, distribute, sub
9848b8605Smrg# license, and/or sell copies of the Software, and to permit persons to whom
10848b8605Smrg# the Software is furnished to do so, subject to the following conditions:
11848b8605Smrg#
12848b8605Smrg# The above copyright notice and this permission notice (including the next
13848b8605Smrg# paragraph) shall be included in all copies or substantial portions of the
14848b8605Smrg# Software.
15848b8605Smrg#
16848b8605Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17848b8605Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20848b8605Smrg# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21848b8605Smrg# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22848b8605Smrg# IN THE SOFTWARE.
23848b8605Smrg#
24848b8605Smrg# Authors:
25848b8605Smrg#    Ian Romanick <idr@us.ibm.com>
26848b8605Smrg
27b8e80941Smrgfrom __future__ import print_function
28b8e80941Smrg
29b8e80941Smrgfrom collections import OrderedDict
30848b8605Smrgfrom decimal import Decimal
31848b8605Smrgimport xml.etree.ElementTree as ET
32b8e80941Smrgimport re, sys
33848b8605Smrgimport os.path
34848b8605Smrgimport typeexpr
35b8e80941Smrgimport static_data
36848b8605Smrg
37848b8605Smrg
38848b8605Smrgdef parse_GL_API( file_name, factory = None ):
39848b8605Smrg
40848b8605Smrg    if not factory:
41848b8605Smrg        factory = gl_item_factory()
42848b8605Smrg
43848b8605Smrg    api = factory.create_api()
44848b8605Smrg    api.parse_file( file_name )
45848b8605Smrg
46848b8605Smrg    # After the XML has been processed, we need to go back and assign
47848b8605Smrg    # dispatch offsets to the functions that request that their offsets
48848b8605Smrg    # be assigned by the scripts.  Typically this means all functions
49848b8605Smrg    # that are not part of the ABI.
50848b8605Smrg
51848b8605Smrg    for func in api.functionIterateByCategory():
52b8e80941Smrg        if func.assign_offset and func.offset < 0:
53848b8605Smrg            func.offset = api.next_offset;
54848b8605Smrg            api.next_offset += 1
55848b8605Smrg
56848b8605Smrg    return api
57848b8605Smrg
58848b8605Smrg
59848b8605Smrgdef is_attr_true( element, name, default = "false" ):
60848b8605Smrg    """Read a name value from an element's attributes.
61848b8605Smrg
62848b8605Smrg    The value read from the attribute list must be either 'true' or
63848b8605Smrg    'false'.  If the value is 'false', zero will be returned.  If the
64848b8605Smrg    value is 'true', non-zero will be returned.  An exception will be
65848b8605Smrg    raised for any other value."""
66848b8605Smrg
67848b8605Smrg    value = element.get( name, default )
68848b8605Smrg    if value == "true":
69848b8605Smrg        return 1
70848b8605Smrg    elif value == "false":
71848b8605Smrg        return 0
72848b8605Smrg    else:
73848b8605Smrg        raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
74848b8605Smrg
75848b8605Smrg
76848b8605Smrgclass gl_print_base(object):
77848b8605Smrg    """Base class of all API pretty-printers.
78848b8605Smrg
79848b8605Smrg    In the model-view-controller pattern, this is the view.  Any derived
80848b8605Smrg    class will want to over-ride the printBody, printRealHader, and
81848b8605Smrg    printRealFooter methods.  Some derived classes may want to over-ride
82848b8605Smrg    printHeader and printFooter, or even Print (though this is unlikely).
83848b8605Smrg    """
84848b8605Smrg
85848b8605Smrg    def __init__(self):
86848b8605Smrg        # Name of the script that is generating the output file.
87848b8605Smrg        # Every derived class should set this to the name of its
88848b8605Smrg        # source file.
89848b8605Smrg
90848b8605Smrg        self.name = "a"
91848b8605Smrg
92848b8605Smrg
93848b8605Smrg        # License on the *generated* source file.  This may differ
94848b8605Smrg        # from the license on the script that is generating the file.
95848b8605Smrg        # Every derived class should set this to some reasonable
96848b8605Smrg        # value.
97848b8605Smrg        #
98848b8605Smrg        # See license.py for an example of a reasonable value.
99848b8605Smrg
100848b8605Smrg        self.license = "The license for this file is unspecified."
101848b8605Smrg
102848b8605Smrg
103848b8605Smrg        # The header_tag is the name of the C preprocessor define
104848b8605Smrg        # used to prevent multiple inclusion.  Typically only
105848b8605Smrg        # generated C header files need this to be set.  Setting it
106848b8605Smrg        # causes code to be generated automatically in printHeader
107848b8605Smrg        # and printFooter.
108848b8605Smrg
109848b8605Smrg        self.header_tag = None
110848b8605Smrg
111848b8605Smrg
112848b8605Smrg        # List of file-private defines that must be undefined at the
113848b8605Smrg        # end of the file.  This can be used in header files to define
114848b8605Smrg        # names for use in the file, then undefine them at the end of
115848b8605Smrg        # the header file.
116848b8605Smrg
117848b8605Smrg        self.undef_list = []
118848b8605Smrg        return
119848b8605Smrg
120848b8605Smrg
121848b8605Smrg    def Print(self, api):
122848b8605Smrg        self.printHeader()
123848b8605Smrg        self.printBody(api)
124848b8605Smrg        self.printFooter()
125848b8605Smrg        return
126848b8605Smrg
127848b8605Smrg
128848b8605Smrg    def printHeader(self):
129848b8605Smrg        """Print the header associated with all files and call the printRealHeader method."""
130848b8605Smrg
131b8e80941Smrg        print('/* DO NOT EDIT - This file generated automatically by %s script */' \
132b8e80941Smrg                % (self.name))
133b8e80941Smrg        print('')
134b8e80941Smrg        print('/*')
135b8e80941Smrg        print((' * ' + self.license.replace('\n', '\n * ')).replace(' \n', '\n'))
136b8e80941Smrg        print(' */')
137b8e80941Smrg        print('')
138848b8605Smrg        if self.header_tag:
139b8e80941Smrg            print('#if !defined( %s )' % (self.header_tag))
140b8e80941Smrg            print('#  define %s' % (self.header_tag))
141b8e80941Smrg            print('')
142848b8605Smrg        self.printRealHeader();
143848b8605Smrg        return
144848b8605Smrg
145848b8605Smrg
146848b8605Smrg    def printFooter(self):
147848b8605Smrg        """Print the header associated with all files and call the printRealFooter method."""
148848b8605Smrg
149848b8605Smrg        self.printRealFooter()
150848b8605Smrg
151848b8605Smrg        if self.undef_list:
152b8e80941Smrg            print('')
153848b8605Smrg            for u in self.undef_list:
154b8e80941Smrg                print("#  undef %s" % (u))
155848b8605Smrg
156848b8605Smrg        if self.header_tag:
157b8e80941Smrg            print('')
158b8e80941Smrg            print('#endif /* !defined( %s ) */' % (self.header_tag))
159848b8605Smrg
160848b8605Smrg
161848b8605Smrg    def printRealHeader(self):
162848b8605Smrg        """Print the "real" header for the created file.
163848b8605Smrg
164848b8605Smrg        In the base class, this function is empty.  All derived
165848b8605Smrg        classes should over-ride this function."""
166848b8605Smrg        return
167848b8605Smrg
168848b8605Smrg
169848b8605Smrg    def printRealFooter(self):
170848b8605Smrg        """Print the "real" footer for the created file.
171848b8605Smrg
172848b8605Smrg        In the base class, this function is empty.  All derived
173848b8605Smrg        classes should over-ride this function."""
174848b8605Smrg        return
175848b8605Smrg
176848b8605Smrg
177848b8605Smrg    def printPure(self):
178848b8605Smrg        """Conditionally define `PURE' function attribute.
179848b8605Smrg
180848b8605Smrg        Conditionally defines a preprocessor macro `PURE' that wraps
181848b8605Smrg        GCC's `pure' function attribute.  The conditional code can be
182848b8605Smrg        easilly adapted to other compilers that support a similar
183848b8605Smrg        feature.
184848b8605Smrg
185848b8605Smrg        The name is also added to the file's undef_list.
186848b8605Smrg        """
187848b8605Smrg        self.undef_list.append("PURE")
188b8e80941Smrg        print("""#  if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
189848b8605Smrg#    define PURE __attribute__((pure))
190848b8605Smrg#  else
191848b8605Smrg#    define PURE
192b8e80941Smrg#  endif""")
193848b8605Smrg        return
194848b8605Smrg
195848b8605Smrg
196848b8605Smrg    def printFastcall(self):
197848b8605Smrg        """Conditionally define `FASTCALL' function attribute.
198848b8605Smrg
199848b8605Smrg        Conditionally defines a preprocessor macro `FASTCALL' that
200848b8605Smrg        wraps GCC's `fastcall' function attribute.  The conditional
201848b8605Smrg        code can be easilly adapted to other compilers that support a
202848b8605Smrg        similar feature.
203848b8605Smrg
204848b8605Smrg        The name is also added to the file's undef_list.
205848b8605Smrg        """
206848b8605Smrg
207848b8605Smrg        self.undef_list.append("FASTCALL")
208b8e80941Smrg        print("""#  if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
209848b8605Smrg#    define FASTCALL __attribute__((fastcall))
210848b8605Smrg#  else
211848b8605Smrg#    define FASTCALL
212b8e80941Smrg#  endif""")
213848b8605Smrg        return
214848b8605Smrg
215848b8605Smrg
216848b8605Smrg    def printVisibility(self, S, s):
217848b8605Smrg        """Conditionally define visibility function attribute.
218848b8605Smrg
219848b8605Smrg        Conditionally defines a preprocessor macro name S that wraps
220848b8605Smrg        GCC's visibility function attribute.  The visibility used is
221848b8605Smrg        the parameter s.  The conditional code can be easilly adapted
222848b8605Smrg        to other compilers that support a similar feature.
223848b8605Smrg
224848b8605Smrg        The name is also added to the file's undef_list.
225848b8605Smrg        """
226848b8605Smrg
227848b8605Smrg        self.undef_list.append(S)
228b8e80941Smrg        print("""#  if defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
229848b8605Smrg#    define %s  __attribute__((visibility("%s")))
230848b8605Smrg#  else
231848b8605Smrg#    define %s
232b8e80941Smrg#  endif""" % (S, s, S))
233848b8605Smrg        return
234848b8605Smrg
235848b8605Smrg
236848b8605Smrg    def printNoinline(self):
237848b8605Smrg        """Conditionally define `NOINLINE' function attribute.
238848b8605Smrg
239848b8605Smrg        Conditionally defines a preprocessor macro `NOINLINE' that
240848b8605Smrg        wraps GCC's `noinline' function attribute.  The conditional
241848b8605Smrg        code can be easilly adapted to other compilers that support a
242848b8605Smrg        similar feature.
243848b8605Smrg
244848b8605Smrg        The name is also added to the file's undef_list.
245848b8605Smrg        """
246848b8605Smrg
247848b8605Smrg        self.undef_list.append("NOINLINE")
248b8e80941Smrg        print("""#  if defined(__GNUC__)
249848b8605Smrg#    define NOINLINE __attribute__((noinline))
250848b8605Smrg#  else
251848b8605Smrg#    define NOINLINE
252b8e80941Smrg#  endif""")
253848b8605Smrg        return
254848b8605Smrg
255848b8605Smrg
256848b8605Smrgdef real_function_name(element):
257848b8605Smrg    name = element.get( "name" )
258848b8605Smrg    alias = element.get( "alias" )
259848b8605Smrg
260848b8605Smrg    if alias:
261848b8605Smrg        return alias
262848b8605Smrg    else:
263848b8605Smrg        return name
264848b8605Smrg
265848b8605Smrg
266848b8605Smrgdef real_category_name(c):
267848b8605Smrg    if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
268848b8605Smrg        return "GL_VERSION_" + c.replace(".", "_")
269848b8605Smrg    else:
270848b8605Smrg        return c
271848b8605Smrg
272848b8605Smrg
273848b8605Smrgdef classify_category(name, number):
274848b8605Smrg    """Based on the category name and number, select a numerical class for it.
275848b8605Smrg
276848b8605Smrg    Categories are divided into four classes numbered 0 through 3.  The
277848b8605Smrg    classes are:
278848b8605Smrg
279848b8605Smrg            0. Core GL versions, sorted by version number.
280848b8605Smrg            1. ARB extensions, sorted by extension number.
281848b8605Smrg            2. Non-ARB extensions, sorted by extension number.
282848b8605Smrg            3. Un-numbered extensions, sorted by extension name.
283848b8605Smrg    """
284848b8605Smrg
285848b8605Smrg    try:
286848b8605Smrg        core_version = float(name)
287b8e80941Smrg    except Exception:
288848b8605Smrg        core_version = 0.0
289848b8605Smrg
290848b8605Smrg    if core_version > 0.0:
291848b8605Smrg        cat_type = 0
292848b8605Smrg        key = name
293848b8605Smrg    elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"):
294848b8605Smrg        cat_type = 1
295848b8605Smrg        key = int(number)
296848b8605Smrg    else:
297848b8605Smrg        if number != None:
298848b8605Smrg            cat_type = 2
299848b8605Smrg            key = int(number)
300848b8605Smrg        else:
301848b8605Smrg            cat_type = 3
302848b8605Smrg            key = name
303848b8605Smrg
304848b8605Smrg
305848b8605Smrg    return [cat_type, key]
306848b8605Smrg
307848b8605Smrg
308848b8605Smrgdef create_parameter_string(parameters, include_names):
309848b8605Smrg    """Create a parameter string from a list of gl_parameters."""
310848b8605Smrg
311848b8605Smrg    list = []
312848b8605Smrg    for p in parameters:
313848b8605Smrg        if p.is_padding:
314848b8605Smrg            continue
315848b8605Smrg
316848b8605Smrg        if include_names:
317848b8605Smrg            list.append( p.string() )
318848b8605Smrg        else:
319848b8605Smrg            list.append( p.type_string() )
320848b8605Smrg
321848b8605Smrg    if len(list) == 0: list = ["void"]
322848b8605Smrg
323b8e80941Smrg    return ", ".join(list)
324848b8605Smrg
325848b8605Smrg
326848b8605Smrgclass gl_item(object):
327848b8605Smrg    def __init__(self, element, context, category):
328848b8605Smrg        self.context = context
329848b8605Smrg        self.name = element.get( "name" )
330848b8605Smrg        self.category = real_category_name( category )
331848b8605Smrg
332848b8605Smrg        return
333848b8605Smrg
334848b8605Smrg
335848b8605Smrgclass gl_type( gl_item ):
336848b8605Smrg    def __init__(self, element, context, category):
337848b8605Smrg        gl_item.__init__(self, element, context, category)
338848b8605Smrg        self.size = int( element.get( "size" ), 0 )
339848b8605Smrg
340848b8605Smrg        te = typeexpr.type_expression( None )
341848b8605Smrg        tn = typeexpr.type_node()
342848b8605Smrg        tn.size = int( element.get( "size" ), 0 )
343848b8605Smrg        tn.integer = not is_attr_true( element, "float" )
344848b8605Smrg        tn.unsigned = is_attr_true( element, "unsigned" )
345848b8605Smrg        tn.pointer = is_attr_true( element, "pointer" )
346848b8605Smrg        tn.name = "GL" + self.name
347848b8605Smrg        te.set_base_type_node( tn )
348848b8605Smrg
349848b8605Smrg        self.type_expr = te
350848b8605Smrg        return
351848b8605Smrg
352848b8605Smrg
353848b8605Smrg    def get_type_expression(self):
354848b8605Smrg        return self.type_expr
355848b8605Smrg
356848b8605Smrg
357848b8605Smrgclass gl_enum( gl_item ):
358848b8605Smrg    def __init__(self, element, context, category):
359848b8605Smrg        gl_item.__init__(self, element, context, category)
360848b8605Smrg        self.value = int( element.get( "value" ), 0 )
361848b8605Smrg
362848b8605Smrg        temp = element.get( "count" )
363848b8605Smrg        if not temp or temp == "?":
364848b8605Smrg            self.default_count = -1
365848b8605Smrg        else:
366848b8605Smrg            try:
367848b8605Smrg                c = int(temp)
368b8e80941Smrg            except Exception:
369848b8605Smrg                raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
370848b8605Smrg
371848b8605Smrg            self.default_count = c
372848b8605Smrg
373848b8605Smrg        return
374848b8605Smrg
375848b8605Smrg
376848b8605Smrg    def priority(self):
377848b8605Smrg        """Calculate a 'priority' for this enum name.
378848b8605Smrg
379848b8605Smrg        When an enum is looked up by number, there may be many
380848b8605Smrg        possible names, but only one is the 'prefered' name.  The
381848b8605Smrg        priority is used to select which name is the 'best'.
382848b8605Smrg
383848b8605Smrg        Highest precedence is given to core GL name.  ARB extension
384848b8605Smrg        names have the next highest, followed by EXT extension names.
385848b8605Smrg        Vendor extension names are the lowest.
386848b8605Smrg        """
387848b8605Smrg
388848b8605Smrg        if self.name.endswith( "_BIT" ):
389848b8605Smrg            bias = 1
390848b8605Smrg        else:
391848b8605Smrg            bias = 0
392848b8605Smrg
393848b8605Smrg        if self.category.startswith( "GL_VERSION_" ):
394848b8605Smrg            priority = 0
395848b8605Smrg        elif self.category.startswith( "GL_ARB_" ):
396848b8605Smrg            priority = 2
397848b8605Smrg        elif self.category.startswith( "GL_EXT_" ):
398848b8605Smrg            priority = 4
399848b8605Smrg        else:
400848b8605Smrg            priority = 6
401848b8605Smrg
402848b8605Smrg        return priority + bias
403848b8605Smrg
404848b8605Smrg
405848b8605Smrg
406848b8605Smrgclass gl_parameter(object):
407848b8605Smrg    def __init__(self, element, context):
408848b8605Smrg        self.name = element.get( "name" )
409848b8605Smrg
410848b8605Smrg        ts = element.get( "type" )
411848b8605Smrg        self.type_expr = typeexpr.type_expression( ts, context )
412848b8605Smrg
413848b8605Smrg        temp = element.get( "variable_param" )
414848b8605Smrg        if temp:
415848b8605Smrg            self.count_parameter_list = temp.split( ' ' )
416848b8605Smrg        else:
417848b8605Smrg            self.count_parameter_list = []
418848b8605Smrg
419848b8605Smrg        # The count tag can be either a numeric string or the name of
420848b8605Smrg        # a variable.  If it is the name of a variable, the int(c)
421848b8605Smrg        # statement will throw an exception, and the except block will
422848b8605Smrg        # take over.
423848b8605Smrg
424848b8605Smrg        c = element.get( "count" )
425848b8605Smrg        try:
426848b8605Smrg            count = int(c)
427848b8605Smrg            self.count = count
428848b8605Smrg            self.counter = None
429b8e80941Smrg        except Exception:
430848b8605Smrg            count = 1
431848b8605Smrg            self.count = 0
432848b8605Smrg            self.counter = c
433848b8605Smrg
434848b8605Smrg        self.count_scale = int(element.get( "count_scale", "1" ))
435848b8605Smrg
436848b8605Smrg        elements = (count * self.count_scale)
437848b8605Smrg        if elements == 1:
438848b8605Smrg            elements = 0
439848b8605Smrg
440848b8605Smrg        #if ts == "GLdouble":
441848b8605Smrg        #	print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
442848b8605Smrg        #	print '/* # elements = %u */' % (elements)
443848b8605Smrg        self.type_expr.set_elements( elements )
444848b8605Smrg        #if ts == "GLdouble":
445848b8605Smrg        #	print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
446848b8605Smrg
447848b8605Smrg        self.is_client_only = is_attr_true( element, 'client_only' )
448848b8605Smrg        self.is_counter     = is_attr_true( element, 'counter' )
449848b8605Smrg        self.is_output      = is_attr_true( element, 'output' )
450848b8605Smrg
451848b8605Smrg
452848b8605Smrg        # Pixel data has special parameters.
453848b8605Smrg
454848b8605Smrg        self.width      = element.get('img_width')
455848b8605Smrg        self.height     = element.get('img_height')
456848b8605Smrg        self.depth      = element.get('img_depth')
457848b8605Smrg        self.extent     = element.get('img_extent')
458848b8605Smrg
459848b8605Smrg        self.img_xoff   = element.get('img_xoff')
460848b8605Smrg        self.img_yoff   = element.get('img_yoff')
461848b8605Smrg        self.img_zoff   = element.get('img_zoff')
462848b8605Smrg        self.img_woff   = element.get('img_woff')
463848b8605Smrg
464848b8605Smrg        self.img_format = element.get('img_format')
465848b8605Smrg        self.img_type   = element.get('img_type')
466848b8605Smrg        self.img_target = element.get('img_target')
467848b8605Smrg
468848b8605Smrg        self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
469848b8605Smrg        self.img_null_flag      = is_attr_true( element, 'img_null_flag' )
470848b8605Smrg        self.img_send_null      = is_attr_true( element, 'img_send_null' )
471848b8605Smrg
472848b8605Smrg        self.is_padding = is_attr_true( element, 'padding' )
473848b8605Smrg        return
474848b8605Smrg
475848b8605Smrg
476848b8605Smrg    def compatible(self, other):
477848b8605Smrg        return 1
478848b8605Smrg
479848b8605Smrg
480848b8605Smrg    def is_array(self):
481848b8605Smrg        return self.is_pointer()
482848b8605Smrg
483848b8605Smrg
484848b8605Smrg    def is_pointer(self):
485848b8605Smrg        return self.type_expr.is_pointer()
486848b8605Smrg
487848b8605Smrg
488848b8605Smrg    def is_image(self):
489848b8605Smrg        if self.width:
490848b8605Smrg            return 1
491848b8605Smrg        else:
492848b8605Smrg            return 0
493848b8605Smrg
494848b8605Smrg
495848b8605Smrg    def is_variable_length(self):
496848b8605Smrg        return len(self.count_parameter_list) or self.counter
497848b8605Smrg
498848b8605Smrg
499848b8605Smrg    def is_64_bit(self):
500848b8605Smrg        count = self.type_expr.get_element_count()
501848b8605Smrg        if count:
502848b8605Smrg            if (self.size() / count) == 8:
503848b8605Smrg                return 1
504848b8605Smrg        else:
505848b8605Smrg            if self.size() == 8:
506848b8605Smrg                return 1
507848b8605Smrg
508848b8605Smrg        return 0
509848b8605Smrg
510848b8605Smrg
511848b8605Smrg    def string(self):
512848b8605Smrg        return self.type_expr.original_string + " " + self.name
513848b8605Smrg
514848b8605Smrg
515848b8605Smrg    def type_string(self):
516848b8605Smrg        return self.type_expr.original_string
517848b8605Smrg
518848b8605Smrg
519848b8605Smrg    def get_base_type_string(self):
520848b8605Smrg        return self.type_expr.get_base_name()
521848b8605Smrg
522848b8605Smrg
523848b8605Smrg    def get_dimensions(self):
524848b8605Smrg        if not self.width:
525848b8605Smrg            return [ 0, "0", "0", "0", "0" ]
526848b8605Smrg
527848b8605Smrg        dim = 1
528848b8605Smrg        w = self.width
529848b8605Smrg        h = "1"
530848b8605Smrg        d = "1"
531848b8605Smrg        e = "1"
532848b8605Smrg
533848b8605Smrg        if self.height:
534848b8605Smrg            dim = 2
535848b8605Smrg            h = self.height
536848b8605Smrg
537848b8605Smrg        if self.depth:
538848b8605Smrg            dim = 3
539848b8605Smrg            d = self.depth
540848b8605Smrg
541848b8605Smrg        if self.extent:
542848b8605Smrg            dim = 4
543848b8605Smrg            e = self.extent
544848b8605Smrg
545848b8605Smrg        return [ dim, w, h, d, e ]
546848b8605Smrg
547848b8605Smrg
548848b8605Smrg    def get_stack_size(self):
549848b8605Smrg        return self.type_expr.get_stack_size()
550848b8605Smrg
551848b8605Smrg
552848b8605Smrg    def size(self):
553848b8605Smrg        if self.is_image():
554848b8605Smrg            return 0
555848b8605Smrg        else:
556848b8605Smrg            return self.type_expr.get_element_size()
557848b8605Smrg
558848b8605Smrg
559848b8605Smrg    def get_element_count(self):
560848b8605Smrg        c = self.type_expr.get_element_count()
561848b8605Smrg        if c == 0:
562848b8605Smrg            return 1
563848b8605Smrg
564848b8605Smrg        return c
565848b8605Smrg
566848b8605Smrg
567848b8605Smrg    def size_string(self, use_parens = 1):
568848b8605Smrg        s = self.size()
569848b8605Smrg        if self.counter or self.count_parameter_list:
570848b8605Smrg            list = [ "compsize" ]
571848b8605Smrg
572848b8605Smrg            if self.counter and self.count_parameter_list:
573848b8605Smrg                list.append( self.counter )
574848b8605Smrg            elif self.counter:
575848b8605Smrg                list = [ self.counter ]
576848b8605Smrg
577848b8605Smrg            if s > 1:
578848b8605Smrg                list.append( str(s) )
579848b8605Smrg
580848b8605Smrg            if len(list) > 1 and use_parens :
581b8e80941Smrg                return "safe_mul(%s)" % ", ".join(list)
582848b8605Smrg            else:
583b8e80941Smrg                return " * ".join(list)
584848b8605Smrg
585848b8605Smrg        elif self.is_image():
586848b8605Smrg            return "compsize"
587848b8605Smrg        else:
588848b8605Smrg            return str(s)
589848b8605Smrg
590848b8605Smrg
591848b8605Smrg    def format_string(self):
592848b8605Smrg        if self.type_expr.original_string == "GLenum":
593848b8605Smrg            return "0x%x"
594848b8605Smrg        else:
595848b8605Smrg            return self.type_expr.format_string()
596848b8605Smrg
597848b8605Smrg
598848b8605Smrgclass gl_function( gl_item ):
599848b8605Smrg    def __init__(self, element, context):
600848b8605Smrg        self.context = context
601848b8605Smrg        self.name = None
602848b8605Smrg
603848b8605Smrg        self.entry_points = []
604848b8605Smrg        self.return_type = "void"
605848b8605Smrg        self.parameters = []
606848b8605Smrg        self.offset = -1
607848b8605Smrg        self.initialized = 0
608848b8605Smrg        self.images = []
609848b8605Smrg        self.exec_flavor = 'mesa'
610848b8605Smrg        self.desktop = True
611848b8605Smrg        self.deprecated = None
612b8e80941Smrg        self.has_no_error_variant = False
613848b8605Smrg
614848b8605Smrg        # self.api_map[api] is a decimal value indicating the earliest
615848b8605Smrg        # version of the given API in which ANY alias for the function
616848b8605Smrg        # exists.  The map only lists APIs which contain the function
617848b8605Smrg        # in at least one version.  For example, for the ClipPlanex
618b8e80941Smrg        # function, self.api_map == { 'es1':
619848b8605Smrg        # Decimal('1.1') }.
620848b8605Smrg        self.api_map = {}
621848b8605Smrg
622b8e80941Smrg        self.assign_offset = False
623848b8605Smrg
624848b8605Smrg        self.static_entry_points = []
625848b8605Smrg
626848b8605Smrg        # Track the parameter string (for the function prototype)
627848b8605Smrg        # for each entry-point.  This is done because some functions
628848b8605Smrg        # change their prototype slightly when promoted from extension
629848b8605Smrg        # to ARB extension to core.  glTexImage3DEXT and glTexImage3D
630848b8605Smrg        # are good examples of this.  Scripts that need to generate
631848b8605Smrg        # code for these differing aliases need to real prototype
632848b8605Smrg        # for each entry-point.  Otherwise, they may generate code
633848b8605Smrg        # that won't compile.
634848b8605Smrg
635848b8605Smrg        self.entry_point_parameters = {}
636848b8605Smrg
637848b8605Smrg        self.process_element( element )
638848b8605Smrg
639848b8605Smrg        return
640848b8605Smrg
641848b8605Smrg
642848b8605Smrg    def process_element(self, element):
643848b8605Smrg        name = element.get( "name" )
644848b8605Smrg        alias = element.get( "alias" )
645848b8605Smrg
646b8e80941Smrg        if name in static_data.functions:
647848b8605Smrg            self.static_entry_points.append(name)
648848b8605Smrg
649848b8605Smrg        self.entry_points.append( name )
650848b8605Smrg
651848b8605Smrg        for api in ('es1', 'es2'):
652848b8605Smrg            version_str = element.get(api, 'none')
653848b8605Smrg            assert version_str is not None
654848b8605Smrg            if version_str != 'none':
655848b8605Smrg                version_decimal = Decimal(version_str)
656848b8605Smrg                if api not in self.api_map or \
657848b8605Smrg                        version_decimal < self.api_map[api]:
658848b8605Smrg                    self.api_map[api] = version_decimal
659848b8605Smrg
660848b8605Smrg        exec_flavor = element.get('exec')
661848b8605Smrg        if exec_flavor:
662848b8605Smrg            self.exec_flavor = exec_flavor
663848b8605Smrg
664848b8605Smrg        deprecated = element.get('deprecated', 'none')
665848b8605Smrg        if deprecated != 'none':
666848b8605Smrg            self.deprecated = Decimal(deprecated)
667848b8605Smrg
668848b8605Smrg        if not is_attr_true(element, 'desktop', 'true'):
669848b8605Smrg            self.desktop = False
670848b8605Smrg
671b8e80941Smrg        if self.has_no_error_variant or is_attr_true(element, 'no_error'):
672b8e80941Smrg            self.has_no_error_variant = True
673b8e80941Smrg        else:
674b8e80941Smrg            self.has_no_error_variant = False
675b8e80941Smrg
676848b8605Smrg        if alias:
677848b8605Smrg            true_name = alias
678848b8605Smrg        else:
679848b8605Smrg            true_name = name
680848b8605Smrg
681848b8605Smrg            # Only try to set the offset when a non-alias entry-point
682848b8605Smrg            # is being processed.
683848b8605Smrg
684b8e80941Smrg            if name in static_data.offsets and static_data.offsets[name] <= static_data.MAX_OFFSETS:
685b8e80941Smrg                self.offset = static_data.offsets[name]
686b8e80941Smrg            elif name in static_data.offsets and static_data.offsets[name] > static_data.MAX_OFFSETS:
687b8e80941Smrg                self.offset = static_data.offsets[name]
688b8e80941Smrg                self.assign_offset = True
689b8e80941Smrg            else:
690b8e80941Smrg                if self.exec_flavor != "skip":
691b8e80941Smrg                    raise RuntimeError("Entry-point %s is missing offset in static_data.py. Add one at the bottom of the list." % (name))
692b8e80941Smrg                self.assign_offset = self.exec_flavor != "skip" or name in static_data.unused_functions
693848b8605Smrg
694848b8605Smrg        if not self.name:
695848b8605Smrg            self.name = true_name
696848b8605Smrg        elif self.name != true_name:
697848b8605Smrg            raise RuntimeError("Function true name redefined.  Was %s, now %s." % (self.name, true_name))
698848b8605Smrg
699848b8605Smrg
700848b8605Smrg        # There are two possible cases.  The first time an entry-point
701848b8605Smrg        # with data is seen, self.initialized will be 0.  On that
702848b8605Smrg        # pass, we just fill in the data.  The next time an
703848b8605Smrg        # entry-point with data is seen, self.initialized will be 1.
704848b8605Smrg        # On that pass we have to make that the new values match the
705848b8605Smrg        # valuse from the previous entry-point.
706848b8605Smrg
707848b8605Smrg        parameters = []
708848b8605Smrg        return_type = "void"
709848b8605Smrg        for child in element.getchildren():
710848b8605Smrg            if child.tag == "return":
711848b8605Smrg                return_type = child.get( "type", "void" )
712848b8605Smrg            elif child.tag == "param":
713848b8605Smrg                param = self.context.factory.create_parameter(child, self.context)
714848b8605Smrg                parameters.append( param )
715848b8605Smrg
716848b8605Smrg
717848b8605Smrg        if self.initialized:
718848b8605Smrg            if self.return_type != return_type:
719848b8605Smrg                raise RuntimeError( "Return type changed in %s.  Was %s, now %s." % (name, self.return_type, return_type))
720848b8605Smrg
721848b8605Smrg            if len(parameters) != len(self.parameters):
722848b8605Smrg                raise RuntimeError( "Parameter count mismatch in %s.  Was %d, now %d." % (name, len(self.parameters), len(parameters)))
723848b8605Smrg
724848b8605Smrg            for j in range(0, len(parameters)):
725848b8605Smrg                p1 = parameters[j]
726848b8605Smrg                p2 = self.parameters[j]
727848b8605Smrg                if not p1.compatible( p2 ):
728848b8605Smrg                    raise RuntimeError( 'Parameter type mismatch in %s.  "%s" was "%s", now "%s".' % (name, p2.name, p2.type_expr.original_string, p1.type_expr.original_string))
729848b8605Smrg
730848b8605Smrg
731848b8605Smrg        if true_name == name or not self.initialized:
732848b8605Smrg            self.return_type = return_type
733848b8605Smrg            self.parameters = parameters
734848b8605Smrg
735848b8605Smrg            for param in self.parameters:
736848b8605Smrg                if param.is_image():
737848b8605Smrg                    self.images.append( param )
738848b8605Smrg
739848b8605Smrg        if element.getchildren():
740848b8605Smrg            self.initialized = 1
741848b8605Smrg            self.entry_point_parameters[name] = parameters
742848b8605Smrg        else:
743848b8605Smrg            self.entry_point_parameters[name] = []
744848b8605Smrg
745848b8605Smrg        return
746848b8605Smrg
747848b8605Smrg    def filter_entry_points(self, entry_point_list):
748848b8605Smrg        """Filter out entry points not in entry_point_list."""
749848b8605Smrg        if not self.initialized:
750848b8605Smrg            raise RuntimeError('%s is not initialized yet' % self.name)
751848b8605Smrg
752848b8605Smrg        entry_points = []
753848b8605Smrg        for ent in self.entry_points:
754848b8605Smrg            if ent not in entry_point_list:
755848b8605Smrg                if ent in self.static_entry_points:
756848b8605Smrg                    self.static_entry_points.remove(ent)
757848b8605Smrg                self.entry_point_parameters.pop(ent)
758848b8605Smrg            else:
759848b8605Smrg                entry_points.append(ent)
760848b8605Smrg
761848b8605Smrg        if not entry_points:
762848b8605Smrg            raise RuntimeError('%s has no entry point after filtering' % self.name)
763848b8605Smrg
764848b8605Smrg        self.entry_points = entry_points
765848b8605Smrg        if self.name not in entry_points:
766848b8605Smrg            # use the first remaining entry point
767848b8605Smrg            self.name = entry_points[0]
768848b8605Smrg            self.parameters = self.entry_point_parameters[entry_points[0]]
769848b8605Smrg
770848b8605Smrg    def get_images(self):
771848b8605Smrg        """Return potentially empty list of input images."""
772848b8605Smrg        return self.images
773848b8605Smrg
774848b8605Smrg
775848b8605Smrg    def parameterIterator(self, name = None):
776848b8605Smrg        if name is not None:
777b8e80941Smrg            return iter(self.entry_point_parameters[name]);
778848b8605Smrg        else:
779b8e80941Smrg            return iter(self.parameters);
780848b8605Smrg
781848b8605Smrg
782848b8605Smrg    def get_parameter_string(self, entrypoint = None):
783848b8605Smrg        if entrypoint:
784848b8605Smrg            params = self.entry_point_parameters[ entrypoint ]
785848b8605Smrg        else:
786848b8605Smrg            params = self.parameters
787848b8605Smrg
788848b8605Smrg        return create_parameter_string( params, 1 )
789848b8605Smrg
790848b8605Smrg    def get_called_parameter_string(self):
791848b8605Smrg        p_string = ""
792848b8605Smrg        comma = ""
793848b8605Smrg
794848b8605Smrg        for p in self.parameterIterator():
795848b8605Smrg            if p.is_padding:
796848b8605Smrg                continue
797848b8605Smrg            p_string = p_string + comma + p.name
798848b8605Smrg            comma = ", "
799848b8605Smrg
800848b8605Smrg        return p_string
801848b8605Smrg
802848b8605Smrg
803848b8605Smrg    def is_abi(self):
804848b8605Smrg        return (self.offset >= 0 and not self.assign_offset)
805848b8605Smrg
806848b8605Smrg    def is_static_entry_point(self, name):
807848b8605Smrg        return name in self.static_entry_points
808848b8605Smrg
809848b8605Smrg    def dispatch_name(self):
810848b8605Smrg        if self.name in self.static_entry_points:
811848b8605Smrg            return self.name
812848b8605Smrg        else:
813848b8605Smrg            return "_dispatch_stub_%u" % (self.offset)
814848b8605Smrg
815848b8605Smrg    def static_name(self, name):
816848b8605Smrg        if name in self.static_entry_points:
817848b8605Smrg            return name
818848b8605Smrg        else:
819848b8605Smrg            return "_dispatch_stub_%u" % (self.offset)
820848b8605Smrg
821848b8605Smrgclass gl_item_factory(object):
822848b8605Smrg    """Factory to create objects derived from gl_item."""
823848b8605Smrg
824848b8605Smrg    def create_function(self, element, context):
825848b8605Smrg        return gl_function(element, context)
826848b8605Smrg
827848b8605Smrg    def create_type(self, element, context, category):
828848b8605Smrg        return gl_type(element, context, category)
829848b8605Smrg
830848b8605Smrg    def create_enum(self, element, context, category):
831848b8605Smrg        return gl_enum(element, context, category)
832848b8605Smrg
833848b8605Smrg    def create_parameter(self, element, context):
834848b8605Smrg        return gl_parameter(element, context)
835848b8605Smrg
836848b8605Smrg    def create_api(self):
837848b8605Smrg        return gl_api(self)
838848b8605Smrg
839848b8605Smrg
840848b8605Smrgclass gl_api(object):
841848b8605Smrg    def __init__(self, factory):
842b8e80941Smrg        self.functions_by_name = OrderedDict()
843848b8605Smrg        self.enums_by_name = {}
844848b8605Smrg        self.types_by_name = {}
845848b8605Smrg
846848b8605Smrg        self.category_dict = {}
847848b8605Smrg        self.categories = [{}, {}, {}, {}]
848848b8605Smrg
849848b8605Smrg        self.factory = factory
850848b8605Smrg
851848b8605Smrg        self.next_offset = 0
852848b8605Smrg
853848b8605Smrg        typeexpr.create_initial_types()
854848b8605Smrg        return
855848b8605Smrg
856848b8605Smrg    def parse_file(self, file_name):
857848b8605Smrg        doc = ET.parse( file_name )
858848b8605Smrg        self.process_element(file_name, doc)
859848b8605Smrg
860848b8605Smrg
861848b8605Smrg    def process_element(self, file_name, doc):
862848b8605Smrg        element = doc.getroot()
863848b8605Smrg        if element.tag == "OpenGLAPI":
864848b8605Smrg            self.process_OpenGLAPI(file_name, element)
865848b8605Smrg        return
866848b8605Smrg
867848b8605Smrg
868848b8605Smrg    def process_OpenGLAPI(self, file_name, element):
869848b8605Smrg        for child in element.getchildren():
870848b8605Smrg            if child.tag == "category":
871848b8605Smrg                self.process_category( child )
872848b8605Smrg            elif child.tag == "OpenGLAPI":
873848b8605Smrg                self.process_OpenGLAPI( file_name, child )
874848b8605Smrg            elif child.tag == '{http://www.w3.org/2001/XInclude}include':
875848b8605Smrg                href = child.get('href')
876848b8605Smrg                href = os.path.join(os.path.dirname(file_name), href)
877848b8605Smrg                self.parse_file(href)
878848b8605Smrg
879848b8605Smrg        return
880848b8605Smrg
881848b8605Smrg
882848b8605Smrg    def process_category(self, cat):
883848b8605Smrg        cat_name = cat.get( "name" )
884848b8605Smrg        cat_number = cat.get( "number" )
885848b8605Smrg
886848b8605Smrg        [cat_type, key] = classify_category(cat_name, cat_number)
887848b8605Smrg        self.categories[cat_type][key] = [cat_name, cat_number]
888848b8605Smrg
889848b8605Smrg        for child in cat.getchildren():
890848b8605Smrg            if child.tag == "function":
891848b8605Smrg                func_name = real_function_name( child )
892848b8605Smrg
893848b8605Smrg                temp_name = child.get( "name" )
894848b8605Smrg                self.category_dict[ temp_name ] = [cat_name, cat_number]
895848b8605Smrg
896b8e80941Smrg                if func_name in self.functions_by_name:
897848b8605Smrg                    func = self.functions_by_name[ func_name ]
898848b8605Smrg                    func.process_element( child )
899848b8605Smrg                else:
900848b8605Smrg                    func = self.factory.create_function( child, self )
901848b8605Smrg                    self.functions_by_name[ func_name ] = func
902848b8605Smrg
903848b8605Smrg                if func.offset >= self.next_offset:
904848b8605Smrg                    self.next_offset = func.offset + 1
905848b8605Smrg
906848b8605Smrg
907848b8605Smrg            elif child.tag == "enum":
908848b8605Smrg                enum = self.factory.create_enum( child, self, cat_name )
909848b8605Smrg                self.enums_by_name[ enum.name ] = enum
910848b8605Smrg            elif child.tag == "type":
911848b8605Smrg                t = self.factory.create_type( child, self, cat_name )
912848b8605Smrg                self.types_by_name[ "GL" + t.name ] = t
913848b8605Smrg
914848b8605Smrg        return
915848b8605Smrg
916848b8605Smrg
917848b8605Smrg    def functionIterateByCategory(self, cat = None):
918848b8605Smrg        """Iterate over functions by category.
919848b8605Smrg
920848b8605Smrg        If cat is None, all known functions are iterated in category
921848b8605Smrg        order.  See classify_category for details of the ordering.
922848b8605Smrg        Within a category, functions are sorted by name.  If cat is
923848b8605Smrg        not None, then only functions in that category are iterated.
924848b8605Smrg        """
925848b8605Smrg        lists = [{}, {}, {}, {}]
926848b8605Smrg
927848b8605Smrg        for func in self.functionIterateAll():
928848b8605Smrg            [cat_name, cat_number] = self.category_dict[func.name]
929848b8605Smrg
930848b8605Smrg            if (cat == None) or (cat == cat_name):
931848b8605Smrg                [func_cat_type, key] = classify_category(cat_name, cat_number)
932848b8605Smrg
933b8e80941Smrg                if key not in lists[func_cat_type]:
934848b8605Smrg                    lists[func_cat_type][key] = {}
935848b8605Smrg
936848b8605Smrg                lists[func_cat_type][key][func.name] = func
937848b8605Smrg
938848b8605Smrg
939848b8605Smrg        functions = []
940848b8605Smrg        for func_cat_type in range(0,4):
941b8e80941Smrg            keys = sorted(lists[func_cat_type].keys())
942848b8605Smrg
943848b8605Smrg            for key in keys:
944b8e80941Smrg                names = sorted(lists[func_cat_type][key].keys())
945848b8605Smrg
946848b8605Smrg                for name in names:
947848b8605Smrg                    functions.append(lists[func_cat_type][key][name])
948848b8605Smrg
949b8e80941Smrg        return iter(functions)
950848b8605Smrg
951848b8605Smrg
952848b8605Smrg    def functionIterateByOffset(self):
953848b8605Smrg        max_offset = -1
954b8e80941Smrg        for func in self.functions_by_name.values():
955848b8605Smrg            if func.offset > max_offset:
956848b8605Smrg                max_offset = func.offset
957848b8605Smrg
958848b8605Smrg
959848b8605Smrg        temp = [None for i in range(0, max_offset + 1)]
960b8e80941Smrg        for func in self.functions_by_name.values():
961848b8605Smrg            if func.offset != -1:
962848b8605Smrg                temp[ func.offset ] = func
963848b8605Smrg
964848b8605Smrg
965848b8605Smrg        list = []
966848b8605Smrg        for i in range(0, max_offset + 1):
967848b8605Smrg            if temp[i]:
968848b8605Smrg                list.append(temp[i])
969848b8605Smrg
970b8e80941Smrg        return iter(list);
971848b8605Smrg
972848b8605Smrg
973848b8605Smrg    def functionIterateAll(self):
974b8e80941Smrg        return self.functions_by_name.values()
975848b8605Smrg
976848b8605Smrg
977848b8605Smrg    def enumIterateByName(self):
978b8e80941Smrg        keys = sorted(self.enums_by_name.keys())
979848b8605Smrg
980848b8605Smrg        list = []
981848b8605Smrg        for enum in keys:
982848b8605Smrg            list.append( self.enums_by_name[ enum ] )
983848b8605Smrg
984b8e80941Smrg        return iter(list)
985848b8605Smrg
986848b8605Smrg
987848b8605Smrg    def categoryIterate(self):
988848b8605Smrg        """Iterate over categories.
989848b8605Smrg
990848b8605Smrg        Iterate over all known categories in the order specified by
991848b8605Smrg        classify_category.  Each iterated value is a tuple of the
992848b8605Smrg        name and number (which may be None) of the category.
993848b8605Smrg        """
994848b8605Smrg
995848b8605Smrg        list = []
996848b8605Smrg        for cat_type in range(0,4):
997b8e80941Smrg            keys = sorted(self.categories[cat_type].keys())
998848b8605Smrg
999848b8605Smrg            for key in keys:
1000848b8605Smrg                list.append(self.categories[cat_type][key])
1001848b8605Smrg
1002b8e80941Smrg        return iter(list)
1003848b8605Smrg
1004848b8605Smrg
1005848b8605Smrg    def get_category_for_name( self, name ):
1006b8e80941Smrg        if name in self.category_dict:
1007848b8605Smrg            return self.category_dict[name]
1008848b8605Smrg        else:
1009848b8605Smrg            return ["<unknown category>", None]
1010848b8605Smrg
1011848b8605Smrg
1012848b8605Smrg    def typeIterate(self):
1013b8e80941Smrg        return self.types_by_name.values()
1014848b8605Smrg
1015848b8605Smrg
1016848b8605Smrg    def find_type( self, type_name ):
1017848b8605Smrg        if type_name in self.types_by_name:
1018848b8605Smrg            return self.types_by_name[ type_name ].type_expr
1019848b8605Smrg        else:
1020b8e80941Smrg            print("Unable to find base type matching \"%s\"." % (type_name))
1021848b8605Smrg            return None
1022