diff options
Diffstat (limited to 'mesalib/src/mesa/main/es_generator.py')
-rw-r--r-- | mesalib/src/mesa/main/es_generator.py | 1503 |
1 files changed, 760 insertions, 743 deletions
diff --git a/mesalib/src/mesa/main/es_generator.py b/mesalib/src/mesa/main/es_generator.py index ecb34bb5c..36bd14d6c 100644 --- a/mesalib/src/mesa/main/es_generator.py +++ b/mesalib/src/mesa/main/es_generator.py @@ -1,743 +1,760 @@ -#************************************************************************* -# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. -# All Rights Reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# TUNGSTEN GRAPHICS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF -# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -#************************************************************************* - - -import sys, os -import APIspecutil as apiutil - -# These dictionary entries are used for automatic conversion. -# The string will be used as a format string with the conversion -# variable. -Converters = { - 'GLfloat': { - 'GLdouble': "(GLdouble) (%s)", - 'GLfixed' : "(GLint) (%s * 65536)", - }, - 'GLfixed': { - 'GLfloat': "(GLfloat) (%s / 65536.0f)", - 'GLdouble': "(GLdouble) (%s / 65536.0)", - }, - 'GLdouble': { - 'GLfloat': "(GLfloat) (%s)", - 'GLfixed': "(GLfixed) (%s * 65536)", - }, - 'GLclampf': { - 'GLclampd': "(GLclampd) (%s)", - 'GLclampx': "(GLclampx) (%s * 65536)", - }, - 'GLclampx': { - 'GLclampf': "(GLclampf) (%s / 65536.0f)", - 'GLclampd': "(GLclampd) (%s / 65536.0)", - }, - 'GLubyte': { - 'GLfloat': "(GLfloat) (%s / 255.0f)", - }, -} - -def GetBaseType(type): - typeTokens = type.split(' ') - baseType = None - typeModifiers = [] - for t in typeTokens: - if t in ['const', '*']: - typeModifiers.append(t) - else: - baseType = t - return (baseType, typeModifiers) - -def ConvertValue(value, fromType, toType): - """Returns a string that represents the given parameter string, - type-converted if necessary.""" - - if not Converters.has_key(fromType): - print >> sys.stderr, "No base converter for type '%s' found. Ignoring." % fromType - return value - - if not Converters[fromType].has_key(toType): - print >> sys.stderr, "No converter found for type '%s' to type '%s'. Ignoring." % (fromType, toType) - return value - - # This part is simple. Return the proper conversion. - conversionString = Converters[fromType][toType] - return conversionString % value - -FormatStrings = { - 'GLenum' : '0x%x', - 'GLfloat' : '%f', - 'GLint' : '%d', - 'GLbitfield' : '0x%x', -} -def GetFormatString(type): - if FormatStrings.has_key(type): - return FormatStrings[type] - else: - return None - - -###################################################################### -# Version-specific values to be used in the main script -# header: which header file to include -# api: what text specifies an API-level function -VersionSpecificValues = { - 'GLES1.1' : { - 'description' : 'GLES1.1 functions', - 'header' : 'GLES/gl.h', - 'extheader' : 'GLES/glext.h', - 'shortname' : 'es1' - }, - 'GLES2.0': { - 'description' : 'GLES2.0 functions', - 'header' : 'GLES2/gl2.h', - 'extheader' : 'GLES2/gl2ext.h', - 'shortname' : 'es2' - } -} - - -###################################################################### -# Main code for the script begins here. - -# Get the name of the program (without the directory part) for use in -# error messages. -program = os.path.basename(sys.argv[0]) - -# Set default values -verbose = 0 -functionList = "APIspec.xml" -version = "GLES1.1" - -# Allow for command-line switches -import getopt, time -options = "hvV:S:" -try: - optlist, args = getopt.getopt(sys.argv[1:], options) -except getopt.GetoptError, message: - sys.stderr.write("%s: %s. Use -h for help.\n" % (program, message)) - sys.exit(1) - -for option, optarg in optlist: - if option == "-h": - sys.stderr.write("Usage: %s [-%s]\n" % (program, options)) - sys.stderr.write("Parse an API specification file and generate wrapper functions for a given GLES version\n") - sys.stderr.write("-h gives help\n") - sys.stderr.write("-v is verbose\n") - sys.stderr.write("-V specifies GLES version to generate [%s]:\n" % version) - for key in VersionSpecificValues.keys(): - sys.stderr.write(" %s - %s\n" % (key, VersionSpecificValues[key]['description'])) - sys.stderr.write("-S specifies API specification file to use [%s]\n" % functionList) - sys.exit(1) - elif option == "-v": - verbose += 1 - elif option == "-V": - version = optarg - elif option == "-S": - functionList = optarg - -# Beyond switches, we support no further command-line arguments -if len(args) > 0: - sys.stderr.write("%s: only switch arguments are supported - use -h for help\n" % program) - sys.exit(1) - -# If we don't have a valid version, abort. -if not VersionSpecificValues.has_key(version): - sys.stderr.write("%s: version '%s' is not valid - use -h for help\n" % (program, version)) - sys.exit(1) - -# Grab the version-specific items we need to use -versionHeader = VersionSpecificValues[version]['header'] -versionExtHeader = VersionSpecificValues[version]['extheader'] -shortname = VersionSpecificValues[version]['shortname'] - -# If we get to here, we're good to go. The "version" parameter -# directs GetDispatchedFunctions to only allow functions from -# that "category" (version in our parlance). This allows -# functions with different declarations in different categories -# to exist (glTexImage2D, for example, is different between -# GLES1 and GLES2). -keys = apiutil.GetAllFunctions(functionList, version) - -allSpecials = apiutil.AllSpecials() - -print """/* DO NOT EDIT ************************************************* - * THIS FILE AUTOMATICALLY GENERATED BY THE %s SCRIPT - * API specification file: %s - * GLES version: %s - * date: %s - */ -""" % (program, functionList, version, time.strftime("%Y-%m-%d %H:%M:%S")) - -# The headers we choose are version-specific. -print """ -#include "%s" -#include "%s" -#include "main/mfeatures.h" - -#if FEATURE_%s -""" % (versionHeader, versionExtHeader, shortname.upper()) - -# Everyone needs these types. -print """ -/* These types are needed for the Mesa veneer, but are not defined in - * the standard GLES headers. - */ -typedef double GLdouble; -typedef double GLclampd; - -/* Mesa error handling requires these */ -extern void *_mesa_get_current_context(void); -extern void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... ); - -#include "main/compiler.h" -#include "main/api_exec.h" -#include "main/remap.h" - -/* cannot include main/dispatch.h here */ -#ifdef IN_DRI_DRIVER -#define _GLAPI_USE_REMAP_TABLE -#endif -/* glapi uses GLAPIENTRY while GLES headers define GL_APIENTRY */ -#ifndef GLAPIENTRY -#define GLAPIENTRY GL_APIENTRY -#endif -#include "%sapi/glapi/glapitable.h" -#include "%sapi/glapi/glapioffsets.h" -#include "%sapi/glapi/glapidispatch.h" - -#if FEATURE_remap_table - -#if !FEATURE_GL -int driDispatchRemapTable[driDispatchRemapTable_size]; -#endif - -#define need_MESA_remap_table - -#include "%sapi/main/remap_helper.h" - -void -_mesa_init_remap_table_%s(void) -{ - _mesa_do_init_remap_table(_mesa_function_pool, - driDispatchRemapTable_size, - MESA_remap_table_functions); -} - -void -_mesa_map_static_functions_%s(void) -{ -} - -#endif - -typedef void (*_glapi_proc)(void); /* generic function pointer */ -""" % (shortname, shortname, shortname, shortname, shortname, shortname); - -# Finally we get to the all-important functions -print """/************************************************************* - * Generated functions begin here - */ -""" -for funcName in keys: - if verbose > 0: sys.stderr.write("%s: processing function %s\n" % (program, funcName)) - - # start figuring out what this function will look like. - returnType = apiutil.ReturnType(funcName) - props = apiutil.Properties(funcName) - params = apiutil.Parameters(funcName) - declarationString = apiutil.MakeDeclarationString(params) - - # In case of error, a function may have to return. Make - # sure we have valid return values in this case. - if returnType == "void": - errorReturn = "return" - elif returnType == "GLboolean": - errorReturn = "return GL_FALSE" - else: - errorReturn = "return (%s) 0" % returnType - - # These are the output of this large calculation block. - # passthroughDeclarationString: a typed set of parameters that - # will be used to create the "extern" reference for the - # underlying Mesa or support function. Note that as generated - # these have an extra ", " at the beginning, which will be - # removed before use. - # - # passthroughDeclarationString: an untyped list of parameters - # that will be used to call the underlying Mesa or support - # function (including references to converted parameters). - # This will also be generated with an extra ", " at the - # beginning, which will be removed before use. - # - # variables: C code to create any local variables determined to - # be necessary. - # conversionCodeOutgoing: C code to convert application parameters - # to a necessary type before calling the underlying support code. - # May be empty if no conversion is required. - # conversionCodeIncoming: C code to do the converse: convert - # values returned by underlying Mesa code to the types needed - # by the application. - # Note that *either* the conversionCodeIncoming will be used (for - # generated query functions), *or* the conversionCodeOutgoing will - # be used (for generated non-query functions), never both. - passthroughFuncName = "" - passthroughDeclarationString = "" - passthroughCallString = "" - prefixOverride = None - variables = [] - conversionCodeOutgoing = [] - conversionCodeIncoming = [] - switchCode = [] - - # Calculate the name of the underlying support function to call. - # By default, the passthrough function is named _mesa_<funcName>. - # We're allowed to override the prefix and/or the function name - # for each function record, though. The "ConversionFunction" - # utility is poorly named, BTW... - if funcName in allSpecials: - # perform checks and pass through - funcPrefix = "_check_" - aliasprefix = "_es_" - else: - funcPrefix = "_es_" - aliasprefix = apiutil.AliasPrefix(funcName) - alias = apiutil.ConversionFunction(funcName) - prefixOverride = apiutil.FunctionPrefix(funcName) - if prefixOverride != "_mesa_": - aliasprefix = apiutil.FunctionPrefix(funcName) - if not alias: - # There may still be a Mesa alias for the function - if apiutil.Alias(funcName): - passthroughFuncName = "%s%s" % (aliasprefix, apiutil.Alias(funcName)) - else: - passthroughFuncName = "%s%s" % (aliasprefix, funcName) - else: # a specific alias is provided - passthroughFuncName = "%s%s" % (aliasprefix, alias) - - # Look at every parameter: each one may have only specific - # allowed values, or dependent parameters to check, or - # variant-sized vector arrays to calculate - for (paramName, paramType, paramMaxVecSize, paramConvertToType, paramValidValues, paramValueConversion) in params: - # We'll need this below if we're doing conversions - (paramBaseType, paramTypeModifiers) = GetBaseType(paramType) - - # Conversion management. - # We'll handle three cases, easiest to hardest: a parameter - # that doesn't require conversion, a scalar parameter that - # requires conversion, and a vector parameter that requires - # conversion. - if paramConvertToType == None: - # Unconverted parameters are easy, whether they're vector - # or scalar - just add them to the call list. No conversions - # or anything to worry about. - passthroughDeclarationString += ", %s %s" % (paramType, paramName) - passthroughCallString += ", %s" % paramName - - elif paramMaxVecSize == 0: # a scalar parameter that needs conversion - # A scalar to hold a converted parameter - variables.append(" %s converted_%s;" % (paramConvertToType, paramName)) - - # Outgoing conversion depends on whether we have to conditionally - # perform value conversion. - if paramValueConversion == "none": - conversionCodeOutgoing.append(" converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName)) - elif paramValueConversion == "some": - # We'll need a conditional variable to keep track of - # whether we're converting values or not. - if (" int convert_%s_value = 1;" % paramName) not in variables: - variables.append(" int convert_%s_value = 1;" % paramName) - - # Write code based on that conditional. - conversionCodeOutgoing.append(" if (convert_%s_value) {" % paramName) - conversionCodeOutgoing.append(" converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType))) - conversionCodeOutgoing.append(" } else {") - conversionCodeOutgoing.append(" converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName)) - conversionCodeOutgoing.append(" }") - else: # paramValueConversion == "all" - conversionCodeOutgoing.append(" converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType))) - - # Note that there can be no incoming conversion for a - # scalar parameter; changing the scalar will only change - # the local value, and won't ultimately change anything - # that passes back to the application. - - # Call strings. The unusual " ".join() call will join the - # array of parameter modifiers with spaces as separators. - passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName) - passthroughCallString += ", converted_%s" % paramName - - else: # a vector parameter that needs conversion - # We'll need an index variable for conversions - if " register unsigned int i;" not in variables: - variables.append(" register unsigned int i;") - - # This variable will hold the (possibly variant) size of - # this array needing conversion. By default, we'll set - # it to the maximal size (which is correct for functions - # with a constant-sized vector parameter); for true - # variant arrays, we'll modify it with other code. - variables.append(" unsigned int n_%s = %d;" % (paramName, paramMaxVecSize)) - - # This array will hold the actual converted values. - variables.append(" %s converted_%s[%d];" % (paramConvertToType, paramName, paramMaxVecSize)) - - # Again, we choose the conversion code based on whether we - # have to always convert values, never convert values, or - # conditionally convert values. - if paramValueConversion == "none": - conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeOutgoing.append(" converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName)) - conversionCodeOutgoing.append(" }") - elif paramValueConversion == "some": - # We'll need a conditional variable to keep track of - # whether we're converting values or not. - if (" int convert_%s_value = 1;" % paramName) not in variables: - variables.append(" int convert_%s_value = 1;" % paramName) - # Write code based on that conditional. - conversionCodeOutgoing.append(" if (convert_%s_value) {" % paramName) - conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeOutgoing.append(" converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType))) - conversionCodeOutgoing.append(" }") - conversionCodeOutgoing.append(" } else {") - conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeOutgoing.append(" converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName)) - conversionCodeOutgoing.append(" }") - conversionCodeOutgoing.append(" }") - else: # paramValueConversion == "all" - conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeOutgoing.append(" converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType))) - - conversionCodeOutgoing.append(" }") - - # If instead we need an incoming conversion (i.e. results - # from Mesa have to be converted before handing back - # to the application), this is it. Fortunately, we don't - # have to worry about conditional value conversion - the - # functions that do (e.g. glGetFixedv()) are handled - # specially, outside this code generation. - # - # Whether we use incoming conversion or outgoing conversion - # is determined later - we only ever use one or the other. - - if paramValueConversion == "none": - conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeIncoming.append(" %s[i] = (%s) converted_%s[i];" % (paramName, paramConvertToType, paramName)) - conversionCodeIncoming.append(" }") - elif paramValueConversion == "some": - # We'll need a conditional variable to keep track of - # whether we're converting values or not. - if (" int convert_%s_value = 1;" % paramName) not in variables: - variables.append(" int convert_%s_value = 1;" % paramName) - - # Write code based on that conditional. - conversionCodeIncoming.append(" if (convert_%s_value) {" % paramName) - conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeIncoming.append(" %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType))) - conversionCodeIncoming.append(" }") - conversionCodeIncoming.append(" } else {") - conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeIncoming.append(" %s[i] = (%s) converted_%s[i];" % (paramName, paramBaseType, paramName)) - conversionCodeIncoming.append(" }") - conversionCodeIncoming.append(" }") - else: # paramValueConversion == "all" - conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName) - conversionCodeIncoming.append(" %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType))) - conversionCodeIncoming.append(" }") - - # Call strings. The unusual " ".join() call will join the - # array of parameter modifiers with spaces as separators. - passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName) - passthroughCallString += ", converted_%s" % paramName - - # endif conversion management - - # Parameter checking. If the parameter has a specific list of - # valid values, we have to make sure that the passed-in values - # match these, or we make an error. - if len(paramValidValues) > 0: - # We're about to make a big switch statement with an - # error at the end. By default, the error is GL_INVALID_ENUM, - # unless we find a "case" statement in the middle with a - # non-GLenum value. - errorDefaultCase = "GL_INVALID_ENUM" - - # This parameter has specific valid values. Make a big - # switch statement to handle it. Note that the original - # parameters are always what is checked, not the - # converted parameters. - switchCode.append(" switch(%s) {" % paramName) - - for valueIndex in range(len(paramValidValues)): - (paramValue, dependentVecSize, dependentParamName, dependentValidValues, errorCode, valueConvert) = paramValidValues[valueIndex] - - # We're going to need information on the dependent param - # as well. - if dependentParamName: - depParamIndex = apiutil.FindParamIndex(params, dependentParamName) - if depParamIndex == None: - sys.stderr.write("%s: can't find dependent param '%s' for function '%s'\n" % (program, dependentParamName, funcName)) - - (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = params[depParamIndex] - else: - (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = (None, None, None, None, [], None) - - # This is a sneaky trick. It's valid syntax for a parameter - # that is *not* going to be converted to be declared - # with a dependent vector size; but in this case, the - # dependent vector size is unused and unnecessary. - # So check for this and ignore the dependent vector size - # if the parameter is not going to be converted. - if depParamConvertToType: - usedDependentVecSize = dependentVecSize - else: - usedDependentVecSize = None - - # We'll peek ahead at the next parameter, to see whether - # we can combine cases - if valueIndex + 1 < len(paramValidValues) : - (nextParamValue, nextDependentVecSize, nextDependentParamName, nextDependentValidValues, nextErrorCode, nextValueConvert) = paramValidValues[valueIndex + 1] - if depParamConvertToType: - usedNextDependentVecSize = nextDependentVecSize - else: - usedNextDependentVecSize = None - - # Create a case for this value. As a mnemonic, - # if we have a dependent vector size that we're ignoring, - # add it as a comment. - if usedDependentVecSize == None and dependentVecSize != None: - switchCode.append(" case %s: /* size %s */" % (paramValue, dependentVecSize)) - else: - switchCode.append(" case %s:" % paramValue) - - # If this is not a GLenum case, then switch our error - # if no value is matched to be GL_INVALID_VALUE instead - # of GL_INVALID_ENUM. (Yes, this does get confused - # if there are both values and GLenums in the same - # switch statement, which shouldn't happen.) - if paramValue[0:3] != "GL_": - errorDefaultCase = "GL_INVALID_VALUE" - - # If all the remaining parameters are identical to the - # next set, then we're done - we'll just create the - # official code on the next pass through, and the two - # cases will share the code. - if valueIndex + 1 < len(paramValidValues) and usedDependentVecSize == usedNextDependentVecSize and dependentParamName == nextDependentParamName and dependentValidValues == nextDependentValidValues and errorCode == nextErrorCode and valueConvert == nextValueConvert: - continue - - # Otherwise, we'll have to generate code for this case. - # Start off with a check: if there is a dependent parameter, - # and a list of valid values for that parameter, we need - # to generate an error if something other than one - # of those values is passed. - if len(dependentValidValues) > 0: - conditional="" - - # If the parameter being checked is actually an array, - # check only its first element. - if depParamMaxVecSize == 0: - valueToCheck = dependentParamName - else: - valueToCheck = "%s[0]" % dependentParamName - - for v in dependentValidValues: - conditional += " && %s != %s" % (valueToCheck, v) - switchCode.append(" if (%s) {" % conditional[4:]) - if errorCode == None: - errorCode = "GL_INVALID_ENUM" - switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=0x%s)", %s);' % (errorCode, funcName, paramName, "%x", paramName)) - switchCode.append(" %s;" % errorReturn) - switchCode.append(" }") - # endif there are dependent valid values - - # The dependent parameter may require conditional - # value conversion. If it does, and we don't want - # to convert values, we'll have to generate code for that - if depParamValueConversion == "some" and valueConvert == "noconvert": - switchCode.append(" convert_%s_value = 0;" % dependentParamName) - - # If there's a dependent vector size for this parameter - # that we're actually going to use (i.e. we need conversion), - # mark it. - if usedDependentVecSize: - switchCode.append(" n_%s = %s;" % (dependentParamName, dependentVecSize)) - - # In all cases, break out of the switch if any valid - # value is found. - switchCode.append(" break;") - - - # Need a default case to catch all the other, invalid - # parameter values. These will all generate errors. - switchCode.append(" default:") - if errorCode == None: - errorCode = "GL_INVALID_ENUM" - formatString = GetFormatString(paramType) - if formatString == None: - switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s)");' % (errorCode, funcName, paramName)) - else: - switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=%s)", %s);' % (errorCode, funcName, paramName, formatString, paramName)) - switchCode.append(" %s;" % errorReturn) - - # End of our switch code. - switchCode.append(" }") - - # endfor every recognized parameter value - - # endfor every param - - # Here, the passthroughDeclarationString and passthroughCallString - # are complete; remove the extra ", " at the front of each. - passthroughDeclarationString = passthroughDeclarationString[2:] - passthroughCallString = passthroughCallString[2:] - if not passthroughDeclarationString: - passthroughDeclarationString = "void" - - # The Mesa functions are scattered across all the Mesa - # header files. The easiest way to manage declarations - # is to create them ourselves. - if funcName in allSpecials: - print "/* this function is special and is defined elsewhere */" - print "extern %s GL_APIENTRY %s(%s);" % (returnType, passthroughFuncName, passthroughDeclarationString) - - # A function may be a core function (i.e. it exists in - # the core specification), a core addition (extension - # functions added officially to the core), a required - # extension (usually an extension for an earlier version - # that has been officially adopted), or an optional extension. - # - # Core functions have a simple category (e.g. "GLES1.1"); - # we generate only a simple callback for them. - # - # Core additions have two category listings, one simple - # and one compound (e.g. ["GLES1.1", "GLES1.1:OES_fixed_point"]). - # We generate the core function, and also an extension function. - # - # Required extensions and implemented optional extensions - # have a single compound category "GLES1.1:OES_point_size_array". - # For these we generate just the extension function. - for categorySpec in apiutil.Categories(funcName): - compoundCategory = categorySpec.split(":") - - # This category isn't for us, if the base category doesn't match - # our version - if compoundCategory[0] != version: - continue - - # Otherwise, determine if we're writing code for a core - # function (no suffix) or an extension function. - if len(compoundCategory) == 1: - # This is a core function - extensionName = None - extensionSuffix = "" - else: - # This is an extension function. We'll need to append - # the extension suffix. - extensionName = compoundCategory[1] - extensionSuffix = extensionName.split("_")[0] - fullFuncName = funcPrefix + funcName + extensionSuffix - - # Now the generated function. The text used to mark an API-level - # function, oddly, is version-specific. - if extensionName: - print "/* Extension %s */" % extensionName - - if (not variables and - not switchCode and - not conversionCodeOutgoing and - not conversionCodeIncoming): - # pass through directly - print "#define %s %s" % (fullFuncName, passthroughFuncName) - print - continue - - print "static %s GL_APIENTRY %s(%s)" % (returnType, fullFuncName, declarationString) - print "{" - - # Start printing our code pieces. Start with any local - # variables we need. This unusual syntax joins the - # lines in the variables[] array with the "\n" separator. - if len(variables) > 0: - print "\n".join(variables) + "\n" - - # If there's any sort of parameter checking or variable - # array sizing, the switch code will contain it. - if len(switchCode) > 0: - print "\n".join(switchCode) + "\n" - - # In the case of an outgoing conversion (i.e. parameters must - # be converted before calling the underlying Mesa function), - # use the appropriate code. - if "get" not in props and len(conversionCodeOutgoing) > 0: - print "\n".join(conversionCodeOutgoing) + "\n" - - # Call the Mesa function. Note that there are very few functions - # that return a value (i.e. returnType is not "void"), and that - # none of them require incoming translation; so we're safe - # to generate code that directly returns in those cases, - # even though it's not completely independent. - - if returnType == "void": - print " %s(%s);" % (passthroughFuncName, passthroughCallString) - else: - print " return %s(%s);" % (passthroughFuncName, passthroughCallString) - - # If the function is one that returns values (i.e. "get" in props), - # it might return values of a different type than we need, that - # require conversion before passing back to the application. - if "get" in props and len(conversionCodeIncoming) > 0: - print "\n".join(conversionCodeIncoming) - - # All done. - print "}" - print - # end for each category provided for a function - -# end for each function - -print """ -struct _glapi_table * -_mesa_create_exec_table_%s(void) -{ - struct _glapi_table *exec; - exec = _mesa_alloc_dispatch_table(sizeof *exec); - if (exec == NULL) - return NULL; - -""" % shortname - -for func in keys: - prefix = "_es_" if func not in allSpecials else "_check_" - for spec in apiutil.Categories(func): - ext = spec.split(":") - # version does not match - if ext.pop(0) != version: - continue - entry = func - if ext: - suffix = ext[0].split("_")[0] - entry += suffix - print " SET_%s(exec, %s%s);" % (entry, prefix, entry) -print "" -print " return exec;" -print "}" - -print """ -#endif /* FEATURE_%s */""" % (shortname.upper()) +#*************************************************************************
+# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# TUNGSTEN GRAPHICS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#*************************************************************************
+
+
+import sys, os
+import APIspecutil as apiutil
+
+# These dictionary entries are used for automatic conversion.
+# The string will be used as a format string with the conversion
+# variable.
+Converters = {
+ 'GLfloat': {
+ 'GLdouble': "(GLdouble) (%s)",
+ 'GLfixed' : "(GLint) (%s * 65536)",
+ },
+ 'GLfixed': {
+ 'GLfloat': "(GLfloat) (%s / 65536.0f)",
+ 'GLdouble': "(GLdouble) (%s / 65536.0)",
+ },
+ 'GLdouble': {
+ 'GLfloat': "(GLfloat) (%s)",
+ 'GLfixed': "(GLfixed) (%s * 65536)",
+ },
+ 'GLclampf': {
+ 'GLclampd': "(GLclampd) (%s)",
+ 'GLclampx': "(GLclampx) (%s * 65536)",
+ },
+ 'GLclampx': {
+ 'GLclampf': "(GLclampf) (%s / 65536.0f)",
+ 'GLclampd': "(GLclampd) (%s / 65536.0)",
+ },
+ 'GLubyte': {
+ 'GLfloat': "(GLfloat) (%s / 255.0f)",
+ },
+}
+
+def GetBaseType(type):
+ typeTokens = type.split(' ')
+ baseType = None
+ typeModifiers = []
+ for t in typeTokens:
+ if t in ['const', '*']:
+ typeModifiers.append(t)
+ else:
+ baseType = t
+ return (baseType, typeModifiers)
+
+def ConvertValue(value, fromType, toType):
+ """Returns a string that represents the given parameter string,
+ type-converted if necessary."""
+
+ if not Converters.has_key(fromType):
+ print >> sys.stderr, "No base converter for type '%s' found. Ignoring." % fromType
+ return value
+
+ if not Converters[fromType].has_key(toType):
+ print >> sys.stderr, "No converter found for type '%s' to type '%s'. Ignoring." % (fromType, toType)
+ return value
+
+ # This part is simple. Return the proper conversion.
+ conversionString = Converters[fromType][toType]
+ return conversionString % value
+
+FormatStrings = {
+ 'GLenum' : '0x%x',
+ 'GLfloat' : '%f',
+ 'GLint' : '%d',
+ 'GLbitfield' : '0x%x',
+}
+def GetFormatString(type):
+ if FormatStrings.has_key(type):
+ return FormatStrings[type]
+ else:
+ return None
+
+
+######################################################################
+# Version-specific values to be used in the main script
+# header: which header file to include
+# api: what text specifies an API-level function
+VersionSpecificValues = {
+ 'GLES1.1' : {
+ 'description' : 'GLES1.1 functions',
+ 'header' : 'GLES/gl.h',
+ 'extheader' : 'GLES/glext.h',
+ 'shortname' : 'es1'
+ },
+ 'GLES2.0': {
+ 'description' : 'GLES2.0 functions',
+ 'header' : 'GLES2/gl2.h',
+ 'extheader' : 'GLES2/gl2ext.h',
+ 'shortname' : 'es2'
+ }
+}
+
+
+######################################################################
+# Main code for the script begins here.
+
+# Get the name of the program (without the directory part) for use in
+# error messages.
+program = os.path.basename(sys.argv[0])
+
+# Set default values
+verbose = 0
+functionList = "APIspec.xml"
+version = "GLES1.1"
+
+# Allow for command-line switches
+import getopt, time
+options = "hvV:S:"
+try:
+ optlist, args = getopt.getopt(sys.argv[1:], options)
+except getopt.GetoptError, message:
+ sys.stderr.write("%s: %s. Use -h for help.\n" % (program, message))
+ sys.exit(1)
+
+for option, optarg in optlist:
+ if option == "-h":
+ sys.stderr.write("Usage: %s [-%s]\n" % (program, options))
+ sys.stderr.write("Parse an API specification file and generate wrapper functions for a given GLES version\n")
+ sys.stderr.write("-h gives help\n")
+ sys.stderr.write("-v is verbose\n")
+ sys.stderr.write("-V specifies GLES version to generate [%s]:\n" % version)
+ for key in VersionSpecificValues.keys():
+ sys.stderr.write(" %s - %s\n" % (key, VersionSpecificValues[key]['description']))
+ sys.stderr.write("-S specifies API specification file to use [%s]\n" % functionList)
+ sys.exit(1)
+ elif option == "-v":
+ verbose += 1
+ elif option == "-V":
+ version = optarg
+ elif option == "-S":
+ functionList = optarg
+
+# Beyond switches, we support no further command-line arguments
+if len(args) > 0:
+ sys.stderr.write("%s: only switch arguments are supported - use -h for help\n" % program)
+ sys.exit(1)
+
+# If we don't have a valid version, abort.
+if not VersionSpecificValues.has_key(version):
+ sys.stderr.write("%s: version '%s' is not valid - use -h for help\n" % (program, version))
+ sys.exit(1)
+
+# Grab the version-specific items we need to use
+versionHeader = VersionSpecificValues[version]['header']
+versionExtHeader = VersionSpecificValues[version]['extheader']
+shortname = VersionSpecificValues[version]['shortname']
+
+# If we get to here, we're good to go. The "version" parameter
+# directs GetDispatchedFunctions to only allow functions from
+# that "category" (version in our parlance). This allows
+# functions with different declarations in different categories
+# to exist (glTexImage2D, for example, is different between
+# GLES1 and GLES2).
+keys = apiutil.GetAllFunctions(functionList, version)
+
+allSpecials = apiutil.AllSpecials()
+
+print """/* DO NOT EDIT *************************************************
+ * THIS FILE AUTOMATICALLY GENERATED BY THE %s SCRIPT
+ * API specification file: %s
+ * GLES version: %s
+ * date: %s
+ */
+""" % (program, functionList, version, time.strftime("%Y-%m-%d %H:%M:%S"))
+
+# The headers we choose are version-specific.
+print """
+#include "%s"
+#include "%s"
+#include "main/mfeatures.h"
+#include "main/compiler.h"
+#include "main/api_exec.h"
+
+#if FEATURE_%s
+""" % (versionHeader, versionExtHeader, shortname.upper())
+
+# Everyone needs these types.
+print """
+/* These types are needed for the Mesa veneer, but are not defined in
+ * the standard GLES headers.
+ */
+typedef double GLdouble;
+typedef double GLclampd;
+
+/* Mesa error handling requires these */
+extern void *_mesa_get_current_context(void);
+extern void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... );
+"""
+
+# Finally we get to the all-important functions
+print """/*************************************************************
+ * Generated functions begin here
+ */
+"""
+for funcName in keys:
+ if verbose > 0: sys.stderr.write("%s: processing function %s\n" % (program, funcName))
+
+ # start figuring out what this function will look like.
+ returnType = apiutil.ReturnType(funcName)
+ props = apiutil.Properties(funcName)
+ params = apiutil.Parameters(funcName)
+ declarationString = apiutil.MakeDeclarationString(params)
+
+ # In case of error, a function may have to return. Make
+ # sure we have valid return values in this case.
+ if returnType == "void":
+ errorReturn = "return"
+ elif returnType == "GLboolean":
+ errorReturn = "return GL_FALSE"
+ else:
+ errorReturn = "return (%s) 0" % returnType
+
+ # These are the output of this large calculation block.
+ # passthroughDeclarationString: a typed set of parameters that
+ # will be used to create the "extern" reference for the
+ # underlying Mesa or support function. Note that as generated
+ # these have an extra ", " at the beginning, which will be
+ # removed before use.
+ #
+ # passthroughDeclarationString: an untyped list of parameters
+ # that will be used to call the underlying Mesa or support
+ # function (including references to converted parameters).
+ # This will also be generated with an extra ", " at the
+ # beginning, which will be removed before use.
+ #
+ # variables: C code to create any local variables determined to
+ # be necessary.
+ # conversionCodeOutgoing: C code to convert application parameters
+ # to a necessary type before calling the underlying support code.
+ # May be empty if no conversion is required.
+ # conversionCodeIncoming: C code to do the converse: convert
+ # values returned by underlying Mesa code to the types needed
+ # by the application.
+ # Note that *either* the conversionCodeIncoming will be used (for
+ # generated query functions), *or* the conversionCodeOutgoing will
+ # be used (for generated non-query functions), never both.
+ passthroughFuncName = ""
+ passthroughDeclarationString = ""
+ passthroughCallString = ""
+ prefixOverride = None
+ variables = []
+ conversionCodeOutgoing = []
+ conversionCodeIncoming = []
+ switchCode = []
+
+ # Calculate the name of the underlying support function to call.
+ # By default, the passthrough function is named _mesa_<funcName>.
+ # We're allowed to override the prefix and/or the function name
+ # for each function record, though. The "ConversionFunction"
+ # utility is poorly named, BTW...
+ if funcName in allSpecials:
+ # perform checks and pass through
+ funcPrefix = "_check_"
+ aliasprefix = "_es_"
+ else:
+ funcPrefix = "_es_"
+ aliasprefix = apiutil.AliasPrefix(funcName)
+ alias = apiutil.ConversionFunction(funcName)
+ prefixOverride = apiutil.FunctionPrefix(funcName)
+ if prefixOverride != "_mesa_":
+ aliasprefix = apiutil.FunctionPrefix(funcName)
+ if not alias:
+ # There may still be a Mesa alias for the function
+ if apiutil.Alias(funcName):
+ passthroughFuncName = "%s%s" % (aliasprefix, apiutil.Alias(funcName))
+ else:
+ passthroughFuncName = "%s%s" % (aliasprefix, funcName)
+ else: # a specific alias is provided
+ passthroughFuncName = "%s%s" % (aliasprefix, alias)
+
+ # Look at every parameter: each one may have only specific
+ # allowed values, or dependent parameters to check, or
+ # variant-sized vector arrays to calculate
+ for (paramName, paramType, paramMaxVecSize, paramConvertToType, paramValidValues, paramValueConversion) in params:
+ # We'll need this below if we're doing conversions
+ (paramBaseType, paramTypeModifiers) = GetBaseType(paramType)
+
+ # Conversion management.
+ # We'll handle three cases, easiest to hardest: a parameter
+ # that doesn't require conversion, a scalar parameter that
+ # requires conversion, and a vector parameter that requires
+ # conversion.
+ if paramConvertToType == None:
+ # Unconverted parameters are easy, whether they're vector
+ # or scalar - just add them to the call list. No conversions
+ # or anything to worry about.
+ passthroughDeclarationString += ", %s %s" % (paramType, paramName)
+ passthroughCallString += ", %s" % paramName
+
+ elif paramMaxVecSize == 0: # a scalar parameter that needs conversion
+ # A scalar to hold a converted parameter
+ variables.append(" %s converted_%s;" % (paramConvertToType, paramName))
+
+ # Outgoing conversion depends on whether we have to conditionally
+ # perform value conversion.
+ if paramValueConversion == "none":
+ conversionCodeOutgoing.append(" converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
+ elif paramValueConversion == "some":
+ # We'll need a conditional variable to keep track of
+ # whether we're converting values or not.
+ if (" int convert_%s_value = 1;" % paramName) not in variables:
+ variables.append(" int convert_%s_value = 1;" % paramName)
+
+ # Write code based on that conditional.
+ conversionCodeOutgoing.append(" if (convert_%s_value) {" % paramName)
+ conversionCodeOutgoing.append(" converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
+ conversionCodeOutgoing.append(" } else {")
+ conversionCodeOutgoing.append(" converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
+ conversionCodeOutgoing.append(" }")
+ else: # paramValueConversion == "all"
+ conversionCodeOutgoing.append(" converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
+
+ # Note that there can be no incoming conversion for a
+ # scalar parameter; changing the scalar will only change
+ # the local value, and won't ultimately change anything
+ # that passes back to the application.
+
+ # Call strings. The unusual " ".join() call will join the
+ # array of parameter modifiers with spaces as separators.
+ passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName)
+ passthroughCallString += ", converted_%s" % paramName
+
+ else: # a vector parameter that needs conversion
+ # We'll need an index variable for conversions
+ if " register unsigned int i;" not in variables:
+ variables.append(" register unsigned int i;")
+
+ # This variable will hold the (possibly variant) size of
+ # this array needing conversion. By default, we'll set
+ # it to the maximal size (which is correct for functions
+ # with a constant-sized vector parameter); for true
+ # variant arrays, we'll modify it with other code.
+ variables.append(" unsigned int n_%s = %d;" % (paramName, paramMaxVecSize))
+
+ # This array will hold the actual converted values.
+ variables.append(" %s converted_%s[%d];" % (paramConvertToType, paramName, paramMaxVecSize))
+
+ # Again, we choose the conversion code based on whether we
+ # have to always convert values, never convert values, or
+ # conditionally convert values.
+ if paramValueConversion == "none":
+ conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeOutgoing.append(" converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
+ conversionCodeOutgoing.append(" }")
+ elif paramValueConversion == "some":
+ # We'll need a conditional variable to keep track of
+ # whether we're converting values or not.
+ if (" int convert_%s_value = 1;" % paramName) not in variables:
+ variables.append(" int convert_%s_value = 1;" % paramName)
+ # Write code based on that conditional.
+ conversionCodeOutgoing.append(" if (convert_%s_value) {" % paramName)
+ conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeOutgoing.append(" converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
+ conversionCodeOutgoing.append(" }")
+ conversionCodeOutgoing.append(" } else {")
+ conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeOutgoing.append(" converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
+ conversionCodeOutgoing.append(" }")
+ conversionCodeOutgoing.append(" }")
+ else: # paramValueConversion == "all"
+ conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeOutgoing.append(" converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
+
+ conversionCodeOutgoing.append(" }")
+
+ # If instead we need an incoming conversion (i.e. results
+ # from Mesa have to be converted before handing back
+ # to the application), this is it. Fortunately, we don't
+ # have to worry about conditional value conversion - the
+ # functions that do (e.g. glGetFixedv()) are handled
+ # specially, outside this code generation.
+ #
+ # Whether we use incoming conversion or outgoing conversion
+ # is determined later - we only ever use one or the other.
+
+ if paramValueConversion == "none":
+ conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeIncoming.append(" %s[i] = (%s) converted_%s[i];" % (paramName, paramConvertToType, paramName))
+ conversionCodeIncoming.append(" }")
+ elif paramValueConversion == "some":
+ # We'll need a conditional variable to keep track of
+ # whether we're converting values or not.
+ if (" int convert_%s_value = 1;" % paramName) not in variables:
+ variables.append(" int convert_%s_value = 1;" % paramName)
+
+ # Write code based on that conditional.
+ conversionCodeIncoming.append(" if (convert_%s_value) {" % paramName)
+ conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeIncoming.append(" %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
+ conversionCodeIncoming.append(" }")
+ conversionCodeIncoming.append(" } else {")
+ conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeIncoming.append(" %s[i] = (%s) converted_%s[i];" % (paramName, paramBaseType, paramName))
+ conversionCodeIncoming.append(" }")
+ conversionCodeIncoming.append(" }")
+ else: # paramValueConversion == "all"
+ conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
+ conversionCodeIncoming.append(" %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
+ conversionCodeIncoming.append(" }")
+
+ # Call strings. The unusual " ".join() call will join the
+ # array of parameter modifiers with spaces as separators.
+ passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName)
+ passthroughCallString += ", converted_%s" % paramName
+
+ # endif conversion management
+
+ # Parameter checking. If the parameter has a specific list of
+ # valid values, we have to make sure that the passed-in values
+ # match these, or we make an error.
+ if len(paramValidValues) > 0:
+ # We're about to make a big switch statement with an
+ # error at the end. By default, the error is GL_INVALID_ENUM,
+ # unless we find a "case" statement in the middle with a
+ # non-GLenum value.
+ errorDefaultCase = "GL_INVALID_ENUM"
+
+ # This parameter has specific valid values. Make a big
+ # switch statement to handle it. Note that the original
+ # parameters are always what is checked, not the
+ # converted parameters.
+ switchCode.append(" switch(%s) {" % paramName)
+
+ for valueIndex in range(len(paramValidValues)):
+ (paramValue, dependentVecSize, dependentParamName, dependentValidValues, errorCode, valueConvert) = paramValidValues[valueIndex]
+
+ # We're going to need information on the dependent param
+ # as well.
+ if dependentParamName:
+ depParamIndex = apiutil.FindParamIndex(params, dependentParamName)
+ if depParamIndex == None:
+ sys.stderr.write("%s: can't find dependent param '%s' for function '%s'\n" % (program, dependentParamName, funcName))
+
+ (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = params[depParamIndex]
+ else:
+ (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = (None, None, None, None, [], None)
+
+ # This is a sneaky trick. It's valid syntax for a parameter
+ # that is *not* going to be converted to be declared
+ # with a dependent vector size; but in this case, the
+ # dependent vector size is unused and unnecessary.
+ # So check for this and ignore the dependent vector size
+ # if the parameter is not going to be converted.
+ if depParamConvertToType:
+ usedDependentVecSize = dependentVecSize
+ else:
+ usedDependentVecSize = None
+
+ # We'll peek ahead at the next parameter, to see whether
+ # we can combine cases
+ if valueIndex + 1 < len(paramValidValues) :
+ (nextParamValue, nextDependentVecSize, nextDependentParamName, nextDependentValidValues, nextErrorCode, nextValueConvert) = paramValidValues[valueIndex + 1]
+ if depParamConvertToType:
+ usedNextDependentVecSize = nextDependentVecSize
+ else:
+ usedNextDependentVecSize = None
+
+ # Create a case for this value. As a mnemonic,
+ # if we have a dependent vector size that we're ignoring,
+ # add it as a comment.
+ if usedDependentVecSize == None and dependentVecSize != None:
+ switchCode.append(" case %s: /* size %s */" % (paramValue, dependentVecSize))
+ else:
+ switchCode.append(" case %s:" % paramValue)
+
+ # If this is not a GLenum case, then switch our error
+ # if no value is matched to be GL_INVALID_VALUE instead
+ # of GL_INVALID_ENUM. (Yes, this does get confused
+ # if there are both values and GLenums in the same
+ # switch statement, which shouldn't happen.)
+ if paramValue[0:3] != "GL_":
+ errorDefaultCase = "GL_INVALID_VALUE"
+
+ # If all the remaining parameters are identical to the
+ # next set, then we're done - we'll just create the
+ # official code on the next pass through, and the two
+ # cases will share the code.
+ if valueIndex + 1 < len(paramValidValues) and usedDependentVecSize == usedNextDependentVecSize and dependentParamName == nextDependentParamName and dependentValidValues == nextDependentValidValues and errorCode == nextErrorCode and valueConvert == nextValueConvert:
+ continue
+
+ # Otherwise, we'll have to generate code for this case.
+ # Start off with a check: if there is a dependent parameter,
+ # and a list of valid values for that parameter, we need
+ # to generate an error if something other than one
+ # of those values is passed.
+ if len(dependentValidValues) > 0:
+ conditional=""
+
+ # If the parameter being checked is actually an array,
+ # check only its first element.
+ if depParamMaxVecSize == 0:
+ valueToCheck = dependentParamName
+ else:
+ valueToCheck = "%s[0]" % dependentParamName
+
+ for v in dependentValidValues:
+ conditional += " && %s != %s" % (valueToCheck, v)
+ switchCode.append(" if (%s) {" % conditional[4:])
+ if errorCode == None:
+ errorCode = "GL_INVALID_ENUM"
+ switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=0x%s)", %s);' % (errorCode, funcName, paramName, "%x", paramName))
+ switchCode.append(" %s;" % errorReturn)
+ switchCode.append(" }")
+ # endif there are dependent valid values
+
+ # The dependent parameter may require conditional
+ # value conversion. If it does, and we don't want
+ # to convert values, we'll have to generate code for that
+ if depParamValueConversion == "some" and valueConvert == "noconvert":
+ switchCode.append(" convert_%s_value = 0;" % dependentParamName)
+
+ # If there's a dependent vector size for this parameter
+ # that we're actually going to use (i.e. we need conversion),
+ # mark it.
+ if usedDependentVecSize:
+ switchCode.append(" n_%s = %s;" % (dependentParamName, dependentVecSize))
+
+ # In all cases, break out of the switch if any valid
+ # value is found.
+ switchCode.append(" break;")
+
+
+ # Need a default case to catch all the other, invalid
+ # parameter values. These will all generate errors.
+ switchCode.append(" default:")
+ if errorCode == None:
+ errorCode = "GL_INVALID_ENUM"
+ formatString = GetFormatString(paramType)
+ if formatString == None:
+ switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s)");' % (errorCode, funcName, paramName))
+ else:
+ switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=%s)", %s);' % (errorCode, funcName, paramName, formatString, paramName))
+ switchCode.append(" %s;" % errorReturn)
+
+ # End of our switch code.
+ switchCode.append(" }")
+
+ # endfor every recognized parameter value
+
+ # endfor every param
+
+ # Here, the passthroughDeclarationString and passthroughCallString
+ # are complete; remove the extra ", " at the front of each.
+ passthroughDeclarationString = passthroughDeclarationString[2:]
+ passthroughCallString = passthroughCallString[2:]
+ if not passthroughDeclarationString:
+ passthroughDeclarationString = "void"
+
+ # The Mesa functions are scattered across all the Mesa
+ # header files. The easiest way to manage declarations
+ # is to create them ourselves.
+ if funcName in allSpecials:
+ print "/* this function is special and is defined elsewhere */"
+ print "extern %s GL_APIENTRY %s(%s);" % (returnType, passthroughFuncName, passthroughDeclarationString)
+
+ # A function may be a core function (i.e. it exists in
+ # the core specification), a core addition (extension
+ # functions added officially to the core), a required
+ # extension (usually an extension for an earlier version
+ # that has been officially adopted), or an optional extension.
+ #
+ # Core functions have a simple category (e.g. "GLES1.1");
+ # we generate only a simple callback for them.
+ #
+ # Core additions have two category listings, one simple
+ # and one compound (e.g. ["GLES1.1", "GLES1.1:OES_fixed_point"]).
+ # We generate the core function, and also an extension function.
+ #
+ # Required extensions and implemented optional extensions
+ # have a single compound category "GLES1.1:OES_point_size_array".
+ # For these we generate just the extension function.
+ for categorySpec in apiutil.Categories(funcName):
+ compoundCategory = categorySpec.split(":")
+
+ # This category isn't for us, if the base category doesn't match
+ # our version
+ if compoundCategory[0] != version:
+ continue
+
+ # Otherwise, determine if we're writing code for a core
+ # function (no suffix) or an extension function.
+ if len(compoundCategory) == 1:
+ # This is a core function
+ extensionName = None
+ extensionSuffix = ""
+ else:
+ # This is an extension function. We'll need to append
+ # the extension suffix.
+ extensionName = compoundCategory[1]
+ extensionSuffix = extensionName.split("_")[0]
+ fullFuncName = funcPrefix + funcName + extensionSuffix
+
+ # Now the generated function. The text used to mark an API-level
+ # function, oddly, is version-specific.
+ if extensionName:
+ print "/* Extension %s */" % extensionName
+
+ if (not variables and
+ not switchCode and
+ not conversionCodeOutgoing and
+ not conversionCodeIncoming):
+ # pass through directly
+ print "#define %s %s" % (fullFuncName, passthroughFuncName)
+ print
+ continue
+
+ print "static %s GL_APIENTRY %s(%s)" % (returnType, fullFuncName, declarationString)
+ print "{"
+
+ # Start printing our code pieces. Start with any local
+ # variables we need. This unusual syntax joins the
+ # lines in the variables[] array with the "\n" separator.
+ if len(variables) > 0:
+ print "\n".join(variables) + "\n"
+
+ # If there's any sort of parameter checking or variable
+ # array sizing, the switch code will contain it.
+ if len(switchCode) > 0:
+ print "\n".join(switchCode) + "\n"
+
+ # In the case of an outgoing conversion (i.e. parameters must
+ # be converted before calling the underlying Mesa function),
+ # use the appropriate code.
+ if "get" not in props and len(conversionCodeOutgoing) > 0:
+ print "\n".join(conversionCodeOutgoing) + "\n"
+
+ # Call the Mesa function. Note that there are very few functions
+ # that return a value (i.e. returnType is not "void"), and that
+ # none of them require incoming translation; so we're safe
+ # to generate code that directly returns in those cases,
+ # even though it's not completely independent.
+
+ if returnType == "void":
+ print " %s(%s);" % (passthroughFuncName, passthroughCallString)
+ else:
+ print " return %s(%s);" % (passthroughFuncName, passthroughCallString)
+
+ # If the function is one that returns values (i.e. "get" in props),
+ # it might return values of a different type than we need, that
+ # require conversion before passing back to the application.
+ if "get" in props and len(conversionCodeIncoming) > 0:
+ print "\n".join(conversionCodeIncoming)
+
+ # All done.
+ print "}"
+ print
+ # end for each category provided for a function
+
+# end for each function
+
+print """
+#include "glapi/glapi.h"
+
+#if FEATURE_remap_table
+
+/* cannot include main/dispatch.h here */
+#define _GLAPI_USE_REMAP_TABLE
+#include "%sapi/main/glapidispatch.h"
+
+#define need_MESA_remap_table
+#include "%sapi/main/remap_helper.h"
+
+/* force SET_* macros to use the local remap table */
+#define driDispatchRemapTable remap_table
+static int remap_table[driDispatchRemapTable_size];
+
+static void
+init_remap_table(void)
+{
+ _glthread_DECLARE_STATIC_MUTEX(mutex);
+ static GLboolean initialized = GL_FALSE;
+ const struct gl_function_pool_remap *remap = MESA_remap_table_functions;
+ int i;
+
+ _glthread_LOCK_MUTEX(mutex);
+ if (initialized) {
+ _glthread_UNLOCK_MUTEX(mutex);
+ return;
+ }
+
+ for (i = 0; i < driDispatchRemapTable_size; i++) {
+ GLint offset;
+ const char *spec;
+
+ /* sanity check */
+ ASSERT(i == remap[i].remap_index);
+ spec = _mesa_function_pool + remap[i].pool_index;
+
+ offset = _mesa_map_function_spec(spec);
+ remap_table[i] = offset;
+ }
+ initialized = GL_TRUE;
+ _glthread_UNLOCK_MUTEX(mutex);
+}
+
+#else /* FEATURE_remap_table */
+
+/* cannot include main/dispatch.h here */
+#include "%sapi/main/glapidispatch.h"
+
+static INLINE void
+init_remap_table(void)
+{
+}
+
+#endif /* FEATURE_remap_table */
+
+struct _glapi_table *
+_mesa_create_exec_table_%s(void)
+{
+ struct _glapi_table *exec;
+
+ exec = _mesa_alloc_dispatch_table(_gloffset_COUNT);
+ if (exec == NULL)
+ return NULL;
+
+ init_remap_table();
+""" % (shortname, shortname, shortname, shortname)
+
+for func in keys:
+ prefix = "_es_" if func not in allSpecials else "_check_"
+ for spec in apiutil.Categories(func):
+ ext = spec.split(":")
+ # version does not match
+ if ext.pop(0) != version:
+ continue
+ entry = func
+ if ext:
+ suffix = ext[0].split("_")[0]
+ entry += suffix
+ print " SET_%s(exec, %s%s);" % (entry, prefix, entry)
+print ""
+print " return exec;"
+print "}"
+
+print """
+#endif /* FEATURE_%s */""" % (shortname.upper())
|