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