Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 1
#!/usr/bin/env python
2
 
3
# Mesa 3-D graphics library
4
# Version:  7.9
5
#
6
# Copyright (C) 2010 LunarG Inc.
7
#
8
# Permission is hereby granted, free of charge, to any person obtaining a
9
# copy of this software and associated documentation files (the "Software"),
10
# to deal in the Software without restriction, including without limitation
11
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
# and/or sell copies of the Software, and to permit persons to whom the
13
# Software is furnished to do so, subject to the following conditions:
14
#
15
# The above copyright notice and this permission notice shall be included
16
# in all copies or substantial portions of the Software.
17
#
18
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
# DEALINGS IN THE SOFTWARE.
25
#
26
# Authors:
27
#    Chia-I Wu 
28
 
29
import sys
30
import re
31
from optparse import OptionParser
32
 
33
# number of dynamic entries
34
ABI_NUM_DYNAMIC_ENTRIES = 256
35
 
36
class ABIEntry(object):
37
    """Represent an ABI entry."""
38
 
39
    _match_c_param = re.compile(
40
            '^(?P[\w\s*]+?)(?P\w+)(\[(?P\d+)\])?$')
41
 
42
    def __init__(self, cols, attrs):
43
        self._parse(cols)
44
 
45
        self.slot = attrs['slot']
46
        self.hidden = attrs['hidden']
47
        self.alias = attrs['alias']
48
 
49
    def c_prototype(self):
50
        return '%s %s(%s)' % (self.c_return(), self.name, self.c_params())
51
 
52
    def c_return(self):
53
        ret = self.ret
54
        if not ret:
55
            ret = 'void'
56
 
57
        return ret
58
 
59
    def c_params(self):
60
        """Return the parameter list used in the entry prototype."""
61
        c_params = []
62
        for t, n, a in self.params:
63
            sep = '' if t.endswith('*') else ' '
64
            arr = '[%d]' % a if a else ''
65
            c_params.append(t + sep + n + arr)
66
        if not c_params:
67
            c_params.append('void')
68
 
69
        return ", ".join(c_params)
70
 
71
    def c_args(self):
72
        """Return the argument list used in the entry invocation."""
73
        c_args = []
74
        for t, n, a in self.params:
75
            c_args.append(n)
76
 
77
        return ", ".join(c_args)
78
 
79
    def _parse(self, cols):
80
        ret = cols.pop(0)
81
        if ret == 'void':
82
            ret = None
83
 
84
        name = cols.pop(0)
85
 
86
        params = []
87
        if not cols:
88
            raise Exception(cols)
89
        elif len(cols) == 1 and cols[0] == 'void':
90
            pass
91
        else:
92
            for val in cols:
93
                params.append(self._parse_param(val))
94
 
95
        self.ret = ret
96
        self.name = name
97
        self.params = params
98
 
99
    def _parse_param(self, c_param):
100
        m = self._match_c_param.match(c_param)
101
        if not m:
102
            raise Exception('unrecognized param ' + c_param)
103
 
104
        c_type = m.group('type').strip()
105
        c_name = m.group('name')
106
        c_array = m.group('array')
107
        c_array = int(c_array) if c_array else 0
108
 
109
        return (c_type, c_name, c_array)
110
 
111
    def __str__(self):
112
        return self.c_prototype()
113
 
114
    def __cmp__(self, other):
115
        # compare slot, alias, and then name
116
        res = cmp(self.slot, other.slot)
117
        if not res:
118
            if not self.alias:
119
                res = -1
120
            elif not other.alias:
121
                res = 1
122
 
123
            if not res:
124
                res = cmp(self.name, other.name)
125
 
126
        return res
127
 
128
def abi_parse_line(line):
129
    cols = [col.strip() for col in line.split(',')]
130
 
131
    attrs = {
132
            'slot': -1,
133
            'hidden': False,
134
            'alias': None,
135
    }
136
 
137
    # extract attributes from the first column
138
    vals = cols[0].split(':')
139
    while len(vals) > 1:
140
        val = vals.pop(0)
141
        if val.startswith('slot='):
142
            attrs['slot'] = int(val[5:])
143
        elif val == 'hidden':
