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