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