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