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