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