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