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