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