blob: df3e6bb1cb874aebb32e1652f656ceee1899c7ec [file] [log] [blame]
Ian Romanick74764062004-12-03 20:31:59 +00001#!/usr/bin/python2
2
Ian Romanick5f1f2292005-01-07 02:39:09 +00003# (C) Copyright IBM Corporation 2004, 2005
Ian Romanick74764062004-12-03 20:31:59 +00004# 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
28from xml.sax import saxutils
29from xml.sax import make_parser
30from xml.sax.handler import feature_namespaces
31
32import gl_XML
33import license
34import sys, getopt
35
36
37def printPure():
38 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
39# define PURE __attribute__((pure))
40# else
41# define PURE
42# endif"""
43
44def printFastcall():
45 print """# if defined(__i386__) && defined(__GNUC__)
46# define FASTCALL __attribute__((fastcall))
47# else
48# define FASTCALL
49# endif"""
50
51def 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
58def printNoinline():
59 print """# if defined(__GNUC__)
60# define NOINLINE __attribute__((noinline))
61# else
62# define NOINLINE
63# endif"""
64
Ian Romanick7f958e92005-01-24 20:08:28 +000065def printHaveAlias():
66 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
67# define HAVE_ALIAS
68# endif"""
Ian Romanick74764062004-12-03 20:31:59 +000069
70class 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
83class glXEnumFunction:
84 def __init__(self, name):
85 self.name = name
Ian Romanick5aa6dc322005-01-27 01:08:48 +000086 self.mode = 0
87 self.sig = None
88
Ian Romanick74764062004-12-03 20:31:59 +000089 # "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 ):
Ian Romanick5aa6dc322005-01-27 01:08:48 +0000120 if self.sig == None:
121 self.sig = ""
122 for i in self.count:
Ian Romanick82e22f52005-01-27 19:39:16 +0000123 self.count[i].sort()
Ian Romanick5aa6dc322005-01-27 01:08:48 +0000124 for e in self.count[i]:
125 self.sig += "%04x,%u," % (e, i)
Ian Romanick74764062004-12-03 20:31:59 +0000126
Ian Romanick5aa6dc322005-01-27 01:08:48 +0000127 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
Ian Romanick74764062004-12-03 20:31:59 +0000138
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
254class glXEnum(gl_XML.glEnum):
255 def __init__(self, context, name, attrs):
256 gl_XML.glEnum.__init__(self, context, name, attrs)
Ian Romanick0246b2a2005-01-24 20:59:32 +0000257
Ian Romanick74764062004-12-03 20:31:59 +0000258
259 def startElement(self, name, attrs):
260 if name == "size":
Ian Romanick85f0fa32005-01-25 01:20:11 +0000261 [n, c, mode] = self.process_attributes(attrs)
Ian Romanick5ff2b942005-01-24 21:29:13 +0000262
Ian Romanick74764062004-12-03 20:31:59 +0000263 if not self.context.glx_enum_functions.has_key( n ):
264 f = glXEnumFunction( n )
Ian Romanick5aa6dc322005-01-27 01:08:48 +0000265 f.set_mode( mode )
Ian Romanick74764062004-12-03 20:31:59 +0000266 self.context.glx_enum_functions[ f.name ] = f
267
Ian Romanick74764062004-12-03 20:31:59 +0000268 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
274class 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
Ian Romanick1d270842004-12-21 21:26:36 +0000280class 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
Ian Romanick74764062004-12-03 20:31:59 +0000316class 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
Ian Romanick1d270842004-12-21 21:26:36 +0000346
347 def parameterIterator(self, skip_output, max_order):
348 return glXParameterIterator(self.fn_parameters, skip_output, max_order)
349
350
Ian Romanick74764062004-12-03 20:31:59 +0000351 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
Ian Romanick7f958e92005-01-24 20:08:28 +0000388 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
Ian Romanick74764062004-12-03 20:31:59 +0000410 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
Ian Romanick0246b2a2005-01-24 20:59:32 +0000429
Ian Romanick74764062004-12-03 20:31:59 +0000430 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
Ian Romanick0246b2a2005-01-24 20:59:32 +0000438 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."""
Ian Romanick5f1f2292005-01-07 02:39:09 +0000446
447 if self.image:
448 [dim, junk, junk, junk, junk] = self.dimensions()
Ian Romanick0246b2a2005-01-24 20:59:32 +0000449
Ian Romanick5f1f2292005-01-07 02:39:09 +0000450 # 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:
Ian Romanick0246b2a2005-01-24 20:59:32 +0000455 return 20
Ian Romanick5f1f2292005-01-07 02:39:09 +0000456 elif dim <= 4:
Ian Romanick0246b2a2005-01-24 20:59:32 +0000457 return 36
Ian Romanick5f1f2292005-01-07 02:39:09 +0000458 else:
459 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim, self.image.name, self.name))
Ian Romanick0246b2a2005-01-24 20:59:32 +0000460 else:
461 return 0
Ian Romanick5f1f2292005-01-07 02:39:09 +0000462
Ian Romanick5f1f2292005-01-07 02:39:09 +0000463
Ian Romanick0246b2a2005-01-24 20:59:32 +0000464 def command_fixed_length(self):
465 """Return the length, in bytes as an integer, of the
466 fixed-size portion of the command."""
Ian Romanick5f1f2292005-01-07 02:39:09 +0000467
Ian Romanick0246b2a2005-01-24 20:59:32 +0000468 size = self.offset_of_first_parameter()
Ian Romanick5f1f2292005-01-07 02:39:09 +0000469
Ian Romanick0246b2a2005-01-24 20:59:32 +0000470 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
Ian Romanick74764062004-12-03 20:31:59 +0000486 size_string = ""
Ian Romanick1d270842004-12-21 21:26:36 +0000487 for p in gl_XML.glFunction.parameterIterator(self):
Ian Romanick0246b2a2005-01-24 20:59:32 +0000488 if (not p.is_output) and (p.size() == 0):
489 size_string = size_string + " + __GLX_PAD(%s)" % (p.size_string())
Ian Romanick74764062004-12-03 20:31:59 +0000490
Ian Romanick0246b2a2005-01-24 20:59:32 +0000491 return size_string
492
Ian Romanick74764062004-12-03 20:31:59 +0000493
494 def command_length(self):
Ian Romanick0246b2a2005-01-24 20:59:32 +0000495 size = self.command_fixed_length()
Ian Romanick74764062004-12-03 20:31:59 +0000496
497 if self.glx_rop != 0:
498 size += 4
499
500 size = ((size + 3) & ~3)
Ian Romanick0246b2a2005-01-24 20:59:32 +0000501 return "%u%s" % (size, self.command_variable_length())
Ian Romanick74764062004-12-03 20:31:59 +0000502
503
504 def opcode_real_value(self):
Ian Romanick1d270842004-12-21 21:26:36 +0000505 """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
Ian Romanick74764062004-12-03 20:31:59 +0000515 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):
Ian Romanick1d270842004-12-21 21:26:36 +0000524 """Get the unique protocol opcode for the glXFunction"""
525
Ian Romanick74764062004-12-03 20:31:59 +0000526 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):
Ian Romanick1d270842004-12-21 21:26:36 +0000536 """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
Ian Romanick74764062004-12-03 20:31:59 +0000542 if self.vectorequiv == None:
543 return self.name
544 else:
545 return self.vectorequiv
546
547 def opcode_name(self):
Ian Romanick1d270842004-12-21 21:26:36 +0000548 """Get the unique protocol enum name for the glXFunction"""
549
Ian Romanick74764062004-12-03 20:31:59 +0000550 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):
Ian Romanick1d270842004-12-21 21:26:36 +0000560 """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
Ian Romanick74764062004-12-03 20:31:59 +0000569 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
Ian Romanick5f1f2292005-01-07 02:39:09 +0000589 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
Ian Romanick74764062004-12-03 20:31:59 +0000643class 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