mesa/es: Add OpenGL ES overlay.
[mesa.git] / src / mesa / es / main / es_generator.py
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 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 def GetLoopSizeExpression(funcName, paramName, paramMaxVecSize):
85 # The VariantArrays() list will have all the information (for all
86 # parameters) on how to calculate variant array sizes.
87 variantArrays = apiutil.VariantArrays(funcName)
88 defaultSize = paramMaxVecSize
89 loopSizeExpression = ''
90
91 # There can be many different entries in the variantArrays for the
92 # same parameter. We have to look at all of them and pick out the
93 # ones of interest.
94 for (variantName, variantSize, controllingParam, controllingValues) in variantArrays:
95 if paramName == variantName:
96 # This variant specification applies to us. It may be of
97 # the form "param size default", meaning that the value should
98 # replace the default size, or it may be
99 # "param size controlParam value...", in which case the size should
100 # be used if the controlParam has any one of the given values.
101 if len(controllingValues) == 0:
102 defaultSize = variantSize
103 else:
104 # Create a compound conditional that expresses
105 # all the possible values in the list
106 conditional = ''
107 for value in controllingValues:
108 if len(conditional) > 0:
109 conditional = conditional + " || "
110 conditional = conditional + "%s == %s" % (controllingParam, value)
111
112 # Add the possibly compound conditional and
113 # the associated vector size to the
114 # loop control expression
115 loopSizeExpression = loopSizeExpression + "(%s) ? %s : " % (conditional, variantSize)
116
117 # end if the name matches
118 # end for the list of all variant array declarations
119
120 # Return the expression that returns the actual size of the
121 # array. Note that 'loopSizeExpression' will already have a
122 # trailing ": " if it is nonempty.
123 if len(loopSizeExpression) > 0:
124 return "(%s%s)" % (loopSizeExpression, defaultSize)
125 else:
126 return "%s" % defaultSize
127
128 FormatStrings = {
129 'GLenum' : '0x%x',
130 'GLfloat' : '%f',
131 'GLint' : '%d',
132 'GLbitfield' : '0x%x',
133 }
134 def GetFormatString(type):
135 if FormatStrings.has_key(type):
136 return FormatStrings[type]
137 else:
138 return None
139
140
141 ######################################################################
142 # Version-specific values to be used in the main script
143 # header: which header file to include
144 # api: what text specifies an API-level function
145 # special: the name of the "specials" file
146 VersionSpecificValues = {
147 'GLES1.1' : {
148 'description' : 'GLES1.1 functions',
149 'header' : 'GLES/gl.h',
150 'extheader' : 'GLES/glext.h',
151 'special' : 'es1_special',
152 },
153 'GLES2.0': {
154 'description' : 'GLES2.0 functions',
155 'header' : 'GLES2/gl2.h',
156 'extheader' : 'GLES2/gl2ext.h',
157 'special' : 'es2_special',
158 }
159 }
160
161
162 ######################################################################
163 # Main code for the script begins here.
164
165 # Get the name of the program (without the directory part) for use in
166 # error messages.
167 program = os.path.basename(sys.argv[0])
168
169 # We assume that the directory that the Python script is in also
170 # houses the "special" files.
171 programDir = os.path.dirname(sys.argv[0])
172
173 # Set default values
174 verbose = 0
175 functionList = "APIspec.txt"
176 version = "GLES1.1"
177
178 # Allow for command-line switches
179 import getopt, time
180 options = "hvV:S:"
181 try:
182 optlist, args = getopt.getopt(sys.argv[1:], options)
183 except getopt.GetoptError, message:
184 sys.stderr.write("%s: %s. Use -h for help.\n" % (program, message))
185 sys.exit(1)
186
187 for option, optarg in optlist:
188 if option == "-h":
189 sys.stderr.write("Usage: %s [-%s]\n" % (program, options))
190 sys.stderr.write("Parse an API specification file and generate wrapper functions for a given GLES version\n")
191 sys.stderr.write("-h gives help\n")
192 sys.stderr.write("-v is verbose\n")
193 sys.stderr.write("-V specifies GLES version to generate [%s]:\n" % version)
194 for key in VersionSpecificValues.keys():
195 sys.stderr.write(" %s - %s\n" % (key, VersionSpecificValues[key]['description']))
196 sys.stderr.write("-S specifies API specification file to use [%s]\n" % functionList)
197 sys.exit(1)
198 elif option == "-v":
199 verbose += 1
200 elif option == "-V":
201 version = optarg
202 elif option == "-S":
203 functionList = optarg
204
205 # Beyond switches, we support no further command-line arguments
206 if len(args) > 0:
207 sys.stderr.write("%s: only switch arguments are supported - use -h for help\n" % program)
208 sys.exit(1)
209
210 # If we don't have a valid version, abort.
211 if not VersionSpecificValues.has_key(version):
212 sys.stderr.write("%s: version '%s' is not valid - use -h for help\n" % (program, version))
213 sys.exit(1)
214
215 # Grab the version-specific items we need to use
216 versionHeader = VersionSpecificValues[version]['header']
217 versionExtHeader = VersionSpecificValues[version]['extheader']
218 versionSpecial = VersionSpecificValues[version]['special']
219
220 # We're probably being invoked from a different directory,
221 # so look for the "special" file in the same directory that
222 # holds the Python script
223 specialFile = os.path.join(programDir, versionSpecial)
224 if not os.path.isfile(specialFile):
225 sys.stderr.write("%s: can't find special file '%s' for version '%s' - aborting" % (program, specialFile, version))
226 sys.exit(1)
227
228 allSpecials = apiutil.AllSpecials(specialFile.split("_")[0])
229
230 # If we get to here, we're good to go. The "version" parameter
231 # directs GetDispatchedFunctions to only allow functions from
232 # that "category" (version in our parlance). This allows
233 # functions with different declarations in different categories
234 # to exist (glTexImage2D, for example, is different between
235 # GLES1 and GLES2).
236 keys = apiutil.GetAllFunctions(functionList, version)
237
238 print """/* DO NOT EDIT *************************************************
239 * THIS FILE AUTOMATICALLY GENERATED BY THE %s SCRIPT
240 * API specification file: %s
241 * GLES version: %s
242 * date: %s
243 */
244 """ % (program, functionList, version, time.strftime("%Y-%m-%d %H:%M:%S"))
245
246 # The headers we choose are version-specific.
247 print """
248 #include "%s"
249 #include "%s"
250 """ % (versionHeader, versionExtHeader)
251
252 # Everyone needs these types.
253 print """
254 /* These types are needed for the Mesa veneer, but are not defined in
255 * the standard GLES headers.
256 */
257 typedef double GLdouble;
258 typedef double GLclampd;
259
260 /* This type is normally in glext.h, but needed here */
261 typedef char GLchar;
262
263 /* Mesa error handling requires these */
264 extern void *_mesa_get_current_context(void);
265 extern void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... );
266
267 #include "main/compiler.h"
268 #include "main/api_exec.h"
269
270 #include "glapi/dispatch.h"
271
272 typedef void (*_glapi_proc)(void); /* generic function pointer */
273 """
274
275 # All variant-length arrays in the GLES API are controlled by some
276 # selector parameter. Almost all of those are constant length based
277 # on the selector parameter (e.g., in glFogfv(), if the "pname"
278 # parameter is GL_FOG_COLOR, the "params" array is considered to be
279 # 4 floats long; for any other value of "pname", the "params' array
280 # is considered to be 1 float long.
281 #
282 # There are a very few instances where the selector parameter chooses
283 # a runtime-determined value:
284 # glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS)
285 # glGetIntegerv(GL_SHADER_BINARY_FORMATS)
286 # plus the glGetBooleanv, glGetFloatv, glGetFixedv counterparts.
287 #
288 # The number of formats in both cases is not a constant, but is a
289 # runtime-determined value (based on the return value of
290 # glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS) or
291 # glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS).
292 #
293 # Rather than hard-code some value (and risk memory errors when we
294 # overshoot arrays), in these cases we'll use a constant expresssion
295 # (e.g. _get_size(GL_NUM_COMPRESSED_TEXTURE_FORMATS)) to get the
296 # value of the variant array. Note, though, that in these cases the
297 # "vector" parameter should be set to some size large enough to hold
298 # all values (and must be set for GLfixed-based conversions, which
299 # need it to define an auxiliary array size).
300 #
301 # Here's the function itself. Although we only need a couple of values,
302 # we'll make it general.
303 print """
304 extern void GLAPIENTRY _mesa_GetIntegerv(GLenum, GLint *);
305 static INLINE unsigned int _get_size(GLenum pname)
306 {
307 /* In case of error, make sure the value returned is 0. */
308 GLint value = 0;
309 _mesa_GetIntegerv(pname, &value);
310 return (unsigned int) value;
311 }
312 """
313
314 # Finally we get to the all-important functions
315 print """/*************************************************************
316 * Generated functions begin here
317 */
318 """
319 for funcName in keys:
320 if verbose > 0: sys.stderr.write("%s: processing function %s\n" % (program, funcName))
321
322 # start figuring out what this function will look like.
323 returnType = apiutil.ReturnType(funcName)
324 props = apiutil.Properties(funcName)
325 params = apiutil.Parameters(funcName)
326 declarationString = apiutil.MakeDeclarationString(params)
327
328 # In case of error, a function may have to return. Make
329 # sure we have valid return values in this case.
330 if returnType == "void":
331 errorReturn = "return"
332 elif returnType == "GLboolean":
333 errorReturn = "return GL_FALSE"
334 else:
335 errorReturn = "return (%s) 0" % returnType
336
337 # These are the output of this large calculation block.
338 # passthroughDeclarationString: a typed set of parameters that
339 # will be used to create the "extern" reference for the
340 # underlying Mesa or support function. Note that as generated
341 # these have an extra ", " at the beginning, which will be
342 # removed before use.
343 #
344 # passthroughDeclarationString: an untyped list of parameters
345 # that will be used to call the underlying Mesa or support
346 # function (including references to converted parameters).
347 # This will also be generated with an extra ", " at the
348 # beginning, which will be removed before use.
349 #
350 # variables: C code to create any local variables determined to
351 # be necessary.
352 # conversionCodeOutgoing: C code to convert application parameters
353 # to a necessary type before calling the underlying support code.
354 # May be empty if no conversion is required.
355 # conversionCodeIncoming: C code to do the converse: convert
356 # values returned by underlying Mesa code to the types needed
357 # by the application.
358 # Note that *either* the conversionCodeIncoming will be used (for
359 # generated query functions), *or* the conversionCodeOutgoing will
360 # be used (for generated non-query functions), never both.
361 passthroughFuncName = ""
362 passthroughDeclarationString = ""
363 passthroughCallString = ""
364 variables = []
365 conversionCodeOutgoing = []
366 conversionCodeIncoming = []
367 switchCode = []
368
369 # Calculate the name of the underlying support function to call.
370 # By default, the passthrough function is named _mesa_<funcName>.
371 # We're allowed to override the prefix and/or the function name
372 # for each function record, though. The "ConversionFunction"
373 # utility is poorly named, BTW...
374 aliasprefix = apiutil.AliasPrefix(funcName)
375 alias = apiutil.ConversionFunction(funcName)
376 if not alias:
377 # There may still be a Mesa alias for the function
378 if apiutil.Alias(funcName):
379 passthroughFuncName = "%s%s" % (aliasprefix, apiutil.Alias(funcName))
380 else:
381 passthroughFuncName = "%s%s" % (aliasprefix, funcName)
382 else: # a specific alias is provided
383 passthroughFuncName = "%s%s" % (aliasprefix, alias)
384
385 # Look at every parameter: each one may have only specific
386 # allowed values, or dependent parameters to check, or
387 # variant-sized vector arrays to calculate
388 for (paramName, paramType, paramMaxVecSize, paramConvertToType, paramValidValues, paramValueConversion) in params:
389 # We'll need this below if we're doing conversions
390 (paramBaseType, paramTypeModifiers) = GetBaseType(paramType)
391
392 # Conversion management.
393 # We'll handle three cases, easiest to hardest: a parameter
394 # that doesn't require conversion, a scalar parameter that
395 # requires conversion, and a vector parameter that requires
396 # conversion.
397 if paramConvertToType == None:
398 # Unconverted parameters are easy, whether they're vector
399 # or scalar - just add them to the call list. No conversions
400 # or anything to worry about.
401 passthroughDeclarationString += ", %s %s" % (paramType, paramName)
402 passthroughCallString += ", %s" % paramName
403
404 elif paramMaxVecSize == 0: # a scalar parameter that needs conversion
405 # A scalar to hold a converted parameter
406 variables.append(" %s converted_%s;" % (paramConvertToType, paramName))
407
408 # Outgoing conversion depends on whether we have to conditionally
409 # perform value conversion.
410 if paramValueConversion == "none":
411 conversionCodeOutgoing.append(" converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
412 elif paramValueConversion == "some":
413 # We'll need a conditional variable to keep track of
414 # whether we're converting values or not.
415 if (" int convert_%s_value = 1;" % paramName) not in variables:
416 variables.append(" int convert_%s_value = 1;" % paramName)
417
418 # Write code based on that conditional.
419 conversionCodeOutgoing.append(" if (convert_%s_value) {" % paramName)
420 conversionCodeOutgoing.append(" converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
421 conversionCodeOutgoing.append(" } else {")
422 conversionCodeOutgoing.append(" converted_%s = (%s) %s;" % (paramName, paramConvertToType, paramName))
423 conversionCodeOutgoing.append(" }")
424 else: # paramValueConversion == "all"
425 conversionCodeOutgoing.append(" converted_%s = %s;" % (paramName, ConvertValue(paramName, paramBaseType, paramConvertToType)))
426
427 # Note that there can be no incoming conversion for a
428 # scalar parameter; changing the scalar will only change
429 # the local value, and won't ultimately change anything
430 # that passes back to the application.
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 else: # a vector parameter that needs conversion
438 # We'll need an index variable for conversions
439 if " register unsigned int i;" not in variables:
440 variables.append(" register unsigned int i;")
441
442 # This variable will hold the (possibly variant) size of
443 # this array needing conversion. By default, we'll set
444 # it to the maximal size (which is correct for functions
445 # with a constant-sized vector parameter); for true
446 # variant arrays, we'll modify it with other code.
447 variables.append(" unsigned int n_%s = %d;" % (paramName, paramMaxVecSize))
448
449 # This array will hold the actual converted values.
450 variables.append(" %s converted_%s[%d];" % (paramConvertToType, paramName, paramMaxVecSize))
451
452 # Again, we choose the conversion code based on whether we
453 # have to always convert values, never convert values, or
454 # conditionally convert values.
455 if paramValueConversion == "none":
456 conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
457 conversionCodeOutgoing.append(" converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
458 conversionCodeOutgoing.append(" }")
459 elif paramValueConversion == "some":
460 # We'll need a conditional variable to keep track of
461 # whether we're converting values or not.
462 if (" int convert_%s_value = 1;" % paramName) not in variables:
463 variables.append(" int convert_%s_value = 1;" % paramName)
464 # Write code based on that conditional.
465 conversionCodeOutgoing.append(" if (convert_%s_value) {" % paramName)
466 conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
467 conversionCodeOutgoing.append(" converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
468 conversionCodeOutgoing.append(" }")
469 conversionCodeOutgoing.append(" } else {")
470 conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
471 conversionCodeOutgoing.append(" converted_%s[i] = (%s) %s[i];" % (paramName, paramConvertToType, paramName))
472 conversionCodeOutgoing.append(" }")
473 conversionCodeOutgoing.append(" }")
474 else: # paramValueConversion == "all"
475 conversionCodeOutgoing.append(" for (i = 0; i < n_%s; i++) {" % paramName)
476 conversionCodeOutgoing.append(" converted_%s[i] = %s;" % (paramName, ConvertValue("%s[i]" % paramName, paramBaseType, paramConvertToType)))
477
478 conversionCodeOutgoing.append(" }")
479
480 # If instead we need an incoming conversion (i.e. results
481 # from Mesa have to be converted before handing back
482 # to the application), this is it. Fortunately, we don't
483 # have to worry about conditional value conversion - the
484 # functions that do (e.g. glGetFixedv()) are handled
485 # specially, outside this code generation.
486 #
487 # Whether we use incoming conversion or outgoing conversion
488 # is determined later - we only ever use one or the other.
489
490 if paramValueConversion == "none":
491 conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
492 conversionCodeIncoming.append(" %s[i] = (%s) converted_%s[i];" % (paramName, paramConvertToType, paramName))
493 conversionCodeIncoming.append(" }")
494 elif paramValueConversion == "some":
495 # We'll need a conditional variable to keep track of
496 # whether we're converting values or not.
497 if (" int convert_%s_value = 1;" % paramName) not in variables:
498 variables.append(" int convert_%s_value = 1;" % paramName)
499
500 # Write code based on that conditional.
501 conversionCodeIncoming.append(" if (convert_%s_value) {" % paramName)
502 conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
503 conversionCodeIncoming.append(" %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
504 conversionCodeIncoming.append(" }")
505 conversionCodeIncoming.append(" } else {")
506 conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
507 conversionCodeIncoming.append(" %s[i] = (%s) converted_%s[i];" % (paramName, paramBaseType, paramName))
508 conversionCodeIncoming.append(" }")
509 conversionCodeIncoming.append(" }")
510 else: # paramValueConversion == "all"
511 conversionCodeIncoming.append(" for (i = 0; i < n_%s; i++) {" % paramName)
512 conversionCodeIncoming.append(" %s[i] = %s;" % (paramName, ConvertValue("converted_%s[i]" % paramName, paramConvertToType, paramBaseType)))
513 conversionCodeIncoming.append(" }")
514
515 # Call strings. The unusual " ".join() call will join the
516 # array of parameter modifiers with spaces as separators.
517 passthroughDeclarationString += ", %s %s %s" % (paramConvertToType, " ".join(paramTypeModifiers), paramName)
518 passthroughCallString += ", converted_%s" % paramName
519
520 # endif conversion management
521
522 # Parameter checking. If the parameter has a specific list of
523 # valid values, we have to make sure that the passed-in values
524 # match these, or we make an error.
525 if len(paramValidValues) > 0:
526 # We're about to make a big switch statement with an
527 # error at the end. By default, the error is GL_INVALID_ENUM,
528 # unless we find a "case" statement in the middle with a
529 # non-GLenum value.
530 errorDefaultCase = "GL_INVALID_ENUM"
531
532 # This parameter has specific valid values. Make a big
533 # switch statement to handle it. Note that the original
534 # parameters are always what is checked, not the
535 # converted parameters.
536 switchCode.append(" switch(%s) {" % paramName)
537
538 for valueIndex in range(len(paramValidValues)):
539 (paramValue, dependentVecSize, dependentParamName, dependentValidValues, errorCode, valueConvert) = paramValidValues[valueIndex]
540
541 # We're going to need information on the dependent param
542 # as well.
543 if dependentParamName:
544 depParamIndex = apiutil.FindParamIndex(params, dependentParamName)
545 if depParamIndex == None:
546 sys.stderr.write("%s: can't find dependent param '%s' for function '%s'\n" % (program, dependentParamName, funcName))
547
548 (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = params[depParamIndex]
549 else:
550 (depParamName, depParamType, depParamMaxVecSize, depParamConvertToType, depParamValidValues, depParamValueConversion) = (None, None, None, None, [], None)
551
552 # This is a sneaky trick. It's valid syntax for a parameter
553 # that is *not* going to be converted to be declared
554 # with a dependent vector size; but in this case, the
555 # dependent vector size is unused and unnecessary.
556 # So check for this and ignore the dependent vector size
557 # if the parameter is not going to be converted.
558 if depParamConvertToType:
559 usedDependentVecSize = dependentVecSize
560 else:
561 usedDependentVecSize = None
562
563 # We'll peek ahead at the next parameter, to see whether
564 # we can combine cases
565 if valueIndex + 1 < len(paramValidValues) :
566 (nextParamValue, nextDependentVecSize, nextDependentParamName, nextDependentValidValues, nextErrorCode, nextValueConvert) = paramValidValues[valueIndex + 1]
567 if depParamConvertToType:
568 usedNextDependentVecSize = nextDependentVecSize
569 else:
570 usedNextDependentVecSize = None
571
572 # Create a case for this value. As a mnemonic,
573 # if we have a dependent vector size that we're ignoring,
574 # add it as a comment.
575 if usedDependentVecSize == None and dependentVecSize != None:
576 switchCode.append(" case %s: /* size %s */" % (paramValue, dependentVecSize))
577 else:
578 switchCode.append(" case %s:" % paramValue)
579
580 # If this is not a GLenum case, then switch our error
581 # if no value is matched to be GL_INVALID_VALUE instead
582 # of GL_INVALID_ENUM. (Yes, this does get confused
583 # if there are both values and GLenums in the same
584 # switch statement, which shouldn't happen.)
585 if paramValue[0:3] != "GL_":
586 errorDefaultCase = "GL_INVALID_VALUE"
587
588 # If all the remaining parameters are identical to the
589 # next set, then we're done - we'll just create the
590 # official code on the next pass through, and the two
591 # cases will share the code.
592 if valueIndex + 1 < len(paramValidValues) and usedDependentVecSize == usedNextDependentVecSize and dependentParamName == nextDependentParamName and dependentValidValues == nextDependentValidValues and errorCode == nextErrorCode and valueConvert == nextValueConvert:
593 continue
594
595 # Otherwise, we'll have to generate code for this case.
596 # Start off with a check: if there is a dependent parameter,
597 # and a list of valid values for that parameter, we need
598 # to generate an error if something other than one
599 # of those values is passed.
600 if len(dependentValidValues) > 0:
601 conditional=""
602
603 # If the parameter being checked is actually an array,
604 # check only its first element.
605 if depParamMaxVecSize == 0:
606 valueToCheck = dependentParamName
607 else:
608 valueToCheck = "%s[0]" % dependentParamName
609
610 for v in dependentValidValues:
611 conditional += " && %s != %s" % (valueToCheck, v)
612 switchCode.append(" if (%s) {" % conditional[4:])
613 if errorCode == None:
614 errorCode = "GL_INVALID_ENUM"
615 switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=0x%s)", %s);' % (errorCode, funcName, paramName, "%x", paramName))
616 switchCode.append(" %s;" % errorReturn)
617 switchCode.append(" }")
618 # endif there are dependent valid values
619
620 # The dependent parameter may require conditional
621 # value conversion. If it does, and we don't want
622 # to convert values, we'll have to generate code for that
623 if depParamValueConversion == "some" and valueConvert == "noconvert":
624 switchCode.append(" convert_%s_value = 0;" % dependentParamName)
625
626 # If there's a dependent vector size for this parameter
627 # that we're actually going to use (i.e. we need conversion),
628 # mark it.
629 if usedDependentVecSize:
630 switchCode.append(" n_%s = %s;" % (dependentParamName, dependentVecSize))
631
632 # In all cases, break out of the switch if any valid
633 # value is found.
634 switchCode.append(" break;")
635
636
637 # Need a default case to catch all the other, invalid
638 # parameter values. These will all generate errors.
639 switchCode.append(" default:")
640 if errorCode == None:
641 errorCode = "GL_INVALID_ENUM"
642 formatString = GetFormatString(paramType)
643 if formatString == None:
644 switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s)");' % (errorCode, funcName, paramName))
645 else:
646 switchCode.append(' _mesa_error(_mesa_get_current_context(), %s, "gl%s(%s=%s)", %s);' % (errorCode, funcName, paramName, formatString, paramName))
647 switchCode.append(" %s;" % errorReturn)
648
649 # End of our switch code.
650 switchCode.append(" }")
651
652 # endfor every recognized parameter value
653
654 # endfor every param
655
656 # Here, the passthroughDeclarationString and passthroughCallString
657 # are complete; remove the extra ", " at the front of each.
658 passthroughDeclarationString = passthroughDeclarationString[2:]
659 passthroughCallString = passthroughCallString[2:]
660
661 # The Mesa functions are scattered across all the Mesa
662 # header files. The easiest way to manage declarations
663 # is to create them ourselves.
664 if funcName not in allSpecials:
665 print "extern %s GLAPIENTRY %s(%s);" % (returnType, passthroughFuncName, passthroughDeclarationString)
666
667 # A function may be a core function (i.e. it exists in
668 # the core specification), a core addition (extension
669 # functions added officially to the core), a required
670 # extension (usually an extension for an earlier version
671 # that has been officially adopted), or an optional extension.
672 #
673 # Core functions have a simple category (e.g. "GLES1.1");
674 # we generate only a simple callback for them.
675 #
676 # Core additions have two category listings, one simple
677 # and one compound (e.g. ["GLES1.1", "GLES1.1:OES_fixed_point"]).
678 # We generate the core function, and also an extension function.
679 #
680 # Required extensions and implemented optional extensions
681 # have a single compound category "GLES1.1:OES_point_size_array".
682 # For these we generate just the extension function.
683 for categorySpec in apiutil.Categories(funcName):
684 compoundCategory = categorySpec.split(":")
685
686 # This category isn't for us, if the base category doesn't match
687 # our version
688 if compoundCategory[0] != version:
689 continue
690
691 # Otherwise, determine if we're writing code for a core
692 # function (no suffix) or an extension function.
693 if len(compoundCategory) == 1:
694 # This is a core function
695 extensionName = None
696 fullFuncName = "_es_" + funcName
697 else:
698 # This is an extension function. We'll need to append
699 # the extension suffix.
700 extensionName = compoundCategory[1]
701 extensionSuffix = extensionName.split("_")[0]
702 fullFuncName = "_es_" + funcName + extensionSuffix
703
704 # Now the generated function. The text used to mark an API-level
705 # function, oddly, is version-specific.
706 if extensionName:
707 print "/* Extension %s */" % extensionName
708
709 if funcName in allSpecials:
710 print "/* this function is special and is defined elsewhere */"
711 print "extern %s %s(%s);" % (returnType, fullFuncName, declarationString)
712 print
713 continue
714
715 print "static %s %s(%s)" % (returnType, fullFuncName, declarationString)
716 print "{"
717
718 # Start printing our code pieces. Start with any local
719 # variables we need. This unusual syntax joins the
720 # lines in the variables[] array with the "\n" separator.
721 if len(variables) > 0:
722 print "\n".join(variables) + "\n"
723
724 # If there's any sort of parameter checking or variable
725 # array sizing, the switch code will contain it.
726 if len(switchCode) > 0:
727 print "\n".join(switchCode) + "\n"
728
729 # In the case of an outgoing conversion (i.e. parameters must
730 # be converted before calling the underlying Mesa function),
731 # use the appropriate code.
732 if "get" not in props and len(conversionCodeOutgoing) > 0:
733 print "\n".join(conversionCodeOutgoing) + "\n"
734
735 # Call the Mesa function. Note that there are very few functions
736 # that return a value (i.e. returnType is not "void"), and that
737 # none of them require incoming translation; so we're safe
738 # to generate code that directly returns in those cases,
739 # even though it's not completely independent.
740
741 if returnType == "void":
742 print " %s(%s);" % (passthroughFuncName, passthroughCallString)
743 else:
744 print " return %s(%s);" % (passthroughFuncName, passthroughCallString)
745
746 # If the function is one that returns values (i.e. "get" in props),
747 # it might return values of a different type than we need, that
748 # require conversion before passing back to the application.
749 if "get" in props and len(conversionCodeIncoming) > 0:
750 print "\n".join(conversionCodeIncoming)
751
752 # All done.
753 print "}"
754 print
755 # end for each category provided for a function
756
757 # end for each function
758
759 print "void"
760 print "_mesa_init_exec_table(struct _glapi_table *exec)"
761 print "{"
762 for func in keys:
763 for spec in apiutil.Categories(func):
764 ext = spec.split(":")
765 # version does not match
766 if ext.pop(0) != version:
767 continue
768 entry = func
769 if ext:
770 suffix = ext[0].split("_")[0]
771 entry += suffix
772 print " SET_%s(exec, _es_%s);" % (entry, entry)
773 print "}"