144
            attrs['hidden'] = True
145
        elif val.startswith('alias='):
146
            attrs['alias'] = val[6:]
147
        elif not val:
148
            pass
149
        else:
150
            raise Exception('unknown attribute %s' % val)
151
    cols[0] = vals[0]
152
 
153
    return (attrs, cols)
154
 
155
def abi_parse(filename):
156
    """Parse a CSV file for ABI entries."""
157
    fp = open(filename) if filename != '-' else sys.stdin
158
    lines = [line.strip() for line in fp.readlines()
159
            if not line.startswith('#') and line.strip()]
160
 
161
    entry_dict = {}
162
    next_slot = 0
163
    for line in lines:
164
        attrs, cols = abi_parse_line(line)
165
 
166
        # post-process attributes
167
        if attrs['alias']:
168
            try:
169
                ent = entry_dict[attrs['alias']]
170
                slot = ent.slot
171
            except KeyError:
172
                raise Exception('failed to alias %s' % attrs['alias'])
173
        else:
174
            slot = next_slot
175
            next_slot += 1
176
 
177
        if attrs['slot'] < 0:
178
            attrs['slot'] = slot
179
        elif attrs['slot'] != slot:
180
            raise Exception('invalid slot in %s' % (line))
181
 
182
        ent = ABIEntry(cols, attrs)
183
        if entry_dict.has_key(ent.name):
184
            raise Exception('%s is duplicated' % (ent.name))
185
        entry_dict[ent.name] = ent
186
 
187
    entries = entry_dict.values()
188
    entries.sort()
189
 
190
    # sanity check
191
    i = 0
192
    for slot in xrange(next_slot):
193
        if entries[i].slot != slot:
194
            raise Exception('entries are not ordered by slots')
195
        if entries[i].alias:
196
            raise Exception('first entry of slot %d aliases %s'
197
                    % (slot, entries[i].alias))
198
        while i < len(entries) and entries[i].slot == slot:
199
            i += 1
200
    if i < len(entries):
201
        raise Exception('there are %d invalid entries' % (len(entries) - 1))
202
 
203
    return entries
204
 
205
class ABIPrinter(object):
206
    """MAPI Printer"""
207
 
208
    def __init__(self, entries):
209
        self.entries = entries
210
 
211
        # sort entries by their names
212
        self.entries_sorted_by_names = self.entries[:]
213
        self.entries_sorted_by_names.sort(lambda x, y: cmp(x.name, y.name))
214
 
215
        self.indent = ' ' * 3
216
        self.noop_warn = 'noop_warn'
217
        self.noop_generic = 'noop_generic'
218
 
219
        self.api_defines = []
220
        self.api_headers = ['"KHR/khrplatform.h"']
221
        self.api_call = 'KHRONOS_APICALL'
222
        self.api_entry = 'KHRONOS_APIENTRY'
223
        self.api_attrs = 'KHRONOS_APIATTRIBUTES'
224
 
225
    def c_header(self):
226
        return '/* This file is automatically generated by mapi_abi.py.  Do not modify. */'
227
 
228
    def c_includes(self):
229
        """Return includes of the client API headers."""
230
        defines = ['#define ' + d for d in self.api_defines]
231
        includes = ['#include ' + h for h in self.api_headers]
232
        return "\n".join(defines + includes)
233
 
234
    def c_mapi_table(self):
235
        """Return defines of the dispatch table size."""
236
        num_static_entries = 0
237
        for ent in self.entries:
238
            if not ent.alias:
239
                num_static_entries += 1
240
 
241
        return ('#define MAPI_TABLE_NUM_STATIC %d\n' + \
242
                '#define MAPI_TABLE_NUM_DYNAMIC %d') % (
243
                        num_static_entries, ABI_NUM_DYNAMIC_ENTRIES)
244
 
245
    def c_mapi_table_initializer(self, prefix):
246
        """Return the array initializer for mapi_table_fill."""
247
        entries = [ent.name for ent in self.entries if not ent.alias]
248
        pre = self.indent + '(mapi_proc) ' + prefix
249
        return pre + (',\n' + pre).join(entries)
250
 
251
    def c_mapi_table_spec(self):
252
        """Return the spec for mapi_init."""
