• 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
27from __future__ import print_function
28
29import argparse
30import sys, string
31
32import gl_XML, glX_XML
33import license
34
35
36class glx_enum_function(object):
37    def __init__(self, func_name, enum_dict):
38        self.name = func_name
39        self.mode = 1
40        self.sig = None
41
42        # "enums" is a set of lists.  The element in the set is the
43        # value of the enum.  The list is the list of names for that
44        # value.  For example, [0x8126] = {"POINT_SIZE_MIN",
45        # "POINT_SIZE_MIN_ARB", "POINT_SIZE_MIN_EXT",
46        # "POINT_SIZE_MIN_SGIS"}.
47
48        self.enums = {}
49
50        # "count" is indexed by count values.  Each element of count
51        # is a list of index to "enums" that have that number of
52        # associated data elements.  For example, [4] =
53        # {GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION,
54        # GL_AMBIENT_AND_DIFFUSE} (the enum names are used here,
55        # but the actual hexadecimal values would be in the array).
56
57        self.count = {}
58
59
60        # Fill self.count and self.enums using the dictionary of enums
61        # that was passed in.  The generic Get functions (e.g.,
62        # GetBooleanv and friends) are handled specially here.  In
63        # the data the generic Get functions are referred to as "Get".
64
65        if func_name in ["GetIntegerv", "GetBooleanv", "GetFloatv", "GetDoublev"]:
66            match_name = "Get"
67        else:
68            match_name = func_name
69
70        mode_set = 0
71        for enum_name in enum_dict:
72            e = enum_dict[ enum_name ]
73
74            if match_name in e.functions:
75                [count, mode] = e.functions[ match_name ]
76
77                if mode_set and mode != self.mode:
78                    raise RuntimeError("Not all enums for %s have the same mode." % (func_name))
79
80                self.mode = mode
81
82                if e.value in self.enums:
83                    if e.name not in self.enums[ e.value ]:
84                        self.enums[ e.value ].append( e )
85                else:
86                    if count not in self.count:
87                        self.count[ count ] = []
88
89                    self.enums[ e.value ] = [ e ]
90                    self.count[ count ].append( e.value )
91
92
93        return
94
95
96    def signature( self ):
97        if self.sig == None:
98            self.sig = ""
99            for i in self.count:
100                if i == None:
101                    raise RuntimeError("i is None.  WTF?")
102
103                self.count[i].sort()
104                for e in self.count[i]:
105                    self.sig += "%04x,%d," % (e, i)
106
107        return self.sig
108
109
110    def is_set( self ):
111        return self.mode
112
113
114    def PrintUsingTable(self):
115        """Emit the body of the __gl*_size function using a pair
116        of look-up tables and a mask.  The mask is calculated such
117        that (e & mask) is unique for all the valid values of e for
118        this function.  The result of (e & mask) is used as an index
119        into the first look-up table.  If it matches e, then the
120        same entry of the second table is returned.  Otherwise zero
121        is returned.
122
123        It seems like this should cause better code to be generated.
124        However, on x86 at least, the resulting .o file is about 20%
125        larger then the switch-statment version.  I am leaving this
126        code in because the results may be different on other
127        platforms (e.g., PowerPC or x86-64)."""
128
129        return 0
130        count = 0
131        for a in self.enums:
132            count += 1
133
134        if -1 in self.count:
135            return 0
136
137        # Determine if there is some mask M, such that M = (2^N) - 1,
138        # that will generate unique values for all of the enums.
139
140        mask = 0
141        for i in [1, 2, 3, 4, 5, 6, 7, 8]:
142            mask = (1 << i) - 1
143
144            fail = 0;
145            for a in self.enums:
146                for b in self.enums:
147                    if a != b:
148                        if (a & mask) == (b & mask):
149                            fail = 1;
150
151            if not fail:
152                break;
153            else:
154                mask = 0
155
156        if (mask != 0) and (mask < (2 * count)):
157            masked_enums = {}
158            masked_count = {}
159
160            for i in range(0, mask + 1):
161                masked_enums[i] = "0";
162                masked_count[i] = 0;
163
164            for c in self.count:
165                for e in self.count[c]:
166                    i = e & mask
167                    enum_obj = self.enums[e][0]
168                    masked_enums[i] = '0x%04x /* %s */' % (e, enum_obj.name )
169                    masked_count[i] = c
170
171
172            print('    static const GLushort a[%u] = {' % (mask + 1))
173            for e in masked_enums:
174                print('        %s, ' % (masked_enums[e]))
175            print('    };')
176
177            print('    static const GLubyte b[%u] = {' % (mask + 1))
178            for c in masked_count:
179                print('        %u, ' % (masked_count[c]))
180            print('    };')
181
182            print('    const unsigned idx = (e & 0x%02xU);' % (mask))
183            print('')
184            print('    return (e == a[idx]) ? (GLint) b[idx] : 0;')
185            return 1;
186        else:
187            return 0;
188
189
190    def PrintUsingSwitch(self, name):
191        """Emit the body of the __gl*_size function using a
192        switch-statement."""
193
194        print('    switch( e ) {')
195
196        for c in sorted(self.count):
197            for e in self.count[c]:
198                first = 1
199
200                # There may be multiple enums with the same
201                # value.  This happens has extensions are
202                # promoted from vendor-specific or EXT to
203                # ARB and to the core.  Emit the first one as
204                # a case label, and emit the others as
205                # commented-out case labels.
206
207                list = {}
208                for enum_obj in self.enums[e]:
209                    list[ enum_obj.priority() ] = enum_obj.name
210
211                keys = sorted(list.keys())
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 = sorted(foo.keys())
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 sig in enum_sigs:
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 func.name not in enum_functions:
479                enum_functions[ func.name ] = sig
480
481            if sig not in enum_sigs:
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 func.name in enum_functions:
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 sig in self.counter_sigs:
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