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