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>
30 import sys
, getopt
, string
33 class glXItemFactory(gl_XML
.glItemFactory
):
34 """Factory to create GLX protocol oriented objects derived from glItem."""
36 def create(self
, context
, name
, attrs
):
37 if name
== "function":
38 return glXFunction(context
, name
, attrs
)
40 return glXEnum(context
, name
, attrs
)
42 return glXParameter(context
, name
, attrs
)
44 return gl_XML
.glItemFactory
.create(self
, context
, name
, attrs
)
46 class glXEnumFunction
:
47 def __init__(self
, name
, context
):
49 self
.context
= context
53 # "enums" is a set of lists. The element in the set is the
54 # value of the enum. The list is the list of names for that
55 # value. For example, [0x8126] = {"POINT_SIZE_MIN",
56 # "POINT_SIZE_MIN_ARB", "POINT_SIZE_MIN_EXT",
57 # "POINT_SIZE_MIN_SGIS"}.
61 # "count" is indexed by count values. Each element of count
62 # is a list of index to "enums" that have that number of
63 # associated data elements. For example, [4] =
64 # {GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION,
65 # GL_AMBIENT_AND_DIFFUSE} (the enum names are used here,
66 # but the actual hexadecimal values would be in the array).
71 def append(self
, count
, value
, name
):
72 if self
.enums
.has_key( value
):
73 self
.enums
[value
].append(name
)
75 if not self
.count
.has_key(count
):
76 self
.count
[count
] = []
78 self
.enums
[value
] = []
79 self
.enums
[value
].append(name
)
80 self
.count
[count
].append(value
)
83 def signature( self
):
88 for e
in self
.count
[i
]:
89 self
.sig
+= "%04x,%u," % (e
, i
)
94 def set_mode( self
, mode
):
95 """Mark an enum-function as a 'set' function."""
104 def PrintUsingTable(self
):
105 """Emit the body of the __gl*_size function using a pair
106 of look-up tables and a mask. The mask is calculated such
107 that (e & mask) is unique for all the valid values of e for
108 this function. The result of (e & mask) is used as an index
109 into the first look-up table. If it matches e, then the
110 same entry of the second table is returned. Otherwise zero
113 It seems like this should cause better code to be generated.
114 However, on x86 at least, the resulting .o file is about 20%
115 larger then the switch-statment version. I am leaving this
116 code in because the results may be different on other
117 platforms (e.g., PowerPC or x86-64)."""
124 if self
.count
.has_key(-1):
127 # Determine if there is some mask M, such that M = (2^N) - 1,
128 # that will generate unique values for all of the enums.
131 for i
in [1, 2, 3, 4, 5, 6, 7, 8]:
138 if (a
& mask
) == (b
& mask
):
146 if (mask
!= 0) and (mask
< (2 * count
)):
150 for i
in range(0, mask
+ 1):
151 masked_enums
[i
] = "0";
155 for e
in self
.count
[c
]:
157 masked_enums
[i
] = '0x%04x /* %s */' % (e
, self
.enums
[e
][0])
161 print ' static const GLushort a[%u] = {' % (mask
+ 1)
162 for e
in masked_enums
:
163 print ' %s, ' % (masked_enums
[e
])
166 print ' static const GLubyte b[%u] = {' % (mask
+ 1)
167 for c
in masked_count
:
168 print ' %u, ' % (masked_count
[c
])
171 print ' const unsigned idx = (e & 0x%02xU);' % (mask
)
173 print ' return (e == a[idx]) ? (GLint) b[idx] : 0;'
178 def PrintUsingSwitch(self
, name
):
179 """Emit the body of the __gl*_size function using a
182 print ' switch( e ) {'
185 for e
in self
.count
[c
]:
188 # There may be multiple enums with the same
189 # value. This happens has extensions are
190 # promoted from vendor-specific or EXT to
191 # ARB and to the core. Emit the first one as
192 # a case label, and emit the others as
193 # commented-out case labels.
195 for j
in self
.enums
[e
]:
197 print ' case %s:' % (j
)
200 print '/* case %s:*/' % (j
)
203 print ' return __gl%s_variable_size( e );' % (name
)
205 print ' return %u;' % (c
)
207 print ' default: return 0;'
211 def Print(self
, name
):
212 print 'INTERNAL PURE FASTCALL GLint'
213 print '__gl%s_size( GLenum e )' % (name
)
216 if not self
.PrintUsingTable():
217 self
.PrintUsingSwitch(name
)
224 class glXEnum(gl_XML
.glEnum
):
225 def __init__(self
, context
, name
, attrs
):
226 gl_XML
.glEnum
.__init
__(self
, context
, name
, attrs
)
229 def startElementNS(self
, name
, qname
, attrs
):
230 [uri
, true_name
] = name
231 if true_name
== "size":
232 [temp_n
, c
, mode
] = self
.process_attributes(attrs
)
235 names
= ["GetIntegerv", "GetBooleanv", "GetFloatv", "GetDoublev" ]
240 if not self
.context
.glx_enum_functions
.has_key( n
):
241 f
= self
.context
.createEnumFunction( n
)
243 self
.context
.glx_enum_functions
[ f
.name
] = f
245 self
.context
.glx_enum_functions
[ n
].append( c
, self
.value
, self
.name
)
247 gl_XML
.glEnum
.startElementNS(self
, name
, qname
, attrs
)
251 class glXParameter(gl_XML
.glParameter
):
252 def __init__(self
, context
, name
, attrs
):
254 gl_XML
.glParameter
.__init
__(self
, context
, name
, attrs
);
257 class glXParameterIterator
:
258 """Class to iterate over a list of glXParameters.
260 Objects of this class are returned by the parameterIterator method of
261 the glXFunction class. They are used to iterate over the list of
262 parameters to the function."""
264 def __init__(self
, data
, skip_output
, max_order
):
268 self
.skip_output
= skip_output
269 self
.max_order
= max_order
275 if len( self
.data
) == 0:
279 if self
.index
== len( self
.data
):
280 if self
.order
== self
.max_order
:
289 if self
.data
[i
].order
== self
.order
and not (self
.data
[i
].is_output
and self
.skip_output
):
293 class glXFunction(gl_XML
.glFunction
):
298 # If this is set to true, it means that GLdouble parameters should be
299 # written to the GLX protocol packet in the order they appear in the
300 # prototype. This is different from the "classic" ordering. In the
301 # classic ordering GLdoubles are written to the protocol packet first,
302 # followed by non-doubles. NV_vertex_program was the first extension
303 # to break with this tradition.
305 glx_doubles_in_order
= 0
310 def __init__(self
, context
, name
, attrs
):
311 self
.vectorequiv
= attrs
.get((None, 'vectorequiv'), None)
314 self
.can_be_large
= 0
315 self
.reply_always_array
= 0
316 self
.dimensions_in_reply
= 0
317 self
.img_reset
= None
319 self
.server_handcode
= 0
320 self
.client_handcode
= 0
323 gl_XML
.glFunction
.__init
__(self
, context
, name
, attrs
)
327 def parameterIterator(self
, skip_output
, max_order
):
328 return glXParameterIterator(self
.fn_parameters
, skip_output
, max_order
)
331 def startElementNS(self
, name
, qname
, attrs
):
332 """Process elements within a function that are specific to GLX."""
334 [uri
, true_name
] = name
335 if true_name
== "glx":
336 self
.glx_rop
= int(attrs
.get((None, 'rop'), "0"))
337 self
.glx_sop
= int(attrs
.get((None, 'sop'), "0"))
338 self
.glx_vendorpriv
= int(attrs
.get((None, 'vendorpriv'), "0"))
339 self
.img_reset
= attrs
.get((None, 'img_reset'), None)
341 # The 'handcode' attribute can be one of 'true',
342 # 'false', 'client', or 'server'.
344 handcode
= attrs
.get((None, 'handcode'), "false")
345 if handcode
== "false":
346 self
.server_handcode
= 0
347 self
.client_handcode
= 0
348 elif handcode
== "true":
349 self
.server_handcode
= 1
350 self
.client_handcode
= 1
351 elif handcode
== "client":
352 self
.server_handcode
= 0
353 self
.client_handcode
= 1
354 elif handcode
== "server":
355 self
.server_handcode
= 1
356 self
.client_handcode
= 0
358 raise RuntimeError('Invalid handcode mode "%s" in function "%s".' % (handcode
, self
.name
))
360 self
.ignore
= gl_XML
.is_attr_true( attrs
, 'ignore' )
361 self
.can_be_large
= gl_XML
.is_attr_true( attrs
, 'large' )
362 self
.glx_doubles_in_order
= gl_XML
.is_attr_true( attrs
, 'doubles_in_order' )
363 self
.reply_always_array
= gl_XML
.is_attr_true( attrs
, 'always_array' )
364 self
.dimensions_in_reply
= gl_XML
.is_attr_true( attrs
, 'dimensions_in_reply' )
366 gl_XML
.glFunction
.startElementNS(self
, name
, qname
, attrs
)
369 def endElementNS(self
, name
, qname
):
370 [uri
, true_name
] = name
371 if true_name
== "function":
372 # Mark any function that does not have GLX protocol
373 # defined as "ignore". This prevents bad things from
374 # happening when people add new functions to the GL
375 # API XML without adding any GLX section.
377 # This will also mark functions that don't have a
378 # dispatch offset at ignored.
380 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
):
382 # if self.fn_offset == -1:
383 # print '/* %s ignored becuase no offset assigned. */' % (self.name)
385 # print '/* %s ignored becuase no GLX opcode assigned. */' % (self.name)
389 return gl_XML
.glFunction
.endElementNS(self
, name
, qname
)
392 def append(self
, tag_name
, p
):
393 gl_XML
.glFunction
.append(self
, tag_name
, p
)
395 if p
.is_variable_length_array():
397 elif not self
.glx_doubles_in_order
and p
.p_type
.size
== 8:
401 self
.counter
= p
.name
409 def variable_length_parameter(self
):
410 if len(self
.variable_length_parameters
):
411 return self
.variable_length_parameters
[0]
416 def output_parameter(self
):
417 for param
in self
.fn_parameters
:
424 def offset_of_first_parameter(self
):
425 """Get the offset of the first parameter in the command.
427 Gets the offset of the first function parameter in the GLX
428 command packet. This byte offset is measured from the end
429 of the Render / RenderLarge header. The offset for all non-
430 pixel commends is zero. The offset for pixel commands depends
431 on the number of dimensions of the pixel data."""
433 if self
.image
and not self
.image
.is_output
:
434 [dim
, junk
, junk
, junk
, junk
] = self
.dimensions()
436 # The base size is the size of the pixel pack info
437 # header used by images with the specified number
445 raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim
, self
.image
.name
, self
.name
))
450 def command_fixed_length(self
):
451 """Return the length, in bytes as an integer, of the
452 fixed-size portion of the command."""
454 size
= self
.offset_of_first_parameter()
456 for p
in gl_XML
.glFunction
.parameterIterator(self
):
457 if not p
.is_output
and p
.name
!= self
.img_reset
:
459 if self
.pad_after(p
):
462 if self
.image
and (self
.image
.img_null_flag
or self
.image
.is_output
):
468 def command_variable_length(self
):
469 """Return the length, as a string, of the variable-sized
470 portion of the command."""
473 for p
in gl_XML
.glFunction
.parameterIterator(self
):
474 if (not p
.is_output
) and (p
.size() == 0):
475 size_string
= size_string
+ " + __GLX_PAD(%s)" % (p
.size_string())
480 def command_length(self
):
481 size
= self
.command_fixed_length()
483 if self
.glx_rop
!= 0:
486 size
= ((size
+ 3) & ~
3)
487 return "%u%s" % (size
, self
.command_variable_length())
490 def opcode_real_value(self
):
491 """Get the true numeric value of the GLX opcode
493 Behaves similarly to opcode_value, except for
494 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
495 In these cases the value for the GLX opcode field (i.e.,
496 16 for X_GLXVendorPrivate or 17 for
497 X_GLXVendorPrivateWithReply) is returned. For other 'single'
498 commands, the opcode for the command (e.g., 101 for
499 X_GLsop_NewList) is returned."""
501 if self
.glx_vendorpriv
!= 0:
502 if self
.needs_reply():
507 return self
.opcode_value()
509 def opcode_value(self
):
510 """Get the unique protocol opcode for the glXFunction"""
512 if self
.glx_rop
!= 0:
514 elif self
.glx_sop
!= 0:
516 elif self
.glx_vendorpriv
!= 0:
517 return self
.glx_vendorpriv
521 def opcode_rop_basename(self
):
522 """Return either the name to be used for GLX protocol enum.
524 Returns either the name of the function or the name of the
525 name of the equivalent vector (e.g., glVertex3fv for
526 glVertex3f) function."""
528 if self
.vectorequiv
== None:
531 return self
.vectorequiv
533 def opcode_name(self
):
534 """Get the unique protocol enum name for the glXFunction"""
536 if self
.glx_rop
!= 0:
537 return "X_GLrop_%s" % (self
.opcode_rop_basename())
538 elif self
.glx_sop
!= 0:
539 return "X_GLsop_%s" % (self
.name
)
540 elif self
.glx_vendorpriv
!= 0:
541 return "X_GLvop_%s" % (self
.name
)
543 raise RuntimeError('Function "%s" has no opcode.' % (self
.name
))
546 def opcode_real_name(self
):
547 """Get the true protocol enum name for the GLX opcode
549 Behaves similarly to opcode_name, except for
550 X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
551 In these cases the string 'X_GLXVendorPrivate' or
552 'X_GLXVendorPrivateWithReply' is returned. For other
553 single or render commands 'X_GLsop' or 'X_GLrop' plus the
554 name of the function returned."""
556 if self
.glx_vendorpriv
!= 0:
557 if self
.needs_reply():
558 return "X_GLXVendorPrivateWithReply"
560 return "X_GLXVendorPrivate"
562 return self
.opcode_name()
565 def return_string(self
):
566 if self
.fn_return_type
!= 'void':
567 return "return retval;"
572 def needs_reply(self
):
573 return self
.fn_return_type
!= 'void' or self
.output
!= None
576 def dimensions(self
):
577 """Determine the dimensions of an image.
579 Returns a tuple representing the number of dimensions and the
580 string name of each of the dimensions of an image, If the
581 function is not a pixel function, the number of dimensions
585 return [0, "0", "0", "0", "0"]
590 if self
.image
.height
:
592 h
= self
.image
.height
602 if self
.image
.extent
:
604 e
= self
.image
.extent
608 return [dim
, w
, h
, d
, e
]
611 def pad_after(self
, p
):
612 """Returns the name of the field inserted after the
613 specified field to pad out the command header."""
615 if self
.image
and self
.image
.img_pad_dimensions
:
616 if not self
.image
.height
:
617 if p
.name
== self
.image
.width
:
619 elif p
.name
== self
.image
.img_xoff
:
621 elif not self
.image
.extent
:
622 if p
.name
== self
.image
.depth
:
623 # Should this be "size4d"?
625 elif p
.name
== self
.image
.img_zoff
:
630 class glXFunctionIterator(gl_XML
.glFunctionIterator
):
631 """Class to iterate over a list of glXFunctions"""
633 def __init__(self
, context
):
634 self
.context
= context
635 self
.keys
= context
.functions
.keys()
638 for self
.index
in range(0, len(self
.keys
)):
639 if self
.keys
[ self
.index
] >= 0: break
645 if self
.index
== len(self
.keys
):
648 f
= self
.context
.functions
[ self
.keys
[ self
.index
] ]
657 class GlxProto(gl_XML
.FilterGLAPISpecBase
):
658 name
= "glX_proto_send.py (from Mesa)"
661 gl_XML
.FilterGLAPISpecBase
.__init
__(self
)
662 self
.factory
= glXItemFactory()
663 self
.glx_enum_functions
= {}
666 def endElementNS(self
, name
, qname
):
667 [uri
, true_name
] = name
668 if true_name
== 'OpenGLAPI':
669 # Once all the parsing is done, we have to go back and
670 # fix-up some cross references between different
673 for k
in self
.functions
:
674 f
= self
.functions
[k
]
675 if f
.vectorequiv
!= None:
676 equiv
= self
.find_function(f
.vectorequiv
)
678 f
.glx_doubles_in_order
= equiv
.glx_doubles_in_order
679 f
.glx_rop
= equiv
.glx_rop
681 raise RuntimeError("Could not find the vector equiv. function %s for %s!" % (f
.name
, f
.vectorequiv
))
683 gl_XML
.FilterGLAPISpecBase
.endElementNS(self
, name
, qname
)
687 def createEnumFunction(self
, n
):
688 return glXEnumFunction(n
, self
)
691 def functionIterator(self
):
692 return glXFunctionIterator(self
)
695 def size_call(self
, func
):
696 """Create C code to calculate 'compsize'.
698 Creates code to calculate 'compsize'. If the function does
699 not need 'compsize' to be calculated, None will be
702 if not func
.image
and not func
.count_parameter_list
:
706 parameters
= string
.join( func
.count_parameter_list
, "," )
707 compsize
= "__gl%s_size(%s)" % (func
.name
, parameters
)
709 [dim
, w
, h
, d
, junk
] = func
.dimensions()
711 compsize
= '__glImageSize(%s, %s, %s, %s, %s, %s)' % (w
, h
, d
, func
.image
.img_format
, func
.image
.img_type
, func
.image
.img_target
)
712 if not func
.image
.img_send_null
:
713 compsize
= '(%s != NULL) ? %s : 0' % (func
.image
.name
, compsize
)