253
        specv1 = []
254
        line = '"1'
255
        for ent in self.entries:
256
            if not ent.alias:
257
                line += '\\0"\n'
258
                specv1.append(line)
259
                line = '"'
260
            line += '%s\\0' % ent.name
261
        line += '";'
262
        specv1.append(line)
263
 
264
        return self.indent + self.indent.join(specv1)
265
 
266
    def _c_decl(self, ent, prefix, need_attr=True):
267
        """Return the C declaration for the entry."""
268
        decl = '%s %s %s%s(%s)' % (ent.c_return(), self.api_entry,
269
                prefix, ent.name, ent.c_params())
270
        if need_attr and self.api_attrs:
271
            decl += ' ' + self.api_attrs
272
 
273
        return decl
274
 
275
    def _c_cast(self, ent):
276
        """Return the C cast for the entry."""
277
        cast = '%s (%s *)(%s)' % (
278
                ent.c_return(), self.api_entry, ent.c_params())
279
 
280
        return cast
281
 
282
    def c_private_declarations(self, prefix):
283
        """Return the declarations of private functions."""
284
        decls = [self._c_decl(ent, prefix)
285
                for ent in self.entries if not ent.alias]
286
 
287
        return ";\n".join(decls) + ";"
288
 
289
    def c_public_dispatches(self, prefix):
290
        """Return the public dispatch functions."""
291
        dispatches = []
292
        for ent in self.entries:
293
            if ent.hidden:
294
                continue
295
 
296
            proto = self.api_call + ' ' + self._c_decl(ent, prefix)
297
            cast = self._c_cast(ent)
298
 
299
            ret = ''
300
            if ent.ret:
301
                ret = 'return '
302
            stmt1 = self.indent
303
            stmt1 += 'const struct mapi_table *tbl = u_current_get();'
304
            stmt2 = self.indent
305
            stmt2 += 'mapi_func func = ((const mapi_func *) tbl)[%d];' % (
306
                    ent.slot)
307
            stmt3 = self.indent
308
            stmt3 += '%s((%s) func)(%s);' % (ret, cast, ent.c_args())
309
 
310
            disp = '%s\n{\n%s\n%s\n%s\n}' % (proto, stmt1, stmt2, stmt3)
311
            dispatches.append(disp)
312
 
313
        return '\n\n'.join(dispatches)
314
 
315
    def c_stub_string_pool(self):
316
        """Return the string pool for use by stubs."""
317
        # sort entries by their names
318
        sorted_entries = self.entries[:]
319
        sorted_entries.sort(lambda x, y: cmp(x.name, y.name))
320
 
321
        pool = []
322
        offsets = {}
323
        count = 0
324
        for ent in sorted_entries:
325
            offsets[ent] = count
326
            pool.append('%s' % (ent.name))
327
            count += len(ent.name) + 1
328
 
329
        pool_str =  self.indent + '"' + \
330
                ('\\0"\n' + self.indent + '"').join(pool) + '";'
331
        return (pool_str, offsets)
332
 
333
    def c_stub_initializer(self, prefix, pool_offsets):
334
        """Return the initializer for struct mapi_stub array."""
335
        stubs = []
336
        for ent in self.entries_sorted_by_names:
337
            stubs.append('%s{ (mapi_func) %s%s, %d, (void *) %d }' % (
338
                self.indent, prefix, ent.name, ent.slot, pool_offsets[ent]))
339
 
340
        return ',\n'.join(stubs)
341
 
342
    def c_noop_functions(self, prefix, warn_prefix):
343
        """Return the noop functions."""
344
        noops = []
345
        for ent in self.entries:
346
            if ent.alias:
347
                continue
348
 
349
            proto = 'static ' + self._c_decl(ent, prefix)
350
 
351
            stmt1 = self.indent + '%s("%s%s");' % (
352
                    self.noop_warn, warn_prefix, ent.name)
353
 
354
            if ent.ret:
355
                stmt2 = self.indent + 'return (%s) 0;' % (ent.ret)
356
                noop = '%s\n{\n%s\n%s\n}' % (proto, stmt1, stmt2)
357
            else:
358
                noop = '%s\n{\n%s\n}' % (proto, stmt1)
