blob: b7a7388400dd261b303d3239998362ecdf134558 [file] [log] [blame]
Ian Romanick66a55482005-06-21 23:42:43 +00001#!/usr/bin/env python
Ian Romanick73f59b02004-05-18 18:33:40 +00002
Ian Romanick5f1f2292005-01-07 02:39:09 +00003# (C) Copyright IBM Corporation 2004, 2005
Ian Romanick73f59b02004-05-18 18:33:40 +00004# All Rights Reserved.
5#
6# Permission is hereby granted, free of charge, to any person obtaining a
7# copy of this software and associated documentation files (the "Software"),
8# to deal in the Software without restriction, including without limitation
9# on the rights to use, copy, modify, merge, publish, distribute, sub
10# license, and/or sell copies of the Software, and to permit persons to whom
11# the Software is furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice (including the next
14# paragraph) shall be included in all copies or substantial portions of the
15# Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23# IN THE SOFTWARE.
24#
25# Authors:
26# Ian Romanick <idr@us.ibm.com>
27
Ian Romanick66a55482005-06-21 23:42:43 +000028import libxml2
29import re, sys, string
30import typeexpr
Ian Romanick73f59b02004-05-18 18:33:40 +000031
Ian Romanick73f59b02004-05-18 18:33:40 +000032
Ian Romanick66a55482005-06-21 23:42:43 +000033def parse_GL_API( file_name, factory = None ):
34 doc = libxml2.readFile( file_name, None, libxml2.XML_PARSE_XINCLUDE + libxml2.XML_PARSE_NOBLANKS + libxml2.XML_PARSE_DTDVALID + libxml2.XML_PARSE_DTDATTR + libxml2.XML_PARSE_DTDLOAD + libxml2.XML_PARSE_NOENT )
35 ret = doc.xincludeProcess()
36
37 if not factory:
38 factory = gl_item_factory()
39
40 api = factory.create_item( "api", None, None )
41 api.process_element( doc )
42
Ian Romanickbf83e652006-08-24 20:14:45 +000043 # After the XML has been processed, we need to go back and assign
44 # dispatch offsets to the functions that request that their offsets
45 # be assigned by the scripts. Typically this means all functions
46 # that are not part of the ABI.
Ian Romanickbf83e652006-08-24 20:14:45 +000047
Ian Romanickeaeaaf62006-10-04 20:45:59 +000048 for func in api.functionIterateByCategory():
Ian Romanickbf83e652006-08-24 20:14:45 +000049 if func.assign_offset:
Ian Romanickeaeaaf62006-10-04 20:45:59 +000050 func.offset = api.next_offset;
51 api.next_offset += 1
Ian Romanickbf83e652006-08-24 20:14:45 +000052
Ian Romanick66a55482005-06-21 23:42:43 +000053 doc.freeDoc()
54
55 return api
56
57
58def is_attr_true( element, name ):
Ian Romanick73b4c1b2005-04-14 23:00:34 +000059 """Read a name value from an element's attributes.
60
61 The value read from the attribute list must be either 'true' or
62 'false'. If the value is 'false', zero will be returned. If the
63 value is 'true', non-zero will be returned. An exception will be
64 raised for any other value."""
65
Ian Romanick66a55482005-06-21 23:42:43 +000066 value = element.nsProp( name, None )
Ian Romanick73b4c1b2005-04-14 23:00:34 +000067 if value == "true":
68 return 1
69 elif value == "false":
70 return 0
71 else:
72 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
73
74
Ian Romanick66a55482005-06-21 23:42:43 +000075class gl_print_base:
76 """Base class of all API pretty-printers.
Ian Romanick93d2d542005-04-18 19:42:23 +000077
Ian Romanick66a55482005-06-21 23:42:43 +000078 In the model-view-controller pattern, this is the view. Any derived
79 class will want to over-ride the printBody, printRealHader, and
80 printRealFooter methods. Some derived classes may want to over-ride
81 printHeader and printFooter, or even Print (though this is unlikely).
Ian Romanick93d2d542005-04-18 19:42:23 +000082 """
Ian Romanickd03ab102005-04-18 21:30:20 +000083
Ian Romanick73f59b02004-05-18 18:33:40 +000084 def __init__(self):
Ian Romanick66a55482005-06-21 23:42:43 +000085 # Name of the script that is generating the output file.
86 # Every derived class should set this to the name of its
87 # source file.
88
89 self.name = "a"
90
91
92 # License on the *generated* source file. This may differ
93 # from the license on the script that is generating the file.
94 # Every derived class should set this to some reasonable
95 # value.
96 #
97 # See license.py for an example of a reasonable value.
98
99 self.license = "The license for this file is unspecified."
100
101
102 # The header_tag is the name of the C preprocessor define
103 # used to prevent multiple inclusion. Typically only
104 # generated C header files need this to be set. Setting it
105 # causes code to be generated automatically in printHeader
106 # and printFooter.
107
Ian Romanick16c3c742005-01-28 19:00:54 +0000108 self.header_tag = None
Ian Romanick66a55482005-06-21 23:42:43 +0000109
110
111 # List of file-private defines that must be undefined at the
112 # end of the file. This can be used in header files to define
113 # names for use in the file, then undefine them at the end of
114 # the header file.
115
Ian Romanickc2803582005-02-01 00:28:47 +0000116 self.undef_list = []
Ian Romanick66a55482005-06-21 23:42:43 +0000117 return
Ian Romanick73f59b02004-05-18 18:33:40 +0000118
Ian Romanicka9d033c2004-05-19 23:33:08 +0000119
Ian Romanick66a55482005-06-21 23:42:43 +0000120 def Print(self, api):
121 self.printHeader()
122 self.printBody(api)
123 self.printFooter()
Ian Romanick73f59b02004-05-18 18:33:40 +0000124 return
125
Ian Romanicka9d033c2004-05-19 23:33:08 +0000126
Ian Romanick73f59b02004-05-18 18:33:40 +0000127 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000128 """Print the header associated with all files and call the printRealHeader method."""
129
Ian Romanick73f59b02004-05-18 18:33:40 +0000130 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
131 % (self.name)
132 print ''
133 print '/*'
134 print ' * ' + self.license.replace('\n', '\n * ')
135 print ' */'
136 print ''
Ian Romanick16c3c742005-01-28 19:00:54 +0000137 if self.header_tag:
138 print '#if !defined( %s )' % (self.header_tag)
139 print '# define %s' % (self.header_tag)
140 print ''
Ian Romanick73f59b02004-05-18 18:33:40 +0000141 self.printRealHeader();
142 return
143
Ian Romanicka9d033c2004-05-19 23:33:08 +0000144
Ian Romanick73f59b02004-05-18 18:33:40 +0000145 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000146 """Print the header associated with all files and call the printRealFooter method."""
147
Ian Romanick73f59b02004-05-18 18:33:40 +0000148 self.printRealFooter()
Ian Romanick66a55482005-06-21 23:42:43 +0000149
150 if self.undef_list:
151 print ''
152 for u in self.undef_list:
153 print "# undef %s" % (u)
154
Ian Romanick16c3c742005-01-28 19:00:54 +0000155 if self.header_tag:
Ian Romanickc2803582005-02-01 00:28:47 +0000156 print ''
157 print '#endif /* !defined( %s ) */' % (self.header_tag)
Ian Romanick73f59b02004-05-18 18:33:40 +0000158
159
Ian Romanick73f59b02004-05-18 18:33:40 +0000160 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000161 """Print the "real" header for the created file.
162
163 In the base class, this function is empty. All derived
164 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000165 return
166
Ian Romanicka9d033c2004-05-19 23:33:08 +0000167
Ian Romanick73f59b02004-05-18 18:33:40 +0000168 def printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000169 """Print the "real" footer for the created file.
170
171 In the base class, this function is empty. All derived
172 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000173 return
Ian Romanick66a55482005-06-21 23:42:43 +0000174
175
176 def printPure(self):
177 """Conditionally define `PURE' function attribute.
178
179 Conditionally defines a preprocessor macro `PURE' that wraps
180 GCC's `pure' function attribute. The conditional code can be
181 easilly adapted to other compilers that support a similar
182 feature.
183
184 The name is also added to the file's undef_list.
185 """
186 self.undef_list.append("PURE")
187 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
188# define PURE __attribute__((pure))
189# else
190# define PURE
191# endif"""
192 return
193
194
195 def printFastcall(self):
196 """Conditionally define `FASTCALL' function attribute.
197
198 Conditionally defines a preprocessor macro `FASTCALL' that
199 wraps GCC's `fastcall' function attribute. The conditional
200 code can be easilly adapted to other compilers that support a
201 similar feature.
202
203 The name is also added to the file's undef_list.
204 """
205
206 self.undef_list.append("FASTCALL")
Brian Paulf468dfd2005-10-20 22:51:50 +0000207 print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
208# define FASTCALL __attribute__((fastcall))
209# else
210# define FASTCALL
211# endif"""
Ian Romanick66a55482005-06-21 23:42:43 +0000212 return
213
214
215 def printVisibility(self, S, s):
216 """Conditionally define visibility function attribute.
217
218 Conditionally defines a preprocessor macro name S that wraps
219 GCC's visibility function attribute. The visibility used is
220 the parameter s. The conditional code can be easilly adapted
221 to other compilers that support a similar feature.
222
223 The name is also added to the file's undef_list.
224 """
225
226 self.undef_list.append(S)
Adam Jacksonca1ac982005-08-26 17:50:39 +0000227 print """# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
Ian Romanick66a55482005-06-21 23:42:43 +0000228# define %s __attribute__((visibility("%s")))
229# else
230# define %s
231# endif""" % (S, s, S)
232 return
233
234
235 def printNoinline(self):
236 """Conditionally define `NOINLINE' function attribute.
237
238 Conditionally defines a preprocessor macro `NOINLINE' that
239 wraps GCC's `noinline' function attribute. The conditional
240 code can be easilly adapted to other compilers that support a
241 similar feature.
242
243 The name is also added to the file's undef_list.
244 """
245
246 self.undef_list.append("NOINLINE")
247 print """# if defined(__GNUC__)
248# define NOINLINE __attribute__((noinline))
249# else
250# define NOINLINE
251# endif"""
252 return
253
254
Ian Romanick66a55482005-06-21 23:42:43 +0000255def real_function_name(element):
256 name = element.nsProp( "name", None )
257 alias = element.nsProp( "alias", None )
258
259 if alias:
260 return alias
261 else:
262 return name
263
264
Ian Romanick5aafea02005-06-24 18:35:31 +0000265def real_category_name(c):
266 if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
267 return "GL_VERSION_" + c.replace(".", "_")
268 else:
269 return c
270
271
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000272def classify_category(name, number):
273 """Based on the category name and number, select a numerical class for it.
274
275 Categories are divided into four classes numbered 0 through 3. The
276 classes are:
277
278 0. Core GL versions, sorted by version number.
279 1. ARB extensions, sorted by extension number.
280 2. Non-ARB extensions, sorted by extension number.
281 3. Un-numbered extensions, sorted by extension name.
282 """
283
284 try:
285 core_version = float(name)
286 except Exception,e:
287 core_version = 0.0
288
289 if core_version > 0.0:
290 cat_type = 0
291 key = name
292 elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"):
293 cat_type = 1
294 key = int(number)
295 else:
296 if number != None:
297 cat_type = 2
298 key = int(number)
299 else:
300 cat_type = 3
301 key = name
302
303
304 return [cat_type, key]
305
306
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000307def create_parameter_string(parameters, include_names):
Ian Romanick5aafea02005-06-24 18:35:31 +0000308 """Create a parameter string from a list of gl_parameters."""
309
310 list = []
311 for p in parameters:
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000312 if include_names:
313 list.append( p.string() )
314 else:
315 list.append( p.type_string() )
Ian Romanick5aafea02005-06-24 18:35:31 +0000316
317 if len(list) == 0: list = ["void"]
318
319 return string.join(list, ", ")
320
321
Ian Romanick66a55482005-06-21 23:42:43 +0000322class gl_item:
323 def __init__(self, element, context):
324 self.context = context
Ian Romanick66a55482005-06-21 23:42:43 +0000325 self.name = element.nsProp( "name", None )
Ian Romanick5aafea02005-06-24 18:35:31 +0000326 self.category = real_category_name( element.parent.nsProp( "name", None ) )
Ian Romanick66a55482005-06-21 23:42:43 +0000327 return
328
329
330class gl_type( gl_item ):
331 def __init__(self, element, context):
332 gl_item.__init__(self, element, context)
333 self.size = int( element.nsProp( "size", None ), 0 )
334
335 te = typeexpr.type_expression( None )
336 tn = typeexpr.type_node()
337 tn.size = int( element.nsProp( "size", None ), 0 )
338 tn.integer = not is_attr_true( element, "float" )
339 tn.unsigned = is_attr_true( element, "unsigned" )
340 tn.name = "GL" + self.name
341 te.set_base_type_node( tn )
342
343 self.type_expr = te
344 return
345
346
347 def get_type_expression(self):
348 return self.type_expr
349
350
351class gl_enum( gl_item ):
352 def __init__(self, element, context):
353 gl_item.__init__(self, element, context)
354 self.value = int( element.nsProp( "value", None ), 0 )
355
356 temp = element.nsProp( "count", None )
357 if not temp or temp == "?":
358 self.default_count = -1
359 else:
360 try:
361 c = int(temp)
362 except Exception,e:
363 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
364
365 self.default_count = c
366
367 return
368
369
370 def priority(self):
371 """Calculate a 'priority' for this enum name.
372
373 When an enum is looked up by number, there may be many
374 possible names, but only one is the 'prefered' name. The
375 priority is used to select which name is the 'best'.
376
377 Highest precedence is given to core GL name. ARB extension
378 names have the next highest, followed by EXT extension names.
379 Vendor extension names are the lowest.
380 """
381
382 if self.name.endswith( "_BIT" ):
383 bias = 1
384 else:
385 bias = 0
386
387 if self.category.startswith( "GL_VERSION_" ):
388 priority = 0
389 elif self.category.startswith( "GL_ARB_" ):
390 priority = 2
391 elif self.category.startswith( "GL_EXT_" ):
392 priority = 4
393 else:
394 priority = 6
395
396 return priority + bias
397
398
399
400class gl_parameter:
401 def __init__(self, element, context):
402 self.name = element.nsProp( "name", None )
403
404 ts = element.nsProp( "type", None )
405 self.type_expr = typeexpr.type_expression( ts, context )
406
407 temp = element.nsProp( "variable_param", None )
408 if temp:
409 self.count_parameter_list = temp.split( ' ' )
410 else:
411 self.count_parameter_list = []
412
413 # The count tag can be either a numeric string or the name of
414 # a variable. If it is the name of a variable, the int(c)
415 # statement will throw an exception, and the except block will
416 # take over.
417
418 c = element.nsProp( "count", None )
419 try:
420 count = int(c)
421 self.count = count
422 self.counter = None
423 except Exception,e:
424 count = 1
425 self.count = 0
426 self.counter = c
427
428 self.count_scale = int(element.nsProp( "count_scale", None ))
429
430 elements = (count * self.count_scale)
431 if elements == 1:
432 elements = 0
433
434 #if ts == "GLdouble":
435 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
436 # print '/* # elements = %u */' % (elements)
437 self.type_expr.set_elements( elements )
438 #if ts == "GLdouble":
439 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
440
Brian Paul9540c9c2006-11-22 16:01:48 +0000441 self.is_client_only = is_attr_true( element, 'client_only' )
442 self.is_counter = is_attr_true( element, 'counter' )
443 self.is_output = is_attr_true( element, 'output' )
Ian Romanick66a55482005-06-21 23:42:43 +0000444
445
446 # Pixel data has special parameters.
447
448 self.width = element.nsProp('img_width', None)
449 self.height = element.nsProp('img_height', None)
450 self.depth = element.nsProp('img_depth', None)
451 self.extent = element.nsProp('img_extent', None)
452
453 self.img_xoff = element.nsProp('img_xoff', None)
454 self.img_yoff = element.nsProp('img_yoff', None)
455 self.img_zoff = element.nsProp('img_zoff', None)
456 self.img_woff = element.nsProp('img_woff', None)
457
458 self.img_format = element.nsProp('img_format', None)
459 self.img_type = element.nsProp('img_type', None)
460 self.img_target = element.nsProp('img_target', None)
461
462 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
463 self.img_null_flag = is_attr_true( element, 'img_null_flag' )
464 self.img_send_null = is_attr_true( element, 'img_send_null' )
465
466 return
467
468
469 def compatible(self, other):
470 return 1
471
472
473 def is_array(self):
474 return self.is_pointer()
475
476
477 def is_pointer(self):
478 return self.type_expr.is_pointer()
479
480
481 def is_image(self):
482 if self.width:
483 return 1
484 else:
485 return 0
486
487
488 def is_variable_length(self):
489 return len(self.count_parameter_list) or self.counter
490
491
492 def is_64_bit(self):
493 count = self.type_expr.get_element_count()
494 if count:
495 if (self.size() / count) == 8:
496 return 1
497 else:
498 if self.size() == 8:
499 return 1
500
501 return 0
502
503
504 def string(self):
505 return self.type_expr.original_string + " " + self.name
506
507
508 def type_string(self):
509 return self.type_expr.original_string
510
511
512 def get_base_type_string(self):
513 return self.type_expr.get_base_name()
514
515
516 def get_dimensions(self):
517 if not self.width:
518 return [ 0, "0", "0", "0", "0" ]
519
520 dim = 1
521 w = self.width
522 h = "1"
523 d = "1"
524 e = "1"
525
526 if self.height:
527 dim = 2
528 h = self.height
529
530 if self.depth:
531 dim = 3
532 d = self.depth
533
534 if self.extent:
535 dim = 4
536 e = self.extent
537
538 return [ dim, w, h, d, e ]
539
540
541 def get_stack_size(self):
542 return self.type_expr.get_stack_size()
543
544
545 def size(self):
546 if self.is_image():
547 return 0
548 else:
549 return self.type_expr.get_element_size()
550
551
552 def get_element_count(self):
553 c = self.type_expr.get_element_count()
554 if c == 0:
555 return 1
556
557 return c
558
559
560 def size_string(self, use_parens = 1):
561 s = self.size()
562 if self.counter or self.count_parameter_list:
563 list = [ "compsize" ]
564
565 if self.counter and self.count_parameter_list:
566 list.append( self.counter )
567 elif self.counter:
568 list = [ self.counter ]
569
570 if s > 1:
571 list.append( str(s) )
572
573 if len(list) > 1 and use_parens :
574 return "(%s)" % (string.join(list, " * "))
575 else:
576 return string.join(list, " * ")
577
578 elif self.is_image():
579 return "compsize"
580 else:
581 return str(s)
582
583
584 def format_string(self):
585 if self.type_expr.original_string == "GLenum":
586 return "0x%x"
587 else:
588 return self.type_expr.format_string()
589
590
591
592class gl_function( gl_item ):
593 def __init__(self, element, context):
594 self.context = context
595 self.name = None
596
597 self.entry_points = []
598 self.return_type = "void"
599 self.parameters = []
600 self.offset = -1
Ian Romanick5aafea02005-06-24 18:35:31 +0000601 self.initialized = 0
Ian Romanick66a55482005-06-21 23:42:43 +0000602 self.images = []
603
Ian Romanickbf83e652006-08-24 20:14:45 +0000604 self.assign_offset = 0
605
Ian Romanick7e9737b2006-08-26 21:26:55 +0000606 self.static_entry_points = []
607
Ian Romanick5aafea02005-06-24 18:35:31 +0000608 # Track the parameter string (for the function prototype)
609 # for each entry-point. This is done because some functions
610 # change their prototype slightly when promoted from extension
611 # to ARB extension to core. glTexImage3DEXT and glTexImage3D
612 # are good examples of this. Scripts that need to generate
613 # code for these differing aliases need to real prototype
614 # for each entry-point. Otherwise, they may generate code
615 # that won't compile.
616
617 self.parameter_strings = {}
618
Ian Romanick66a55482005-06-21 23:42:43 +0000619 self.process_element( element )
620
621 return
622
623
624 def process_element(self, element):
625 name = element.nsProp( "name", None )
626 alias = element.nsProp( "alias", None )
627
Ian Romanick7e9737b2006-08-26 21:26:55 +0000628 if is_attr_true(element, "static_dispatch"):
629 self.static_entry_points.append(name)
Ian Romanick4e4b5f42006-08-22 16:34:38 +0000630
Ian Romanick66a55482005-06-21 23:42:43 +0000631 self.entry_points.append( name )
632 if alias:
633 true_name = alias
634 else:
635 true_name = name
636
637 # Only try to set the offset when a non-alias
638 # entry-point is being processes.
639
640 offset = element.nsProp( "offset", None )
641 if offset:
642 try:
643 o = int( offset )
644 self.offset = o
645 except Exception, e:
646 self.offset = -1
Ian Romanickbf83e652006-08-24 20:14:45 +0000647 if offset == "assign":
648 self.assign_offset = 1
Ian Romanick66a55482005-06-21 23:42:43 +0000649
650
651 if not self.name:
652 self.name = true_name
653 elif self.name != true_name:
654 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
655
656
657 # There are two possible cases. The first time an entry-point
Ian Romanick5aafea02005-06-24 18:35:31 +0000658 # with data is seen, self.initialized will be 0. On that
Ian Romanick66a55482005-06-21 23:42:43 +0000659 # pass, we just fill in the data. The next time an
Ian Romanick5aafea02005-06-24 18:35:31 +0000660 # entry-point with data is seen, self.initialized will be 1.
Ian Romanick66a55482005-06-21 23:42:43 +0000661 # On that pass we have to make that the new values match the
662 # valuse from the previous entry-point.
663
Ian Romanick5aafea02005-06-24 18:35:31 +0000664 parameters = []
665 return_type = "void"
Ian Romanick66a55482005-06-21 23:42:43 +0000666 child = element.children
Ian Romanick5aafea02005-06-24 18:35:31 +0000667 while child:
668 if child.type == "element":
669 if child.name == "return":
670 return_type = child.nsProp( "type", None )
671 elif child.name == "param":
672 param = self.context.factory.create_item( "parameter", child, self.context)
673 parameters.append( param )
Ian Romanick66a55482005-06-21 23:42:43 +0000674
Ian Romanick5aafea02005-06-24 18:35:31 +0000675 child = child.next
Ian Romanick66a55482005-06-21 23:42:43 +0000676
Ian Romanick5aafea02005-06-24 18:35:31 +0000677
678 if self.initialized:
679 if self.return_type != return_type:
680 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
Ian Romanick66a55482005-06-21 23:42:43 +0000681
682 if len(parameters) != len(self.parameters):
683 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
684
685 for j in range(0, len(parameters)):
686 p1 = parameters[j]
687 p2 = self.parameters[j]
688 if not p1.compatible( p2 ):
689 raise RuntimeError( 'Parameter type mismatch in %s. "%s" was "%s", now "%s".' % (name, p2.name, p2.type_expr.original_string, p1.type_expr.original_string))
690
691
Ian Romanick5aafea02005-06-24 18:35:31 +0000692 if true_name == name or not self.initialized:
693 self.return_type = return_type
694 self.parameters = parameters
Ian Romanick66a55482005-06-21 23:42:43 +0000695
Ian Romanick66a55482005-06-21 23:42:43 +0000696 for param in self.parameters:
697 if param.is_image():
698 self.images.append( param )
699
700 if element.children:
Ian Romanick5aafea02005-06-24 18:35:31 +0000701 self.initialized = 1
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000702 self.parameter_strings[name] = create_parameter_string(parameters, 1)
Ian Romanick5aafea02005-06-24 18:35:31 +0000703 else:
704 self.parameter_strings[name] = None
Ian Romanick66a55482005-06-21 23:42:43 +0000705
706 return
707
708
709 def get_images(self):
710 """Return potentially empty list of input images."""
711 return self.images
712
713
714 def parameterIterator(self):
715 return self.parameters.__iter__();
716
717
Ian Romanick5aafea02005-06-24 18:35:31 +0000718 def get_parameter_string(self, entrypoint = None):
719 if entrypoint:
720 s = self.parameter_strings[ entrypoint ]
721 if s:
722 return s
723
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000724 return create_parameter_string( self.parameters, 1 )
Ian Romanick66a55482005-06-21 23:42:43 +0000725
Ian Romanickf3f51bc2006-10-11 22:37:14 +0000726 def get_called_parameter_string(self):
727 p_string = ""
728 comma = ""
729
730 for p in self.parameterIterator():
731 p_string = p_string + comma + p.name
732 comma = ", "
733
734 return p_string
735
736
Ian Romanick7e9737b2006-08-26 21:26:55 +0000737 def is_static_entry_point(self, name):
738 return name in self.static_entry_points
739
Ian Romanick258751f2006-08-28 17:40:45 +0000740 def dispatch_name(self):
741 if self.name in self.static_entry_points:
742 return self.name
743 else:
744 return "_dispatch_stub_%u" % (self.offset)
745
746 def static_name(self, name):
747 if name in self.static_entry_points:
748 return name
749 else:
750 return "_dispatch_stub_%u" % (self.offset)
751
Ian Romanick66a55482005-06-21 23:42:43 +0000752
753class gl_item_factory:
754 """Factory to create objects derived from gl_item."""
755
756 def create_item(self, item_name, element, context):
757 if item_name == "function":
758 return gl_function(element, context)
759 if item_name == "type":
760 return gl_type(element, context)
761 elif item_name == "enum":
762 return gl_enum(element, context)
763 elif item_name == "parameter":
764 return gl_parameter(element, context)
765 elif item_name == "api":
766 return gl_api(self)
767 else:
768 return None
769
770
771class gl_api:
772 def __init__(self, factory):
773 self.functions_by_name = {}
774 self.enums_by_name = {}
775 self.types_by_name = {}
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000776
Ian Romanick66a55482005-06-21 23:42:43 +0000777 self.category_dict = {}
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000778 self.categories = [{}, {}, {}, {}]
Ian Romanick66a55482005-06-21 23:42:43 +0000779
780 self.factory = factory
781
Ian Romanickbf83e652006-08-24 20:14:45 +0000782 self.next_offset = 0
783
Ian Romanick66a55482005-06-21 23:42:43 +0000784 typeexpr.create_initial_types()
785 return
786
787
788 def process_element(self, doc):
789 element = doc.children
790 while element.type != "element" or element.name != "OpenGLAPI":
791 element = element.next
792
793 if element:
794 self.process_OpenGLAPI(element)
795 return
796
797
798 def process_OpenGLAPI(self, element):
799 child = element.children
800 while child:
801 if child.type == "element":
802 if child.name == "category":
803 self.process_category( child )
804 elif child.name == "OpenGLAPI":
805 self.process_OpenGLAPI( child )
806
807 child = child.next
808
809 return
810
811
812 def process_category(self, cat):
813 cat_name = cat.nsProp( "name", None )
814 cat_number = cat.nsProp( "number", None )
815
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000816 [cat_type, key] = classify_category(cat_name, cat_number)
817 self.categories[cat_type][key] = [cat_name, cat_number]
818
Ian Romanick66a55482005-06-21 23:42:43 +0000819 child = cat.children
820 while child:
821 if child.type == "element":
822 if child.name == "function":
823 func_name = real_function_name( child )
824
Ian Romanick5aafea02005-06-24 18:35:31 +0000825 temp_name = child.nsProp( "name", None )
826 self.category_dict[ temp_name ] = [cat_name, cat_number]
827
Ian Romanick66a55482005-06-21 23:42:43 +0000828 if self.functions_by_name.has_key( func_name ):
829 func = self.functions_by_name[ func_name ]
830 func.process_element( child )
831 else:
832 func = self.factory.create_item( "function", child, self )
833 self.functions_by_name[ func_name ] = func
834
Ian Romanickbf83e652006-08-24 20:14:45 +0000835 if func.offset >= self.next_offset:
836 self.next_offset = func.offset + 1
837
Ian Romanick66a55482005-06-21 23:42:43 +0000838
839 elif child.name == "enum":
840 enum = self.factory.create_item( "enum", child, self )
841 self.enums_by_name[ enum.name ] = enum
842 elif child.name == "type":
843 t = self.factory.create_item( "type", child, self )
844 self.types_by_name[ "GL" + t.name ] = t
845
846
847 child = child.next
848
849 return
850
851
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000852 def functionIterateByCategory(self, cat = None):
853 """Iterate over functions by category.
854
855 If cat is None, all known functions are iterated in category
856 order. See classify_category for details of the ordering.
857 Within a category, functions are sorted by name. If cat is
858 not None, then only functions in that category are iterated.
859 """
860 lists = [{}, {}, {}, {}]
861
862 for func in self.functionIterateAll():
863 [cat_name, cat_number] = self.category_dict[func.name]
864
865 if (cat == None) or (cat == cat_name):
866 [func_cat_type, key] = classify_category(cat_name, cat_number)
867
868 if not lists[func_cat_type].has_key(key):
869 lists[func_cat_type][key] = {}
870
871 lists[func_cat_type][key][func.name] = func
872
873
874 functions = []
875 for func_cat_type in range(0,4):
876 keys = lists[func_cat_type].keys()
877 keys.sort()
878
879 for key in keys:
880 names = lists[func_cat_type][key].keys()
881 names.sort()
882
883 for name in names:
884 functions.append(lists[func_cat_type][key][name])
885
886 return functions.__iter__()
887
888
Ian Romanick66a55482005-06-21 23:42:43 +0000889 def functionIterateByOffset(self):
890 max_offset = -1
891 for func in self.functions_by_name.itervalues():
892 if func.offset > max_offset:
893 max_offset = func.offset
894
895
896 temp = [None for i in range(0, max_offset + 1)]
897 for func in self.functions_by_name.itervalues():
898 if func.offset != -1:
899 temp[ func.offset ] = func
900
901
902 list = []
903 for i in range(0, max_offset + 1):
904 if temp[i]:
905 list.append(temp[i])
906
907 return list.__iter__();
908
909
910 def functionIterateAll(self):
911 return self.functions_by_name.itervalues()
912
913
914 def enumIterateByName(self):
915 keys = self.enums_by_name.keys()
916 keys.sort()
917
918 list = []
919 for enum in keys:
920 list.append( self.enums_by_name[ enum ] )
921
922 return list.__iter__()
923
924
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000925 def categoryIterate(self):
926 """Iterate over categories.
927
928 Iterate over all known categories in the order specified by
929 classify_category. Each iterated value is a tuple of the
930 name and number (which may be None) of the category.
931 """
932
933 list = []
934 for cat_type in range(0,4):
935 keys = self.categories[cat_type].keys()
936 keys.sort()
937
938 for key in keys:
939 list.append(self.categories[cat_type][key])
940
941 return list.__iter__()
942
943
Ian Romanick66a55482005-06-21 23:42:43 +0000944 def get_category_for_name( self, name ):
945 if self.category_dict.has_key(name):
946 return self.category_dict[name]
947 else:
948 return ["<unknown category>", None]
949
950
951 def typeIterate(self):
952 return self.types_by_name.itervalues()
953
954
955 def find_type( self, type_name ):
956 if type_name in self.types_by_name:
957 return self.types_by_name[ type_name ].type_expr
958 else:
959 print "Unable to find base type matching \"%s\"." % (type_name)
960 return None