Subversion Repositories Kolibri OS

Rev

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

  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 <olv@lunarg.com>
  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<type>[\w\s*]+?)(?P<name>\w+)(\[(?P<array>\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] <filename>')
  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()
  562.