359
 
360
            noops.append(noop)
361
 
362
        return '\n\n'.join(noops)
363
 
364
    def c_noop_initializer(self, prefix, use_generic):
365
        """Return an initializer for the noop dispatch table."""
366
        entries = [prefix + ent.name for ent in self.entries if not ent.alias]
367
        if use_generic:
368
            entries = [self.noop_generic] * len(entries)
369
 
370
        entries.extend([self.noop_generic] * ABI_NUM_DYNAMIC_ENTRIES)
371
 
372
        pre = self.indent + '(mapi_func) '
373
        return pre + (',\n' + pre).join(entries)
374
 
375
    def c_asm_gcc(self, prefix):
376
        asm = []
377
        to_name = None
378
 
379
        asm.append('__asm__(')
380
        for ent in self.entries:
381
            name = prefix + ent.name
382
 
383
            if ent.hidden:
384
                asm.append('".hidden %s\\n"' % (name))
385
 
386
            if ent.alias:
387
                asm.append('".globl %s\\n"' % (name))
388
                asm.append('".set %s, %s\\n"' % (name, to_name))
389
            else:
390
                asm.append('STUB_ASM_ENTRY("%s")"\\n"' % (name))
391
                asm.append('"\\t"STUB_ASM_CODE("%d")"\\n"' % (ent.slot))
392
                to_name = name
393
        asm.append(');')
394
 
395
        return "\n".join(asm)
396
 
397
    def output_for_lib(self):
398
        print self.c_header()
399
        print
400
        print '#ifdef MAPI_TMP_DEFINES'
401
        print self.c_includes()
402
        print '#undef MAPI_TMP_DEFINES'
403
        print '#endif /* MAPI_TMP_DEFINES */'
404
        print
405
        print '#ifdef MAPI_TMP_TABLE'
406
        print self.c_mapi_table()
407
        print '#undef MAPI_TMP_TABLE'
408
        print '#endif /* MAPI_TMP_TABLE */'
409
        print
410
 
411
        pool, pool_offsets = self.c_stub_string_pool()
412
        print '#ifdef MAPI_TMP_PUBLIC_STUBS'
413
        print 'static const char public_string_pool[] ='
414
        print pool
415
        print
416
        print 'static const struct mapi_stub public_stubs[] = {'
417
        print self.c_stub_initializer(self.prefix_lib, pool_offsets)
418
        print '};'
419
        print '#undef MAPI_TMP_PUBLIC_STUBS'
420
        print '#endif /* MAPI_TMP_PUBLIC_STUBS */'
421
        print
422
 
423
        print '#ifdef MAPI_TMP_PUBLIC_ENTRIES'
424
        print self.c_public_dispatches(self.prefix_lib)
425
        print '#undef MAPI_TMP_PUBLIC_ENTRIES'
426
        print '#endif /* MAPI_TMP_PUBLIC_ENTRIES */'
427
        print
428
 
429
        print '#ifdef MAPI_TMP_NOOP_ARRAY'
430
        print '#ifdef DEBUG'
431
        print
432
        print self.c_noop_functions(self.prefix_noop, self.prefix_lib)
433
        print
434
        print 'const mapi_func table_%s_array[] = {' % (self.prefix_noop)
435
        print self.c_noop_initializer(self.prefix_noop, False)
436
        print '};'
437
        print
438
        print '#else /* DEBUG */'
439
        print
440
        print 'const mapi_func table_%s_array[] = {' % (self.prefix_noop)
441
        print self.c_noop_initializer(self.prefix_noop, True)
442
        print '};'
443
        print '#endif /* DEBUG */'
444
        print '#undef MAPI_TMP_NOOP_ARRAY'
445
        print '#endif /* MAPI_TMP_NOOP_ARRAY */'
446
        print
447
 
448
        print '#ifdef MAPI_TMP_STUB_ASM_GCC'
449
        print self.c_asm_gcc(self.prefix_lib)
450
        print '#undef MAPI_TMP_STUB_ASM_GCC'
451
        print '#endif /* MAPI_TMP_STUB_ASM_GCC */'
452
 
453
    def output_for_app(self):
454
        print self.c_header()
