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
):
89 # "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"}.
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).
107 def append(self
, count
, value
, name
):
108 if self
.enums
.has_key( value
):
109 self
.enums
[value
].append(name
)
111 if not self
.count
.has_key(count
):
112 self
.count
[count
] = []
114 self
.enums
[value
] = []
115 self
.enums
[value
].append(name
)
116 self
.count
[count
].append(value
)
119 def signature( self
):
123 for e
in self
.count
[i
]:
124 self
.sig
+= "%04x,%u," % (e
, i
)
129 def set_mode( self
, mode
):
130 """Mark an enum-function as a 'set' function."""
139 def PrintUsingTable(self
):
140 """Emit the body of the __gl*_size function using a pair
141 of look-up tables and a mask. The mask is calculated such
142 that (e & mask) is unique for all the valid values of e for
143 this function. The result of (e & mask) is used as an index
144 into the first look-up table. If it matches e, then the
145 same entry of the second table is returned. Otherwise zero
148 It seems like this should cause better code to be generated.
149 However, on x86 at least, the resulting .o file is about 20%
150 larger then the switch-statment version. I am leaving this
151 code in because the results may be different on other
152 platforms (e.g., PowerPC or x86-64)."""
159 # Determine if there is some mask M, such that M = (2^N) - 1,
160 # that will generate unique values for all of the enums.
163 for i
in [1, 2, 3, 4, 5, 6, 7, 8]:
170 if (a
& mask
) == (b
& mask
):
178 if (mask
!= 0) and (mask
< (2 * count
)):
182 for i
in range(0, mask
+ 1):
183 masked_enums
[i
] = "0";
187 for e
in self
.count
[c
]:
189 masked_enums
[i
] = '0x%04x /* %s */' % (e
, self
.enums
[e
][0])
193 print ' static const GLushort a[%u] = {' % (mask
+ 1)
194 for e
in masked_enums
:
195 print ' %s, ' % (masked_enums
[e
])
198 print ' static const GLubyte b[%u] = {' % (mask
+ 1)
199 for c
in masked_count
:
200 print ' %u, ' % (masked_count
[c
])
203 print ' const unsigned idx = (e & 0x%02xU);' % (mask
)
205 print ' return (e == a[idx]) ? (GLint) b[idx] : 0;'
210 def PrintUsingSwitch(self
):
211 """Emit the body of the __gl*_size function using a
214 print ' switch( e ) {'
217 for e
in self
.count
[c
]:
220 # There may be multiple enums with the same
221 # value. This happens has extensions are
222 # promoted from vendor-specific or EXT to
223 # ARB and to the core. Emit the first one as
224 # a case label, and emit the others as
225 # commented-out case labels.
227 for j
in self
.enums
[e
]:
229 print ' case %s:' % (j
)
232 print '/* case %s:*/' % (j
)
234 print ' return %u;' % (c
)
236 print ' default: return 0;'
240 def Print(self
, name
):
241 print 'INTERNAL PURE FASTCALL GLint'
242 print '__gl%s_size( GLenum e )' % (name
)
245 if not self
.PrintUsingTable():
246 self
.PrintUsingSwitch()
253 class glXEnum(gl_XML
.glEnum
):
254 def __init__(self
, context
, name
, attrs
):
255 gl_XML
.glEnum
.__init
__(self
, context
, name
, attrs
)
258 def startElement(self
, name
, attrs
):
260 [n
, c
, mode
] = self
.process_attributes(attrs
)
262 if not self
.context
.glx_enum_functions
.has_key( n
):
263 f
= glXEnumFunction( n
)
265 self
.context
.glx_enum_functions
[ f
.name
] = f
267 self
.context
.glx_enum_functions
[ n
].append( c
, self
.value
, self
.name
)
269 gl_XML
.glEnum
.startElement(self
, context
, name
, attrs
)
273 class glXParameter(gl_XML
.glParameter
):
274 def __init__(self
, context
, name
, attrs
):
276 gl_XML
.glParameter
.__init
__(self
, context
, name
, attrs
);
279 class glXParameterIterator
:
280 """Class to iterate over a list of glXParameters.
282 Objects of this class are returned by the parameterIterator method of
283 the glXFunction class. They are used to iterate over the list of
284 parameters to the function."""
286 def __init__(self
, data
, skip_output
, max_order
):
290 self
.skip_output
= skip_output
291 self
.max_order
= max_order
297 if len( self
.data
) == 0:
301 if self
.index
== len( self
.data
):
302 if self
.order
== self
.max_order
:
311 if self
.data
[i
].order
== self
.order
and not (self
.data
[i
].is_output
and self
.skip_output
):
315 class glXFunction(gl_XML
.glFunction
):
320 # If this is set to true, it means that GLdouble parameters should be
321 # written to the GLX protocol packet in the order they appear in the
322 # prototype. This is different from the "classic" ordering. In the
323 # classic ordering GLdoubles are written to the protocol packet first,
324 # followed by non-doubles. NV_vertex_program was the first extension
325 # to break with this tradition.
327 glx_doubles_in_order
= 0
334 def __init__(self
, context
, name
, attrs
):
335 self
.vectorequiv
= attrs
.get('vectorequiv', None)
336 self
.count_parameters
= None
339 self
.can_be_large
= 0
340 self
.reply_always_array
= 0
342 gl_XML
.glFunction
.__init
__(self
, context
, name
, attrs
)
346 def parameterIterator(self
, skip_output
, max_order
):
347 return glXParameterIterator(self
.fn_parameters
, skip_output
, max_order
)
350 def startElement(self
, name
, attrs
):
351 """Process elements within a function that are specific to GLX."""
354 self
.glx_rop
= int(attrs
.get('rop', "0"))
355 self
.glx_sop
= int(attrs
.get('sop', "0"))
356 self
.glx_vendorpriv
= int(attrs
.get('vendorpriv', "0"))
358 if attrs
.get('handcode', "false") == "true":
363 if attrs
.get('ignore', "false") == "true":
368 if attrs
.get('large', "false") == "true":
369 self
.can_be_large
= 1
371 self
.can_be_large
= 0
373 if attrs
.get('doubles_in_order', "false") == "true":
374 self
.glx_doubles_in_order
= 1
376 self
.glx_doubles_in_order
= 0
378 if attrs
.get('always_array', "false") == "true":
379 self
.reply_always_array
= 1
381 self
.reply_always_array
= 0
384 gl_XML
.glFunction
.startElement(self
, name
, attrs
)
387 def endElement(self
, name
):
388 if name
== "function":
389 # Mark any function that does not have GLX protocol
390 # defined as "ignore". This prevents bad things from
391 # happening when people add new functions to the GL
392 # API XML without adding any GLX section.
394 # This will also mark functions that don't have a
395 # dispatch offset at ignored.
397 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 self.fn_offset == -1:
400 # print '/* %s ignored becuase no offset assigned. */' % (self.name)
402 # print '/* %s ignored becuase no GLX opcode assigned. */' % (self.name)
406 return gl_XML
.glFunction
.endElement(self
, name
)
409 def append(self
, tag_name
, p
):
410 gl_XML
.glFunction
.append(self
, tag_name
, p
)
412 if p
.is_variable_length_array():
414 elif not self
.glx_doubles_in_order
and p
.p_type
.size
== 8:
417 if p
.p_count_parameters
!= None:
418 self
.count_parameters
= p
.p_count_parameters
421 self
.counter
= p
.name
429 def variable_length_parameter(self
):
430 for param
in self
.fn_parameters
:
431 if param
.is_variable_length_array():
437 def offset_of_first_parameter(self
):
438 """Get the offset of the first parameter in the command.
440 Gets the offset of the first function parameter in the GLX
441 command packet. This byte offset is measured from the end
442 of the Render / RenderLarge header. The offset for all non-
443 pixel commends is zero. The offset for pixel commands depends
444 on the number of dimensions of the pixel data."""
447 [dim
, junk
, junk
, junk
, junk
] = self
.dimensions()
449 # The base size is the size of the pixel pack info
450 # header used by images with the specified number
458 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim
, self
.image
.name
, self
.name
))
463 def command_fixed_length(self
):
464 """Return the length, in bytes as an integer, of the
465 fixed-size portion of the command."""
467 size
= self
.offset_of_first_parameter()
469 for p
in gl_XML
.glFunction
.parameterIterator(self
):
472 if self
.pad_after(p
):
475 if self
.image
and self
.image
.img_null_flag
:
481 def command_variable_length(self
):
482 """Return the length, as a string, of the variable-sized
483 portion of the command."""
486 for p
in gl_XML
.glFunction
.parameterIterator(self
):
487 if (not p
.is_output
) and (p
.size() == 0):
488 size_string
= size_string
+ " + __GLX_PAD(%s)" % (p
.size_string())
493 def command_length(self
):
494 size
= self
.command_fixed_length()
496 if self
.glx_rop
!= 0:
499 size
= ((size
+ 3) & ~
3)
500 return "%u%s" % (size
, self
.command_variable_length())
503 def opcode_real_value(self
):
504 """Get the true numeric value of the GLX opcode
506 Behaves similarly to opcode_value, except for
507 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
508 In these cases the value for the GLX opcode field (i.e.,
509 16 for X_GLXVendorPrivate or 17 for
510 X_GLXVendorPrivateWithReply) is returned. For other 'single'
511 commands, the opcode for the command (e.g., 101 for
512 X_GLsop_NewList) is returned."""
514 if self
.glx_vendorpriv
!= 0:
515 if self
.needs_reply():
520 return self
.opcode_value()
522 def opcode_value(self
):
523 """Get the unique protocol opcode for the glXFunction"""
525 if self
.glx_rop
!= 0:
527 elif self
.glx_sop
!= 0:
529 elif self
.glx_vendorpriv
!= 0:
530 return self
.glx_vendorpriv
534 def opcode_rop_basename(self
):
535 """Return either the name to be used for GLX protocol enum.
537 Returns either the name of the function or the name of the
538 name of the equivalent vector (e.g., glVertex3fv for
539 glVertex3f) function."""
541 if self
.vectorequiv
== None:
544 return self
.vectorequiv
546 def opcode_name(self
):
547 """Get the unique protocol enum name for the glXFunction"""
549 if self
.glx_rop
!= 0:
550 return "X_GLrop_%s" % (self
.opcode_rop_basename())
551 elif self
.glx_sop
!= 0:
552 return "X_GLsop_%s" % (self
.name
)
553 elif self
.glx_vendorpriv
!= 0:
554 return "X_GLvop_%s" % (self
.name
)
558 def opcode_real_name(self
):
559 """Get the true protocol enum name for the GLX opcode
561 Behaves similarly to opcode_name, except for
562 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
563 In these cases the string 'X_GLXVendorPrivate' or
564 'X_GLXVendorPrivateWithReply' is returned. For other
565 single or render commands 'X_GLsop' or 'X_GLrop' plus the
566 name of the function returned."""
568 if self
.glx_vendorpriv
!= 0:
569 if self
.needs_reply():
570 return "X_GLXVendorPrivateWithReply"
572 return "X_GLXVendorPrivate"
574 return self
.opcode_name()
577 def return_string(self
):
578 if self
.fn_return_type
!= 'void':
579 return "return retval;"
584 def needs_reply(self
):
585 return self
.fn_return_type
!= 'void' or self
.output
!= None
588 def dimensions(self
):
589 """Determine the dimensions of an image.
591 Returns a tuple representing the number of dimensions and the
592 string name of each of the dimensions of an image, If the
593 function is not a pixel function, the number of dimensions
597 return [0, "0", "0", "0", "0"]
602 if self
.image
.height
:
604 h
= self
.image
.height
614 if self
.image
.extent
:
616 e
= self
.image
.extent
620 return [dim
, w
, h
, d
, e
]
623 def pad_after(self
, p
):
624 """Returns the name of the field inserted after the
625 specified field to pad out the command header."""
627 if self
.image
and self
.image
.img_pad_dimensions
:
628 if not self
.image
.height
:
629 if p
.name
== self
.image
.width
:
631 elif p
.name
== self
.image
.img_xoff
:
633 elif not self
.image
.extent
:
634 if p
.name
== self
.image
.depth
:
635 # Should this be "size4d"?
637 elif p
.name
== self
.image
.img_zoff
:
642 class GlxProto(gl_XML
.FilterGLAPISpecBase
):
643 name
= "glX_proto_send.py (from Mesa)"
646 gl_XML
.FilterGLAPISpecBase
.__init
__(self
)
647 self
.factory
= glXItemFactory()
648 self
.glx_enum_functions
= {}
651 def endElement(self
, name
):
652 if name
== 'OpenGLAPI':
653 # Once all the parsing is done, we have to go back and
654 # fix-up some cross references between different
657 for k
in self
.functions
:
658 f
= self
.functions
[k
]
659 if f
.vectorequiv
!= None:
660 equiv
= self
.find_function(f
.vectorequiv
)
662 f
.glx_doubles_in_order
= equiv
.glx_doubles_in_order
663 f
.glx_rop
= equiv
.glx_rop
665 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f
.name
, f
.vectorequiv
))
667 gl_XML
.FilterGLAPISpecBase
.endElement(self
, name
)