es_generator.py revision 5af46e836073d2112b147b524e441bdb808cc128
1#*************************************************************************
2# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3# All Rights Reserved.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9# and/or sell copies of the Software, and to permit persons to whom the
10# Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included
13# in all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18# TUNGSTEN GRAPHICS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22#*************************************************************************
23
24
25import sys, os
26import APIspecutil as apiutil
27
28# These dictionary entries are used for automatic conversion.
29# The string will be used as a format string with the conversion
30# variable.
31Converters = {
32    'GLfloat': {
33        'GLdouble': "(GLdouble) (%s)",
34        'GLfixed' : "(GLint) (%s * 65536)",
35    },
36    'GLfixed': {
37        'GLfloat': "(GLfloat) (%s / 65536.0f)",
38        'GLdouble': "(GLdouble) (%s / 65536.0)",
39    },
40    'GLdouble': {
41        'GLfloat': "(GLfloat) (%s)",
42        'GLfixed': "(GLfixed) (%s * 65536)",
43    },
44    'GLclampf': {
45        'GLclampd': "(GLclampd) (%s)",
46        'GLclampx': "(GLclampx) (%s * 65536)",
47    },
48    'GLclampx': {
49        'GLclampf': "(GLclampf) (%s / 65536.0f)",
50        'GLclampd': "(GLclampd) (%s / 65536.0)",
51    },
52    'GLubyte': {
53        'GLfloat': "(GLfloat) (%s / 255.0f)",
54    },
55}
56
57def GetBaseType(type):
58    typeTokens = type.split(' ')
59    baseType = None
60    typeModifiers = []
61    for t in typeTokens:
62        if t in ['const', '*']:
63            typeModifiers.append(t)
64        else:
65            baseType = t
66    return (baseType, typeModifiers)
67
68def ConvertValue(value, fromType, toType):
69    """Returns a string that represents the given parameter string,
70    type-converted if necessary."""
71
72    if not Converters.has_key(fromType):
73        print >> sys.stderr, "No base converter for type '%s' found.  Ignoring." % fromType
74        return value
75
76    if not Converters[fromType].has_key(toType):
77        print >> sys.stderr, "No converter found for type '%s' to type '%s'.  Ignoring." % (fromType, toType)
78        return value
79
80    # This part is simple.  Return the proper conversion.
81    conversionString = Converters[fromType][toType]
82    return conversionString % value
83
84FormatStrings = {
85    'GLenum' : '0x%x',
86    'GLfloat' : '%f',
87    'GLint' : '%d',
88    'GLbitfield' : '0x%x',
89}
90def GetFormatString(type):
91    if FormatStrings.has_key(type):
92        return FormatStrings[type]
93    else:
94        return None
95
96
97######################################################################
98# Version-specific values to be used in the main script
99# header: which header file to include
100# api: what text specifies an API-level function
101VersionSpecificValues = {
102    'GLES1.1' : {
103        'description' : 'GLES1.1 functions',
104        'header' : 'GLES/gl.h',
105        'extheader' : 'GLES/glext.h',
106        'shortname' : 'es1'
107    },
108    'GLES2.0': {
109        'description' : 'GLES2.0 functions',
110        'header' : 'GLES2/gl2.h',
111        'extheader' : 'GLES2/gl2ext.h',
112        'shortname' : 'es2'
113    }
114}
115
116
117######################################################################
118# Main code for the script begins here.
119
120# Get the name of the program (without the directory part) for use in
121# error messages.
122program = os.path.basename(sys.argv[0])
123
124# Set default values
125verbose = 0
126functionList = "APIspec.xml"
127version = "GLES1.1"
128
129# Allow for command-line switches
130import getopt, time
131options = "hvV:S:"
132try:
133    optlist, args = getopt.getopt(sys.argv[1:], options)
134except getopt.GetoptError, message:
135    sys.stderr.write("%s: %s.  Use -h for help.\n" % (program, message))
136    sys.exit(1)
137
138for option, optarg in optlist:
139    if option == "-h":
140        sys.stderr.write("Usage: %s [-%s]\n" % (program, options))
141        sys.stderr.write("Parse an API specification file and generate wrapper functions for a given GLES version\n")
142        sys.stderr.write("-h gives help\n")
143        sys.stderr.write("-v is verbose\n")
144        sys.stderr.write("-V specifies GLES version to generate [%s]:\n" % version)
145        for key in VersionSpecificValues.keys():
146            sys.stderr.write("    %s - %s\n" % (key, VersionSpecificValues[key]['description']))
147        sys.stderr.write("-S specifies API specification file to use [%s]\n" % functionList)
148        sys.exit(1)
149    elif option == "-v":
150        verbose += 1
151    elif option == "-V":
152        version = optarg
153    elif option == "-S":
154        functionList = optarg
155
156# Beyond switches, we support no further command-line arguments
157if len(args) >  0:
158    sys.stderr.write("%s: only switch arguments are supported - use -h for help\n" % program)
159    sys.exit(1)
160
161# If we don't have a valid version, abort.
162if not VersionSpecificValues.has_key(version):
163    sys.stderr.write("%s: version '%s' is not valid - use -h for help\n" % (program, version))
164    sys.exit(1)
165
166# Grab the version-specific items we need to use
167versionHeader = VersionSpecificValues[version]['header']
168versionExtHeader = VersionSpecificValues[version]['extheader']
169shortname = VersionSpecificValues[version]['shortname']
170
171# If we get to here, we're good to go.  The "version" parameter
172# directs GetDispatchedFunctions to only allow functions from
173# that "category" (version in our parlance).  This allows
174# functions with different declarations in different categories
175# to exist (glTexImage2D, for example, is different between
176# GLES1 and GLES2).
177keys = apiutil.GetAllFunctions(functionList, version)
178
179allSpecials = apiutil.AllSpecials()
180
181print """/* DO NOT EDIT *************************************************
182 * THIS FILE AUTOMATICALLY GENERATED BY THE %s SCRIPT
183 * API specification file:   %s
184 * GLES version:             %s
185 * date:                     %s
186 */
187""" % (program, functionList, version, time.strftime("%Y-%m-%d %H:%M:%S"))
188
189# The headers we choose are version-specific.
190print """
191#include "%s"
192#include "%s"
193#include "main/mfeatures.h"
194#include "main/compiler.h"
195#include "main/api_exec.h"
196
197#if FEATURE_%s
198
199#ifndef GLAPIENTRYP
200#define GLAPIENTRYP GL_APIENTRYP
201#endif
202""" % (versionHeader, versionExtHeader, shortname.upper())
203
204# Everyone needs these types.
205print """
206/* These types are needed for the Mesa veneer, but are not defined in
207 * the standard GLES headers.
208 */
209typedef double GLdouble;
210typedef double GLclampd;
211
212/* Mesa error handling requires these */
213extern void *_mesa_get_current_context(void);
214extern void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... );
215"""
216
217# Finally we get to the all-important functions
218print """/*************************************************************
219 * Generated functions begin here
220 */
221"""
222for funcName in keys:
223    if verbose > 0: sys.stderr.write("%s: processing function %s\n" % (program, funcName))
224
225    # start figuring out what this function will look like.
226    returnType = apiutil.ReturnType(funcName)
227    props = apiutil.Properties(funcName)
228    params = apiutil.Parameters(funcName)
229    declarationString = apiutil.MakeDeclarationString(params)
230
231    # In case of error, a function may have to return.  Make
232    # sure we have valid return values in this case.
233    if returnType == "void":
234        errorReturn = "return"
235    elif returnType == "GLboolean":
236        errorReturn = "return GL_FALSE"
237    else:
238        errorReturn = "return (%s) 0" % returnType
239
240    # These are the output of this large calculation block.
241    # passthroughDeclarationString: a typed set of parameters that
242    # will be used to create the "extern" reference for the
243    # underlying Mesa or support function.  Note that as generated
244    # these have an extra ", " at the beginning, which will be
245    # removed before use.
246    #
247    # passthroughDeclarationString: an untyped list of parameters
248    # that will be used to call the underlying Mesa or support
249    # function (including references to converted parameters).
250    # This will also be generated with an extra ", " at the
251    # beginning, which will be removed before use.
252    #
253    # variables: C code to create any local variables determined to
254    # be necessary.
255    # conversionCodeOutgoing: C code to convert application parameters
256    # to a necessary type before calling the underlying support code.
257    # May be empty if no conversion is required.
258    # conversionCodeIncoming: C code to do the converse: convert
259    # values returned by underlying Mesa code to the types needed
260    # by the application.
261    # Note that *either* the conversionCodeIncoming will be used (for
262    # generated query functions), *or* the conversionCodeOutgoing will
263    # be used (for generated non-query functions), never both.
264    passthroughFuncName = ""
265    passthroughDeclarationString = ""
266    passthroughCallString = ""
267    prefixOverride = None
268    variables = []
269    conversionCodeOutgoing = []
270    conversionCodeIncoming = []
271    switchCode = []
272
273    # Calculate the name of the underlying support function to call.
274    # By default, the passthrough function is named _mesa_<funcName>.
275    # We're allowed to override the prefix and/or the function name
276    # for each function record, though.  The "ConversionFunction"
277    # utility is poorly named, BTW...
278    if funcName in allSpecials:
279        # perform checks and pass through
280        funcPrefix = "_check_"
281        aliasprefix = "_es_"
282    else:
283        funcPrefix = "_es_"
284        aliasprefix = apiutil.AliasPrefix(funcName)
285    alias = apiutil.ConversionFunction(funcName)
286    prefixOverride = apiutil.FunctionPrefix(funcName)
287    if prefixOverride != "_mesa_":
288        aliasprefix = apiutil.FunctionPrefix(funcName)
289    if not alias:
290        # There may still be a Mesa alias for the function
291        if apiutil.Alias(funcName):
292            passthroughFuncName = "%s%s" % (aliasprefix, apiutil.Alias(funcName))
293        else:
294            passthroughFuncName = "%s%s" % (aliasprefix, funcName)
295    else: # a specific alias is provided
296        passthroughFuncName = "%s%s" % (aliasprefix, alias)
297
298    # Look at every parameter: each one may have only specific
299    # allowed values, or dependent parameters to check, or
300    # variant-sized vector arrays to calculate
301    for (paramName, paramType, paramMaxVecSize, paramConvertToType, paramValidValues, paramValueConversion) in params:
302        # We'll need this below if we're doing conversions
303        (paramBaseType, paramTypeModifiers) = GetBaseType(paramType)
304
305        # Conversion management.
306        # We'll handle three cases, easiest to hardest: a parameter
307        # that doesn't require conversion, a scalar parameter that
308        # requires conversion, and a vector parameter that requires
309        # conversion.
310        if paramConvertToType == None:
311            # Unconverted parameters are easy, whether they're vector
312            # or scalar - just add them to the call list.  No conversions
313            # or anything to worry about.
314            passthroughDeclarationString += ", %s %s" % (paramType, paramName)
315            passthroughCallString += ", %s" % paramName
316
317        elif paramMaxVecSize == 0: # a scalar parameter that needs conversion
318            # A scalar to hold a converted parameter
319            variables.append("    %s converted_%s;" % (paramConvertToType, paramName))
320
321            # Outgoing conversion depends on whether we have to conditionally
322            # perform value conversion.
323            if paramValueConversion == "none":
324                conversionCodeOutgoing.append("    converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
325            elif paramValueConversion == "some":
326                # We'll need a conditional variable to keep track of
327                # whether we're converting values or not.
328                if ("    int convert_%s_value = 1;" % paramName) not in variables:
329                    variables.append("    int convert_%s_value = 1;" % paramName)
330
331                # Write code based on that conditional.
332                conversionCodeOutgoing.append("    if (convert_%s_value) {" % paramName)
333                conversionCodeOutgoing.append("        converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
334                conversionCodeOutgoing.append("    } else {")
335                conversionCodeOutgoing.append("        converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
336                conversionCodeOutgoing.append("    }")
337            else: # paramValueConversion == "all"
338                conversionCodeOutgoing.append("    converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
339
340            # Note that there can be no incoming conversion for a
341            # scalar parameter; changing the scalar will only change
342            # the local value, and won't ultimately change anything
343            # that passes back to the application.
344
345            # Call strings.  The unusual " ".join() call will join the
346            # array of parameter modifiers with spaces as separators.
347            passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName)
348            passthroughCallString += ", converted_%s" % paramName
349
350        else: # a vector parameter that needs conversion
351            # We'll need an index variable for conversions
352            if "    register unsigned int i;" not in variables:
353                variables.append("    register unsigned int i;")
354
355            # This variable will hold the (possibly variant) size of
356            # this array needing conversion.  By default, we'll set
357            # it to the maximal size (which is correct for functions
358            # with a constant-sized vector parameter); for true
359            # variant arrays, we'll modify it with other code.
360            variables.append("    unsigned int n_%s = %d;" % (paramName, paramMaxVecSize))
361
362            # This array will hold the actual converted values.
363            variables.append("    %s converted_%s[%d];" % (paramConvertToType, paramName, paramMaxVecSize))
364
365            # Again, we choose the conversion code based on whether we
366            # have to always convert values, never convert values, or
367            # conditionally convert values.
368            if paramValueConversion == "none":
369                conversionCodeOutgoing.append("    for (i = 0; i < n_%s; i++) {" % paramName)
370                conversionCodeOutgoing.append("        converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
371                conversionCodeOutgoing.append("    }")
372            elif paramValueConversion == "some":
373                # We'll need a conditional variable to keep track of
374                # whether we're converting values or not.
375                if ("    int convert_%s_value = 1;" % paramName) not in variables:
376                    variables.append("    int convert_%s_value = 1;" % paramName)
377                # Write code based on that conditional.
378                conversionCodeOutgoing.append("    if (convert_%s_value) {" % paramName)
379                conversionCodeOutgoing.append("        for (i = 0; i < n_%s; i++) {" % paramName)
380                conversionCodeOutgoing.append("            converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
381                conversionCodeOutgoing.append("        }")
382                conversionCodeOutgoing.append("    } else {")
383                conversionCodeOutgoing.append("        for (i = 0; i < n_%s; i++) {" % paramName)
384                conversionCodeOutgoing.append("            converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
385                conversionCodeOutgoing.append("        }")
386                conversionCodeOutgoing.append("    }")
387            else: # paramValueConversion == "all"
388                conversionCodeOutgoing.append("    for (i = 0; i < n_%s; i++) {" % paramName)
389                conversionCodeOutgoing.append("        converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
390
391                conversionCodeOutgoing.append("    }")
392
393            # If instead we need an incoming conversion (i.e. results
394            # from Mesa have to be converted before handing back
395            # to the application), this is it.  Fortunately, we don't
396            # have to worry about conditional value conversion - the
397            # functions that do (e.g. glGetFixedv()) are handled
398            # specially, outside this code generation.
399            #
400            # Whether we use incoming conversion or outgoing conversion
401            # is determined later - we only ever use one or the other.
402
403            if paramValueConversion == "none":
404                conversionCodeIncoming.append("    for (i = 0; i < n_%s; i++) {" % paramName)
405                conversionCodeIncoming.append("        %s[i] = (%s) converted_%s[i];" % (paramName, paramConvertToType, paramName))
406                conversionCodeIncoming.append("    }")
407            elif paramValueConversion == "some":
408                # We'll need a conditional variable to keep track of
409                # whether we're converting values or not.
410                if ("    int convert_%s_value = 1;" % paramName) not in variables:
411                    variables.append("    int convert_%s_value = 1;" % paramName)
412
413                # Write code based on that conditional.
414                conversionCodeIncoming.append("    if (convert_%s_value) {" % paramName)
415                conversionCodeIncoming.append("        for (i = 0; i < n_%s; i++) {" % paramName)
416                conversionCodeIncoming.append("            %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
417                conversionCodeIncoming.append("        }")
418                conversionCodeIncoming.append("    } else {")
419                conversionCodeIncoming.append("        for (i = 0; i < n_%s; i++) {" % paramName)
420                conversionCodeIncoming.append("            %s[i] = (%s) converted_%s[i];" % (paramName, paramBaseType, paramName))
421                conversionCodeIncoming.append("        }")
422                conversionCodeIncoming.append("    }")
423            else: # paramValueConversion == "all"
424                conversionCodeIncoming.append("    for (i = 0; i < n_%s; i++) {" % paramName)
425                conversionCodeIncoming.append("        %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
426                conversionCodeIncoming.append("    }")
427
428            # Call strings.  The unusual " ".join() call will join the
429            # array of parameter modifiers with spaces as separators.
430            passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName)
431            passthroughCallString += ", converted_%s" % paramName
432
433        # endif conversion management
434
435        # Parameter checking.  If the parameter has a specific list of
436        # valid values, we have to make sure that the passed-in values
437        # match these, or we make an error.
438        if len(paramValidValues) > 0:
439            # We're about to make a big switch statement with an
440            # error at the end.  By default, the error is GL_INVALID_ENUM,
441            # unless we find a "case" statement in the middle with a
442            # non-GLenum value.
443            errorDefaultCase = "GL_INVALID_ENUM"
444
445            # This parameter has specific valid values.  Make a big
446            # switch statement to handle it.  Note that the original
447            # parameters are always what is checked, not the
448            # converted parameters.
449            switchCode.append("    switch(%s) {" % paramName)
450
451            for valueIndex in range(len(paramValidValues)):
452                (paramValue, dependentVecSize, dependentParamName, dependentValidValues, errorCode, valueConvert) = paramValidValues[valueIndex]
453
454                # We're going to need information on the dependent param
455                # as well.
456                if dependentParamName:
457                    depParamIndex = apiutil.FindParamIndex(params, dependentParamName)
458                    if depParamIndex == None:
459                        sys.stderr.write("%s: can't find dependent param '%s' for function '%s'\n" % (program, dependentParamName, funcName))
460
461                    (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = params[depParamIndex]
462                else:
463                    (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = (None, None, None, None, [], None)
464
465                # This is a sneaky trick.  It's valid syntax for a parameter
466                # that is *not* going to be converted to be declared
467                # with a dependent vector size; but in this case, the
468                # dependent vector size is unused and unnecessary.
469                # So check for this and ignore the dependent vector size
470                # if the parameter is not going to be converted.
471                if depParamConvertToType:
472                    usedDependentVecSize = dependentVecSize
473                else:
474                    usedDependentVecSize = None
475
476                # We'll peek ahead at the next parameter, to see whether
477                # we can combine cases
478                if valueIndex + 1 < len(paramValidValues) :
479                    (nextParamValue, nextDependentVecSize, nextDependentParamName, nextDependentValidValues, nextErrorCode, nextValueConvert) = paramValidValues[valueIndex + 1]
480                    if depParamConvertToType:
481                        usedNextDependentVecSize = nextDependentVecSize
482                    else:
483                        usedNextDependentVecSize = None
484
485                # Create a case for this value.  As a mnemonic,
486                # if we have a dependent vector size that we're ignoring,
487                # add it as a comment.
488                if usedDependentVecSize == None and dependentVecSize != None:
489                    switchCode.append("        case %s: /* size %s */" % (paramValue, dependentVecSize))
490                else:
491                    switchCode.append("        case %s:" % paramValue)
492
493                # If this is not a GLenum case, then switch our error
494                # if no value is matched to be GL_INVALID_VALUE instead
495                # of GL_INVALID_ENUM.  (Yes, this does get confused
496                # if there are both values and GLenums in the same
497                # switch statement, which shouldn't happen.)
498                if paramValue[0:3] != "GL_":
499                    errorDefaultCase = "GL_INVALID_VALUE"
500
501                # If all the remaining parameters are identical to the
502                # next set, then we're done - we'll just create the
503                # official code on the next pass through, and the two
504                # cases will share the code.
505                if valueIndex + 1 < len(paramValidValues) and usedDependentVecSize == usedNextDependentVecSize and dependentParamName == nextDependentParamName and dependentValidValues == nextDependentValidValues and errorCode == nextErrorCode and valueConvert == nextValueConvert:
506                    continue
507
508                # Otherwise, we'll have to generate code for this case.
509                # Start off with a check: if there is a dependent parameter,
510                # and a list of valid values for that parameter, we need
511                # to generate an error if something other than one
512                # of those values is passed.
513                if len(dependentValidValues) > 0:
514                    conditional=""
515
516                    # If the parameter being checked is actually an array,
517                    # check only its first element.
518                    if depParamMaxVecSize == 0:
519                        valueToCheck = dependentParamName
520                    else:
521                        valueToCheck = "%s[0]" % dependentParamName
522
523                    for v in dependentValidValues:
524                        conditional += " && %s != %s" % (valueToCheck, v)
525                    switchCode.append("            if (%s) {" % conditional[4:])
526                    if errorCode == None:
527                        errorCode = "GL_INVALID_ENUM"
528                    switchCode.append('                _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=0x%s)", %s);' % (errorCode, funcName, paramName, "%x", paramName))
529                    switchCode.append("                %s;" % errorReturn)
530                    switchCode.append("            }")
531                # endif there are dependent valid values
532
533                # The dependent parameter may require conditional
534                # value conversion.  If it does, and we don't want
535                # to convert values, we'll have to generate code for that
536                if depParamValueConversion == "some" and valueConvert == "noconvert":
537                    switchCode.append("            convert_%s_value = 0;" % dependentParamName)
538
539                # If there's a dependent vector size for this parameter
540                # that we're actually going to use (i.e. we need conversion),
541                # mark it.
542                if usedDependentVecSize:
543                    switchCode.append("            n_%s = %s;" % (dependentParamName, dependentVecSize))
544
545                # In all cases, break out of the switch if any valid
546                # value is found.
547                switchCode.append("            break;")
548
549
550            # Need a default case to catch all the other, invalid
551            # parameter values.  These will all generate errors.
552            switchCode.append("        default:")
553            if errorCode == None:
554                errorCode = "GL_INVALID_ENUM"
555            formatString = GetFormatString(paramType)
556            if formatString == None:
557                switchCode.append('            _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s)");' % (errorCode, funcName, paramName))
558            else:
559                switchCode.append('            _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=%s)", %s);' % (errorCode, funcName, paramName, formatString, paramName))
560            switchCode.append("            %s;" % errorReturn)
561
562            # End of our switch code.
563            switchCode.append("    }")
564
565        # endfor every recognized parameter value
566
567    # endfor every param
568
569    # Here, the passthroughDeclarationString and passthroughCallString
570    # are complete; remove the extra ", " at the front of each.
571    passthroughDeclarationString = passthroughDeclarationString[2:]
572    passthroughCallString = passthroughCallString[2:]
573    if not passthroughDeclarationString:
574        passthroughDeclarationString = "void"
575
576    # The Mesa functions are scattered across all the Mesa
577    # header files.  The easiest way to manage declarations
578    # is to create them ourselves.
579    if funcName in allSpecials:
580        print "/* this function is special and is defined elsewhere */"
581    print "extern %s GL_APIENTRY %s(%s);" % (returnType, passthroughFuncName, passthroughDeclarationString)
582
583    # A function may be a core function (i.e. it exists in
584    # the core specification), a core addition (extension
585    # functions added officially to the core), a required
586    # extension (usually an extension for an earlier version
587    # that has been officially adopted), or an optional extension.
588    #
589    # Core functions have a simple category (e.g. "GLES1.1");
590    # we generate only a simple callback for them.
591    #
592    # Core additions have two category listings, one simple
593    # and one compound (e.g.  ["GLES1.1", "GLES1.1:OES_fixed_point"]).
594    # We generate the core function, and also an extension function.
595    #
596    # Required extensions and implemented optional extensions
597    # have a single compound category "GLES1.1:OES_point_size_array".
598    # For these we generate just the extension function.
599    for categorySpec in apiutil.Categories(funcName):
600        compoundCategory = categorySpec.split(":")
601
602        # This category isn't for us, if the base category doesn't match
603        # our version
604        if compoundCategory[0] != version:
605            continue
606
607        # Otherwise, determine if we're writing code for a core
608        # function (no suffix) or an extension function.
609        if len(compoundCategory) == 1:
610            # This is a core function
611            extensionName = None
612            extensionSuffix = ""
613        else:
614            # This is an extension function.  We'll need to append
615            # the extension suffix.
616            extensionName = compoundCategory[1]
617            extensionSuffix = extensionName.split("_")[0]
618        fullFuncName = funcPrefix + funcName + extensionSuffix
619
620        # Now the generated function.  The text used to mark an API-level
621        # function, oddly, is version-specific.
622        if extensionName:
623            print "/* Extension %s */" % extensionName
624
625        if (not variables and
626            not switchCode and
627            not conversionCodeOutgoing and
628            not conversionCodeIncoming):
629            # pass through directly
630            print "#define %s %s" % (fullFuncName, passthroughFuncName)
631            print
632            continue
633
634        print "static %s GL_APIENTRY %s(%s)" % (returnType, fullFuncName, declarationString)
635        print "{"
636
637        # Start printing our code pieces.  Start with any local
638        # variables we need.  This unusual syntax joins the
639        # lines in the variables[] array with the "\n" separator.
640        if len(variables) > 0:
641            print "\n".join(variables) + "\n"
642
643        # If there's any sort of parameter checking or variable
644        # array sizing, the switch code will contain it.
645        if len(switchCode) > 0:
646            print "\n".join(switchCode) + "\n"
647
648        # In the case of an outgoing conversion (i.e. parameters must
649        # be converted before calling the underlying Mesa function),
650        # use the appropriate code.
651        if "get" not in props and len(conversionCodeOutgoing) > 0:
652            print "\n".join(conversionCodeOutgoing) + "\n"
653
654        # Call the Mesa function.  Note that there are very few functions
655        # that return a value (i.e. returnType is not "void"), and that
656        # none of them require incoming translation; so we're safe
657        # to generate code that directly returns in those cases,
658        # even though it's not completely independent.
659
660        if returnType == "void":
661            print "    %s(%s);" % (passthroughFuncName, passthroughCallString)
662        else:
663            print "    return %s(%s);" % (passthroughFuncName, passthroughCallString)
664
665        # If the function is one that returns values (i.e. "get" in props),
666        # it might return values of a different type than we need, that
667        # require conversion before passing back to the application.
668        if "get" in props and len(conversionCodeIncoming) > 0:
669            print "\n".join(conversionCodeIncoming)
670
671        # All done.
672        print "}"
673        print
674    # end for each category provided for a function
675
676# end for each function
677
678print """
679#include "glapi/glapi.h"
680
681#if FEATURE_remap_table
682
683/* cannot include main/dispatch.h here */
684#define _GLAPI_USE_REMAP_TABLE
685#include "%sapi/main/glapidispatch.h"
686
687#define need_MESA_remap_table
688#include "%sapi/main/remap_helper.h"
689
690static void
691init_remap_table(void)
692{
693   _glthread_DECLARE_STATIC_MUTEX(mutex);
694   static GLboolean initialized = GL_FALSE;
695   const struct gl_function_pool_remap *remap = MESA_remap_table_functions;
696   int i;
697
698   _glthread_LOCK_MUTEX(mutex);
699   if (initialized) {
700      _glthread_UNLOCK_MUTEX(mutex);
701      return;
702   }
703
704   for (i = 0; i < driDispatchRemapTable_size; i++) {
705      GLint offset;
706      const char *spec;
707
708      /* sanity check */
709      ASSERT(i == remap[i].remap_index);
710      spec = _mesa_function_pool + remap[i].pool_index;
711
712      offset = _mesa_map_function_spec(spec);
713      remap_table[i] = offset;
714   }
715   initialized = GL_TRUE;
716   _glthread_UNLOCK_MUTEX(mutex);
717}
718
719#else /* FEATURE_remap_table */
720
721/* cannot include main/dispatch.h here */
722#include "%sapi/main/glapidispatch.h"
723
724static INLINE void
725init_remap_table(void)
726{
727}
728
729#endif /* FEATURE_remap_table */
730
731struct _glapi_table *
732_mesa_create_exec_table_%s(void)
733{
734   struct _glapi_table *exec;
735
736   exec = _mesa_alloc_dispatch_table(_gloffset_COUNT);
737   if (exec == NULL)
738      return NULL;
739
740   init_remap_table();
741""" % (shortname, shortname, shortname, shortname)
742
743for func in keys:
744    prefix = "_es_" if func not in allSpecials else "_check_"
745    for spec in apiutil.Categories(func):
746        ext = spec.split(":")
747        # version does not match
748        if ext.pop(0) != version:
749            continue
750        entry = func
751        if ext:
752            suffix = ext[0].split("_")[0]
753            entry += suffix
754        print "    SET_%s(exec, %s%s);" % (entry, prefix, entry)
755print ""
756print "   return exec;"
757print "}"
758
759print """
760#endif /* FEATURE_%s */""" % (shortname.upper())
761