455
        print
456
        print self.c_private_declarations(self.prefix_app)
457
        print
458
        print '#ifdef API_TMP_DEFINE_SPEC'
459
        print
460
        print 'static const char %s_spec[] =' % (self.prefix_app)
461
        print self.c_mapi_table_spec()
462
        print
463
        print 'static const mapi_proc %s_procs[] = {' % (self.prefix_app)
464
        print self.c_mapi_table_initializer(self.prefix_app)
465
        print '};'
466
        print
467
        print '#endif /* API_TMP_DEFINE_SPEC */'
468
 
469
class GLAPIPrinter(ABIPrinter):
470
    """OpenGL API Printer"""
471
 
472
    def __init__(self, entries):
473
        super(GLAPIPrinter, self).__init__(entries)
474
 
475
        self.api_defines = ['GL_GLEXT_PROTOTYPES']
476
        self.api_headers = ['"GL/gl.h"', '"GL/glext.h"']
477
        self.api_call = 'GLAPI'
478
        self.api_entry = 'APIENTRY'
479
        self.api_attrs = ''
480
 
481
        self.prefix_lib = 'gl'
482
        self.prefix_app = '_mesa_'
483
        self.prefix_noop = 'noop'
484
 
485
    def output_for_app(self):
486
        # not used
487
        pass
488
 
489
class ES1APIPrinter(GLAPIPrinter):
490
    """OpenGL ES 1.x API Printer"""
491
 
492
    def __init__(self, entries):
493
        super(ES1APIPrinter, self).__init__(entries)
494
 
495
        self.api_headers = ['"GLES/gl.h"', '"GLES/glext.h"']
496
        self.api_call = 'GL_API'
497
        self.api_entry = 'GL_APIENTRY'
498
 
499
class ES2APIPrinter(GLAPIPrinter):
500
    """OpenGL ES 2.x API Printer"""
501
 
502
    def __init__(self, entries):
503
        super(ES2APIPrinter, self).__init__(entries)
504
 
505
        self.api_headers = ['"GLES2/gl2.h"', '"GLES2/gl2ext.h"']
506
        self.api_call = 'GL_APICALL'
507
        self.api_entry = 'GL_APIENTRY'
508
 
509
class VGAPIPrinter(ABIPrinter):
510
    """OpenVG API Printer"""
511
 
512
    def __init__(self, entries):
513
        super(VGAPIPrinter, self).__init__(entries)
514
 
515
        self.api_defines = ['VG_VGEXT_PROTOTYPES']
516
        self.api_headers = ['"VG/openvg.h"', '"VG/vgext.h"']
517
        self.api_call = 'VG_API_CALL'
518
        self.api_entry = 'VG_API_ENTRY'
519
        self.api_attrs = 'VG_API_EXIT'
520
 
521
        self.prefix_lib = 'vg'
522
        self.prefix_app = 'vega'
523
        self.prefix_noop = 'noop'
524
 
525
def parse_args():
526
    printers = ['glapi', 'es1api', 'es2api', 'vgapi']
527
    modes = ['lib', 'app']
528
 
529
    parser = OptionParser(usage='usage: %prog [options] ')
530
    parser.add_option('-p', '--printer', dest='printer',
531
            help='printer to use: %s' % (", ".join(printers)))
532
    parser.add_option('-m', '--mode', dest='mode',
533
            help='target user: %s' % (", ".join(modes)))
534
 
535
    options, args = parser.parse_args()
536
    if not args or options.printer not in printers or \
537
            options.mode not in modes:
538
        parser.print_help()
539
        sys.exit(1)
540
 
541
    return (args[0], options)
542
 
543
def main():
544
    printers = {
545
        'vgapi': VGAPIPrinter,
546
        'glapi': GLAPIPrinter,
547
        'es1api': ES1APIPrinter,
548
        'es2api': ES2APIPrinter
549
    }
550
 
551
    filename, options = parse_args()
552
 
553
    entries = abi_parse(filename)
554
    printer = printers[options.printer](entries)
555
    if options.mode == 'lib':
556
        printer.output_for_lib()
557
    else:
558
        printer.output_for_app()
559
 
560
if __name__ == '__main__':
561
    main()