3 # (C) Copyright IBM Corporation 2004, 2005
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:
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
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
26 # Ian Romanick <idr@us.ibm.com>
28 from xml
.sax
import saxutils
29 from xml
.sax
import make_parser
30 from xml
.sax
.handler
import feature_namespaces
38 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
39 # define PURE __attribute__((pure))
45 print """# if defined(__i386__) && defined(__GNUC__)
46 # define FASTCALL __attribute__((fastcall))
51 def printVisibility(S
, s
):
52 print """# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
53 # define %s __attribute__((visibility("%s")))
56 # endif""" % (S
, s
, S
)
59 print """# if defined(__GNUC__)
60 # define NOINLINE __attribute__((noinline))
66 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
70 class glXItemFactory(gl_XML
.glItemFactory
):
71 """Factory to create GLX protocol oriented objects derived from glItem."""
73 def create(self
, context
, name
, attrs
):
74 if name
== "function":
75 return glXFunction(context
, name
, attrs
)
77 return glXEnum(context
, name
, attrs
)
79 return glXParameter(context
, name
, attrs
)
81 return gl_XML
.glItemFactory
.create(self
, context
, name
, attrs
)
83 class glXEnumFunction
:
84 def __init__(self
, name
):
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"}.
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).
105 def append(self
, count
, value
, name
):
106 if self
.enums
.has_key( value
):
107 self
.enums
[value
].append(name
)
109 if not self
.count
.has_key(count
):
110 self
.count
[count
] = []
112 self
.enums
[value
] = []
113 self
.enums
[value
].append(name
)
114 self
.count
[count
].append(value
)
117 def signature( self
):
120 for e
in self
.count
[i
]:
121 sig
+= "%04x,%u," % (e
, i
)
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
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)."""
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.
150 for i
in [1, 2, 3, 4, 5, 6, 7, 8]:
157 if (a
& mask
) == (b
& mask
):
165 if (mask
!= 0) and (mask
< (2 * count
)):
169 for i
in range(0, mask
+ 1):
170 masked_enums
[i
] = "0";
174 for e
in self
.count
[c
]:
176 masked_enums
[i
] = '0x%04x /* %s */' % (e
, self
.enums
[e
][0])
180 print ' static const GLushort a[%u] = {' % (mask
+ 1)
181 for e
in masked_enums
:
182 print ' %s, ' % (masked_enums
[e
])
185 print ' static const GLubyte b[%u] = {' % (mask
+ 1)
186 for c
in masked_count
:
187 print ' %u, ' % (masked_count
[c
])
190 print ' const unsigned idx = (e & 0x%02xU);' % (mask
)
192 print ' return (e == a[idx]) ? (GLint) b[idx] : 0;'
197 def PrintUsingSwitch(self
):
198 """Emit the body of the __gl*_size function using a
201 print ' switch( e ) {'
204 for e
in self
.count
[c
]:
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.
214 for j
in self
.enums
[e
]:
216 print ' case %s:' % (j
)
219 print '/* case %s:*/' % (j
)
221 print ' return %u;' % (c
)
223 print ' default: return 0;'
227 def Print(self
, name
):
228 print 'INTERNAL PURE FASTCALL GLint'
229 print '__gl%s_size( GLenum e )' % (name
)
232 if not self
.PrintUsingTable():
233 self
.PrintUsingSwitch()
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
= []
245 def startElement(self
, name
, attrs
):
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
252 temp
= attrs
.get('count', None)
256 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp
, self
.name
, n
))
258 self
.context
.glx_enum_functions
[ n
].append( c
, self
.value
, self
.name
)
260 gl_XML
.glEnum
.startElement(self
, context
, name
, attrs
)
264 class glXParameter(gl_XML
.glParameter
):
265 def __init__(self
, context
, name
, attrs
):
267 gl_XML
.glParameter
.__init
__(self
, context
, name
, attrs
);
270 class glXParameterIterator
:
271 """Class to iterate over a list of glXParameters.
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."""
277 def __init__(self
, data
, skip_output
, max_order
):
281 self
.skip_output
= skip_output
282 self
.max_order
= max_order
288 if len( self
.data
) == 0:
292 if self
.index
== len( self
.data
):
293 if self
.order
== self
.max_order
:
302 if self
.data
[i
].order
== self
.order
and not (self
.data
[i
].is_output
and self
.skip_output
):
306 class glXFunction(gl_XML
.glFunction
):
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.
318 glx_doubles_in_order
= 0
325 def __init__(self
, context
, name
, attrs
):
326 self
.vectorequiv
= attrs
.get('vectorequiv', None)
327 self
.count_parameters
= None
330 self
.can_be_large
= 0
331 self
.reply_always_array
= 0
333 gl_XML
.glFunction
.__init
__(self
, context
, name
, attrs
)
337 def parameterIterator(self
, skip_output
, max_order
):
338 return glXParameterIterator(self
.fn_parameters
, skip_output
, max_order
)
341 def startElement(self
, name
, attrs
):
342 """Process elements within a function that are specific to 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"))
349 if attrs
.get('handcode', "false") == "true":
354 if attrs
.get('ignore', "false") == "true":
359 if attrs
.get('large', "false") == "true":
360 self
.can_be_large
= 1
362 self
.can_be_large
= 0
364 if attrs
.get('doubles_in_order', "false") == "true":
365 self
.glx_doubles_in_order
= 1
367 self
.glx_doubles_in_order
= 0
369 if attrs
.get('always_array', "false") == "true":
370 self
.reply_always_array
= 1
372 self
.reply_always_array
= 0
375 gl_XML
.glFunction
.startElement(self
, name
, attrs
)
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.
385 # This will also mark functions that don't have a
386 # dispatch offset at ignored.
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
):
390 # if self.fn_offset == -1:
391 # print '/* %s ignored becuase no offset assigned. */' % (self.name)
393 # print '/* %s ignored becuase no GLX opcode assigned. */' % (self.name)
397 return gl_XML
.glFunction
.endElement(self
, name
)
400 def append(self
, tag_name
, p
):
401 gl_XML
.glFunction
.append(self
, tag_name
, p
)
403 if p
.is_variable_length_array():
405 elif not self
.glx_doubles_in_order
and p
.p_type
.size
== 8:
408 if p
.p_count_parameters
!= None:
409 self
.count_parameters
= p
.p_count_parameters
412 self
.counter
= p
.name
419 def variable_length_parameter(self
):
420 for param
in self
.fn_parameters
:
421 if param
.is_variable_length_array():
427 def command_payload_length(self
):
431 [dim
, junk
, junk
, junk
, junk
] = self
.dimensions()
433 # The base size is the size of the pixel pack info
434 # header used by images with the specified number
442 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim
, self
.image
.name
, self
.name
))
444 if self
.image
.img_null_flag
:
447 if self
.image
.img_pad_dimensions
:
448 size
+= 4 * (dim
& 1)
450 # If the image has offset parameters, like
451 # TexSubImage1D or TexSubImage3D, they need to
452 # be padded out as well.
454 if self
.image
.img_xoff
:
455 size
+= 4 * (dim
& 1)
460 for p
in gl_XML
.glFunction
.parameterIterator(self
):
461 if p
.is_output
: continue
462 temp
= p
.size_string()
467 size_string
= size_string
+ " + __GLX_PAD(%s)" % (temp
)
469 return [size
, size_string
]
471 def command_length(self
):
472 [size
, size_string
] = self
.command_payload_length()
474 if self
.glx_rop
!= 0:
477 size
= ((size
+ 3) & ~
3)
478 return "%u%s" % (size
, size_string
)
481 def opcode_real_value(self
):
482 """Get the true numeric value of the GLX opcode
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."""
492 if self
.glx_vendorpriv
!= 0:
493 if self
.needs_reply():
498 return self
.opcode_value()
500 def opcode_value(self
):
501 """Get the unique protocol opcode for the glXFunction"""
503 if self
.glx_rop
!= 0:
505 elif self
.glx_sop
!= 0:
507 elif self
.glx_vendorpriv
!= 0:
508 return self
.glx_vendorpriv
512 def opcode_rop_basename(self
):
513 """Return either the name to be used for GLX protocol enum.
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."""
519 if self
.vectorequiv
== None:
522 return self
.vectorequiv
524 def opcode_name(self
):
525 """Get the unique protocol enum name for the glXFunction"""
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
)
536 def opcode_real_name(self
):
537 """Get the true protocol enum name for the GLX opcode
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."""
546 if self
.glx_vendorpriv
!= 0:
547 if self
.needs_reply():
548 return "X_GLXVendorPrivateWithReply"
550 return "X_GLXVendorPrivate"
552 return self
.opcode_name()
555 def return_string(self
):
556 if self
.fn_return_type
!= 'void':
557 return "return retval;"
562 def needs_reply(self
):
563 return self
.fn_return_type
!= 'void' or self
.output
!= None
566 def dimensions(self
):
567 """Determine the dimensions of an image.
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
575 return [0, "0", "0", "0", "0"]
580 if self
.image
.height
:
582 h
= self
.image
.height
592 if self
.image
.extent
:
594 e
= self
.image
.extent
598 return [dim
, w
, h
, d
, e
]
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."""
605 if self
.image
and self
.image
.img_pad_dimensions
:
606 if not self
.image
.height
:
607 if p
.name
== self
.image
.width
:
609 elif p
.name
== self
.image
.img_xoff
:
611 elif not self
.image
.extent
:
612 if p
.name
== self
.image
.depth
:
613 # Should this be "size4d"?
615 elif p
.name
== self
.image
.img_zoff
:
620 class GlxProto(gl_XML
.FilterGLAPISpecBase
):
621 name
= "glX_proto_send.py (from Mesa)"
624 gl_XML
.FilterGLAPISpecBase
.__init
__(self
)
625 self
.factory
= glXItemFactory()
626 self
.glx_enum_functions
= {}
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
635 for k
in self
.functions
:
636 f
= self
.functions
[k
]
637 if f
.vectorequiv
!= None:
638 equiv
= self
.find_function(f
.vectorequiv
)
640 f
.glx_doubles_in_order
= equiv
.glx_doubles_in_order
641 f
.glx_rop
= equiv
.glx_rop
643 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f
.name
, f
.vectorequiv
))
645 gl_XML
.FilterGLAPISpecBase
.endElement(self
, name
)