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