Add numerous 'get'-type functions to most of the enums supported by the
[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 handcode = 0
332 ignore = 0
333 can_be_large = 0
334
335 def __init__(self, context, name, attrs):
336 self.vectorequiv = attrs.get('vectorequiv', None)
337 self.count_parameters = None
338 self.counter = None
339 self.output = None
340 self.can_be_large = 0
341 self.reply_always_array = 0
342
343 gl_XML.glFunction.__init__(self, context, name, attrs)
344 return
345
346
347 def parameterIterator(self, skip_output, max_order):
348 return glXParameterIterator(self.fn_parameters, skip_output, max_order)
349
350
351 def startElement(self, name, attrs):
352 """Process elements within a function that are specific to GLX."""
353
354 if name == "glx":
355 self.glx_rop = int(attrs.get('rop', "0"))
356 self.glx_sop = int(attrs.get('sop', "0"))
357 self.glx_vendorpriv = int(attrs.get('vendorpriv', "0"))
358
359 if attrs.get('handcode', "false") == "true":
360 self.handcode = 1
361 else:
362 self.handcode = 0
363
364 if attrs.get('ignore', "false") == "true":
365 self.ignore = 1
366 else:
367 self.ignore = 0
368
369 if attrs.get('large', "false") == "true":
370 self.can_be_large = 1
371 else:
372 self.can_be_large = 0
373
374 if attrs.get('doubles_in_order', "false") == "true":
375 self.glx_doubles_in_order = 1
376 else:
377 self.glx_doubles_in_order = 0
378
379 if attrs.get('always_array', "false") == "true":
380 self.reply_always_array = 1
381 else:
382 self.reply_always_array = 0
383
384 else:
385 gl_XML.glFunction.startElement(self, name, attrs)
386
387
388 def endElement(self, name):
389 if name == "function":
390 # Mark any function that does not have GLX protocol
391 # defined as "ignore". This prevents bad things from
392 # happening when people add new functions to the GL
393 # API XML without adding any GLX section.
394 #
395 # This will also mark functions that don't have a
396 # dispatch offset at ignored.
397
398 if (self.fn_offset == -1 and not self.fn_alias) or not (self.handcode or self.glx_rop or self.glx_sop or self.glx_vendorpriv or self.vectorequiv or self.fn_alias):
399 #if not self.ignore:
400 # if self.fn_offset == -1:
401 # print '/* %s ignored becuase no offset assigned. */' % (self.name)
402 # else:
403 # print '/* %s ignored becuase no GLX opcode assigned. */' % (self.name)
404
405 self.ignore = 1
406
407 return gl_XML.glFunction.endElement(self, name)
408
409
410 def append(self, tag_name, p):
411 gl_XML.glFunction.append(self, tag_name, p)
412
413 if p.is_variable_length_array():
414 p.order = 2;
415 elif not self.glx_doubles_in_order and p.p_type.size == 8:
416 p.order = 0;
417
418 if p.p_count_parameters != None:
419 self.count_parameters = p.p_count_parameters
420
421 if p.is_counter:
422 self.counter = p.name
423
424 if p.is_output:
425 self.output = p
426
427 return
428
429
430 def variable_length_parameter(self):
431 for param in self.fn_parameters:
432 if param.is_variable_length_array():
433 return param
434
435 return None
436
437
438 def offset_of_first_parameter(self):
439 """Get the offset of the first parameter in the command.
440
441 Gets the offset of the first function parameter in the GLX
442 command packet. This byte offset is measured from the end
443 of the Render / RenderLarge header. The offset for all non-
444 pixel commends is zero. The offset for pixel commands depends
445 on the number of dimensions of the pixel data."""
446
447 if self.image:
448 [dim, junk, junk, junk, junk] = self.dimensions()
449
450 # The base size is the size of the pixel pack info
451 # header used by images with the specified number
452 # of dimensions.
453
454 if dim <= 2:
455 return 20
456 elif dim <= 4:
457 return 36
458 else:
459 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim, self.image.name, self.name))
460 else:
461 return 0
462
463
464 def command_fixed_length(self):
465 """Return the length, in bytes as an integer, of the
466 fixed-size portion of the command."""
467
468 size = self.offset_of_first_parameter()
469
470 for p in gl_XML.glFunction.parameterIterator(self):
471 if not p.is_output:
472 size += p.size()
473 if self.pad_after(p):
474 size += 4
475
476 if self.image and self.image.img_null_flag:
477 size += 4
478
479 return size
480
481
482 def command_variable_length(self):
483 """Return the length, as a string, of the variable-sized
484 portion of the command."""
485
486 size_string = ""
487 for p in gl_XML.glFunction.parameterIterator(self):
488 if (not p.is_output) and (p.size() == 0):
489 size_string = size_string + " + __GLX_PAD(%s)" % (p.size_string())
490
491 return size_string
492
493
494 def command_length(self):
495 size = self.command_fixed_length()
496
497 if self.glx_rop != 0:
498 size += 4
499
500 size = ((size + 3) & ~3)
501 return "%u%s" % (size, self.command_variable_length())
502
503
504 def opcode_real_value(self):
505 """Get the true numeric value of the GLX opcode
506
507 Behaves similarly to opcode_value, except for
508 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
509 In these cases the value for the GLX opcode field (i.e.,
510 16 for X_GLXVendorPrivate or 17 for
511 X_GLXVendorPrivateWithReply) is returned. For other 'single'
512 commands, the opcode for the command (e.g., 101 for
513 X_GLsop_NewList) is returned."""
514
515 if self.glx_vendorpriv != 0:
516 if self.needs_reply():
517 return 17
518 else:
519 return 16
520 else:
521 return self.opcode_value()
522
523 def opcode_value(self):
524 """Get the unique protocol opcode for the glXFunction"""
525
526 if self.glx_rop != 0:
527 return self.glx_rop
528 elif self.glx_sop != 0:
529 return self.glx_sop
530 elif self.glx_vendorpriv != 0:
531 return self.glx_vendorpriv
532 else:
533 return -1
534
535 def opcode_rop_basename(self):
536 """Return either the name to be used for GLX protocol enum.
537
538 Returns either the name of the function or the name of the
539 name of the equivalent vector (e.g., glVertex3fv for
540 glVertex3f) function."""
541
542 if self.vectorequiv == None:
543 return self.name
544 else:
545 return self.vectorequiv
546
547 def opcode_name(self):
548 """Get the unique protocol enum name for the glXFunction"""
549
550 if self.glx_rop != 0:
551 return "X_GLrop_%s" % (self.opcode_rop_basename())
552 elif self.glx_sop != 0:
553 return "X_GLsop_%s" % (self.name)
554 elif self.glx_vendorpriv != 0:
555 return "X_GLvop_%s" % (self.name)
556 else:
557 return "ERROR"
558
559 def opcode_real_name(self):
560 """Get the true protocol enum name for the GLX opcode
561
562 Behaves similarly to opcode_name, except for
563 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
564 In these cases the string 'X_GLXVendorPrivate' or
565 'X_GLXVendorPrivateWithReply' is returned. For other
566 single or render commands 'X_GLsop' or 'X_GLrop' plus the
567 name of the function returned."""
568
569 if self.glx_vendorpriv != 0:
570 if self.needs_reply():
571 return "X_GLXVendorPrivateWithReply"
572 else:
573 return "X_GLXVendorPrivate"
574 else:
575 return self.opcode_name()
576
577
578 def return_string(self):
579 if self.fn_return_type != 'void':
580 return "return retval;"
581 else:
582 return "return;"
583
584
585 def needs_reply(self):
586 return self.fn_return_type != 'void' or self.output != None
587
588
589 def dimensions(self):
590 """Determine the dimensions of an image.
591
592 Returns a tuple representing the number of dimensions and the
593 string name of each of the dimensions of an image, If the
594 function is not a pixel function, the number of dimensions
595 will be zero."""
596
597 if not self.image:
598 return [0, "0", "0", "0", "0"]
599 else:
600 dim = 1
601 w = self.image.width
602
603 if self.image.height:
604 dim = 2
605 h = self.image.height
606 else:
607 h = "1"
608
609 if self.image.depth:
610 dim = 3
611 d = self.image.depth
612 else:
613 d = "1"
614
615 if self.image.extent:
616 dim = 4
617 e = self.image.extent
618 else:
619 e = "1"
620
621 return [dim, w, h, d, e]
622
623
624 def pad_after(self, p):
625 """Returns the name of the field inserted after the
626 specified field to pad out the command header."""
627
628 if self.image and self.image.img_pad_dimensions:
629 if not self.image.height:
630 if p.name == self.image.width:
631 return "height"
632 elif p.name == self.image.img_xoff:
633 return "yoffset"
634 elif not self.image.extent:
635 if p.name == self.image.depth:
636 # Should this be "size4d"?
637 return "extent"
638 elif p.name == self.image.img_zoff:
639 return "woffset"
640 return None
641
642
643 class GlxProto(gl_XML.FilterGLAPISpecBase):
644 name = "glX_proto_send.py (from Mesa)"
645
646 def __init__(self):
647 gl_XML.FilterGLAPISpecBase.__init__(self)
648 self.factory = glXItemFactory()
649 self.glx_enum_functions = {}
650
651
652 def endElement(self, name):
653 if name == 'OpenGLAPI':
654 # Once all the parsing is done, we have to go back and
655 # fix-up some cross references between different
656 # functions.
657
658 for k in self.functions:
659 f = self.functions[k]
660 if f.vectorequiv != None:
661 equiv = self.find_function(f.vectorequiv)
662 if equiv != None:
663 f.glx_doubles_in_order = equiv.glx_doubles_in_order
664 f.glx_rop = equiv.glx_rop
665 else:
666 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f.name, f.vectorequiv))
667 else:
668 gl_XML.FilterGLAPISpecBase.endElement(self, name)
669 return