Enable the generation of server-side __glGetBooleanv_size and related
[mesa.git] / src / mesa / glapi / gl_XML.py
1 #!/usr/bin/python2
2
3 # (C) Copyright IBM Corporation 2004, 2005
4 # 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
28 from xml.sax import saxutils
29 from xml.sax import make_parser
30 from xml.sax.handler import feature_namespaces
31
32 import re
33
34 class glItem:
35 """Generic class on which all other API entity types are based."""
36
37 def __init__(self, tag_name, name, context):
38 self.name = name
39 self.category = context.get_category_define()
40 self.context = context
41 self.tag_name = tag_name
42
43 context.append(tag_name, self)
44 return
45
46 def startElement(self, name, attrs):
47 """Generic startElement handler.
48
49 The startElement handler is called for all elements except
50 the one that starts the object. For a foo element, the
51 XML "<foo><bar/></foo>" would cause the startElement handler
52 to be called once, but the endElement handler would be called
53 twice."""
54 return
55
56 def endElement(self, name):
57 """Generic endElement handler.
58
59 Generic endElement handler. Returns 1 if the tag containing
60 the object is complete. Otherwise 0 is returned. All
61 derived class endElement handlers should call this method. If
62 the name of the ending tag is the same as the tag that
63 started this object, the object is assumed to be complete.
64
65 This fails if a tag can contain another tag with the same
66 name. The XML "<foo><foo/><bar/></foo>" would fail. The
67 object would end before the bar tag was processed.
68
69 The endElement handler is called for every end element
70 associated with an object, even the element that started the
71 object. See the description of startElement an example."""
72
73 if name == self.tag_name:
74 return 1
75 else:
76 return 0
77
78 def get_category_define(self):
79 return self.category
80
81
82 class glEnum( glItem ):
83 """Subclass of glItem for representing GL enumerants.
84
85 This class is not complete, and is not really used yet."""
86
87 def __init__(self, context, name, attrs):
88 self.value = int(attrs.get('value', "0x0000"), 0)
89
90 enum_name = "GL_" + attrs.get('name', None)
91 glItem.__init__(self, name, enum_name, context)
92
93 temp = attrs.get('count', None)
94 self.default_count = 0
95 if temp == "?":
96 self.default_count = -1
97 elif temp:
98 try:
99 c = int(temp)
100 except Exception,e:
101 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
102
103 self.default_count = c
104 return
105
106
107 def process_attributes(self, attrs):
108 name = attrs.get('name', None)
109
110 temp = attrs.get('count', None)
111 if temp == None:
112 c = self.default_count
113 else:
114 try:
115 c = int(temp)
116 except Exception,e:
117 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
118
119 mode_str = attrs.get('mode', "set")
120 if mode_str == "set":
121 mode = 1
122 elif mode_str == "get":
123 mode = 0
124 else:
125 raise RuntimeError("Invalid mode '%s' for function '%s' in enum '%s'." % (mode_str, self.context.name, self.name))
126
127 return [name, c, mode]
128
129
130 class glType( glItem ):
131 """Subclass of glItem for representing GL types."""
132
133 def __init__(self, context, name, attrs):
134 self.size = int(attrs.get('size', "0"))
135 self.glx_name = attrs.get('glx_name', "")
136
137 type_name = "GL" + attrs.get('name', None)
138 glItem.__init__(self, name, type_name, context)
139
140
141 class glParameter( glItem ):
142 """Parameter of a glFunction."""
143 p_type = None
144 p_type_string = ""
145 p_count = 0
146 counter = None
147 is_output = 0
148 is_counter = 0
149 is_pointer = 0
150
151 def __init__(self, context, name, attrs):
152 p_name = attrs.get('name', None)
153 self.p_type_string = attrs.get('type', None)
154
155 temp = attrs.get('variable_param', None)
156 if temp:
157 self.count_parameter_list = temp.replace( ' ', '' ).split( ',' )
158 else:
159 self.count_parameter_list = []
160
161 self.p_type = context.context.find_type(self.p_type_string)
162 if self.p_type == None:
163 raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
164
165
166 # The count tag can be either a numeric string or the name of
167 # a variable. If it is the name of a variable, the int(c)
168 # statement will throw an exception, and the except block will
169 # take over.
170
171 c = attrs.get('count', "0")
172 try:
173 self.p_count = int(c)
174 self.counter = None
175 except Exception,e:
176 self.p_count = 0
177 self.counter = c
178
179 self.count_scale = int(attrs.get('count_scale', "1"))
180
181 if attrs.get('counter', "false") == "true":
182 self.is_counter = 1
183 else:
184 self.is_counter = 0
185
186 if attrs.get('output', "false") == "true":
187 self.is_output = 1
188 else:
189 self.is_output = 0
190
191
192 # Pixel data has special parameters.
193
194 self.width = attrs.get('img_width', None)
195 self.height = attrs.get('img_height', None)
196 self.depth = attrs.get('img_depth', None)
197 self.extent = attrs.get('img_extent', None)
198
199 self.img_xoff = attrs.get('img_xoff', None)
200 self.img_yoff = attrs.get('img_yoff', None)
201 self.img_zoff = attrs.get('img_zoff', None)
202 self.img_woff = attrs.get('img_woff', None)
203
204 self.img_format = attrs.get('img_format', None)
205 self.img_type = attrs.get('img_type', None)
206 self.img_target = attrs.get('img_target', None)
207
208 pad = attrs.get('img_pad_dimensions', "false")
209 if pad == "true":
210 self.img_pad_dimensions = 1
211 else:
212 self.img_pad_dimensions = 0
213
214
215 null_flag = attrs.get('img_null_flag', "false")
216 if null_flag == "true":
217 self.img_null_flag = 1
218 else:
219 self.img_null_flag = 0
220
221 send_null = attrs.get('img_send_null', "false")
222 if send_null == "true":
223 self.img_send_null = 1
224 else:
225 self.img_send_null = 0
226
227
228
229 if self.p_count > 0 or self.counter or self.count_parameter_list:
230 has_count = 1
231 else:
232 has_count = 0
233
234
235 # If there is a * anywhere in the parameter's type, then it
236 # is a pointer.
237
238 if re.compile("[*]").search(self.p_type_string):
239 # We could do some other validation here. For
240 # example, an output parameter should not be const,
241 # but every non-output parameter should.
242
243 self.is_pointer = 1;
244 else:
245 # If a parameter is not a pointer, then there cannot
246 # be an associated count (either fixed size or
247 # variable) and the parameter cannot be an output.
248
249 if has_count or self.is_output:
250 raise RuntimeError("Non-pointer type has count or is output.")
251 self.is_pointer = 0;
252
253 glItem.__init__(self, name, p_name, context)
254 return
255
256
257 def is_variable_length_array(self):
258 """Determine if a parameter is a variable length array.
259
260 A parameter is considered to be a variable length array if
261 its size depends on the value of another parameter that is
262 an enumerant. The params parameter to glTexEnviv is an
263 example of a variable length array parameter. Arrays whose
264 size depends on a count variable, such as the lists parameter
265 to glCallLists, are not variable length arrays in this
266 sense."""
267
268 return self.count_parameter_list or self.counter or self.width
269
270
271 def is_array(self):
272 return self.is_pointer
273
274
275 def count_string(self):
276 """Return a string representing the number of items
277
278 Returns a string representing the number of items in a
279 parameter. For scalar types this will always be "1". For
280 vector types, it will depend on whether or not it is a
281 fixed length vector (like the parameter of glVertex3fv),
282 a counted length (like the vector parameter of
283 glDeleteTextures), or a general variable length vector."""
284
285 if self.is_array():
286 if self.count_parameter_list:
287 return "compsize"
288 elif self.counter != None:
289 return self.counter
290 else:
291 return str(self.p_count)
292 else:
293 return "1"
294
295
296 def size(self):
297 if self.count_parameter_list or self.counter or self.width or self.is_output:
298 return 0
299 elif self.p_count == 0:
300 return self.p_type.size
301 else:
302 return self.p_type.size * self.p_count * self.count_scale
303
304 def size_string(self):
305 s = self.size()
306 if s == 0:
307 a_prod = "compsize"
308 b_prod = self.p_type.size
309
310 # Handle functions like glCompressedTexImage2D that
311 # have a counted 'void *' parameter.
312
313 if b_prod == 0: b_prod = 1
314
315 if not self.count_parameter_list and self.counter != None:
316 if self.count_scale > 1:
317 a_prod = '(%s * %u)' % (self.counter, self.count_scale)
318 else:
319 a_prod = self.counter
320 elif self.count_parameter_list and self.counter == None:
321 pass
322 elif self.count_parameter_list and self.counter != None:
323 if self.count_scale > 1:
324 b_prod = '(%s * %u)' % (self.counter, self.count_scale)
325 else:
326 b_prod = self.counter
327 elif self.width:
328 return "compsize"
329 else:
330 raise RuntimeError("Parameter '%s' to function '%s' has size 0." % (self.name, self.context.name))
331
332 return "(%s * %s)" % (a_prod, b_prod)
333 else:
334 return str(s)
335
336
337 class glParameterIterator:
338 """Class to iterate over a list of glParameters.
339
340 Objects of this class are returned by the parameterIterator method of
341 the glFunction class. They are used to iterate over the list of
342 parameters to the function."""
343
344 def __init__(self, data):
345 self.data = data
346 self.index = 0
347
348 def __iter__(self):
349 return self
350
351 def next(self):
352 if self.index == len( self.data ):
353 raise StopIteration
354 i = self.index
355 self.index += 1
356 return self.data[i]
357
358
359 class glFunction( glItem ):
360 def __init__(self, context, name, attrs):
361 self.fn_alias = attrs.get('alias', None)
362 self.fn_parameters = []
363 self.image = None
364 self.count_parameter_list = []
365 self.fn_return_type = "void"
366
367 temp = attrs.get('offset', None)
368 if temp == None or temp == "?":
369 self.fn_offset = -1
370 else:
371 self.fn_offset = int(temp)
372
373 fn_name = attrs.get('name', None)
374 if self.fn_alias != None:
375 self.real_name = self.fn_alias
376 else:
377 self.real_name = fn_name
378
379 self.parameters_by_name = {}
380 self.variable_length_parameters = []
381
382 glItem.__init__(self, name, fn_name, context)
383 return
384
385
386 def parameterIterator(self):
387 return glParameterIterator(self.fn_parameters)
388
389
390 def startElement(self, name, attrs):
391 if name == "param":
392 try:
393 self.context.factory.create(self, name, attrs)
394 except RuntimeError:
395 print "Error with parameter '%s' in function '%s'." \
396 % (attrs.get('name','(unknown)'), self.name)
397 raise
398 elif name == "return":
399 self.set_return_type(attrs.get('type', None))
400
401
402 def endElement(self, name):
403 """Handle the end of a <function> element.
404
405 At the end of a <function> element, there is some semantic
406 checking that can be done. This prevents some possible
407 exceptions from being thrown elsewhere in the code.
408 """
409
410 if name == "function":
411 for p in self.variable_length_parameters:
412 if p.counter:
413 counter = self.parameters_by_name[ p.counter ]
414 if not self.parameters_by_name.has_key( p.counter ):
415 raise RuntimeError("Parameter '%s' of function '%s' has counter '%s', but function has no such parameter." % (p.name, self.name, p.counter))
416 elif not self.parameters_by_name[ p.counter ].is_counter:
417 raise RuntimeError("Parameter '%s' of function '%s' has counter '%s', but '%s' is not marked as a counter." % (p.name, self.name, p.counter, p.counter))
418
419 for n in p.count_parameter_list:
420 if not self.parameters_by_name.has_key( n ):
421 raise RuntimeError("Parameter '%s' of function '%s' has size parameter '%s', but function has no such parameter." % (p.name, self.name, n))
422
423 return 1
424 else:
425 return 0
426
427
428 def append(self, tag_name, p):
429 if tag_name != "param":
430 raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
431
432 if p.width:
433 self.image = p
434
435 self.fn_parameters.append(p)
436 if p.count_parameter_list != []:
437 self.count_parameter_list.extend( p.count_parameter_list )
438
439 if p.is_variable_length_array():
440 self.variable_length_parameters.append(p)
441
442 self.parameters_by_name[ p.name ] = p
443
444
445 def set_return_type(self, t):
446 self.fn_return_type = t
447
448
449 def get_parameter_string(self):
450 arg_string = ""
451 comma = ""
452 for p in glFunction.parameterIterator(self):
453 arg_string = arg_string + comma + p.p_type_string + " " + p.name
454 comma = ", "
455
456 if arg_string == "":
457 arg_string = "void"
458
459 return arg_string
460
461
462 class glItemFactory:
463 """Factory to create objects derived from glItem."""
464
465 def create(self, context, name, attrs):
466 if name == "function":
467 return glFunction(context, name, attrs)
468 elif name == "type":
469 return glType(context, name, attrs)
470 elif name == "enum":
471 return glEnum(context, name, attrs)
472 elif name == "param":
473 return glParameter(context, name, attrs)
474 else:
475 return None
476
477
478 class glFunctionIterator:
479 """Class to iterate over a list of glFunctions
480
481 Objects of this classare returned by
482 FilterGLAPISpecBase::functionIterator. This default version
483 iterates over the functions in order of dispatch table offset. All
484 of the "true" functions are iterated first, followed by the alias
485 functions."""
486
487 def __init__(self, context):
488 self.context = context
489 self.keys = context.functions.keys()
490 self.keys.sort()
491
492 self.prevk = -1
493 self.direction = 1
494
495 for self.index in range(0, len(self.keys)):
496 if self.keys[ self.index ] >= 0: break
497
498 if self.index == len(self.keys):
499 self.direction = -1
500 self.index -= 1
501
502 self.split = self.index - 1
503 return
504
505
506 def __iter__(self):
507 return self
508
509
510 def next(self):
511 if self.index < 0:
512 raise StopIteration
513
514 k = self.keys[ self.index ]
515
516 #if self.context.functions[k].fn_alias == None:
517 # if k != self.prevk + 1:
518 # print 'Missing offset %d' % (prevk)
519 # self.prevk = int(k)
520
521 self.index += self.direction
522
523 if self.index == len(self.keys):
524 self.index = self.split
525 self.direction = -1
526
527 return self.context.functions[k]
528
529
530 class FilterGLAPISpecBase(saxutils.XMLFilterBase):
531 name = "a"
532 license = "The license for this file is unspecified."
533 next_alias = -2
534 current_object = None
535
536 def __init__(self):
537 saxutils.XMLFilterBase.__init__(self)
538 self.functions = {}
539 self.types = {}
540 self.functions_by_name = {}
541 self.factory = glItemFactory()
542 self.header_tag = None
543 self.undef_list = []
544 self.current_category = ""
545
546
547 def find_type(self,type_name):
548 for t in self.types:
549 if re.compile(t).search(type_name):
550 return self.types[t]
551 print "Unable to find base type matching \"%s\"." % (type_name)
552 return None
553
554
555 def find_function(self,function_name):
556 return self.functions_by_name[function_name]
557
558
559 def functionIterator(self):
560 return glFunctionIterator(self)
561
562
563 def printFunctions(self):
564 for f in self.functionIterator():
565 self.printFunction(f)
566 return
567
568
569 def printHeader(self):
570 """Print the header associated with all files and call the printRealHeader method."""
571
572 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
573 % (self.name)
574 print ''
575 print '/*'
576 print ' * ' + self.license.replace('\n', '\n * ')
577 print ' */'
578 print ''
579 if self.header_tag:
580 print '#if !defined( %s )' % (self.header_tag)
581 print '# define %s' % (self.header_tag)
582 print ''
583 self.printRealHeader();
584 return
585
586
587 def printFooter(self):
588 """Print the header associated with all files and call the printRealFooter method."""
589
590 self.printFunctions()
591 self.printRealFooter()
592 if self.header_tag:
593 if self.undef_list:
594 print ''
595 for u in self.undef_list:
596 print "# undef %s" % (u)
597 print ''
598 print '#endif /* !defined( %s ) */' % (self.header_tag)
599
600
601 def get_category_define(self):
602 """Convert the category name to the #define that would be found in glext.h"""
603
604 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
605 s = self.current_category
606 return "GL_VERSION_" + s.replace(".", "_")
607 else:
608 return self.current_category
609
610
611 def append(self, object_type, obj):
612 if object_type == "function":
613 # If the function is not an alias and has a negative
614 # offset, then we do not need to track it. These are
615 # functions that don't have an assigned offset
616
617 if obj.fn_offset >= 0 or obj.fn_alias != None:
618 if obj.fn_offset >= 0:
619 index = obj.fn_offset
620 else:
621 index = self.next_alias
622 self.next_alias -= 1
623
624 self.functions[index] = obj
625
626 self.functions_by_name[obj.name] = obj
627
628 elif object_type == "type":
629 self.types[obj.name] = obj
630
631 return
632
633
634 def startElement(self, name, attrs):
635 """Start a new element in the XML stream.
636
637 Starts a new element. There are three types of elements that
638 are specially handled by this function. When a "category"
639 element is encountered, the name of the category is saved.
640 If an element is encountered and no API object is
641 in-progress, a new object is created using the API factory.
642 Any future elements, until that API object is closed, are
643 passed to the current objects startElement method.
644
645 This paradigm was chosen becuase it allows subclasses of the
646 basic API types (i.e., glFunction, glEnum, etc.) to handle
647 additional XML data, GLX protocol information, that the base
648 classes do not know about."""
649
650 if self.current_object != None:
651 self.current_object.startElement(name, attrs)
652 elif name == "category":
653 self.current_category = attrs.get('name', "")
654 elif name == "include":
655 self.next_include = attrs.get('name', "")
656 else:
657 self.current_object = self.factory.create(self, name, attrs)
658 return
659
660
661 def endElement(self, name):
662 if self.current_object != None:
663 if self.current_object.endElement(name):
664 self.current_object = None
665 elif name == "include":
666 parser = make_parser()
667 parser.setFeature(feature_namespaces, 0)
668 parser.setContentHandler(self)
669
670 f = open(self.next_include)
671 parser.parse(f)
672
673 return
674
675
676 def printPure(self):
677 self.undef_list.append("PURE")
678 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
679 # define PURE __attribute__((pure))
680 # else
681 # define PURE
682 # endif"""
683
684 def printFastcall(self):
685 self.undef_list.append("FASTCALL")
686 print """# if defined(__i386__) && defined(__GNUC__)
687 # define FASTCALL __attribute__((fastcall))
688 # else
689 # define FASTCALL
690 # endif"""
691
692 def printVisibility(self, S, s):
693 self.undef_list.append(S)
694 print """# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
695 # define %s __attribute__((visibility("%s")))
696 # else
697 # define %s
698 # endif""" % (S, s, S)
699
700 def printNoinline(self):
701 self.undef_list.append("NOINLINE")
702 print """# if defined(__GNUC__)
703 # define NOINLINE __attribute__((noinline))
704 # else
705 # define NOINLINE
706 # endif"""
707
708 def printHaveAlias(self):
709 self.undef_list.append("HAVE_ALIAS")
710 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
711 # define HAVE_ALIAS
712 # endif"""
713
714 def printFunction(self,offset):
715 """Print a single function.
716
717 In the base class, this function is empty. All derived
718 classes should over-ride this function."""
719 return
720
721
722 def printRealHeader(self):
723 """Print the "real" header for the created file.
724
725 In the base class, this function is empty. All derived
726 classes should over-ride this function."""
727 return
728
729
730 def printRealFooter(self):
731 """Print the "real" footer for the created file.
732
733 In the base class, this function is empty. All derived
734 classes should over-ride this function."""
735 return