Make sure that functions added to gl_API.xml that do not have any GLX
[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 self.glx_functions = []
244
245 def startElement(self, name, attrs):
246 if name == "size":
247 n = attrs.get('name', None)
248 if not self.context.glx_enum_functions.has_key( n ):
249 f = glXEnumFunction( n )
250 self.context.glx_enum_functions[ f.name ] = f
251
252 temp = attrs.get('count', None)
253 try:
254 c = int(temp)
255 except Exception,e:
256 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
257
258 self.context.glx_enum_functions[ n ].append( c, self.value, self.name )
259 else:
260 gl_XML.glEnum.startElement(self, context, name, attrs)
261 return
262
263
264 class glXParameter(gl_XML.glParameter):
265 def __init__(self, context, name, attrs):
266 self.order = 1;
267 gl_XML.glParameter.__init__(self, context, name, attrs);
268
269
270 class glXParameterIterator:
271 """Class to iterate over a list of glXParameters.
272
273 Objects of this class are returned by the parameterIterator method of
274 the glXFunction class. They are used to iterate over the list of
275 parameters to the function."""
276
277 def __init__(self, data, skip_output, max_order):
278 self.data = data
279 self.index = 0
280 self.order = 0
281 self.skip_output = skip_output
282 self.max_order = max_order
283
284 def __iter__(self):
285 return self
286
287 def next(self):
288 if len( self.data ) == 0:
289 raise StopIteration
290
291 while 1:
292 if self.index == len( self.data ):
293 if self.order == self.max_order:
294 raise StopIteration
295 else:
296 self.order += 1
297 self.index = 0
298
299 i = self.index
300 self.index += 1
301
302 if self.data[i].order == self.order and not (self.data[i].is_output and self.skip_output):
303 return self.data[i]
304
305
306 class glXFunction(gl_XML.glFunction):
307 glx_rop = 0
308 glx_sop = 0
309 glx_vendorpriv = 0
310
311 # If this is set to true, it means that GLdouble parameters should be
312 # written to the GLX protocol packet in the order they appear in the
313 # prototype. This is different from the "classic" ordering. In the
314 # classic ordering GLdoubles are written to the protocol packet first,
315 # followed by non-doubles. NV_vertex_program was the first extension
316 # to break with this tradition.
317
318 glx_doubles_in_order = 0
319
320 vectorequiv = None
321 handcode = 0
322 ignore = 0
323 can_be_large = 0
324
325 def __init__(self, context, name, attrs):
326 self.vectorequiv = attrs.get('vectorequiv', None)
327 self.count_parameters = None
328 self.counter = None
329 self.output = None
330 self.can_be_large = 0
331 self.reply_always_array = 0
332
333 gl_XML.glFunction.__init__(self, context, name, attrs)
334 return
335
336
337 def parameterIterator(self, skip_output, max_order):
338 return glXParameterIterator(self.fn_parameters, skip_output, max_order)
339
340
341 def startElement(self, name, attrs):
342 """Process elements within a function that are specific to GLX."""
343
344 if name == "glx":
345 self.glx_rop = int(attrs.get('rop', "0"))
346 self.glx_sop = int(attrs.get('sop', "0"))
347 self.glx_vendorpriv = int(attrs.get('vendorpriv', "0"))
348
349 if attrs.get('handcode', "false") == "true":
350 self.handcode = 1
351 else:
352 self.handcode = 0
353
354 if attrs.get('ignore', "false") == "true":
355 self.ignore = 1
356 else:
357 self.ignore = 0
358
359 if attrs.get('large', "false") == "true":
360 self.can_be_large = 1
361 else:
362 self.can_be_large = 0
363
364 if attrs.get('doubles_in_order', "false") == "true":
365 self.glx_doubles_in_order = 1
366 else:
367 self.glx_doubles_in_order = 0
368
369 if attrs.get('always_array', "false") == "true":
370 self.reply_always_array = 1
371 else:
372 self.reply_always_array = 0
373
374 else:
375 gl_XML.glFunction.startElement(self, name, attrs)
376
377
378 def endElement(self, name):
379 if name == "function":
380 # Mark any function that does not have GLX protocol
381 # defined as "ignore". This prevents bad things from
382 # happening when people add new functions to the GL
383 # API XML without adding any GLX section.
384 #
385 # This will also mark functions that don't have a
386 # dispatch offset at ignored.
387
388 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):
389 #if not self.ignore:
390 # if self.fn_offset == -1:
391 # print '/* %s ignored becuase no offset assigned. */' % (self.name)
392 # else:
393 # print '/* %s ignored becuase no GLX opcode assigned. */' % (self.name)
394
395 self.ignore = 1
396
397 return gl_XML.glFunction.endElement(self, name)
398
399
400 def append(self, tag_name, p):
401 gl_XML.glFunction.append(self, tag_name, p)
402
403 if p.is_variable_length_array():
404 p.order = 2;
405 elif not self.glx_doubles_in_order and p.p_type.size == 8:
406 p.order = 0;
407
408 if p.p_count_parameters != None:
409 self.count_parameters = p.p_count_parameters
410
411 if p.is_counter:
412 self.counter = p.name
413
414 if p.is_output:
415 self.output = p
416
417 return
418
419 def variable_length_parameter(self):
420 for param in self.fn_parameters:
421 if param.is_variable_length_array():
422 return param
423
424 return None
425
426
427 def command_payload_length(self):
428 size = 0
429
430 if self.image:
431 [dim, junk, junk, junk, junk] = self.dimensions()
432
433 # The base size is the size of the pixel pack info
434 # header used by images with the specified number
435 # of dimensions.
436
437 if dim <= 2:
438 size = 20
439 elif dim <= 4:
440 size = 36
441 else:
442 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim, self.image.name, self.name))
443
444 if self.image.img_null_flag:
445 size += 4
446
447 if self.image.img_pad_dimensions:
448 size += 4 * (dim & 1)
449
450 # If the image has offset parameters, like
451 # TexSubImage1D or TexSubImage3D, they need to
452 # be padded out as well.
453
454 if self.image.img_xoff:
455 size += 4 * (dim & 1)
456
457
458
459 size_string = ""
460 for p in gl_XML.glFunction.parameterIterator(self):
461 if p.is_output: continue
462 temp = p.size_string()
463 try:
464 s = int(temp)
465 size += s
466 except Exception,e:
467 size_string = size_string + " + __GLX_PAD(%s)" % (temp)
468
469 return [size, size_string]
470
471 def command_length(self):
472 [size, size_string] = self.command_payload_length()
473
474 if self.glx_rop != 0:
475 size += 4
476
477 size = ((size + 3) & ~3)
478 return "%u%s" % (size, size_string)
479
480
481 def opcode_real_value(self):
482 """Get the true numeric value of the GLX opcode
483
484 Behaves similarly to opcode_value, except for
485 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
486 In these cases the value for the GLX opcode field (i.e.,
487 16 for X_GLXVendorPrivate or 17 for
488 X_GLXVendorPrivateWithReply) is returned. For other 'single'
489 commands, the opcode for the command (e.g., 101 for
490 X_GLsop_NewList) is returned."""
491
492 if self.glx_vendorpriv != 0:
493 if self.needs_reply():
494 return 17
495 else:
496 return 16
497 else:
498 return self.opcode_value()
499
500 def opcode_value(self):
501 """Get the unique protocol opcode for the glXFunction"""
502
503 if self.glx_rop != 0:
504 return self.glx_rop
505 elif self.glx_sop != 0:
506 return self.glx_sop
507 elif self.glx_vendorpriv != 0:
508 return self.glx_vendorpriv
509 else:
510 return -1
511
512 def opcode_rop_basename(self):
513 """Return either the name to be used for GLX protocol enum.
514
515 Returns either the name of the function or the name of the
516 name of the equivalent vector (e.g., glVertex3fv for
517 glVertex3f) function."""
518
519 if self.vectorequiv == None:
520 return self.name
521 else:
522 return self.vectorequiv
523
524 def opcode_name(self):
525 """Get the unique protocol enum name for the glXFunction"""
526
527 if self.glx_rop != 0:
528 return "X_GLrop_%s" % (self.opcode_rop_basename())
529 elif self.glx_sop != 0:
530 return "X_GLsop_%s" % (self.name)
531 elif self.glx_vendorpriv != 0:
532 return "X_GLvop_%s" % (self.name)
533 else:
534 return "ERROR"
535
536 def opcode_real_name(self):
537 """Get the true protocol enum name for the GLX opcode
538
539 Behaves similarly to opcode_name, except for
540 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
541 In these cases the string 'X_GLXVendorPrivate' or
542 'X_GLXVendorPrivateWithReply' is returned. For other
543 single or render commands 'X_GLsop' or 'X_GLrop' plus the
544 name of the function returned."""
545
546 if self.glx_vendorpriv != 0:
547 if self.needs_reply():
548 return "X_GLXVendorPrivateWithReply"
549 else:
550 return "X_GLXVendorPrivate"
551 else:
552 return self.opcode_name()
553
554
555 def return_string(self):
556 if self.fn_return_type != 'void':
557 return "return retval;"
558 else:
559 return "return;"
560
561
562 def needs_reply(self):
563 return self.fn_return_type != 'void' or self.output != None
564
565
566 def dimensions(self):
567 """Determine the dimensions of an image.
568
569 Returns a tuple representing the number of dimensions and the
570 string name of each of the dimensions of an image, If the
571 function is not a pixel function, the number of dimensions
572 will be zero."""
573
574 if not self.image:
575 return [0, "0", "0", "0", "0"]
576 else:
577 dim = 1
578 w = self.image.width
579
580 if self.image.height:
581 dim = 2
582 h = self.image.height
583 else:
584 h = "1"
585
586 if self.image.depth:
587 dim = 3
588 d = self.image.depth
589 else:
590 d = "1"
591
592 if self.image.extent:
593 dim = 4
594 e = self.image.extent
595 else:
596 e = "1"
597
598 return [dim, w, h, d, e]
599
600
601 def pad_after(self, p):
602 """Returns the name of the field inserted after the
603 specified field to pad out the command header."""
604
605 if self.image and self.image.img_pad_dimensions:
606 if not self.image.height:
607 if p.name == self.image.width:
608 return "height"
609 elif p.name == self.image.img_xoff:
610 return "yoffset"
611 elif not self.image.extent:
612 if p.name == self.image.depth:
613 # Should this be "size4d"?
614 return "extent"
615 elif p.name == self.image.img_zoff:
616 return "woffset"
617 return None
618
619
620 class GlxProto(gl_XML.FilterGLAPISpecBase):
621 name = "glX_proto_send.py (from Mesa)"
622
623 def __init__(self):
624 gl_XML.FilterGLAPISpecBase.__init__(self)
625 self.factory = glXItemFactory()
626 self.glx_enum_functions = {}
627
628
629 def endElement(self, name):
630 if name == 'OpenGLAPI':
631 # Once all the parsing is done, we have to go back and
632 # fix-up some cross references between different
633 # functions.
634
635 for k in self.functions:
636 f = self.functions[k]
637 if f.vectorequiv != None:
638 equiv = self.find_function(f.vectorequiv)
639 if equiv != None:
640 f.glx_doubles_in_order = equiv.glx_doubles_in_order
641 f.glx_rop = equiv.glx_rop
642 else:
643 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f.name, f.vectorequiv))
644 else:
645 gl_XML.FilterGLAPISpecBase.endElement(self, name)
646 return