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
34 import sys
, getopt
, string
37 class glXItemFactory(gl_XML
.glItemFactory
):
38 """Factory to create GLX protocol oriented objects derived from glItem."""
40 def create(self
, context
, name
, attrs
):
41 if name
== "function":
42 return glXFunction(context
, name
, attrs
)
44 return glXEnum(context
, name
, attrs
)
46 return glXParameter(context
, name
, attrs
)
48 return gl_XML
.glItemFactory
.create(self
, context
, name
, attrs
)
50 class glXEnumFunction
:
51 def __init__(self
, name
, context
):
53 self
.context
= context
57 # "enums" is a set of lists. The element in the set is the
58 # value of the enum. The list is the list of names for that
59 # value. For example, [0x8126] = {"POINT_SIZE_MIN",
60 # "POINT_SIZE_MIN_ARB", "POINT_SIZE_MIN_EXT",
61 # "POINT_SIZE_MIN_SGIS"}.
65 # "count" is indexed by count values. Each element of count
66 # is a list of index to "enums" that have that number of
67 # associated data elements. For example, [4] =
68 # {GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION,
69 # GL_AMBIENT_AND_DIFFUSE} (the enum names are used here,
70 # but the actual hexadecimal values would be in the array).
75 def append(self
, count
, value
, name
):
76 if self
.enums
.has_key( value
):
77 self
.enums
[value
].append(name
)
79 if not self
.count
.has_key(count
):
80 self
.count
[count
] = []
82 self
.enums
[value
] = []
83 self
.enums
[value
].append(name
)
84 self
.count
[count
].append(value
)
87 def signature( self
):
92 for e
in self
.count
[i
]:
93 self
.sig
+= "%04x,%u," % (e
, i
)
98 def set_mode( self
, mode
):
99 """Mark an enum-function as a 'set' function."""
108 def PrintUsingTable(self
):
109 """Emit the body of the __gl*_size function using a pair
110 of look-up tables and a mask. The mask is calculated such
111 that (e & mask) is unique for all the valid values of e for
112 this function. The result of (e & mask) is used as an index
113 into the first look-up table. If it matches e, then the
114 same entry of the second table is returned. Otherwise zero
117 It seems like this should cause better code to be generated.
118 However, on x86 at least, the resulting .o file is about 20%
119 larger then the switch-statment version. I am leaving this
120 code in because the results may be different on other
121 platforms (e.g., PowerPC or x86-64)."""
128 if self
.count
.has_key(-1):
131 # Determine if there is some mask M, such that M = (2^N) - 1,
132 # that will generate unique values for all of the enums.
135 for i
in [1, 2, 3, 4, 5, 6, 7, 8]:
142 if (a
& mask
) == (b
& mask
):
150 if (mask
!= 0) and (mask
< (2 * count
)):
154 for i
in range(0, mask
+ 1):
155 masked_enums
[i
] = "0";
159 for e
in self
.count
[c
]:
161 masked_enums
[i
] = '0x%04x /* %s */' % (e
, self
.enums
[e
][0])
165 print ' static const GLushort a[%u] = {' % (mask
+ 1)
166 for e
in masked_enums
:
167 print ' %s, ' % (masked_enums
[e
])
170 print ' static const GLubyte b[%u] = {' % (mask
+ 1)
171 for c
in masked_count
:
172 print ' %u, ' % (masked_count
[c
])
175 print ' const unsigned idx = (e & 0x%02xU);' % (mask
)
177 print ' return (e == a[idx]) ? (GLint) b[idx] : 0;'
182 def PrintUsingSwitch(self
, name
):
183 """Emit the body of the __gl*_size function using a
186 print ' switch( e ) {'
189 for e
in self
.count
[c
]:
192 # There may be multiple enums with the same
193 # value. This happens has extensions are
194 # promoted from vendor-specific or EXT to
195 # ARB and to the core. Emit the first one as
196 # a case label, and emit the others as
197 # commented-out case labels.
199 for j
in self
.enums
[e
]:
201 print ' case %s:' % (j
)
204 print '/* case %s:*/' % (j
)
207 print ' return __gl%s_variable_size( e );' % (name
)
209 print ' return %u;' % (c
)
211 print ' default: return 0;'
215 def Print(self
, name
):
216 print 'INTERNAL PURE FASTCALL GLint'
217 print '__gl%s_size( GLenum e )' % (name
)
220 if not self
.PrintUsingTable():
221 self
.PrintUsingSwitch(name
)
228 class glXEnum(gl_XML
.glEnum
):
229 def __init__(self
, context
, name
, attrs
):
230 gl_XML
.glEnum
.__init
__(self
, context
, name
, attrs
)
233 def startElementNS(self
, name
, qname
, attrs
):
234 [uri
, true_name
] = name
235 if true_name
== "size":
236 [temp_n
, c
, mode
] = self
.process_attributes(attrs
)
239 names
= ["GetIntegerv", "GetBooleanv", "GetFloatv", "GetDoublev" ]
244 if not self
.context
.glx_enum_functions
.has_key( n
):
245 f
= self
.context
.createEnumFunction( n
)
247 self
.context
.glx_enum_functions
[ f
.name
] = f
249 self
.context
.glx_enum_functions
[ n
].append( c
, self
.value
, self
.name
)
251 gl_XML
.glEnum
.startElementNS(self
, name
, qname
, attrs
)
255 class glXParameter(gl_XML
.glParameter
):
256 def __init__(self
, context
, name
, attrs
):
258 gl_XML
.glParameter
.__init
__(self
, context
, name
, attrs
);
261 class glXParameterIterator
:
262 """Class to iterate over a list of glXParameters.
264 Objects of this class are returned by the parameterIterator method of
265 the glXFunction class. They are used to iterate over the list of
266 parameters to the function."""
268 def __init__(self
, data
, skip_output
, max_order
):
272 self
.skip_output
= skip_output
273 self
.max_order
= max_order
279 if len( self
.data
) == 0:
283 if self
.index
== len( self
.data
):
284 if self
.order
== self
.max_order
:
293 if self
.data
[i
].order
== self
.order
and not (self
.data
[i
].is_output
and self
.skip_output
):
297 class glXFunction(gl_XML
.glFunction
):
302 # If this is set to true, it means that GLdouble parameters should be
303 # written to the GLX protocol packet in the order they appear in the
304 # prototype. This is different from the "classic" ordering. In the
305 # classic ordering GLdoubles are written to the protocol packet first,
306 # followed by non-doubles. NV_vertex_program was the first extension
307 # to break with this tradition.
309 glx_doubles_in_order
= 0
314 def __init__(self
, context
, name
, attrs
):
315 self
.vectorequiv
= attrs
.get((None, 'vectorequiv'), None)
318 self
.can_be_large
= 0
319 self
.reply_always_array
= 0
320 self
.dimensions_in_reply
= 0
321 self
.img_reset
= None
323 self
.server_handcode
= 0
324 self
.client_handcode
= 0
327 gl_XML
.glFunction
.__init
__(self
, context
, name
, attrs
)
331 def parameterIterator(self
, skip_output
, max_order
):
332 return glXParameterIterator(self
.fn_parameters
, skip_output
, max_order
)
335 def startElementNS(self
, name
, qname
, attrs
):
336 """Process elements within a function that are specific to GLX."""
338 [uri
, true_name
] = name
339 if true_name
== "glx":
340 self
.glx_rop
= int(attrs
.get((None, 'rop'), "0"))
341 self
.glx_sop
= int(attrs
.get((None, 'sop'), "0"))
342 self
.glx_vendorpriv
= int(attrs
.get((None, 'vendorpriv'), "0"))
343 self
.img_reset
= attrs
.get((None, 'img_reset'), None)
345 # The 'handcode' attribute can be one of 'true',
346 # 'false', 'client', or 'server'.
348 handcode
= attrs
.get((None, 'handcode'), "false")
349 if handcode
== "false":
350 self
.server_handcode
= 0
351 self
.client_handcode
= 0
352 elif handcode
== "true":
353 self
.server_handcode
= 1
354 self
.client_handcode
= 1
355 elif handcode
== "client":
356 self
.server_handcode
= 0
357 self
.client_handcode
= 1
358 elif handcode
== "server":
359 self
.server_handcode
= 1
360 self
.client_handcode
= 0
362 raise RuntimeError('Invalid handcode mode "%s" in function "%s".' % (handcode
, self
.name
))
364 self
.ignore
= gl_XML
.is_attr_true( attrs
, 'ignore' )
365 self
.can_be_large
= gl_XML
.is_attr_true( attrs
, 'large' )
366 self
.glx_doubles_in_order
= gl_XML
.is_attr_true( attrs
, 'doubles_in_order' )
367 self
.reply_always_array
= gl_XML
.is_attr_true( attrs
, 'always_array' )
368 self
.dimensions_in_reply
= gl_XML
.is_attr_true( attrs
, 'dimensions_in_reply' )
370 gl_XML
.glFunction
.startElementNS(self
, name
, qname
, attrs
)
373 def endElementNS(self
, name
, qname
):
374 [uri
, true_name
] = name
375 if true_name
== "function":
376 # Mark any function that does not have GLX protocol
377 # defined as "ignore". This prevents bad things from
378 # happening when people add new functions to the GL
379 # API XML without adding any GLX section.
381 # This will also mark functions that don't have a
382 # dispatch offset at ignored.
384 if (self
.fn_offset
== -1 and not self
.fn_alias
) or not (self
.client_handcode
or self
.server_handcode
or self
.glx_rop
or self
.glx_sop
or self
.glx_vendorpriv
or self
.vectorequiv
or self
.fn_alias
):
386 # if self.fn_offset == -1:
387 # print '/* %s ignored becuase no offset assigned. */' % (self.name)
389 # print '/* %s ignored becuase no GLX opcode assigned. */' % (self.name)
393 return gl_XML
.glFunction
.endElementNS(self
, name
, qname
)
396 def append(self
, tag_name
, p
):
397 gl_XML
.glFunction
.append(self
, tag_name
, p
)
399 if p
.is_variable_length_array():
401 elif not self
.glx_doubles_in_order
and p
.p_type
.size
== 8:
405 self
.counter
= p
.name
413 def variable_length_parameter(self
):
414 if len(self
.variable_length_parameters
):
415 return self
.variable_length_parameters
[0]
420 def output_parameter(self
):
421 for param
in self
.fn_parameters
:
428 def offset_of_first_parameter(self
):
429 """Get the offset of the first parameter in the command.
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."""
437 if self
.image
and not self
.image
.is_output
:
438 [dim
, junk
, junk
, junk
, junk
] = self
.dimensions()
440 # The base size is the size of the pixel pack info
441 # header used by images with the specified number
449 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim
, self
.image
.name
, self
.name
))
454 def command_fixed_length(self
):
455 """Return the length, in bytes as an integer, of the
456 fixed-size portion of the command."""
458 size
= self
.offset_of_first_parameter()
460 for p
in gl_XML
.glFunction
.parameterIterator(self
):
461 if not p
.is_output
and p
.name
!= self
.img_reset
:
463 if self
.pad_after(p
):
466 if self
.image
and (self
.image
.img_null_flag
or self
.image
.is_output
):
472 def command_variable_length(self
):
473 """Return the length, as a string, of the variable-sized
474 portion of the command."""
477 for p
in gl_XML
.glFunction
.parameterIterator(self
):
478 if (not p
.is_output
) and (p
.size() == 0):
479 size_string
= size_string
+ " + __GLX_PAD(%s)" % (p
.size_string())
484 def command_length(self
):
485 size
= self
.command_fixed_length()
487 if self
.glx_rop
!= 0:
490 size
= ((size
+ 3) & ~
3)
491 return "%u%s" % (size
, self
.command_variable_length())
494 def opcode_real_value(self
):
495 """Get the true numeric value of the GLX opcode
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."""
505 if self
.glx_vendorpriv
!= 0:
506 if self
.needs_reply():
511 return self
.opcode_value()
513 def opcode_value(self
):
514 """Get the unique protocol opcode for the glXFunction"""
516 if self
.glx_rop
!= 0:
518 elif self
.glx_sop
!= 0:
520 elif self
.glx_vendorpriv
!= 0:
521 return self
.glx_vendorpriv
525 def opcode_rop_basename(self
):
526 """Return either the name to be used for GLX protocol enum.
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."""
532 if self
.vectorequiv
== None:
535 return self
.vectorequiv
537 def opcode_name(self
):
538 """Get the unique protocol enum name for the glXFunction"""
540 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
)
547 raise RuntimeError('Function "%s" has no opcode.' % (self
.name
))
550 def opcode_real_name(self
):
551 """Get the true protocol enum name for the GLX opcode
553 Behaves similarly to opcode_name, except for
554 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
555 In these cases the string 'X_GLXVendorPrivate' or
556 'X_GLXVendorPrivateWithReply' is returned. For other
557 single or render commands 'X_GLsop' or 'X_GLrop' plus the
558 name of the function returned."""
560 if self
.glx_vendorpriv
!= 0:
561 if self
.needs_reply():
562 return "X_GLXVendorPrivateWithReply"
564 return "X_GLXVendorPrivate"
566 return self
.opcode_name()
569 def return_string(self
):
570 if self
.fn_return_type
!= 'void':
571 return "return retval;"
576 def needs_reply(self
):
577 return self
.fn_return_type
!= 'void' or self
.output
!= None
580 def dimensions(self
):
581 """Determine the dimensions of an image.
583 Returns a tuple representing the number of dimensions and the
584 string name of each of the dimensions of an image, If the
585 function is not a pixel function, the number of dimensions
589 return [0, "0", "0", "0", "0"]
594 if self
.image
.height
:
596 h
= self
.image
.height
606 if self
.image
.extent
:
608 e
= self
.image
.extent
612 return [dim
, w
, h
, d
, e
]
615 def pad_after(self
, p
):
616 """Returns the name of the field inserted after the
617 specified field to pad out the command header."""
619 if self
.image
and self
.image
.img_pad_dimensions
:
620 if not self
.image
.height
:
621 if p
.name
== self
.image
.width
:
623 elif p
.name
== self
.image
.img_xoff
:
625 elif not self
.image
.extent
:
626 if p
.name
== self
.image
.depth
:
627 # Should this be "size4d"?
629 elif p
.name
== self
.image
.img_zoff
:
634 class glXFunctionIterator(gl_XML
.glFunctionIterator
):
635 """Class to iterate over a list of glXFunctions"""
637 def __init__(self
, context
):
638 self
.context
= context
639 self
.keys
= context
.functions
.keys()
642 for self
.index
in range(0, len(self
.keys
)):
643 if self
.keys
[ self
.index
] >= 0: break
649 if self
.index
== len(self
.keys
):
652 f
= self
.context
.functions
[ self
.keys
[ self
.index
] ]
661 class GlxProto(gl_XML
.FilterGLAPISpecBase
):
662 name
= "glX_proto_send.py (from Mesa)"
665 gl_XML
.FilterGLAPISpecBase
.__init
__(self
)
666 self
.factory
= glXItemFactory()
667 self
.glx_enum_functions
= {}
670 def endElementNS(self
, name
, qname
):
671 [uri
, true_name
] = name
672 if true_name
== 'OpenGLAPI':
673 # Once all the parsing is done, we have to go back and
674 # fix-up some cross references between different
677 for k
in self
.functions
:
678 f
= self
.functions
[k
]
679 if f
.vectorequiv
!= None:
680 equiv
= self
.find_function(f
.vectorequiv
)
682 f
.glx_doubles_in_order
= equiv
.glx_doubles_in_order
683 f
.glx_rop
= equiv
.glx_rop
685 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f
.name
, f
.vectorequiv
))
687 gl_XML
.FilterGLAPISpecBase
.endElementNS(self
, name
, qname
)
691 def createEnumFunction(self
, n
):
692 return glXEnumFunction(n
, self
)
695 def functionIterator(self
):
696 return glXFunctionIterator(self
)
699 def size_call(self
, func
):
700 """Create C code to calculate 'compsize'.
702 Creates code to calculate 'compsize'. If the function does
703 not need 'compsize' to be calculated, None will be
706 if not func
.image
and not func
.count_parameter_list
:
710 parameters
= string
.join( func
.count_parameter_list
, "," )
711 compsize
= "__gl%s_size(%s)" % (func
.name
, parameters
)
713 [dim
, w
, h
, d
, junk
] = func
.dimensions()
715 compsize
= '__glImageSize(%s, %s, %s, %s, %s, %s)' % (w
, h
, d
, func
.image
.img_format
, func
.image
.img_type
, func
.image
.img_target
)
716 if not func
.image
.img_send_null
:
717 compsize
= '(%s != NULL) ? %s : 0' % (func
.image
.name
, compsize
)