Remove the logic that determines at compile time whether or not HAVE_ALIAS
[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 '#ifdef HAVE_ALIAS'
324 print '# define ALIAS2(from,to) \\'
325 print ' INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\'
326 print ' __attribute__ ((alias( # to )));'
327 print '# define ALIAS(from,to) ALIAS2( from, __gl ## to ## _size )'
328 print '#else'
329 print '# define ALIAS(from,to) \\'
330 print ' INTERNAL PURE FASTCALL GLint __gl ## from ## _size( GLenum e ) \\'
331 print ' { return __gl ## to ## _size( e ); }'
332 print '#endif'
333 print ''
334 print ''
335
336
337 def printBody(self, api):
338 enum_sigs = {}
339 aliases = []
340
341 for func in api.functionIterateGlx():
342 ef = glx_enum_function( func.name, api.enums_by_name )
343 if len(ef.enums) == 0:
344 continue
345
346 if (ef.is_set() and self.emit_set) or (not ef.is_set() and self.emit_get):
347 sig = ef.signature()
348 if enum_sigs.has_key( sig ):
349 aliases.append( [func.name, enum_sigs[ sig ]] )
350 else:
351 enum_sigs[ sig ] = func.name
352 ef.Print( func.name )
353
354
355 for [alias_name, real_name] in aliases:
356 print 'ALIAS( %s, %s )' % (alias_name, real_name)
357
358
359
360 class PrintGlxSizeStubs_h(PrintGlxSizeStubs_common):
361 def printRealHeader(self):
362 print """/**
363 * \\file
364 * Prototypes for functions used to determine the number of data elements in
365 * various GLX protocol messages.
366 *
367 * \\author Ian Romanick <idr@us.ibm.com>
368 */
369 """
370 self.printPure();
371 print ''
372 self.printFastcall();
373 print ''
374 self.printVisibility( "INTERNAL", "internal" );
375 print ''
376
377
378 def printBody(self, api):
379 for func in api.functionIterateGlx():
380 ef = glx_enum_function( func.name, api.enums_by_name )
381 if len(ef.enums) == 0:
382 continue
383
384 if (ef.is_set() and self.emit_set) or (not ef.is_set() and self.emit_get):
385 print 'extern INTERNAL PURE FASTCALL GLint __gl%s_size(GLenum);' % (func.name)
386
387
388 class PrintGlxReqSize_common(gl_XML.gl_print_base):
389 """Common base class for PrintGlxSizeReq_h and PrintGlxSizeReq_h.
390
391 The main purpose of this common base class is to provide the infrastructure
392 for the derrived classes to iterate over the same set of functions.
393 """
394
395 def __init__(self):
396 gl_XML.gl_print_base.__init__(self)
397
398 self.name = "glX_proto_size.py (from Mesa)"
399 self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2005", "IBM")
400
401
402 class PrintGlxReqSize_h(PrintGlxReqSize_common):
403 def __init__(self):
404 PrintGlxReqSize_common.__init__(self)
405 self.header_tag = "_INDIRECT_REQSIZE_H_"
406
407
408 def printRealHeader(self):
409 self.printVisibility("HIDDEN", "hidden")
410 print ''
411 self.printPure()
412 print ''
413
414
415 def printBody(self, api):
416 for func in api.functionIterateGlx():
417 if not func.ignore and func.has_variable_size_request():
418 print 'extern PURE HIDDEN int __glX%sReqSize(const GLbyte *pc, Bool swap);' % (func.name)
419
420
421 class PrintGlxReqSize_c(PrintGlxReqSize_common):
422 def __init__(self):
423 PrintGlxReqSize_common.__init__(self)
424 self.counter_sigs = {}
425
426
427 def printRealHeader(self):
428 print ''
429 print '#include <GL/gl.h>'
430 print '#include <byteswap.h>'
431 print '#include "glxserver.h"'
432 print '#include "indirect_size.h"'
433 print '#include "indirect_reqsize.h"'
434
435 print ''
436 print '#define __GLX_PAD(x) (((x) + 3) & ~3)'
437 print ''
438 print '#ifdef HAVE_ALIAS'
439 print '# define ALIAS2(from,to) \\'
440 print ' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap ) \\'
441 print ' __attribute__ ((alias( # to )));'
442 print '# define ALIAS(from,to) ALIAS2( from, __glX ## to ## ReqSize )'
443 print '#else'
444 print '# define ALIAS(from,to) \\'
445 print ' GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap ) \\'
446 print ' { return __glX ## to ## ReqSize( pc, swap ); }'
447 print '#endif'
448 print ''
449 print ''
450
451
452 def printBody(self, api):
453 aliases = []
454 enum_functions = {}
455 enum_sigs = {}
456
457 for func in api.functionIterateGlx():
458 if not func.has_variable_size_request(): continue
459
460 ef = glx_server_enum_function( func, api.enums_by_name )
461 if len(ef.enums) == 0: continue
462
463 sig = ef.signature()
464
465 if not enum_functions.has_key(func.name):
466 enum_functions[ func.name ] = sig
467
468 if not enum_sigs.has_key( sig ):
469 enum_sigs[ sig ] = ef
470
471
472
473 for func in api.functionIterateGlx():
474 # Even though server-handcode fuctions are on "the
475 # list", and prototypes are generated for them, there
476 # isn't enough information to generate a size
477 # function. If there was enough information, they
478 # probably wouldn't need to be handcoded in the first
479 # place!
480
481 if func.server_handcode: continue
482 if not func.has_variable_size_request(): continue
483
484 if enum_functions.has_key(func.name):
485 sig = enum_functions[func.name]
486 ef = enum_sigs[ sig ]
487
488 if ef.name != func.name:
489 aliases.append( [func.name, ef.name] )
490 else:
491 ef.Print( func.name, self )
492
493 elif func.images:
494 self.printPixelFunction(func)
495 elif func.has_variable_size_request():
496 a = self.printCountedFunction(func)
497 if a: aliases.append(a)
498
499
500 for [alias_name, real_name] in aliases:
501 print 'ALIAS( %s, %s )' % (alias_name, real_name)
502
503 return
504
505
506 def common_emit_fixups(self, fixup):
507 """Utility function to emit conditional byte-swaps."""
508
509 if fixup:
510 print ' if (swap) {'
511 for name in fixup:
512 print ' %-14s = bswap_32( %s );' % (name, name)
513 print ' }'
514
515 return
516
517
518 def common_emit_one_arg(self, p, pc, indent, adjust):
519 offset = p.offset
520 dst = p.string()
521 src = '(%s *)' % (p.type_string())
522 print '%s%-18s = *%11s(%s + %u);' % (indent, dst, src, pc, offset + adjust);
523 return
524
525
526 def common_func_print_just_header(self, f):
527 print 'int'
528 print '__glX%sReqSize( const GLbyte * pc, Bool swap )' % (f.name)
529 print '{'
530
531
532 def printPixelFunction(self, f):
533 self.common_func_print_just_header(f)
534
535 f.offset_of( f.parameters[0].name )
536 [dim, w, h, d, junk] = f.dimensions()
537
538 print ' GLint row_length = * (GLint *)(pc + 4);'
539
540 if dim < 3:
541 fixup = ['row_length', 'skip_rows', 'alignment']
542 print ' GLint image_height = 0;'
543 print ' GLint skip_images = 0;'
544 print ' GLint skip_rows = * (GLint *)(pc + 8);'
545 print ' GLint alignment = * (GLint *)(pc + 16);'
546 else:
547 fixup = ['row_length', 'image_height', 'skip_rows', 'skip_images', 'alignment']
548 print ' GLint image_height = * (GLint *)(pc + 8);'
549 print ' GLint skip_rows = * (GLint *)(pc + 16);'
550 print ' GLint skip_images = * (GLint *)(pc + 20);'
551 print ' GLint alignment = * (GLint *)(pc + 32);'
552
553 img = f.images[0]
554 for p in f.parameterIterateGlxSend():
555 if p.name in [w, h, d, img.img_format, img.img_type, img.img_target]:
556 self.common_emit_one_arg( p, "pc", " ", 0 )
557 fixup.append( p.name )
558
559 print ''
560
561 self.common_emit_fixups(fixup)
562
563 print ''
564 print ' return __glXImageSize(%s, %s, %s, %s, %s, %s,' % (img.img_format, img.img_type, img.img_target, w, h, d )
565 print ' image_height, row_length, skip_images,'
566 print ' skip_rows, alignment);'
567 print '}'
568 print ''
569 return
570
571
572 def printCountedFunction(self, f):
573
574 sig = ""
575 offset = 0
576 fixup = []
577 params = []
578 plus = ''
579 size = ''
580 param_offsets = {}
581
582 # Calculate the offset of each counter parameter and the
583 # size string for the variable length parameter(s). While
584 # that is being done, calculate a unique signature for this
585 # function.
586
587 for p in f.parameterIterateGlxSend():
588 if p.is_counter:
589 fixup.append( p.name )
590 params.append( p )
591 elif p.counter:
592 s = p.size()
593 if s == 0: s = 1
594
595 sig += "(%u,%u)" % (f.offset_of(p.counter), s)
596 size += '%s%s' % (plus, p.size_string())
597 plus = ' + '
598
599
600 # If the calculated signature matches a function that has
601 # already be emitted, don't emit this function. Instead, add
602 # it to the list of function aliases.
603
604 if self.counter_sigs.has_key(sig):
605 n = self.counter_sigs[sig];
606 alias = [f.name, n]
607 else:
608 alias = None
609 self.counter_sigs[sig] = f.name
610
611 self.common_func_print_just_header(f)
612
613 for p in params:
614 self.common_emit_one_arg(p, "pc", " ", 0 )
615
616
617 print ''
618 self.common_emit_fixups(fixup)
619 print ''
620
621 print ' return __GLX_PAD(%s);' % (size)
622 print '}'
623 print ''
624
625 return alias
626
627
628 def show_usage():
629 print "Usage: %s [-f input_file_name] -m output_mode [--only-get | --only-set] [--get-alias-set]" % sys.argv[0]
630 print " -m output_mode Output mode can be one of 'size_c' or 'size_h'."
631 print " --only-get Only emit 'get'-type functions."
632 print " --only-set Only emit 'set'-type functions."
633 print " --get-alias-set When only 'get'-type functions are emitted, allow them"
634 print " to be aliases to 'set'-type funcitons."
635 print ""
636 print "By default, both 'get' and 'set'-type functions are emitted."
637 sys.exit(1)
638
639
640 if __name__ == '__main__':
641 file_name = "gl_API.xml"
642
643 try:
644 (args, trail) = getopt.getopt(sys.argv[1:], "f:m:h:", ["only-get", "only-set", "header-tag"])
645 except Exception,e:
646 show_usage()
647
648 mode = None
649 header_tag = None
650 which_functions = PrintGlxSizeStubs_common.do_get | PrintGlxSizeStubs_common.do_set
651
652 for (arg,val) in args:
653 if arg == "-f":
654 file_name = val
655 elif arg == "-m":
656 mode = val
657 elif arg == "--only-get":
658 which_functions = PrintGlxSizeStubs_common.do_get
659 elif arg == "--only-set":
660 which_functions = PrintGlxSizeStubs_common.do_set
661 elif (arg == '-h') or (arg == "--header-tag"):
662 header_tag = val
663
664 if mode == "size_c":
665 printer = PrintGlxSizeStubs_c( which_functions )
666 elif mode == "size_h":
667 printer = PrintGlxSizeStubs_h( which_functions )
668 if header_tag:
669 printer.header_tag = header_tag
670 elif mode == "reqsize_c":
671 printer = PrintGlxReqSize_c()
672 elif mode == "reqsize_h":
673 printer = PrintGlxReqSize_h()
674 else:
675 show_usage()
676
677 api = gl_XML.parse_GL_API( file_name, glX_XML.glx_item_factory() )
678
679
680 printer.Print( api )