1db12f5c940dfb24baf4e34d2581863f85bfc718
[mesa.git] / src / mesa / glapi / glX_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 gl_XML
33 import license
34 import sys, getopt
35
36
37 def printPure():
38 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
39 # define PURE __attribute__((pure))
40 # else
41 # define PURE
42 # endif"""
43
44 def printFastcall():
45 print """# if defined(__i386__) && defined(__GNUC__)
46 # define FASTCALL __attribute__((fastcall))
47 # else
48 # define FASTCALL
49 # endif"""
50
51 def printVisibility(S, s):
52 print """# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
53 # define %s __attribute__((visibility("%s")))
54 # else
55 # define %s
56 # endif""" % (S, s, S)
57
58 def printNoinline():
59 print """# if defined(__GNUC__)
60 # define NOINLINE __attribute__((noinline))
61 # else
62 # define NOINLINE
63 # endif"""
64
65 def printHaveAlias():
66 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
67 # define HAVE_ALIAS
68 # endif"""
69
70 class glXItemFactory(gl_XML.glItemFactory):
71 """Factory to create GLX protocol oriented objects derived from glItem."""
72
73 def create(self, context, name, attrs):
74 if name == "function":
75 return glXFunction(context, name, attrs)
76 elif name == "enum":
77 return glXEnum(context, name, attrs)
78 elif name == "param":
79 return glXParameter(context, name, attrs)
80 else:
81 return gl_XML.glItemFactory.create(self, context, name, attrs)
82
83 class glXEnumFunction:
84 def __init__(self, name):
85 self.name = name
86 self.mode = 0
87 self.sig = None
88
89 # "enums" is a set of lists. The element in the set is the
90 # value of the enum. The list is the list of names for that
91 # value. For example, [0x8126] = {"POINT_SIZE_MIN",
92 # "POINT_SIZE_MIN_ARB", "POINT_SIZE_MIN_EXT",
93 # "POINT_SIZE_MIN_SGIS"}.
94
95 self.enums = {}
96
97 # "count" is indexed by count values. Each element of count
98 # is a list of index to "enums" that have that number of
99 # associated data elements. For example, [4] =
100 # {GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION,
101 # GL_AMBIENT_AND_DIFFUSE} (the enum names are used here,
102 # but the actual hexadecimal values would be in the array).
103
104 self.count = {}
105
106
107 def append(self, count, value, name):
108 if self.enums.has_key( value ):
109 self.enums[value].append(name)
110 else:
111 if not self.count.has_key(count):
112 self.count[count] = []
113
114 self.enums[value] = []
115 self.enums[value].append(name)
116 self.count[count].append(value)
117
118
119 def signature( self ):
120 if self.sig == None:
121 self.sig = ""
122 for i in self.count:
123 self.count[i].sort()
124 for e in self.count[i]:
125 self.sig += "%04x,%u," % (e, i)
126
127 return self.sig
128
129
130 def set_mode( self, mode ):
131 """Mark an enum-function as a 'set' function."""
132
133 self.mode = mode
134
135
136 def is_set( self ):
137 return self.mode
138
139
140 def PrintUsingTable(self):
141 """Emit the body of the __gl*_size function using a pair
142 of look-up tables and a mask. The mask is calculated such
143 that (e & mask) is unique for all the valid values of e for
144 this function. The result of (e & mask) is used as an index
145 into the first look-up table. If it matches e, then the
146 same entry of the second table is returned. Otherwise zero
147 is returned.
148
149 It seems like this should cause better code to be generated.
150 However, on x86 at least, the resulting .o file is about 20%
151 larger then the switch-statment version. I am leaving this
152 code in because the results may be different on other
153 platforms (e.g., PowerPC or x86-64)."""
154
155 return 0
156 count = 0
157 for a in self.enums:
158 count += 1
159
160 # Determine if there is some mask M, such that M = (2^N) - 1,
161 # that will generate unique values for all of the enums.
162
163 mask = 0
164 for i in [1, 2, 3, 4, 5, 6, 7, 8]:
165 mask = (1 << i) - 1
166
167 fail = 0;
168 for a in self.enums:
169 for b in self.enums:
170 if a != b:
171 if (a & mask) == (b & mask):
172 fail = 1;
173
174 if not fail:
175 break;
176 else:
177 mask = 0
178
179 if (mask != 0) and (mask < (2 * count)):
180 masked_enums = {}
181 masked_count = {}
182
183 for i in range(0, mask + 1):
184 masked_enums[i] = "0";
185 masked_count[i] = 0;
186
187 for c in self.count:
188 for e in self.count[c]:
189 i = e & mask
190 masked_enums[i] = '0x%04x /* %s */' % (e, self.enums[e][0])
191 masked_count[i] = c
192
193
194 print ' static const GLushort a[%u] = {' % (mask + 1)
195 for e in masked_enums:
196 print ' %s, ' % (masked_enums[e])
197 print ' };'
198
199 print ' static const GLubyte b[%u] = {' % (mask + 1)
200 for c in masked_count:
201 print ' %u, ' % (masked_count[c])
202 print ' };'
203
204 print ' const unsigned idx = (e & 0x%02xU);' % (mask)
205 print ''
206 print ' return (e == a[idx]) ? (GLint) b[idx] : 0;'
207 return 1;
208 else:
209 return 0;
210
211 def PrintUsingSwitch(self):
212 """Emit the body of the __gl*_size function using a
213 switch-statement."""
214
215 print ' switch( e ) {'
216
217 for c in self.count:
218 for e in self.count[c]:
219 first = 1
220
221 # There may be multiple enums with the same
222 # value. This happens has extensions are
223 # promoted from vendor-specific or EXT to
224 # ARB and to the core. Emit the first one as
225 # a case label, and emit the others as
226 # commented-out case labels.
227
228 for j in self.enums[e]:
229 if first:
230 print ' case %s:' % (j)
231 first = 0
232 else:
233 print '/* case %s:*/' % (j)
234
235 print ' return %u;' % (c)
236
237 print ' default: return 0;'
238 print ' }'
239
240
241 def Print(self, name):
242 print 'INTERNAL PURE FASTCALL GLint'
243 print '__gl%s_size( GLenum e )' % (name)
244 print '{'
245
246 if not self.PrintUsingTable():
247 self.PrintUsingSwitch()
248
249 print '}'
250 print ''
251
252
253
254 class glXEnum(gl_XML.glEnum):
255 def __init__(self, context, name, attrs):
256 gl_XML.glEnum.__init__(self, context, name, attrs)
257
258
259 def startElement(self, name, attrs):
260 if name == "size":
261 [n, c, mode] = self.process_attributes(attrs)
262
263 if not self.context.glx_enum_functions.has_key( n ):
264 f = glXEnumFunction( n )
265 f.set_mode( mode )
266 self.context.glx_enum_functions[ f.name ] = f
267
268 self.context.glx_enum_functions[ n ].append( c, self.value, self.name )
269 else:
270 gl_XML.glEnum.startElement(self, context, name, attrs)
271 return
272
273
274 class glXParameter(gl_XML.glParameter):
275 def __init__(self, context, name, attrs):
276 self.order = 1;
277 gl_XML.glParameter.__init__(self, context, name, attrs);
278
279
280 class glXParameterIterator:
281 """Class to iterate over a list of glXParameters.
282
283 Objects of this class are returned by the parameterIterator method of
284 the glXFunction class. They are used to iterate over the list of
285 parameters to the function."""
286
287 def __init__(self, data, skip_output, max_order):
288 self.data = data
289 self.index = 0
290 self.order = 0
291 self.skip_output = skip_output
292 self.max_order = max_order
293
294 def __iter__(self):
295 return self
296
297 def next(self):
298 if len( self.data ) == 0:
299 raise StopIteration
300
301 while 1:
302 if self.index == len( self.data ):
303 if self.order == self.max_order:
304 raise StopIteration
305 else:
306 self.order += 1
307 self.index = 0
308
309 i = self.index
310 self.index += 1
311
312 if self.data[i].order == self.order and not (self.data[i].is_output and self.skip_output):
313 return self.data[i]
314
315
316 class glXFunction(gl_XML.glFunction):
317 glx_rop = 0
318 glx_sop = 0
319 glx_vendorpriv = 0
320
321 # If this is set to true, it means that GLdouble parameters should be
322 # written to the GLX protocol packet in the order they appear in the
323 # prototype. This is different from the "classic" ordering. In the
324 # classic ordering GLdoubles are written to the protocol packet first,
325 # followed by non-doubles. NV_vertex_program was the first extension
326 # to break with this tradition.
327
328 glx_doubles_in_order = 0
329
330 vectorequiv = None
331 can_be_large = 0
332
333 def __init__(self, context, name, attrs):
334 self.vectorequiv = attrs.get('vectorequiv', None)
335 self.count_parameters = None
336 self.counter = None
337 self.output = None
338 self.can_be_large = 0
339 self.reply_always_array = 0
340
341 self.server_handcode = 0
342 self.client_handcode = 0
343 self.ignore = 0
344
345 gl_XML.glFunction.__init__(self, context, name, attrs)
346 return
347
348
349 def parameterIterator(self, skip_output, max_order):
350 return glXParameterIterator(self.fn_parameters, skip_output, max_order)
351
352
353 def startElement(self, name, attrs):
354 """Process elements within a function that are specific to GLX."""
355
356 if name == "glx":
357 self.glx_rop = int(attrs.get('rop', "0"))
358 self.glx_sop = int(attrs.get('sop', "0"))
359 self.glx_vendorpriv = int(attrs.get('vendorpriv', "0"))
360
361 # The 'handcode' attribute can be one of 'true',
362 # 'false', 'client', or 'server'.
363
364 handcode = attrs.get('handcode', "false")
365 if handcode == "false":
366 self.server_handcode = 0
367 self.client_handcode = 0
368 elif handcode == "true":
369 self.server_handcode = 1
370 self.client_handcode = 1
371 elif handcode == "client":
372 self.server_handcode = 0
373 self.client_handcode = 1
374 elif handcode == "server":
375 self.server_handcode = 1
376 self.client_handcode = 0
377 else:
378 raise RuntimeError('Invalid handcode mode "%s" in function "%s".' % (handcode, self.name))
379
380
381 if attrs.get('ignore', "false") == "true":
382 self.ignore = 1
383 else:
384 self.ignore = 0
385
386 if attrs.get('large', "false") == "true":
387 self.can_be_large = 1
388 else:
389 self.can_be_large = 0
390
391 if attrs.get('doubles_in_order', "false") == "true":
392 self.glx_doubles_in_order = 1
393 else:
394 self.glx_doubles_in_order = 0
395
396 if attrs.get('always_array', "false") == "true":
397 self.reply_always_array = 1
398 else:
399 self.reply_always_array = 0
400
401 else:
402 gl_XML.glFunction.startElement(self, name, attrs)
403
404
405 def endElement(self, name):
406 if name == "function":
407 # Mark any function that does not have GLX protocol
408 # defined as "ignore". This prevents bad things from
409 # happening when people add new functions to the GL
410 # API XML without adding any GLX section.
411 #
412 # This will also mark functions that don't have a
413 # dispatch offset at ignored.
414
415 if (self.fn_offset == -1 and not self.fn_alias) or not (self.client_handcode or self.server_handcode or self.glx_rop or self.glx_sop or self.glx_vendorpriv or self.vectorequiv or self.fn_alias):
416 #if not self.ignore:
417 # if self.fn_offset == -1:
418 # print '/* %s ignored becuase no offset assigned. */' % (self.name)
419 # else:
420 # print '/* %s ignored becuase no GLX opcode assigned. */' % (self.name)
421
422 self.ignore = 1
423
424 return gl_XML.glFunction.endElement(self, name)
425
426
427 def append(self, tag_name, p):
428 gl_XML.glFunction.append(self, tag_name, p)
429
430 if p.is_variable_length_array():
431 p.order = 2;
432 elif not self.glx_doubles_in_order and p.p_type.size == 8:
433 p.order = 0;
434
435 if p.p_count_parameters != None:
436 self.count_parameters = p.p_count_parameters
437
438 if p.is_counter:
439 self.counter = p.name
440
441 if p.is_output:
442 self.output = p
443
444 return
445
446
447 def variable_length_parameter(self):
448 for param in self.fn_parameters:
449 if param.is_variable_length_array():
450 return param
451
452 return None
453
454
455 def output_parameter(self):
456 for param in self.fn_parameters:
457 if param.is_output:
458 return param
459
460 return None
461
462
463 def offset_of_first_parameter(self):
464 """Get the offset of the first parameter in the command.
465
466 Gets the offset of the first function parameter in the GLX
467 command packet. This byte offset is measured from the end
468 of the Render / RenderLarge header. The offset for all non-
469 pixel commends is zero. The offset for pixel commands depends
470 on the number of dimensions of the pixel data."""
471
472 if self.image:
473 [dim, junk, junk, junk, junk] = self.dimensions()
474
475 # The base size is the size of the pixel pack info
476 # header used by images with the specified number
477 # of dimensions.
478
479 if dim <= 2:
480 return 20
481 elif dim <= 4:
482 return 36
483 else:
484 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim, self.image.name, self.name))
485 else:
486 return 0
487
488
489 def command_fixed_length(self):
490 """Return the length, in bytes as an integer, of the
491 fixed-size portion of the command."""
492
493 size = self.offset_of_first_parameter()
494
495 for p in gl_XML.glFunction.parameterIterator(self):
496 if not p.is_output:
497 size += p.size()
498 if self.pad_after(p):
499 size += 4
500
501 if self.image and self.image.img_null_flag:
502 size += 4
503
504 return size
505
506
507 def command_variable_length(self):
508 """Return the length, as a string, of the variable-sized
509 portion of the command."""
510
511 size_string = ""
512 for p in gl_XML.glFunction.parameterIterator(self):
513 if (not p.is_output) and (p.size() == 0):
514 size_string = size_string + " + __GLX_PAD(%s)" % (p.size_string())
515
516 return size_string
517
518
519 def command_length(self):
520 size = self.command_fixed_length()
521
522 if self.glx_rop != 0:
523 size += 4
524
525 size = ((size + 3) & ~3)
526 return "%u%s" % (size, self.command_variable_length())
527
528
529 def opcode_real_value(self):
530 """Get the true numeric value of the GLX opcode
531
532 Behaves similarly to opcode_value, except for
533 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
534 In these cases the value for the GLX opcode field (i.e.,
535 16 for X_GLXVendorPrivate or 17 for
536 X_GLXVendorPrivateWithReply) is returned. For other 'single'
537 commands, the opcode for the command (e.g., 101 for
538 X_GLsop_NewList) is returned."""
539
540 if self.glx_vendorpriv != 0:
541 if self.needs_reply():
542 return 17
543 else:
544 return 16
545 else:
546 return self.opcode_value()
547
548 def opcode_value(self):
549 """Get the unique protocol opcode for the glXFunction"""
550
551 if self.glx_rop != 0:
552 return self.glx_rop
553 elif self.glx_sop != 0:
554 return self.glx_sop
555 elif self.glx_vendorpriv != 0:
556 return self.glx_vendorpriv
557 else:
558 return -1
559
560 def opcode_rop_basename(self):
561 """Return either the name to be used for GLX protocol enum.
562
563 Returns either the name of the function or the name of the
564 name of the equivalent vector (e.g., glVertex3fv for
565 glVertex3f) function."""
566
567 if self.vectorequiv == None:
568 return self.name
569 else:
570 return self.vectorequiv
571
572 def opcode_name(self):
573 """Get the unique protocol enum name for the glXFunction"""
574
575 if self.glx_rop != 0:
576 return "X_GLrop_%s" % (self.opcode_rop_basename())
577 elif self.glx_sop != 0:
578 return "X_GLsop_%s" % (self.name)
579 elif self.glx_vendorpriv != 0:
580 return "X_GLvop_%s" % (self.name)
581 else:
582 return "ERROR"
583
584 def opcode_real_name(self):
585 """Get the true protocol enum name for the GLX opcode
586
587 Behaves similarly to opcode_name, except for
588 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
589 In these cases the string 'X_GLXVendorPrivate' or
590 'X_GLXVendorPrivateWithReply' is returned. For other
591 single or render commands 'X_GLsop' or 'X_GLrop' plus the
592 name of the function returned."""
593
594 if self.glx_vendorpriv != 0:
595 if self.needs_reply():
596 return "X_GLXVendorPrivateWithReply"
597 else:
598 return "X_GLXVendorPrivate"
599 else:
600 return self.opcode_name()
601
602
603 def return_string(self):
604 if self.fn_return_type != 'void':
605 return "return retval;"
606 else:
607 return "return;"
608
609
610 def needs_reply(self):
611 return self.fn_return_type != 'void' or self.output != None
612
613
614 def dimensions(self):
615 """Determine the dimensions of an image.
616
617 Returns a tuple representing the number of dimensions and the
618 string name of each of the dimensions of an image, If the
619 function is not a pixel function, the number of dimensions
620 will be zero."""
621
622 if not self.image:
623 return [0, "0", "0", "0", "0"]
624 else:
625 dim = 1
626 w = self.image.width
627
628 if self.image.height:
629 dim = 2
630 h = self.image.height
631 else:
632 h = "1"
633
634 if self.image.depth:
635 dim = 3
636 d = self.image.depth
637 else:
638 d = "1"
639
640 if self.image.extent:
641 dim = 4
642 e = self.image.extent
643 else:
644 e = "1"
645
646 return [dim, w, h, d, e]
647
648
649 def pad_after(self, p):
650 """Returns the name of the field inserted after the
651 specified field to pad out the command header."""
652
653 if self.image and self.image.img_pad_dimensions:
654 if not self.image.height:
655 if p.name == self.image.width:
656 return "height"
657 elif p.name == self.image.img_xoff:
658 return "yoffset"
659 elif not self.image.extent:
660 if p.name == self.image.depth:
661 # Should this be "size4d"?
662 return "extent"
663 elif p.name == self.image.img_zoff:
664 return "woffset"
665 return None
666
667
668 class GlxProto(gl_XML.FilterGLAPISpecBase):
669 name = "glX_proto_send.py (from Mesa)"
670
671 def __init__(self):
672 gl_XML.FilterGLAPISpecBase.__init__(self)
673 self.factory = glXItemFactory()
674 self.glx_enum_functions = {}
675
676
677 def endElement(self, name):
678 if name == 'OpenGLAPI':
679 # Once all the parsing is done, we have to go back and
680 # fix-up some cross references between different
681 # functions.
682
683 for k in self.functions:
684 f = self.functions[k]
685 if f.vectorequiv != None:
686 equiv = self.find_function(f.vectorequiv)
687 if equiv != None:
688 f.glx_doubles_in_order = equiv.glx_doubles_in_order
689 f.glx_rop = equiv.glx_rop
690 else:
691 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f.name, f.vectorequiv))
692 else:
693 gl_XML.FilterGLAPISpecBase.endElement(self, name)
694 return