2 # (C) Copyright IBM Corporation 2004, 2005
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # on the rights to use, copy, modify, merge, publish, distribute, sub
9 # license, and/or sell copies of the Software, and to permit persons to whom
10 # the Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 # Ian Romanick <idr@us.ibm.com>
27 from __future__
import print_function
32 import gl_XML
, glX_XML
36 class glx_enum_function(object):
37 def __init__(self
, func_name
, enum_dict
):
42 # "enums" is a set of lists. The element in the set is the
43 # value of the enum. The list is the list of names for that
44 # value. For example, [0x8126] = {"POINT_SIZE_MIN",
45 # "POINT_SIZE_MIN_ARB", "POINT_SIZE_MIN_EXT",
46 # "POINT_SIZE_MIN_SGIS"}.
50 # "count" is indexed by count values. Each element of count
51 # is a list of index to "enums" that have that number of
52 # associated data elements. For example, [4] =
53 # {GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION,
54 # GL_AMBIENT_AND_DIFFUSE} (the enum names are used here,
55 # but the actual hexadecimal values would be in the array).
60 # Fill self.count and self.enums using the dictionary of enums
61 # that was passed in. The generic Get functions (e.g.,
62 # GetBooleanv and friends) are handled specially here. In
63 # the data the generic Get functions are referred to as "Get".
65 if func_name
in ["GetIntegerv", "GetBooleanv", "GetFloatv", "GetDoublev"]:
68 match_name
= func_name
71 for enum_name
in enum_dict
:
72 e
= enum_dict
[ enum_name
]
74 if match_name
in e
.functions
:
75 [count
, mode
] = e
.functions
[ match_name
]
77 if mode_set
and mode
!= self
.mode
:
78 raise RuntimeError("Not all enums for %s have the same mode." % (func_name
))
82 if e
.value
in self
.enums
:
83 if e
.name
not in self
.enums
[ e
.value
]:
84 self
.enums
[ e
.value
].append( e
)
86 if count
not in self
.count
:
87 self
.count
[ count
] = []
89 self
.enums
[ e
.value
] = [ e
]
90 self
.count
[ count
].append( e
.value
)
96 def signature( self
):
101 raise RuntimeError("i is None. WTF?")
104 for e
in self
.count
[i
]:
105 self
.sig
+= "%04x,%d," % (e
, i
)
114 def PrintUsingTable(self
):
115 """Emit the body of the __gl*_size function using a pair
116 of look-up tables and a mask. The mask is calculated such
117 that (e & mask) is unique for all the valid values of e for
118 this function. The result of (e & mask) is used as an index
119 into the first look-up table. If it matches e, then the
120 same entry of the second table is returned. Otherwise zero
123 It seems like this should cause better code to be generated.
124 However, on x86 at least, the resulting .o file is about 20%
125 larger then the switch-statment version. I am leaving this
126 code in because the results may be different on other
127 platforms (e.g., PowerPC or x86-64)."""
137 # Determine if there is some mask M, such that M = (2^N) - 1,
138 # that will generate unique values for all of the enums.
141 for i
in [1, 2, 3, 4, 5, 6, 7, 8]:
148 if (a
& mask
) == (b
& mask
):
156 if (mask
!= 0) and (mask
< (2 * count
)):
160 for i
in range(0, mask
+ 1):
161 masked_enums
[i
] = "0";
165 for e
in self
.count
[c
]:
167 enum_obj
= self
.enums
[e
][0]
168 masked_enums
[i
] = '0x%04x /* %s */' % (e
, enum_obj
.name
)
172 print(' static const GLushort a[%u] = {' % (mask
+ 1))
173 for e
in masked_enums
:
174 print(' %s, ' % (masked_enums
[e
]))
177 print(' static const GLubyte b[%u] = {' % (mask
+ 1))
178 for c
in masked_count
:
179 print(' %u, ' % (masked_count
[c
]))
182 print(' const unsigned idx = (e & 0x%02xU);' % (mask
))
184 print(' return (e == a[idx]) ? (GLint) b[idx] : 0;')
190 def PrintUsingSwitch(self
, name
):
191 """Emit the body of the __gl*_size function using a
194 print(' switch( e ) {')
196 for c
in sorted(self
.count
):
197 for e
in self
.count
[c
]:
200 # There may be multiple enums with the same
201 # value. This happens has extensions are
202 # promoted from vendor-specific or EXT to
203 # ARB and to the core. Emit the first one as
204 # a case label, and emit the others as
205 # commented-out case labels.
208 for enum_obj
in self
.enums
[e
]:
209 list[ enum_obj
.priority() ] = enum_obj
.name
211 keys
= sorted(list.keys())
215 print(' case GL_%s:' % (j
))
218 print('/* case GL_%s:*/' % (j
))
221 print(' return __gl%s_variable_size( e );' % (name
))
223 print(' return %u;' % (c
))
225 print(' default: return 0;')
229 def Print(self
, name
):
230 print('_X_INTERNAL PURE FASTCALL GLint')
231 print('__gl%s_size( GLenum e )' % (name
))
234 if not self
.PrintUsingTable():
235 self
.PrintUsingSwitch(name
)
241 class glx_server_enum_function(glx_enum_function
):
242 def __init__(self
, func
, enum_dict
):
243 glx_enum_function
.__init
__(self
, func
.name
, enum_dict
)
249 def signature( self
):
251 sig
= glx_enum_function
.signature(self
)
253 p
= self
.function
.variable_length_parameter()
255 sig
+= "%u" % (p
.size())
262 def Print(self
, name
, printer
):
264 printer
.common_func_print_just_header( f
)
269 for param_name
in f
.count_parameter_list
:
270 o
= f
.offset_of( param_name
)
273 for param_name
in f
.counter_list
:
274 o
= f
.offset_of( param_name
)
277 keys
= sorted(foo
.keys())
279 p
= f
.parameters_by_name
[ foo
[o
] ]
281 printer
.common_emit_one_arg(p
, "pc", 0)
282 fixup
.append( p
.name
)
285 print(' GLsizei compsize;')
288 printer
.common_emit_fixups(fixup
)
291 print(' compsize = __gl%s_size(%s);' % (f
.name
, string
.join(f
.count_parameter_list
, ",")))
292 p
= f
.variable_length_parameter()
293 print(' return safe_pad(%s);' % (p
.size_string()))
299 class PrintGlxSizeStubs_common(gl_XML
.gl_print_base
):
303 def __init__(self
, which_functions
):
304 gl_XML
.gl_print_base
.__init
__(self
)
306 self
.name
= "glX_proto_size.py (from Mesa)"
307 self
.license
= license
.bsd_license_template
% ( "(C) Copyright IBM Corporation 2004", "IBM")
309 self
.emit_set
= ((which_functions
& PrintGlxSizeStubs_common
.do_set
) != 0)
310 self
.emit_get
= ((which_functions
& PrintGlxSizeStubs_common
.do_get
) != 0)
314 class PrintGlxSizeStubs_c(PrintGlxSizeStubs_common
):
315 def printRealHeader(self
):
317 print('#include <X11/Xfuncproto.h>')
318 print('#include <GL/gl.h>')
320 print('#include "indirect_size_get.h"')
321 print('#include "glxserver.h"')
322 print('#include "indirect_util.h"')
324 print('#include "indirect_size.h"')
332 print('#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS')
333 print('# define ALIAS2(from,to) \\')
334 print(' _X_INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\')
335 print(' __attribute__ ((alias( # to )));')
336 print('# define ALIAS(from,to) ALIAS2( from, __gl ## to ## _size )')
338 print('# define ALIAS(from,to) \\')
339 print(' _X_INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\')
340 print(' { return __gl ## to ## _size( e ); }')
346 def printBody(self
, api
):
350 for func
in api
.functionIterateGlx():
351 ef
= glx_enum_function( func
.name
, api
.enums_by_name
)
352 if len(ef
.enums
) == 0:
355 if (ef
.is_set() and self
.emit_set
) or (not ef
.is_set() and self
.emit_get
):
358 aliases
.append( [func
.name
, enum_sigs
[ sig
]] )
360 enum_sigs
[ sig
] = func
.name
361 ef
.Print( func
.name
)
364 for [alias_name
, real_name
] in aliases
:
365 print('ALIAS( %s, %s )' % (alias_name
, real_name
))
369 class PrintGlxSizeStubs_h(PrintGlxSizeStubs_common
):
370 def printRealHeader(self
):
373 * Prototypes for functions used to determine the number of data elements in
374 * various GLX protocol messages.
376 * \\author Ian Romanick <idr@us.ibm.com>
379 print('#include <X11/Xfuncproto.h>')
383 self
.printFastcall();
387 def printBody(self
, api
):
388 for func
in api
.functionIterateGlx():
389 ef
= glx_enum_function( func
.name
, api
.enums_by_name
)
390 if len(ef
.enums
) == 0:
393 if (ef
.is_set() and self
.emit_set
) or (not ef
.is_set() and self
.emit_get
):
394 print('extern _X_INTERNAL PURE FASTCALL GLint __gl%s_size(GLenum);' % (func
.name
))
397 class PrintGlxReqSize_common(gl_XML
.gl_print_base
):
398 """Common base class for PrintGlxSizeReq_h and PrintGlxSizeReq_h.
400 The main purpose of this common base class is to provide the infrastructure
401 for the derrived classes to iterate over the same set of functions.
405 gl_XML
.gl_print_base
.__init
__(self
)
407 self
.name
= "glX_proto_size.py (from Mesa)"
408 self
.license
= license
.bsd_license_template
% ( "(C) Copyright IBM Corporation 2005", "IBM")
411 class PrintGlxReqSize_h(PrintGlxReqSize_common
):
413 PrintGlxReqSize_common
.__init
__(self
)
414 self
.header_tag
= "_INDIRECT_REQSIZE_H_"
417 def printRealHeader(self
):
418 print('#include <X11/Xfuncproto.h>')
424 def printBody(self
, api
):
425 for func
in api
.functionIterateGlx():
426 if not func
.ignore
and func
.has_variable_size_request():
427 print('extern PURE _X_HIDDEN int __glX%sReqSize(const GLbyte *pc, Bool swap, int reqlen);' % (func
.name
))
430 class PrintGlxReqSize_c(PrintGlxReqSize_common
):
431 """Create the server-side 'request size' functions.
433 Create the server-side functions that are used to determine what the
434 size of a varible length command should be. The server then uses
435 this value to determine if the incoming command packed it malformed.
439 PrintGlxReqSize_common
.__init
__(self
)
440 self
.counter_sigs
= {}
443 def printRealHeader(self
):
445 print('#include <GL/gl.h>')
446 print('#include "glxserver.h"')
447 print('#include "glxbyteorder.h"')
448 print('#include "indirect_size.h"')
449 print('#include "indirect_reqsize.h"')
451 print('#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS')
452 print('# define ALIAS2(from,to) \\')
453 print(' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\')
454 print(' __attribute__ ((alias( # to )));')
455 print('# define ALIAS(from,to) ALIAS2( from, __glX ## to ## ReqSize )')
457 print('# define ALIAS(from,to) \\')
458 print(' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\')
459 print(' { return __glX ## to ## ReqSize( pc, swap, reqlen ); }')
465 def printBody(self
, api
):
470 for func
in api
.functionIterateGlx():
471 if not func
.has_variable_size_request(): continue
473 ef
= glx_server_enum_function( func
, api
.enums_by_name
)
474 if len(ef
.enums
) == 0: continue
478 if func
.name
not in enum_functions
:
479 enum_functions
[ func
.name
] = sig
481 if sig
not in enum_sigs
:
482 enum_sigs
[ sig
] = ef
486 for func
in api
.functionIterateGlx():
487 # Even though server-handcode fuctions are on "the
488 # list", and prototypes are generated for them, there
489 # isn't enough information to generate a size
490 # function. If there was enough information, they
491 # probably wouldn't need to be handcoded in the first
494 if func
.server_handcode
: continue
495 if not func
.has_variable_size_request(): continue
497 if func
.name
in enum_functions
:
498 sig
= enum_functions
[func
.name
]
499 ef
= enum_sigs
[ sig
]
501 if ef
.name
!= func
.name
:
502 aliases
.append( [func
.name
, ef
.name
] )
504 ef
.Print( func
.name
, self
)
507 self
.printPixelFunction(func
)
508 elif func
.has_variable_size_request():
509 a
= self
.printCountedFunction(func
)
510 if a
: aliases
.append(a
)
513 for [alias_name
, real_name
] in aliases
:
514 print('ALIAS( %s, %s )' % (alias_name
, real_name
))
519 def common_emit_fixups(self
, fixup
):
520 """Utility function to emit conditional byte-swaps."""
523 print(' if (swap) {')
525 print(' %s = bswap_32(%s);' % (name
, name
))
531 def common_emit_one_arg(self
, p
, pc
, adjust
):
534 src
= '(%s *)' % (p
.type_string())
535 print('%-18s = *%11s(%s + %u);' % (dst
, src
, pc
, offset
+ adjust
));
539 def common_func_print_just_header(self
, f
):
541 print('__glX%sReqSize( const GLbyte * pc, Bool swap, int reqlen )' % (f
.name
))
545 def printPixelFunction(self
, f
):
546 self
.common_func_print_just_header(f
)
548 f
.offset_of( f
.parameters
[0].name
)
549 [dim
, w
, h
, d
, junk
] = f
.get_images()[0].get_dimensions()
551 print(' GLint row_length = * (GLint *)(pc + 4);')
554 fixup
= ['row_length', 'skip_rows', 'alignment']
555 print(' GLint image_height = 0;')
556 print(' GLint skip_images = 0;')
557 print(' GLint skip_rows = * (GLint *)(pc + 8);')
558 print(' GLint alignment = * (GLint *)(pc + 16);')
560 fixup
= ['row_length', 'image_height', 'skip_rows', 'skip_images', 'alignment']
561 print(' GLint image_height = * (GLint *)(pc + 8);')
562 print(' GLint skip_rows = * (GLint *)(pc + 16);')
563 print(' GLint skip_images = * (GLint *)(pc + 20);')
564 print(' GLint alignment = * (GLint *)(pc + 32);')
567 for p
in f
.parameterIterateGlxSend():
568 if p
.name
in [w
, h
, d
, img
.img_format
, img
.img_type
, img
.img_target
]:
569 self
.common_emit_one_arg(p
, "pc", 0)
570 fixup
.append( p
.name
)
574 self
.common_emit_fixups(fixup
)
576 if img
.img_null_flag
:
578 print(' if (*(CARD32 *) (pc + %s))' % (img
.offset
- 4))
582 print(' return __glXImageSize(%s, %s, %s, %s, %s, %s,' % (img
.img_format
, img
.img_type
, img
.img_target
, w
, h
, d
))
583 print(' image_height, row_length, skip_images,')
584 print(' skip_rows, alignment);')
590 def printCountedFunction(self
, f
):
599 # Calculate the offset of each counter parameter and the
600 # size string for the variable length parameter(s). While
601 # that is being done, calculate a unique signature for this
604 for p
in f
.parameterIterateGlxSend():
606 fixup
.append( p
.name
)
612 sig
+= "(%u,%u)" % (f
.offset_of(p
.counter
), s
)
614 size
= p
.size_string()
616 size
= "safe_add(%s, %s)" % (size
, p
.size_string())
618 # If the calculated signature matches a function that has
619 # already be emitted, don't emit this function. Instead, add
620 # it to the list of function aliases.
622 if sig
in self
.counter_sigs
:
623 n
= self
.counter_sigs
[sig
];
627 self
.counter_sigs
[sig
] = f
.name
629 self
.common_func_print_just_header(f
)
632 self
.common_emit_one_arg(p
, "pc", 0)
636 self
.common_emit_fixups(fixup
)
639 print(' return safe_pad(%s);' % (size
))
647 """Parse arguments and return a namespace."""
648 parser
= argparse
.ArgumentParser()
649 parser
.set_defaults(which_functions
=(PrintGlxSizeStubs_common
.do_get |
650 PrintGlxSizeStubs_common
.do_set
))
651 parser
.add_argument('-f',
653 default
='gl_API.xml',
654 help='an XML file describing an OpenGL API.')
655 parser
.add_argument('-m',
657 choices
=['size_c', 'size_h', 'reqsize_c', 'reqsize_h'],
658 help='Which file to generate')
659 getset
= parser
.add_mutually_exclusive_group()
660 getset
.add_argument('--only-get',
661 dest
='which_functions',
662 action
='store_const',
663 const
=PrintGlxSizeStubs_common
.do_get
,
664 help='only emit "get-type" functions')
665 getset
.add_argument('--only-set',
666 dest
='which_functions',
667 action
='store_const',
668 const
=PrintGlxSizeStubs_common
.do_set
,
669 help='only emit "set-type" functions')
670 parser
.add_argument('--header-tag',
674 help='set header tag value')
675 return parser
.parse_args()
682 if args
.mode
== "size_c":
683 printer
= PrintGlxSizeStubs_c(args
.which_functions
)
684 elif args
.mode
== "size_h":
685 printer
= PrintGlxSizeStubs_h(args
.which_functions
)
686 if args
.header_tag
is not None:
687 printer
.header_tag
= args
.header_tag
688 elif args
.mode
== "reqsize_c":
689 printer
= PrintGlxReqSize_c()
690 elif args
.mode
== "reqsize_h":
691 printer
= PrintGlxReqSize_h()
693 api
= gl_XML
.parse_GL_API(args
.filename
, glX_XML
.glx_item_factory())
698 if __name__
== '__main__':