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 25 import sys, os 26 import 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. 31 Converters = { 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 57 def 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 68 def 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 84 FormatStrings = { 85 'GLenum' : '0x%x', 86 'GLfloat' : '%f', 87 'GLint' : '%d', 88 'GLbitfield' : '0x%x', 89 } 90 def 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 101 VersionSpecificValues = { 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. 122 program = os.path.basename(sys.argv[0]) 123 124 # Set default values 125 verbose = 0 126 functionList = "APIspec.xml" 127 version = "GLES1.1" 128 129 # Allow for command-line switches 130 import getopt, time 131 options = "hvV:S:" 132 try: 133 optlist, args = getopt.getopt(sys.argv[1:], options) 134 except getopt.GetoptError, message: 135 sys.stderr.write("%s: %s. Use -h for help.\n" % (program, message)) 136 sys.exit(1) 137 138 for 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 157 if 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. 162 if 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 167 versionHeader = VersionSpecificValues[version]['header'] 168 versionExtHeader = VersionSpecificValues[version]['extheader'] 169 shortname = 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). 177 keys = apiutil.GetAllFunctions(functionList, version) 178 179 allSpecials = apiutil.AllSpecials() 180 181 print """/* 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. 190 print """ 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 if version == "GLES1.1": 205 print '#include "main/es1_conversion.h"' 206 print 207 208 # Everyone needs these types. 209 print """ 210 /* These types are needed for the Mesa veneer, but are not defined in 211 * the standard GLES headers. 212 */ 213 typedef double GLdouble; 214 typedef double GLclampd; 215 216 /* Mesa error handling requires these */ 217 extern void *_mesa_get_current_context(void); 218 extern void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... ); 219 """ 220 221 # Finally we get to the all-important functions 222 print """/************************************************************* 223 * Generated functions begin here 224 */ 225 """ 226 for 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 685 print """ 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 696 static void 697 init_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 729 static INLINE void 730 init_remap_table(void) 731 { 732 } 733 734 #endif /* FEATURE_remap_table */ 735 736 struct _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 748 for 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) 760 print "" 761 print " return exec;" 762 print "}" 763 764 print """ 765 #endif /* FEATURE_%s */""" % (shortname.upper()) 766