es_generator.py revision 34472a0d8713c4eb300c9d1de0844c8b78bcf1ab
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
204if version == "GLES1.1":
205    print '#include "main/es1_conversion.h"'
206    print
207
208# Everyone needs these types.
209print """
210/* These types are needed for the Mesa veneer, but are not defined in
211 * the standard GLES headers.
212 */
213typedef double GLdouble;
214typedef double GLclampd;
215
216/* Mesa error handling requires these */
217extern void *_mesa_get_current_context(void);
218extern void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... );
219"""
220
221# Finally we get to the all-important functions
222print """/*************************************************************
223 * Generated functions begin here
224 */
225"""
226for funcName in keys:
227    if verbose > 0: sys.stderr.write("%s: processing function %s\n" % (program, funcName))
228
229    # start figuring out what this function will look like.
230    returnType = apiutil.ReturnType(funcName)
231    props = apiutil.Properties(funcName)
232    params = apiutil.Parameters(funcName)
233    declarationString = apiutil.MakeDeclarationString(params)
234
235    # In case of error, a function may have to return.  Make
236    # sure we have valid return values in this case.
237    if returnType == "void":
238        errorReturn = "return"
239    elif returnType == "GLboolean":
240        errorReturn = "return GL_FALSE"
241    else:
242        errorReturn = "return (%s) 0" % returnType
243
244    # These are the output of this large calculation block.
245    # passthroughDeclarationString: a typed set of parameters that
246    # will be used to create the "extern" reference for the
247    # underlying Mesa or support function.  Note that as generated
248    # these have an extra ", " at the beginning, which will be
249    # removed before use.
250    #
251    # passthroughDeclarationString: an untyped list of parameters
252    # that will be used to call the underlying Mesa or support
253    # function (including references to converted parameters).
254    # This will also be generated with an extra ", " at the
255    # beginning, which will be removed before use.
256    #
257    # variables: C code to create any local variables determined to
258    # be necessary.
259    # conversionCodeOutgoing: C code to convert application parameters
260    # to a necessary type before calling the underlying support code.
261    # May be empty if no conversion is required.
262    # conversionCodeIncoming: C code to do the converse: convert
263    # values returned by underlying Mesa code to the types needed
264    # by the application.
265    # Note that *either* the conversionCodeIncoming will be used (for
266    # generated query functions), *or* the conversionCodeOutgoing will
267    # be used (for generated non-query functions), never both.
268    passthroughFuncName = ""
269    passthroughDeclarationString = ""
270    passthroughCallString = ""
271    prefixOverride = None
272    variables = []
273    conversionCodeOutgoing = []
274    conversionCodeIncoming = []
275    switchCode = []
276
277    # Calculate the name of the underlying support function to call.
278    # By default, the passthrough function is named _mesa_<funcName>.
279    # We're allowed to override the prefix and/or the function name
280    # for each function record, though.  The "ConversionFunction"
281    # utility is poorly named, BTW...
282    if funcName in allSpecials:
283        # perform checks and pass through
284        funcPrefix = "_check_"
285        aliasprefix = "_es_"
286    else:
287        funcPrefix = "_es_"
288        aliasprefix = apiutil.AliasPrefix(funcName)
289    alias = apiutil.ConversionFunction(funcName)
290    prefixOverride = apiutil.FunctionPrefix(funcName)
291    if prefixOverride != "_mesa_":
292        aliasprefix = apiutil.FunctionPrefix(funcName)
293    if not alias:
294        # There may still be a Mesa alias for the function
295        if apiutil.Alias(funcName):
296            passthroughFuncName = "%s%s" % (aliasprefix, apiutil.Alias(funcName))
297        else:
298            passthroughFuncName = "%s%s" % (aliasprefix, funcName)
299    else: # a specific alias is provided
300        passthroughFuncName = "%s%s" % (aliasprefix, alias)
301
302    # Look at every parameter: each one may have only specific
303    # allowed values, or dependent parameters to check, or
304    # variant-sized vector arrays to calculate
305    for (paramName, paramType, paramMaxVecSize, paramConvertToType, paramValidValues, paramValueConversion) in params:
306        # We'll need this below if we're doing conversions
307        (paramBaseType, paramTypeModifiers) = GetBaseType(paramType)
308
309        # Conversion management.
310        # We'll handle three cases, easiest to hardest: a parameter
311        # that doesn't require conversion, a scalar parameter that
312        # requires conversion, and a vector parameter that requires
313        # conversion.
314        if paramConvertToType == None:
315            # Unconverted parameters are easy, whether they're vector
316            # or scalar - just add them to the call list.  No conversions
317            # or anything to worry about.
318            passthroughDeclarationString += ", %s %s" % (paramType, paramName)
319            passthroughCallString += ", %s" % paramName
320
321        elif paramMaxVecSize == 0: # a scalar parameter that needs conversion
322            # A scalar to hold a converted parameter
323            variables.append("    %s converted_%s;" % (paramConvertToType, paramName))
324
325            # Outgoing conversion depends on whether we have to conditionally
326            # perform value conversion.
327            if paramValueConversion == "none":
328                conversionCodeOutgoing.append("    converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
329            elif paramValueConversion == "some":
330                # We'll need a conditional variable to keep track of
331                # whether we're converting values or not.
332                if ("    int convert_%s_value = 1;" % paramName) not in variables:
333                    variables.append("    int convert_%s_value = 1;" % paramName)
334
335                # Write code based on that conditional.
336                conversionCodeOutgoing.append("    if (convert_%s_value) {" % paramName)
337                conversionCodeOutgoing.append("        converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
338                conversionCodeOutgoing.append("    } else {")
339                conversionCodeOutgoing.append("        converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
340                conversionCodeOutgoing.append("    }")
341            else: # paramValueConversion == "all"
342                conversionCodeOutgoing.append("    converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
343
344            # Note that there can be no incoming conversion for a
345            # scalar parameter; changing the scalar will only change
346            # the local value, and won't ultimately change anything
347            # that passes back to the application.
348
349            # Call strings.  The unusual " ".join() call will join the
350            # array of parameter modifiers with spaces as separators.
351            passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName)
352            passthroughCallString += ", converted_%s" % paramName
353
354        else: # a vector parameter that needs conversion
355            # We'll need an index variable for conversions
356            if "    register unsigned int i;" not in variables:
357                variables.append("    register unsigned int i;")
358
359            # This variable will hold the (possibly variant) size of
360            # this array needing conversion.  By default, we'll set
361            # it to the maximal size (which is correct for functions
362            # with a constant-sized vector parameter); for true
363            # variant arrays, we'll modify it with other code.
364            variables.append("    unsigned int n_%s = %d;" % (paramName, paramMaxVecSize))
365
366            # This array will hold the actual converted values.
367            variables.append("    %s converted_%s[%d];" % (paramConvertToType, paramName, paramMaxVecSize))
368
369            # Again, we choose the conversion code based on whether we
370            # have to always convert values, never convert values, or
371            # conditionally convert values.
372            if paramValueConversion == "none":
373                conversionCodeOutgoing.append("    for (i = 0; i < n_%s; i++) {" % paramName)
374                conversionCodeOutgoing.append("        converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
375                conversionCodeOutgoing.append("    }")
376            elif paramValueConversion == "some":
377                # We'll need a conditional variable to keep track of
378                # whether we're converting values or not.
379                if ("    int convert_%s_value = 1;" % paramName) not in variables:
380                    variables.append("    int convert_%s_value = 1;" % paramName)
381                # Write code based on that conditional.
382                conversionCodeOutgoing.append("    if (convert_%s_value) {" % paramName)
383                conversionCodeOutgoing.append("        for (i = 0; i < n_%s; i++) {" % paramName)
384                conversionCodeOutgoing.append("            converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
385                conversionCodeOutgoing.append("        }")
386                conversionCodeOutgoing.append("    } else {")
387                conversionCodeOutgoing.append("        for (i = 0; i < n_%s; i++) {" % paramName)
388                conversionCodeOutgoing.append("            converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
389                conversionCodeOutgoing.append("        }")
390                conversionCodeOutgoing.append("    }")
391            else: # paramValueConversion == "all"
392                conversionCodeOutgoing.append("    for (i = 0; i < n_%s; i++) {" % paramName)
393                conversionCodeOutgoing.append("        converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
394
395                conversionCodeOutgoing.append("    }")
396
397            # If instead we need an incoming conversion (i.e. results
398            # from Mesa have to be converted before handing back
399            # to the application), this is it.  Fortunately, we don't
400            # have to worry about conditional value conversion - the
401            # functions that do (e.g. glGetFixedv()) are handled
402            # specially, outside this code generation.
403            #
404            # Whether we use incoming conversion or outgoing conversion
405            # is determined later - we only ever use one or the other.
406
407            if paramValueConversion == "none":
408                conversionCodeIncoming.append("    for (i = 0; i < n_%s; i++) {" % paramName)
409                conversionCodeIncoming.append("        %s[i] = (%s) converted_%s[i];" % (paramName, paramConvertToType, paramName))
410                conversionCodeIncoming.append("    }")
411            elif paramValueConversion == "some":
412                # We'll need a conditional variable to keep track of
413                # whether we're converting values or not.
414                if ("    int convert_%s_value = 1;" % paramName) not in variables:
415                    variables.append("    int convert_%s_value = 1;" % paramName)
416
417                # Write code based on that conditional.
418                conversionCodeIncoming.append("    if (convert_%s_value) {" % paramName)
419                conversionCodeIncoming.append("        for (i = 0; i < n_%s; i++) {" % paramName)
420                conversionCodeIncoming.append("            %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
421                conversionCodeIncoming.append("        }")
422                conversionCodeIncoming.append("    } else {")
423                conversionCodeIncoming.append("        for (i = 0; i < n_%s; i++) {" % paramName)
424                conversionCodeIncoming.append("            %s[i] = (%s) converted_%s[i];" % (paramName, paramBaseType, paramName))
425                conversionCodeIncoming.append("        }")
426                conversionCodeIncoming.append("    }")
427            else: # paramValueConversion == "all"
428                conversionCodeIncoming.append("    for (i = 0; i < n_%s; i++) {" % paramName)
429                conversionCodeIncoming.append("        %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
430                conversionCodeIncoming.append("    }")
431
432            # Call strings.  The unusual " ".join() call will join the
433            # array of parameter modifiers with spaces as separators.
434            passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName)
435            passthroughCallString += ", converted_%s" % paramName
436
437        # endif conversion management
438
439        # Parameter checking.  If the parameter has a specific list of
440        # valid values, we have to make sure that the passed-in values
441        # match these, or we make an error.
442        if len(paramValidValues) > 0:
443            # We're about to make a big switch statement with an
444            # error at the end.  By default, the error is GL_INVALID_ENUM,
445            # unless we find a "case" statement in the middle with a
446            # non-GLenum value.
447            errorDefaultCase = "GL_INVALID_ENUM"
448
449            # This parameter has specific valid values.  Make a big
450            # switch statement to handle it.  Note that the original
451            # parameters are always what is checked, not the
452            # converted parameters.
453            switchCode.append("    switch(%s) {" % paramName)
454
455            for valueIndex in range(len(paramValidValues)):
456                (paramValue, dependentVecSize, dependentParamName, dependentValidValues, errorCode, valueConvert) = paramValidValues[valueIndex]
457
458                # We're going to need information on the dependent param
459                # as well.
460                if dependentParamName:
461                    depParamIndex = apiutil.FindParamIndex(params, dependentParamName)
462                    if depParamIndex == None:
463                        sys.stderr.write("%s: can't find dependent param '%s' for function '%s'\n" % (program, dependentParamName, funcName))
464
465                    (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = params[depParamIndex]
466                else:
467                    (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = (None, None, None, None, [], None)
468
469                # This is a sneaky trick.  It's valid syntax for a parameter
470                # that is *not* going to be converted to be declared
471                # with a dependent vector size; but in this case, the
472                # dependent vector size is unused and unnecessary.
473                # So check for this and ignore the dependent vector size
474                # if the parameter is not going to be converted.
475                if depParamConvertToType:
476                    usedDependentVecSize = dependentVecSize
477                else:
478                    usedDependentVecSize = None
479
480                # We'll peek ahead at the next parameter, to see whether
481                # we can combine cases
482                if valueIndex + 1 < len(paramValidValues) :
483                    (nextParamValue, nextDependentVecSize, nextDependentParamName, nextDependentValidValues, nextErrorCode, nextValueConvert) = paramValidValues[valueIndex + 1]
484                    if depParamConvertToType:
485                        usedNextDependentVecSize = nextDependentVecSize
486                    else:
487                        usedNextDependentVecSize = None
488
489                # Create a case for this value.  As a mnemonic,
490                # if we have a dependent vector size that we're ignoring,
491                # add it as a comment.
492                if usedDependentVecSize == None and dependentVecSize != None:
493                    switchCode.append("        case %s: /* size %s */" % (paramValue, dependentVecSize))
494                else:
495                    switchCode.append("        case %s:" % paramValue)
496
497                # If this is not a GLenum case, then switch our error
498                # if no value is matched to be GL_INVALID_VALUE instead
499                # of GL_INVALID_ENUM.  (Yes, this does get confused
500                # if there are both values and GLenums in the same
501                # switch statement, which shouldn't happen.)
502                if paramValue[0:3] != "GL_":
503                    errorDefaultCase = "GL_INVALID_VALUE"
504
505                # If all the remaining parameters are identical to the
506                # next set, then we're done - we'll just create the
507                # official code on the next pass through, and the two
508                # cases will share the code.
509                if valueIndex + 1 < len(paramValidValues) and usedDependentVecSize == usedNextDependentVecSize and dependentParamName == nextDependentParamName and dependentValidValues == nextDependentValidValues and errorCode == nextErrorCode and valueConvert == nextValueConvert:
510                    continue
511
512                # Otherwise, we'll have to generate code for this case.
513                # Start off with a check: if there is a dependent parameter,
514                # and a list of valid values for that parameter, we need
515                # to generate an error if something other than one
516                # of those values is passed.
517                if len(dependentValidValues) > 0:
518                    conditional=""
519
520                    # If the parameter being checked is actually an array,
521                    # check only its first element.
522                    if depParamMaxVecSize == 0:
523                        valueToCheck = dependentParamName
524                    else:
525                        valueToCheck = "%s[0]" % dependentParamName
526
527                    for v in dependentValidValues:
528                        conditional += " && %s != %s" % (valueToCheck, v)
529                    switchCode.append("            if (%s) {" % conditional[4:])
530                    if errorCode == None:
531                        errorCode = "GL_INVALID_ENUM"
532                    switchCode.append('                _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=0x%s)", %s);' % (errorCode, funcName, paramName, "%x", paramName))
533                    switchCode.append("                %s;" % errorReturn)
534                    switchCode.append("            }")
535                # endif there are dependent valid values
536
537                # The dependent parameter may require conditional
538                # value conversion.  If it does, and we don't want
539                # to convert values, we'll have to generate code for that
540                if depParamValueConversion == "some" and valueConvert == "noconvert":
541                    switchCode.append("            convert_%s_value = 0;" % dependentParamName)
542
543                # If there's a dependent vector size for this parameter
544                # that we're actually going to use (i.e. we need conversion),
545                # mark it.
546                if usedDependentVecSize:
547                    switchCode.append("            n_%s = %s;" % (dependentParamName, dependentVecSize))
548
549                # In all cases, break out of the switch if any valid
550                # value is found.
551                switchCode.append("            break;")
552
553
554            # Need a default case to catch all the other, invalid
555            # parameter values.  These will all generate errors.
556            switchCode.append("        default:")
557            if errorCode == None:
558                errorCode = "GL_INVALID_ENUM"
559            formatString = GetFormatString(paramType)
560            if formatString == None:
561                switchCode.append('            _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s)");' % (errorCode, funcName, paramName))
562            else:
563                switchCode.append('            _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=%s)", %s);' % (errorCode, funcName, paramName, formatString, paramName))
564            switchCode.append("            %s;" % errorReturn)
565
566            # End of our switch code.
567            switchCode.append("    }")
568
569        # endfor every recognized parameter value
570
571    # endfor every param
572
573    if conversionCodeOutgoing != [] or conversionCodeIncoming != []:
574        continue
575
576    # Here, the passthroughDeclarationString and passthroughCallString
577    # are complete; remove the extra ", " at the front of each.
578    passthroughDeclarationString = passthroughDeclarationString[2:]
579    passthroughCallString = passthroughCallString[2:]
580    if not passthroughDeclarationString:
581        passthroughDeclarationString = "void"
582
583    # The Mesa functions are scattered across all the Mesa
584    # header files.  The easiest way to manage declarations
585    # is to create them ourselves.
586    if funcName in allSpecials:
587        print "/* this function is special and is defined elsewhere */"
588    print "extern %s GL_APIENTRY %s(%s);" % (returnType, passthroughFuncName, passthroughDeclarationString)
589
590    # A function may be a core function (i.e. it exists in
591    # the core specification), a core addition (extension
592    # functions added officially to the core), a required
593    # extension (usually an extension for an earlier version
594    # that has been officially adopted), or an optional extension.
595    #
596    # Core functions have a simple category (e.g. "GLES1.1");
597    # we generate only a simple callback for them.
598    #
599    # Core additions have two category listings, one simple
600    # and one compound (e.g.  ["GLES1.1", "GLES1.1:OES_fixed_point"]).
601    # We generate the core function, and also an extension function.
602    #
603    # Required extensions and implemented optional extensions
604    # have a single compound category "GLES1.1:OES_point_size_array".
605    # For these we generate just the extension function.
606    for categorySpec in apiutil.Categories(funcName):
607        compoundCategory = categorySpec.split(":")
608
609        # This category isn't for us, if the base category doesn't match
610        # our version
611        if compoundCategory[0] != version:
612            continue
613
614        # Otherwise, determine if we're writing code for a core
615        # function (no suffix) or an extension function.
616        if len(compoundCategory) == 1:
617            # This is a core function
618            extensionName = None
619            extensionSuffix = ""
620        else:
621            # This is an extension function.  We'll need to append
622            # the extension suffix.
623            extensionName = compoundCategory[1]
624            extensionSuffix = extensionName.split("_")[0]
625        fullFuncName = funcPrefix + funcName + extensionSuffix
626
627        # Now the generated function.  The text used to mark an API-level
628        # function, oddly, is version-specific.
629        if extensionName:
630            print "/* Extension %s */" % extensionName
631
632        if (not variables and
633            not switchCode and
634            not conversionCodeOutgoing and
635            not conversionCodeIncoming):
636            # pass through directly
637            print "#define %s %s" % (fullFuncName, passthroughFuncName)
638            print
639            continue
640
641        print "static %s GL_APIENTRY %s(%s)" % (returnType, fullFuncName, declarationString)
642        print "{"
643
644        # Start printing our code pieces.  Start with any local
645        # variables we need.  This unusual syntax joins the
646        # lines in the variables[] array with the "\n" separator.
647        if len(variables) > 0:
648            print "\n".join(variables) + "\n"
649
650        # If there's any sort of parameter checking or variable
651        # array sizing, the switch code will contain it.
652        if len(switchCode) > 0:
653            print "\n".join(switchCode) + "\n"
654
655        # In the case of an outgoing conversion (i.e. parameters must
656        # be converted before calling the underlying Mesa function),
657        # use the appropriate code.
658        if "get" not in props and len(conversionCodeOutgoing) > 0:
659            print "\n".join(conversionCodeOutgoing) + "\n"
660
661        # Call the Mesa function.  Note that there are very few functions
662        # that return a value (i.e. returnType is not "void"), and that
663        # none of them require incoming translation; so we're safe
664        # to generate code that directly returns in those cases,
665        # even though it's not completely independent.
666
667        if returnType == "void":
668            print "    %s(%s);" % (passthroughFuncName, passthroughCallString)
669        else:
670            print "    return %s(%s);" % (passthroughFuncName, passthroughCallString)
671
672        # If the function is one that returns values (i.e. "get" in props),
673        # it might return values of a different type than we need, that
674        # require conversion before passing back to the application.
675        if "get" in props and len(conversionCodeIncoming) > 0:
676            print "\n".join(conversionCodeIncoming)
677
678        # All done.
679        print "}"
680        print
681    # end for each category provided for a function
682
683# end for each function
684
685print """
686#include "glapi/glapi.h"
687
688#if FEATURE_remap_table
689
690/* define esLocalRemapTable */
691#include "main/api_exec_%s_dispatch.h"
692
693#define need_MESA_remap_table
694#include "main/api_exec_%s_remap_helper.h"
695
696static void
697init_remap_table(void)
698{
699   _glthread_DECLARE_STATIC_MUTEX(mutex);
700   static GLboolean initialized = GL_FALSE;
701   const struct gl_function_pool_remap *remap = MESA_remap_table_functions;
702   int i;
703
704   _glthread_LOCK_MUTEX(mutex);
705   if (initialized) {
706      _glthread_UNLOCK_MUTEX(mutex);
707      return;
708   }
709
710   for (i = 0; i < esLocalRemapTable_size; i++) {
711      GLint offset;
712      const char *spec;
713
714      /* sanity check */
715      ASSERT(i == remap[i].remap_index);
716      spec = _mesa_function_pool + remap[i].pool_index;
717
718      offset = _mesa_map_function_spec(spec);
719      esLocalRemapTable[i] = offset;
720   }
721   initialized = GL_TRUE;
722   _glthread_UNLOCK_MUTEX(mutex);
723}
724
725#else /* FEATURE_remap_table */
726
727#include "%sapi/main/dispatch.h"
728
729static INLINE void
730init_remap_table(void)
731{
732}
733
734#endif /* FEATURE_remap_table */
735
736struct _glapi_table *
737_mesa_create_exec_table_%s(void)
738{
739   struct _glapi_table *exec;
740
741   exec = _mesa_alloc_dispatch_table(_gloffset_COUNT);
742   if (exec == NULL)
743      return NULL;
744
745   init_remap_table();
746""" % (shortname, shortname, shortname, shortname)
747
748for func in keys:
749    prefix = "_es_" if func not in allSpecials else "_check_"
750    for spec in apiutil.Categories(func):
751        ext = spec.split(":")
752        # version does not match
753        if ext.pop(0) != version:
754            continue
755        entry = func
756        if ext:
757            suffix = ext[0].split("_")[0]
758            entry += suffix
759        print "    SET_%s(exec, %s%s);" % (entry, prefix, entry)
760print ""
761print "   return exec;"
762print "}"
763
764print """
765#endif /* FEATURE_%s */""" % (shortname.upper())
766