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