python: Use the print function
[mesa.git] / src / mapi / glapi / gen / glX_proto_size.py
1
2 # (C) Copyright IBM Corporation 2004, 2005
3 # All Rights Reserved.
4 #
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:
11 #
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
14 # Software.
15 #
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
22 # IN THE SOFTWARE.
23 #
24 # Authors:
25 # Ian Romanick <idr@us.ibm.com>
26
27 from __future__ import print_function
28
29 import argparse
30 import sys, string
31
32 import gl_XML, glX_XML
33 import license
34
35
36 class glx_enum_function(object):
37 def __init__(self, func_name, enum_dict):
38 self.name = func_name
39 self.mode = 1
40 self.sig = None
41
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"}.
47
48 self.enums = {}
49
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).
56
57 self.count = {}
58
59
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".
64
65 if func_name in ["GetIntegerv", "GetBooleanv", "GetFloatv", "GetDoublev"]:
66 match_name = "Get"
67 else:
68 match_name = func_name
69
70 mode_set = 0
71 for enum_name in enum_dict:
72 e = enum_dict[ enum_name ]
73
74 if e.functions.has_key( match_name ):
75 [count, mode] = e.functions[ match_name ]
76
77 if mode_set and mode != self.mode:
78 raise RuntimeError("Not all enums for %s have the same mode." % (func_name))
79
80 self.mode = mode
81
82 if self.enums.has_key( e.value ):
83 if e.name not in self.enums[ e.value ]:
84 self.enums[ e.value ].append( e )
85 else:
86 if not self.count.has_key( count ):
87 self.count[ count ] = []
88
89 self.enums[ e.value ] = [ e ]
90 self.count[ count ].append( e.value )
91
92
93 return
94
95
96 def signature( self ):
97 if self.sig == None:
98 self.sig = ""
99 for i in self.count:
100 if i == None:
101 raise RuntimeError("i is None. WTF?")
102
103 self.count[i].sort()
104 for e in self.count[i]:
105 self.sig += "%04x,%d," % (e, i)
106
107 return self.sig
108
109
110 def is_set( self ):
111 return self.mode
112
113
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
121 is returned.
122
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)."""
128
129 return 0
130 count = 0
131 for a in self.enums:
132 count += 1
133
134 if self.count.has_key(-1):
135 return 0
136
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.
139
140 mask = 0
141 for i in [1, 2, 3, 4, 5, 6, 7, 8]:
142 mask = (1 << i) - 1
143
144 fail = 0;
145 for a in self.enums:
146 for b in self.enums:
147 if a != b:
148 if (a & mask) == (b & mask):
149 fail = 1;
150
151 if not fail:
152 break;
153 else:
154 mask = 0
155
156 if (mask != 0) and (mask < (2 * count)):
157 masked_enums = {}
158 masked_count = {}
159
160 for i in range(0, mask + 1):
161 masked_enums[i] = "0";
162 masked_count[i] = 0;
163
164 for c in self.count:
165 for e in self.count[c]:
166 i = e & mask
167 enum_obj = self.enums[e][0]
168 masked_enums[i] = '0x%04x /* %s */' % (e, enum_obj.name )
169 masked_count[i] = c
170
171
172 print(' static const GLushort a[%u] = {' % (mask + 1))
173 for e in masked_enums:
174 print(' %s, ' % (masked_enums[e]))
175 print(' };')
176
177 print(' static const GLubyte b[%u] = {' % (mask + 1))
178 for c in masked_count:
179 print(' %u, ' % (masked_count[c]))
180 print(' };')
181
182 print(' const unsigned idx = (e & 0x%02xU);' % (mask))
183 print('')
184 print(' return (e == a[idx]) ? (GLint) b[idx] : 0;')
185 return 1;
186 else:
187 return 0;
188
189
190 def PrintUsingSwitch(self, name):
191 """Emit the body of the __gl*_size function using a
192 switch-statement."""
193
194 print(' switch( e ) {')
195
196 for c in sorted(self.count):
197 for e in self.count[c]:
198 first = 1
199
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.
206
207 list = {}
208 for enum_obj in self.enums[e]:
209 list[ enum_obj.priority() ] = enum_obj.name
210
211 keys = list.keys()
212 keys.sort()
213 for k in keys:
214 j = list[k]
215 if first:
216 print(' case GL_%s:' % (j))
217 first = 0
218 else:
219 print('/* case GL_%s:*/' % (j))
220
221 if c == -1:
222 print(' return __gl%s_variable_size( e );' % (name))
223 else:
224 print(' return %u;' % (c))
225
226 print(' default: return 0;')
227 print(' }')
228
229
230 def Print(self, name):
231 print('_X_INTERNAL PURE FASTCALL GLint')
232 print('__gl%s_size( GLenum e )' % (name))
233 print('{')
234
235 if not self.PrintUsingTable():
236 self.PrintUsingSwitch(name)
237
238 print('}')
239 print('')
240
241
242 class glx_server_enum_function(glx_enum_function):
243 def __init__(self, func, enum_dict):
244 glx_enum_function.__init__(self, func.name, enum_dict)
245
246 self.function = func
247 return
248
249
250 def signature( self ):
251 if self.sig == None:
252 sig = glx_enum_function.signature(self)
253
254 p = self.function.variable_length_parameter()
255 if p:
256 sig += "%u" % (p.size())
257
258 self.sig = sig
259
260 return self.sig;
261
262
263 def Print(self, name, printer):
264 f = self.function
265 printer.common_func_print_just_header( f )
266
267 fixup = []
268
269 foo = {}
270 for param_name in f.count_parameter_list:
271 o = f.offset_of( param_name )
272 foo[o] = param_name
273
274 for param_name in f.counter_list:
275 o = f.offset_of( param_name )
276 foo[o] = param_name
277
278 keys = foo.keys()
279 keys.sort()
280 for o in keys:
281 p = f.parameters_by_name[ foo[o] ]
282
283 printer.common_emit_one_arg(p, "pc", 0)
284 fixup.append( p.name )
285
286
287 print(' GLsizei compsize;')
288 print('')
289
290 printer.common_emit_fixups(fixup)
291
292 print('')
293 print(' compsize = __gl%s_size(%s);' % (f.name, string.join(f.count_parameter_list, ",")))
294 p = f.variable_length_parameter()
295 print(' return safe_pad(%s);' % (p.size_string()))
296
297 print('}')
298 print('')
299
300
301 class PrintGlxSizeStubs_common(gl_XML.gl_print_base):
302 do_get = (1 << 0)
303 do_set = (1 << 1)
304
305 def __init__(self, which_functions):
306 gl_XML.gl_print_base.__init__(self)
307
308 self.name = "glX_proto_size.py (from Mesa)"
309 self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2004", "IBM")
310
311 self.emit_set = ((which_functions & PrintGlxSizeStubs_common.do_set) != 0)
312 self.emit_get = ((which_functions & PrintGlxSizeStubs_common.do_get) != 0)
313 return
314
315
316 class PrintGlxSizeStubs_c(PrintGlxSizeStubs_common):
317 def printRealHeader(self):
318 print('')
319 print('#include <X11/Xfuncproto.h>')
320 print('#include <GL/gl.h>')
321 if self.emit_get:
322 print('#include "indirect_size_get.h"')
323 print('#include "glxserver.h"')
324 print('#include "indirect_util.h"')
325
326 print('#include "indirect_size.h"')
327
328 print('')
329 self.printPure()
330 print('')
331 self.printFastcall()
332 print('')
333 print('')
334 print('#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS')
335 print('# define ALIAS2(from,to) \\')
336 print(' _X_INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\')
337 print(' __attribute__ ((alias( # to )));')
338 print('# define ALIAS(from,to) ALIAS2( from, __gl ## to ## _size )')
339 print('#else')
340 print('# define ALIAS(from,to) \\')
341 print(' _X_INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\')
342 print(' { return __gl ## to ## _size( e ); }')
343 print('#endif')
344 print('')
345 print('')
346
347
348 def printBody(self, api):
349 enum_sigs = {}
350 aliases = []
351
352 for func in api.functionIterateGlx():
353 ef = glx_enum_function( func.name, api.enums_by_name )
354 if len(ef.enums) == 0:
355 continue
356
357 if (ef.is_set() and self.emit_set) or (not ef.is_set() and self.emit_get):
358 sig = ef.signature()
359 if enum_sigs.has_key( sig ):
360 aliases.append( [func.name, enum_sigs[ sig ]] )
361 else:
362 enum_sigs[ sig ] = func.name
363 ef.Print( func.name )
364
365
366 for [alias_name, real_name] in aliases:
367 print('ALIAS( %s, %s )' % (alias_name, real_name))
368
369
370
371 class PrintGlxSizeStubs_h(PrintGlxSizeStubs_common):
372 def printRealHeader(self):
373 print("""/**
374 * \\file
375 * Prototypes for functions used to determine the number of data elements in
376 * various GLX protocol messages.
377 *
378 * \\author Ian Romanick <idr@us.ibm.com>
379 */
380 """)
381 print('#include <X11/Xfuncproto.h>')
382 print('')
383 self.printPure();
384 print('')
385 self.printFastcall();
386 print('')
387
388
389 def printBody(self, api):
390 for func in api.functionIterateGlx():
391 ef = glx_enum_function( func.name, api.enums_by_name )
392 if len(ef.enums) == 0:
393 continue
394
395 if (ef.is_set() and self.emit_set) or (not ef.is_set() and self.emit_get):
396 print('extern _X_INTERNAL PURE FASTCALL GLint __gl%s_size(GLenum);' % (func.name))
397
398
399 class PrintGlxReqSize_common(gl_XML.gl_print_base):
400 """Common base class for PrintGlxSizeReq_h and PrintGlxSizeReq_h.
401
402 The main purpose of this common base class is to provide the infrastructure
403 for the derrived classes to iterate over the same set of functions.
404 """
405
406 def __init__(self):
407 gl_XML.gl_print_base.__init__(self)
408
409 self.name = "glX_proto_size.py (from Mesa)"
410 self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2005", "IBM")
411
412
413 class PrintGlxReqSize_h(PrintGlxReqSize_common):
414 def __init__(self):
415 PrintGlxReqSize_common.__init__(self)
416 self.header_tag = "_INDIRECT_REQSIZE_H_"
417
418
419 def printRealHeader(self):
420 print('#include <X11/Xfuncproto.h>')
421 print('')
422 self.printPure()
423 print('')
424
425
426 def printBody(self, api):
427 for func in api.functionIterateGlx():
428 if not func.ignore and func.has_variable_size_request():
429 print('extern PURE _X_HIDDEN int __glX%sReqSize(const GLbyte *pc, Bool swap, int reqlen);' % (func.name))
430
431
432 class PrintGlxReqSize_c(PrintGlxReqSize_common):
433 """Create the server-side 'request size' functions.
434
435 Create the server-side functions that are used to determine what the
436 size of a varible length command should be. The server then uses
437 this value to determine if the incoming command packed it malformed.
438 """
439
440 def __init__(self):
441 PrintGlxReqSize_common.__init__(self)
442 self.counter_sigs = {}
443
444
445 def printRealHeader(self):
446 print('')
447 print('#include <GL/gl.h>')
448 print('#include "glxserver.h"')
449 print('#include "glxbyteorder.h"')
450 print('#include "indirect_size.h"')
451 print('#include "indirect_reqsize.h"')
452 print('')
453 print('#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS')
454 print('# define ALIAS2(from,to) \\')
455 print(' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\')
456 print(' __attribute__ ((alias( # to )));')
457 print('# define ALIAS(from,to) ALIAS2( from, __glX ## to ## ReqSize )')
458 print('#else')
459 print('# define ALIAS(from,to) \\')
460 print(' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\')
461 print(' { return __glX ## to ## ReqSize( pc, swap, reqlen ); }')
462 print('#endif')
463 print('')
464 print('')
465
466
467 def printBody(self, api):
468 aliases = []
469 enum_functions = {}
470 enum_sigs = {}
471
472 for func in api.functionIterateGlx():
473 if not func.has_variable_size_request(): continue
474
475 ef = glx_server_enum_function( func, api.enums_by_name )
476 if len(ef.enums) == 0: continue
477
478 sig = ef.signature()
479
480 if not enum_functions.has_key(func.name):
481 enum_functions[ func.name ] = sig
482
483 if not enum_sigs.has_key( sig ):
484 enum_sigs[ sig ] = ef
485
486
487
488 for func in api.functionIterateGlx():
489 # Even though server-handcode fuctions are on "the
490 # list", and prototypes are generated for them, there
491 # isn't enough information to generate a size
492 # function. If there was enough information, they
493 # probably wouldn't need to be handcoded in the first
494 # place!
495
496 if func.server_handcode: continue
497 if not func.has_variable_size_request(): continue
498
499 if enum_functions.has_key(func.name):
500 sig = enum_functions[func.name]
501 ef = enum_sigs[ sig ]
502
503 if ef.name != func.name:
504 aliases.append( [func.name, ef.name] )
505 else:
506 ef.Print( func.name, self )
507
508 elif func.images:
509 self.printPixelFunction(func)
510 elif func.has_variable_size_request():
511 a = self.printCountedFunction(func)
512 if a: aliases.append(a)
513
514
515 for [alias_name, real_name] in aliases:
516 print('ALIAS( %s, %s )' % (alias_name, real_name))
517
518 return
519
520
521 def common_emit_fixups(self, fixup):
522 """Utility function to emit conditional byte-swaps."""
523
524 if fixup:
525 print(' if (swap) {')
526 for name in fixup:
527 print(' %s = bswap_32(%s);' % (name, name))
528 print(' }')
529
530 return
531
532
533 def common_emit_one_arg(self, p, pc, adjust):
534 offset = p.offset
535 dst = p.string()
536 src = '(%s *)' % (p.type_string())
537 print('%-18s = *%11s(%s + %u);' % (dst, src, pc, offset + adjust));
538 return
539
540
541 def common_func_print_just_header(self, f):
542 print('int')
543 print('__glX%sReqSize( const GLbyte * pc, Bool swap, int reqlen )' % (f.name))
544 print('{')
545
546
547 def printPixelFunction(self, f):
548 self.common_func_print_just_header(f)
549
550 f.offset_of( f.parameters[0].name )
551 [dim, w, h, d, junk] = f.get_images()[0].get_dimensions()
552
553 print(' GLint row_length = * (GLint *)(pc + 4);')
554
555 if dim < 3:
556 fixup = ['row_length', 'skip_rows', 'alignment']
557 print(' GLint image_height = 0;')
558 print(' GLint skip_images = 0;')
559 print(' GLint skip_rows = * (GLint *)(pc + 8);')
560 print(' GLint alignment = * (GLint *)(pc + 16);')
561 else:
562 fixup = ['row_length', 'image_height', 'skip_rows', 'skip_images', 'alignment']
563 print(' GLint image_height = * (GLint *)(pc + 8);')
564 print(' GLint skip_rows = * (GLint *)(pc + 16);')
565 print(' GLint skip_images = * (GLint *)(pc + 20);')
566 print(' GLint alignment = * (GLint *)(pc + 32);')
567
568 img = f.images[0]
569 for p in f.parameterIterateGlxSend():
570 if p.name in [w, h, d, img.img_format, img.img_type, img.img_target]:
571 self.common_emit_one_arg(p, "pc", 0)
572 fixup.append( p.name )
573
574 print('')
575
576 self.common_emit_fixups(fixup)
577
578 if img.img_null_flag:
579 print('')
580 print(' if (*(CARD32 *) (pc + %s))' % (img.offset - 4))
581 print(' return 0;')
582
583 print('')
584 print(' return __glXImageSize(%s, %s, %s, %s, %s, %s,' % (img.img_format, img.img_type, img.img_target, w, h, d ))
585 print(' image_height, row_length, skip_images,')
586 print(' skip_rows, alignment);')
587 print('}')
588 print('')
589 return
590
591
592 def printCountedFunction(self, f):
593
594 sig = ""
595 offset = 0
596 fixup = []
597 params = []
598 size = ''
599 param_offsets = {}
600
601 # Calculate the offset of each counter parameter and the
602 # size string for the variable length parameter(s). While
603 # that is being done, calculate a unique signature for this
604 # function.
605
606 for p in f.parameterIterateGlxSend():
607 if p.is_counter:
608 fixup.append( p.name )
609 params.append( p )
610 elif p.counter:
611 s = p.size()
612 if s == 0: s = 1
613
614 sig += "(%u,%u)" % (f.offset_of(p.counter), s)
615 if size == '':
616 size = p.size_string()
617 else:
618 size = "safe_add(%s, %s)" % (size, p.size_string())
619
620 # If the calculated signature matches a function that has
621 # already be emitted, don't emit this function. Instead, add
622 # it to the list of function aliases.
623
624 if self.counter_sigs.has_key(sig):
625 n = self.counter_sigs[sig];
626 alias = [f.name, n]
627 else:
628 alias = None
629 self.counter_sigs[sig] = f.name
630
631 self.common_func_print_just_header(f)
632
633 for p in params:
634 self.common_emit_one_arg(p, "pc", 0)
635
636
637 print('')
638 self.common_emit_fixups(fixup)
639 print('')
640
641 print(' return safe_pad(%s);' % (size))
642 print('}')
643 print('')
644
645 return alias
646
647
648 def _parser():
649 """Parse arguments and return a namespace."""
650 parser = argparse.ArgumentParser()
651 parser.set_defaults(which_functions=(PrintGlxSizeStubs_common.do_get |
652 PrintGlxSizeStubs_common.do_set))
653 parser.add_argument('-f',
654 dest='filename',
655 default='gl_API.xml',
656 help='an XML file describing an OpenGL API.')
657 parser.add_argument('-m',
658 dest='mode',
659 choices=['size_c', 'size_h', 'reqsize_c', 'reqsize_h'],
660 help='Which file to generate')
661 getset = parser.add_mutually_exclusive_group()
662 getset.add_argument('--only-get',
663 dest='which_functions',
664 action='store_const',
665 const=PrintGlxSizeStubs_common.do_get,
666 help='only emit "get-type" functions')
667 getset.add_argument('--only-set',
668 dest='which_functions',
669 action='store_const',
670 const=PrintGlxSizeStubs_common.do_set,
671 help='only emit "set-type" functions')
672 parser.add_argument('--header-tag',
673 dest='header_tag',
674 action='store',
675 default=None,
676 help='set header tag value')
677 return parser.parse_args()
678
679
680 def main():
681 """Main function."""
682 args = _parser()
683
684 if args.mode == "size_c":
685 printer = PrintGlxSizeStubs_c(args.which_functions)
686 elif args.mode == "size_h":
687 printer = PrintGlxSizeStubs_h(args.which_functions)
688 if args.header_tag is not None:
689 printer.header_tag = args.header_tag
690 elif args.mode == "reqsize_c":
691 printer = PrintGlxReqSize_c()
692 elif args.mode == "reqsize_h":
693 printer = PrintGlxReqSize_h()
694
695 api = gl_XML.parse_GL_API(args.filename, glX_XML.glx_item_factory())
696
697 printer.Print(api)
698
699
700 if __name__ == '__main__':
701 main()