blob: 8efc90ca56a1cf9f1876d25c34dbd5215ecb7b4b [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
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
240class glXEnum(gl_XML.glEnum):
241 def __init__(self, context, name, attrs):
242 gl_XML.glEnum.__init__(self, context, name, attrs)
Ian Romanick0246b2a2005-01-24 20:59:32 +0000243
Ian Romanick74764062004-12-03 20:31:59 +0000244
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
264class 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
Ian Romanick1d270842004-12-21 21:26:36 +0000270class 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
Ian Romanick74764062004-12-03 20:31:59 +0000306class 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
Ian Romanick1d270842004-12-21 21:26:36 +0000336
337 def parameterIterator(self, skip_output, max_order):
338 return glXParameterIterator(self.fn_parameters, skip_output, max_order)
339
340
Ian Romanick74764062004-12-03 20:31:59 +0000341 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
Ian Romanick7f958e92005-01-24 20:08:28 +0000378 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
Ian Romanick74764062004-12-03 20:31:59 +0000400 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
Ian Romanick0246b2a2005-01-24 20:59:32 +0000419
Ian Romanick74764062004-12-03 20:31:59 +0000420 def variable_length_parameter(self):
421 for param in self.fn_parameters:
422 if param.is_variable_length_array():
423 return param
424
425 return None
426
427
Ian Romanick0246b2a2005-01-24 20:59:32 +0000428 def offset_of_first_parameter(self):
429 """Get the offset of the first parameter in the command.
430
431 Gets the offset of the first function parameter in the GLX
432 command packet. This byte offset is measured from the end
433 of the Render / RenderLarge header. The offset for all non-
434 pixel commends is zero. The offset for pixel commands depends
435 on the number of dimensions of the pixel data."""
Ian Romanick5f1f2292005-01-07 02:39:09 +0000436
437 if self.image:
438 [dim, junk, junk, junk, junk] = self.dimensions()
Ian Romanick0246b2a2005-01-24 20:59:32 +0000439
Ian Romanick5f1f2292005-01-07 02:39:09 +0000440 # The base size is the size of the pixel pack info
441 # header used by images with the specified number
442 # of dimensions.
443
444 if dim <= 2:
Ian Romanick0246b2a2005-01-24 20:59:32 +0000445 return 20
Ian Romanick5f1f2292005-01-07 02:39:09 +0000446 elif dim <= 4:
Ian Romanick0246b2a2005-01-24 20:59:32 +0000447 return 36
Ian Romanick5f1f2292005-01-07 02:39:09 +0000448 else:
449 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 +0000450 else:
451 return 0
Ian Romanick5f1f2292005-01-07 02:39:09 +0000452
Ian Romanick5f1f2292005-01-07 02:39:09 +0000453
Ian Romanick0246b2a2005-01-24 20:59:32 +0000454 def command_fixed_length(self):
455 """Return the length, in bytes as an integer, of the
456 fixed-size portion of the command."""
Ian Romanick5f1f2292005-01-07 02:39:09 +0000457
Ian Romanick0246b2a2005-01-24 20:59:32 +0000458 size = self.offset_of_first_parameter()
Ian Romanick5f1f2292005-01-07 02:39:09 +0000459
Ian Romanick0246b2a2005-01-24 20:59:32 +0000460 for p in gl_XML.glFunction.parameterIterator(self):
461 if not p.is_output:
462 size += p.size()
463 if self.pad_after(p):
464 size += 4
465
466 if self.image and self.image.img_null_flag:
467 size += 4
468
469 return size
470
471
472 def command_variable_length(self):
473 """Return the length, as a string, of the variable-sized
474 portion of the command."""
475
Ian Romanick74764062004-12-03 20:31:59 +0000476 size_string = ""
Ian Romanick1d270842004-12-21 21:26:36 +0000477 for p in gl_XML.glFunction.parameterIterator(self):
Ian Romanick0246b2a2005-01-24 20:59:32 +0000478 if (not p.is_output) and (p.size() == 0):
479 size_string = size_string + " + __GLX_PAD(%s)" % (p.size_string())
Ian Romanick74764062004-12-03 20:31:59 +0000480
Ian Romanick0246b2a2005-01-24 20:59:32 +0000481 return size_string
482
Ian Romanick74764062004-12-03 20:31:59 +0000483
484 def command_length(self):
Ian Romanick0246b2a2005-01-24 20:59:32 +0000485 size = self.command_fixed_length()
Ian Romanick74764062004-12-03 20:31:59 +0000486
487 if self.glx_rop != 0:
488 size += 4
489
490 size = ((size + 3) & ~3)
Ian Romanick0246b2a2005-01-24 20:59:32 +0000491 return "%u%s" % (size, self.command_variable_length())
Ian Romanick74764062004-12-03 20:31:59 +0000492
493
494 def opcode_real_value(self):
Ian Romanick1d270842004-12-21 21:26:36 +0000495 """Get the true numeric value of the GLX opcode
496
497 Behaves similarly to opcode_value, except for
498 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
499 In these cases the value for the GLX opcode field (i.e.,
500 16 for X_GLXVendorPrivate or 17 for
501 X_GLXVendorPrivateWithReply) is returned. For other 'single'
502 commands, the opcode for the command (e.g., 101 for
503 X_GLsop_NewList) is returned."""
504
Ian Romanick74764062004-12-03 20:31:59 +0000505 if self.glx_vendorpriv != 0:
506 if self.needs_reply():
507 return 17
508 else:
509 return 16
510 else:
511 return self.opcode_value()
512
513 def opcode_value(self):
Ian Romanick1d270842004-12-21 21:26:36 +0000514 """Get the unique protocol opcode for the glXFunction"""
515
Ian Romanick74764062004-12-03 20:31:59 +0000516 if self.glx_rop != 0:
517 return self.glx_rop
518 elif self.glx_sop != 0:
519 return self.glx_sop
520 elif self.glx_vendorpriv != 0:
521 return self.glx_vendorpriv
522 else:
523 return -1
524
525 def opcode_rop_basename(self):
Ian Romanick1d270842004-12-21 21:26:36 +0000526 """Return either the name to be used for GLX protocol enum.
527
528 Returns either the name of the function or the name of the
529 name of the equivalent vector (e.g., glVertex3fv for
530 glVertex3f) function."""
531
Ian Romanick74764062004-12-03 20:31:59 +0000532 if self.vectorequiv == None:
533 return self.name
534 else:
535 return self.vectorequiv
536
537 def opcode_name(self):
Ian Romanick1d270842004-12-21 21:26:36 +0000538 """Get the unique protocol enum name for the glXFunction"""
539
Ian Romanick74764062004-12-03 20:31:59 +0000540 if self.glx_rop != 0:
541 return "X_GLrop_%s" % (self.opcode_rop_basename())
542 elif self.glx_sop != 0:
543 return "X_GLsop_%s" % (self.name)
544 elif self.glx_vendorpriv != 0:
545 return "X_GLvop_%s" % (self.name)
546 else:
547 return "ERROR"
548
549 def opcode_real_name(self):
Ian Romanick1d270842004-12-21 21:26:36 +0000550 """Get the true protocol enum name for the GLX opcode
551
552 Behaves similarly to opcode_name, except for
553 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
554 In these cases the string 'X_GLXVendorPrivate' or
555 'X_GLXVendorPrivateWithReply' is returned. For other
556 single or render commands 'X_GLsop' or 'X_GLrop' plus the
557 name of the function returned."""
558
Ian Romanick74764062004-12-03 20:31:59 +0000559 if self.glx_vendorpriv != 0:
560 if self.needs_reply():
561 return "X_GLXVendorPrivateWithReply"
562 else:
563 return "X_GLXVendorPrivate"
564 else:
565 return self.opcode_name()
566
567
568 def return_string(self):
569 if self.fn_return_type != 'void':
570 return "return retval;"
571 else:
572 return "return;"
573
574
575 def needs_reply(self):
576 return self.fn_return_type != 'void' or self.output != None
577
578
Ian Romanick5f1f2292005-01-07 02:39:09 +0000579 def dimensions(self):
580 """Determine the dimensions of an image.
581
582 Returns a tuple representing the number of dimensions and the
583 string name of each of the dimensions of an image, If the
584 function is not a pixel function, the number of dimensions
585 will be zero."""
586
587 if not self.image:
588 return [0, "0", "0", "0", "0"]
589 else:
590 dim = 1
591 w = self.image.width
592
593 if self.image.height:
594 dim = 2
595 h = self.image.height
596 else:
597 h = "1"
598
599 if self.image.depth:
600 dim = 3
601 d = self.image.depth
602 else:
603 d = "1"
604
605 if self.image.extent:
606 dim = 4
607 e = self.image.extent
608 else:
609 e = "1"
610
611 return [dim, w, h, d, e]
612
613
614 def pad_after(self, p):
615 """Returns the name of the field inserted after the
616 specified field to pad out the command header."""
617
618 if self.image and self.image.img_pad_dimensions:
619 if not self.image.height:
620 if p.name == self.image.width:
621 return "height"
622 elif p.name == self.image.img_xoff:
623 return "yoffset"
624 elif not self.image.extent:
625 if p.name == self.image.depth:
626 # Should this be "size4d"?
627 return "extent"
628 elif p.name == self.image.img_zoff:
629 return "woffset"
630 return None
631
632
Ian Romanick74764062004-12-03 20:31:59 +0000633class GlxProto(gl_XML.FilterGLAPISpecBase):
634 name = "glX_proto_send.py (from Mesa)"
635
636 def __init__(self):
637 gl_XML.FilterGLAPISpecBase.__init__(self)
638 self.factory = glXItemFactory()
639 self.glx_enum_functions = {}
640
641
642 def endElement(self, name):
643 if name == 'OpenGLAPI':
644 # Once all the parsing is done, we have to go back and
645 # fix-up some cross references between different
646 # functions.
647
648 for k in self.functions:
649 f = self.functions[k]
650 if f.vectorequiv != None:
651 equiv = self.find_function(f.vectorequiv)
652 if equiv != None:
653 f.glx_doubles_in_order = equiv.glx_doubles_in_order
654 f.glx_rop = equiv.glx_rop
655 else:
656 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f.name, f.vectorequiv))
657 else:
658 gl_XML.FilterGLAPISpecBase.endElement(self, name)
659 return