• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
28import argparse
29import sys, string
30
31import gl_XML, glX_XML
32import license
33
34
35class glx_enum_function(object):
36    def __init__(self, func_name, enum_dict):
37        self.name = func_name
38        self.mode = 1
39        self.sig = None
40
41        # "enums" is a set of lists.  The element in the set is the
42        # value of the enum.  The list is the list of names for that
43        # value.  For example, [0x8126] = {"POINT_SIZE_MIN",
44        # "POINT_SIZE_MIN_ARB", "POINT_SIZE_MIN_EXT",
45        # "POINT_SIZE_MIN_SGIS"}.
46
47        self.enums = {}
48
49        # "count" is indexed by count values.  Each element of count
50        # is a list of index to "enums" that have that number of
51        # associated data elements.  For example, [4] =
52        # {GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION,
53        # GL_AMBIENT_AND_DIFFUSE} (the enum names are used here,
54        # but the actual hexadecimal values would be in the array).
55
56        self.count = {}
57
58
59        # Fill self.count and self.enums using the dictionary of enums
60        # that was passed in.  The generic Get functions (e.g.,
61        # GetBooleanv and friends) are handled specially here.  In
62        # the data the generic Get functions are referred to as "Get".
63
64        if func_name in ["GetIntegerv", "GetBooleanv", "GetFloatv", "GetDoublev"]:
65            match_name = "Get"
66        else:
67            match_name = func_name
68
69        mode_set = 0
70        for enum_name in enum_dict:
71            e = enum_dict[ enum_name ]
72
73            if e.functions.has_key( match_name ):
74                [count, mode] = e.functions[ match_name ]
75
76                if mode_set and mode != self.mode:
77                    raise RuntimeError("Not all enums for %s have the same mode." % (func_name))
78
79                self.mode = mode
80
81                if self.enums.has_key( e.value ):
82                    if e.name not in self.enums[ e.value ]:
83                        self.enums[ e.value ].append( e )
84                else:
85                    if not self.count.has_key( count ):
86                        self.count[ count ] = []
87
88                    self.enums[ e.value ] = [ e ]
89                    self.count[ count ].append( e.value )
90
91
92        return
93
94
95    def signature( self ):
96        if self.sig == None:
97            self.sig = ""
98            for i in self.count:
99                if i == None:
100                    raise RuntimeError("i is None.  WTF?")
101
102                self.count[i].sort()
103                for e in self.count[i]:
104                    self.sig += "%04x,%d," % (e, i)
105
106        return self.sig
107
108
109    def is_set( self ):
110        return self.mode
111
112
113    def PrintUsingTable(self):
114        """Emit the body of the __gl*_size function using a pair
115        of look-up tables and a mask.  The mask is calculated such
116        that (e & mask) is unique for all the valid values of e for
117        this function.  The result of (e & mask) is used as an index
118        into the first look-up table.  If it matches e, then the
119        same entry of the second table is returned.  Otherwise zero
120        is returned.
121
122        It seems like this should cause better code to be generated.
123        However, on x86 at least, the resulting .o file is about 20%
124        larger then the switch-statment version.  I am leaving this
125        code in because the results may be different on other
126        platforms (e.g., PowerPC or x86-64)."""
127
128        return 0
129        count = 0
130        for a in self.enums:
131            count += 1
132
133        if self.count.has_key(-1):
134            return 0
135
136        # Determine if there is some mask M, such that M = (2^N) - 1,
137        # that will generate unique values for all of the enums.
138
139        mask = 0
140        for i in [1, 2, 3, 4, 5, 6, 7, 8]:
141            mask = (1 << i) - 1
142
143            fail = 0;
144            for a in self.enums:
145                for b in self.enums:
146                    if a != b:
147                        if (a & mask) == (b & mask):
148                            fail = 1;
149
150            if not fail:
151                break;
152            else:
153                mask = 0
154
155        if (mask != 0) and (mask < (2 * count)):
156            masked_enums = {}
157            masked_count = {}
158
159            for i in range(0, mask + 1):
160                masked_enums[i] = "0";
161                masked_count[i] = 0;
162
163            for c in self.count:
164                for e in self.count[c]:
165                    i = e & mask
166                    enum_obj = self.enums[e][0]
167                    masked_enums[i] = '0x%04x /* %s */' % (e, enum_obj.name )
168                    masked_count[i] = c
169
170
171            print '    static const GLushort a[%u] = {' % (mask + 1)
172            for e in masked_enums:
173                print '        %s, ' % (masked_enums[e])
174            print '    };'
175
176            print '    static const GLubyte b[%u] = {' % (mask + 1)
177            for c in masked_count:
178                print '        %u, ' % (masked_count[c])
179            print '    };'
180
181            print '    const unsigned idx = (e & 0x%02xU);' % (mask)
182            print ''
183            print '    return (e == a[idx]) ? (GLint) b[idx] : 0;'
184            return 1;
185        else:
186            return 0;
187
188
189    def PrintUsingSwitch(self, name):
190        """Emit the body of the __gl*_size function using a
191        switch-statement."""
192
193        print '    switch( e ) {'
194
195        for c in self.count:
196            for e in self.count[c]:
197                first = 1
198
199                # There may be multiple enums with the same
200                # value.  This happens has extensions are
201                # promoted from vendor-specific or EXT to
202                # ARB and to the core.  Emit the first one as
203                # a case label, and emit the others as
204                # commented-out case labels.
205
206                list = {}
207                for enum_obj in self.enums[e]:
208                    list[ enum_obj.priority() ] = enum_obj.name
209
210                keys = list.keys()
211                keys.sort()
212                for k in keys:
213                    j = list[k]
214                    if first:
215                        print '        case GL_%s:' % (j)
216                        first = 0
217                    else:
218                        print '/*      case GL_%s:*/' % (j)
219
220            if c == -1:
221                print '            return __gl%s_variable_size( e );' % (name)
222            else:
223                print '            return %u;' % (c)
224
225        print '        default: return 0;'
226        print '    }'
227
228
229    def Print(self, name):
230        print '_X_INTERNAL PURE FASTCALL GLint'
231        print '__gl%s_size( GLenum e )' % (name)
232        print '{'
233
234        if not self.PrintUsingTable():
235            self.PrintUsingSwitch(name)
236
237        print '}'
238        print ''
239
240
241class glx_server_enum_function(glx_enum_function):
242    def __init__(self, func, enum_dict):
243        glx_enum_function.__init__(self, func.name, enum_dict)
244
245        self.function = func
246        return
247
248
249    def signature( self ):
250        if self.sig == None:
251            sig = glx_enum_function.signature(self)
252
253            p = self.function.variable_length_parameter()
254            if p:
255                sig += "%u" % (p.size())
256
257            self.sig = sig
258
259        return self.sig;
260
261
262    def Print(self, name, printer):
263        f = self.function
264        printer.common_func_print_just_header( f )
265
266        fixup = []
267
268        foo = {}
269        for param_name in f.count_parameter_list:
270            o = f.offset_of( param_name )
271            foo[o] = param_name
272
273        for param_name in f.counter_list:
274            o = f.offset_of( param_name )
275            foo[o] = param_name
276
277        keys = foo.keys()
278        keys.sort()
279        for o in keys:
280            p = f.parameters_by_name[ foo[o] ]
281
282            printer.common_emit_one_arg(p, "pc", 0)
283            fixup.append( p.name )
284
285
286        print '    GLsizei compsize;'
287        print ''
288
289        printer.common_emit_fixups(fixup)
290
291        print ''
292        print '    compsize = __gl%s_size(%s);' % (f.name, string.join(f.count_parameter_list, ","))
293        p = f.variable_length_parameter()
294        print '    return safe_pad(%s);' % (p.size_string())
295
296        print '}'
297        print ''
298
299
300class PrintGlxSizeStubs_common(gl_XML.gl_print_base):
301    do_get = (1 << 0)
302    do_set = (1 << 1)
303
304    def __init__(self, which_functions):
305        gl_XML.gl_print_base.__init__(self)
306
307        self.name = "glX_proto_size.py (from Mesa)"
308        self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2004", "IBM")
309
310        self.emit_set = ((which_functions & PrintGlxSizeStubs_common.do_set) != 0)
311        self.emit_get = ((which_functions & PrintGlxSizeStubs_common.do_get) != 0)
312        return
313
314
315class PrintGlxSizeStubs_c(PrintGlxSizeStubs_common):
316    def printRealHeader(self):
317        print ''
318        print '#include <X11/Xfuncproto.h>'
319        print '#include <GL/gl.h>'
320        if self.emit_get:
321            print '#include "indirect_size_get.h"'
322            print '#include "glxserver.h"'
323            print '#include "indirect_util.h"'
324
325        print '#include "indirect_size.h"'
326
327        print ''
328        self.printPure()
329        print ''
330        self.printFastcall()
331        print ''
332        print ''
333        print '#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS'
334        print '#  define ALIAS2(from,to) \\'
335        print '    _X_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 '    _X_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
370class 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        print '#include <X11/Xfuncproto.h>'
381        print ''
382        self.printPure();
383        print ''
384        self.printFastcall();
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 _X_INTERNAL PURE FASTCALL GLint __gl%s_size(GLenum);' % (func.name)
396
397
398class 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
412class 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        print '#include <X11/Xfuncproto.h>'
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 _X_HIDDEN int __glX%sReqSize(const GLbyte *pc, Bool swap, int reqlen);' % (func.name)
429
430
431class 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 "glxbyteorder.h"'
449        print '#include "indirect_size.h"'
450        print '#include "indirect_reqsize.h"'
451        print ''
452        print '#ifdef HAVE_FUNC_ATTRIBUTE_ALIAS'
453        print '#  define ALIAS2(from,to) \\'
454        print '    GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\'
455        print '        __attribute__ ((alias( # to )));'
456        print '#  define ALIAS(from,to) ALIAS2( from, __glX ## to ## ReqSize )'
457        print '#else'
458        print '#  define ALIAS(from,to) \\'
459        print '    GLint __glX ## from ## ReqSize( const GLbyte * pc, Bool swap, int reqlen ) \\'
460        print '    { return __glX ## to ## ReqSize( pc, swap, reqlen ); }'
461        print '#endif'
462        print ''
463        print ''
464
465
466    def printBody(self, api):
467        aliases = []
468        enum_functions = {}
469        enum_sigs = {}
470
471        for func in api.functionIterateGlx():
472            if not func.has_variable_size_request(): continue
473
474            ef = glx_server_enum_function( func, api.enums_by_name )
475            if len(ef.enums) == 0: continue
476
477            sig = ef.signature()
478
479            if not enum_functions.has_key(func.name):
480                enum_functions[ func.name ] = sig
481
482            if not enum_sigs.has_key( sig ):
483                enum_sigs[ sig ] = ef
484
485
486
487        for func in api.functionIterateGlx():
488            # Even though server-handcode fuctions are on "the
489            # list", and prototypes are generated for them, there
490            # isn't enough information to generate a size
491            # function.  If there was enough information, they
492            # probably wouldn't need to be handcoded in the first
493            # place!
494
495            if func.server_handcode: continue
496            if not func.has_variable_size_request(): continue
497
498            if enum_functions.has_key(func.name):
499                sig = enum_functions[func.name]
500                ef = enum_sigs[ sig ]
501
502                if ef.name != func.name:
503                    aliases.append( [func.name, ef.name] )
504                else:
505                    ef.Print( func.name, self )
506
507            elif func.images:
508                self.printPixelFunction(func)
509            elif func.has_variable_size_request():
510                a = self.printCountedFunction(func)
511                if a: aliases.append(a)
512
513
514        for [alias_name, real_name] in aliases:
515            print 'ALIAS( %s, %s )' % (alias_name, real_name)
516
517        return
518
519
520    def common_emit_fixups(self, fixup):
521        """Utility function to emit conditional byte-swaps."""
522
523        if fixup:
524            print '    if (swap) {'
525            for name in fixup:
526                print '        %s = bswap_32(%s);' % (name, name)
527            print '    }'
528
529        return
530
531
532    def common_emit_one_arg(self, p, pc, adjust):
533        offset = p.offset
534        dst = p.string()
535        src = '(%s *)' % (p.type_string())
536        print '%-18s = *%11s(%s + %u);' % (dst, src, pc, offset + adjust);
537        return
538
539
540    def common_func_print_just_header(self, f):
541        print 'int'
542        print '__glX%sReqSize( const GLbyte * pc, Bool swap, int reqlen )' % (f.name)
543        print '{'
544
545
546    def printPixelFunction(self, f):
547        self.common_func_print_just_header(f)
548
549        f.offset_of( f.parameters[0].name )
550        [dim, w, h, d, junk] = f.get_images()[0].get_dimensions()
551
552        print '    GLint row_length   = *  (GLint *)(pc +  4);'
553
554        if dim < 3:
555            fixup = ['row_length', 'skip_rows', 'alignment']
556            print '    GLint image_height = 0;'
557            print '    GLint skip_images  = 0;'
558            print '    GLint skip_rows    = *  (GLint *)(pc +  8);'
559            print '    GLint alignment    = *  (GLint *)(pc + 16);'
560        else:
561            fixup = ['row_length', 'image_height', 'skip_rows', 'skip_images', 'alignment']
562            print '    GLint image_height = *  (GLint *)(pc +  8);'
563            print '    GLint skip_rows    = *  (GLint *)(pc + 16);'
564            print '    GLint skip_images  = *  (GLint *)(pc + 20);'
565            print '    GLint alignment    = *  (GLint *)(pc + 32);'
566
567        img = f.images[0]
568        for p in f.parameterIterateGlxSend():
569            if p.name in [w, h, d, img.img_format, img.img_type, img.img_target]:
570                self.common_emit_one_arg(p, "pc", 0)
571                fixup.append( p.name )
572
573        print ''
574
575        self.common_emit_fixups(fixup)
576
577        if img.img_null_flag:
578            print ''
579            print '	   if (*(CARD32 *) (pc + %s))' % (img.offset - 4)
580            print '	       return 0;'
581
582        print ''
583        print '    return __glXImageSize(%s, %s, %s, %s, %s, %s,' % (img.img_format, img.img_type, img.img_target, w, h, d )
584        print '                          image_height, row_length, skip_images,'
585        print '                          skip_rows, alignment);'
586        print '}'
587        print ''
588        return
589
590
591    def printCountedFunction(self, f):
592
593        sig = ""
594        offset = 0
595        fixup = []
596        params = []
597        size = ''
598        param_offsets = {}
599
600        # Calculate the offset of each counter parameter and the
601        # size string for the variable length parameter(s).  While
602        # that is being done, calculate a unique signature for this
603        # function.
604
605        for p in f.parameterIterateGlxSend():
606            if p.is_counter:
607                fixup.append( p.name )
608                params.append( p )
609            elif p.counter:
610                s = p.size()
611                if s == 0: s = 1
612
613                sig += "(%u,%u)" % (f.offset_of(p.counter), s)
614		if size == '':
615		    size = p.size_string()
616		else:
617		    size = "safe_add(%s, %s)" % (size, p.size_string())
618
619        # If the calculated signature matches a function that has
620        # already be emitted, don't emit this function.  Instead, add
621        # it to the list of function aliases.
622
623        if self.counter_sigs.has_key(sig):
624            n = self.counter_sigs[sig];
625            alias = [f.name, n]
626        else:
627            alias = None
628            self.counter_sigs[sig] = f.name
629
630            self.common_func_print_just_header(f)
631
632            for p in params:
633                self.common_emit_one_arg(p, "pc", 0)
634
635
636            print ''
637            self.common_emit_fixups(fixup)
638            print ''
639
640            print '    return safe_pad(%s);' % (size)
641            print '}'
642            print ''
643
644        return alias
645
646
647def _parser():
648    """Parse arguments and return a namespace."""
649    parser = argparse.ArgumentParser()
650    parser.set_defaults(which_functions=(PrintGlxSizeStubs_common.do_get |
651                                         PrintGlxSizeStubs_common.do_set))
652    parser.add_argument('-f',
653                        dest='filename',
654                        default='gl_API.xml',
655                        help='an XML file describing an OpenGL API.')
656    parser.add_argument('-m',
657                        dest='mode',
658                        choices=['size_c', 'size_h', 'reqsize_c', 'reqsize_h'],
659                        help='Which file to generate')
660    getset = parser.add_mutually_exclusive_group()
661    getset.add_argument('--only-get',
662                        dest='which_functions',
663                        action='store_const',
664                        const=PrintGlxSizeStubs_common.do_get,
665                        help='only emit "get-type" functions')
666    getset.add_argument('--only-set',
667                        dest='which_functions',
668                        action='store_const',
669                        const=PrintGlxSizeStubs_common.do_set,
670                        help='only emit "set-type" functions')
671    parser.add_argument('--header-tag',
672                        dest='header_tag',
673                        action='store',
674                        default=None,
675                        help='set header tag value')
676    return parser.parse_args()
677
678
679def main():
680    """Main function."""
681    args = _parser()
682
683    if args.mode == "size_c":
684        printer = PrintGlxSizeStubs_c(args.which_functions)
685    elif args.mode == "size_h":
686        printer = PrintGlxSizeStubs_h(args.which_functions)
687        if args.header_tag is not None:
688            printer.header_tag = args.header_tag
689    elif args.mode == "reqsize_c":
690        printer = PrintGlxReqSize_c()
691    elif args.mode == "reqsize_h":
692        printer = PrintGlxReqSize_h()
693
694    api = gl_XML.parse_GL_API(args.filename, glX_XML.glx_item_factory())
695
696    printer.Print(api)
697
698
699if __name__ == '__main__':
700    main()
701