Home | History | Annotate | Download | only in main
      1 #!/usr/bin/python
      2 #
      3 # Copyright (C) 2009 Chia-I Wu <olv (at] 0xlab.org>
      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 Minimal apiutil.py interface for use by es_generator.py.
     25 """
     26 
     27 import sys
     28 import libxml2
     29 
     30 import APIspec
     31 
     32 __spec = {}
     33 __functions = {}
     34 __aliases = {}
     35 
     36 def _ParseXML(filename, apiname):
     37     conversions = {
     38         # from           to
     39         'GLfloat':  [ 'GLdouble' ],
     40         'GLclampf': [ 'GLclampd' ],
     41         'GLubyte':  [ 'GLfloat', 'GLdouble' ],
     42         'GLint':    [ 'GLfloat', 'GLdouble' ],
     43         'GLfixed':  [ 'GLfloat', 'GLdouble' ],
     44         'GLclampx': [ 'GLclampf', 'GLclampd' ],
     45     }
     46 
     47     doc = libxml2.readFile(filename, None,
     48             libxml2.XML_PARSE_DTDLOAD +
     49             libxml2.XML_PARSE_DTDVALID +
     50             libxml2.XML_PARSE_NOBLANKS)
     51     spec = APIspec.Spec(doc)
     52     impl = spec.get_impl()
     53     api = spec.get_api(apiname)
     54     doc.freeDoc()
     55 
     56     __spec["impl"] = impl
     57     __spec["api"] = api
     58 
     59     for func in api.functions:
     60         alias, need_conv = impl.match(func, conversions)
     61         if not alias:
     62             # external functions are manually dispatched
     63             if not func.is_external:
     64                 print >>sys.stderr, "Error: unable to dispatch %s" % func.name
     65             alias = func
     66             need_conv = False
     67 
     68         __functions[func.name] = func
     69         __aliases[func.name] = (alias, need_conv)
     70 
     71 
     72 def AllSpecials(notused=None):
     73     """Return a list of all external functions in the API."""
     74     api = __spec["api"]
     75 
     76     specials = []
     77     for func in api.functions:
     78         if func.is_external:
     79             specials.append(func.name)
     80 
     81     return specials
     82 
     83 
     84 def GetAllFunctions(filename, api):
     85     """Return sorted list of all functions in the API."""
     86     if not __spec:
     87         _ParseXML(filename, api)
     88 
     89     api = __spec["api"]
     90     names = []
     91     for func in api.functions:
     92         names.append(func.name)
     93     names.sort()
     94     return names
     95 
     96 
     97 def ReturnType(funcname):
     98     """Return the C return type of named function."""
     99     func = __functions[funcname]
    100     return func.return_type
    101 
    102 
    103 def Properties(funcname):
    104     """Return list of properties of the named GL function."""
    105     func = __functions[funcname]
    106     return [func.direction]
    107 
    108 
    109 def _ValidValues(func, param):
    110     """Return the valid values of a parameter."""
    111     valid_values = []
    112     switch = func.checker.switches.get(param.name, [])
    113     for desc in switch:
    114         # no dependent vector
    115         if not desc.checker.switches:
    116             for val in desc.values:
    117                 valid_values.append((val, None, None, [], desc.error, None))
    118             continue
    119 
    120         items = desc.checker.switches.items()
    121         if len(items) > 1:
    122             print >>sys.stderr, "%s: more than one parameter depend on %s" % \
    123                     (func.name, desc.name)
    124         dep_name, dep_switch = items[0]
    125 
    126         for dep_desc in dep_switch:
    127             if dep_desc.index >= 0 and dep_desc.index != 0:
    128                 print >>sys.stderr, "%s: not first element of a vector" % func.name
    129             if dep_desc.checker.switches:
    130                 print >>sys.stderr, "%s: deep nested dependence" % func.name
    131 
    132             convert = None if dep_desc.convert else "noconvert"
    133             for val in desc.values:
    134                 valid_values.append((val, dep_desc.size_str, dep_desc.name,
    135                                      dep_desc.values, dep_desc.error, convert))
    136     return valid_values
    137 
    138 
    139 def _Conversion(func, src_param):
    140     """Return the destination type of the conversion, or None."""
    141     alias, need_conv = __aliases[func.name]
    142     if need_conv:
    143         dst_param = alias.get_param(src_param.name)
    144         if src_param.type == dst_param.type:
    145             need_conv = False
    146     if not need_conv:
    147         return (None, "none")
    148 
    149     converts = { True: 0, False: 0 }
    150 
    151     # In Fogx, for example,  pname may be GL_FOG_DENSITY/GL_FOG_START/GL_FOG_END
    152     # or GL_FOG_MODE.  In the former three cases, param is not checked and the
    153     # default is to convert.
    154     if not func.checker.always_check(src_param.name):
    155         converts[True] += 1
    156 
    157     for desc in func.checker.flatten(src_param.name):
    158         converts[desc.convert] += 1
    159         if converts[True] and converts[False]:
    160             break
    161 
    162     # it should be "never", "sometimes", and "always"...
    163     if converts[False]:
    164         if converts[True]:
    165             conversion = "some"
    166         else:
    167             conversion = "none"
    168     else:
    169         conversion = "all"
    170 
    171     return (dst_param.base_type(), conversion)
    172 
    173 
    174 def _MaxVecSize(func, param):
    175     """Return the largest possible size of a vector."""
    176     if not param.is_vector:
    177         return 0
    178     if param.size:
    179         return param.size
    180 
    181     # need to look at all descriptions
    182     size = 0
    183     for desc in func.checker.flatten(param.name):
    184         if desc.size_str and desc.size_str.isdigit():
    185             s = int(desc.size_str)
    186             if s > size:
    187                 size = s
    188     if not size:
    189         need_conv = __aliases[func.name][1]
    190         if need_conv:
    191             print >>sys.stderr, \
    192                     "Error: unable to dicide the max size of %s in %s" % \
    193                     (param.name, func.name)
    194     return size
    195 
    196 
    197 def _ParameterTuple(func, param):
    198     """Return a parameter tuple.
    199 
    200     [0] -- parameter name
    201     [1] -- parameter type
    202     [2] -- max vector size or 0
    203     [3] -- dest type the parameter converts to, or None
    204     [4] -- valid values
    205     [5] -- how often does the conversion happen
    206 
    207     """
    208     vec_size = _MaxVecSize(func, param)
    209     dst_type, conversion = _Conversion(func, param)
    210     valid_values = _ValidValues(func, param)
    211 
    212     return (param.name, param.type, vec_size, dst_type, valid_values, conversion)
    213 
    214 
    215 def Parameters(funcname):
    216     """Return list of tuples of function parameters."""
    217     func = __functions[funcname]
    218     params = []
    219     for param in func.params:
    220         params.append(_ParameterTuple(func, param))
    221 
    222     return params
    223 
    224 
    225 def FunctionPrefix(funcname):
    226     """Return function specific prefix."""
    227     func = __functions[funcname]
    228 
    229     return func.prefix
    230 
    231 
    232 def FindParamIndex(params, paramname):
    233     """Find the index of a named parameter."""
    234     for i in xrange(len(params)):
    235         if params[i][0] == paramname:
    236             return i
    237     return None
    238 
    239 
    240 def MakeDeclarationString(params):
    241     """Return a C-style parameter declaration string."""
    242     string = []
    243     for p in params:
    244         sep = "" if p[1].endswith("*") else " "
    245         string.append("%s%s%s" % (p[1], sep, p[0]))
    246     if not string:
    247         return "void"
    248     return ", ".join(string)
    249 
    250 
    251 def AliasPrefix(funcname):
    252     """Return the prefix of the function the named function is an alias of."""
    253     alias = __aliases[funcname][0]
    254     return alias.prefix
    255 
    256 
    257 def Alias(funcname):
    258     """Return the name of the function the named function is an alias of."""
    259     alias, need_conv = __aliases[funcname]
    260     return alias.name if not need_conv else None
    261 
    262 
    263 def ConversionFunction(funcname):
    264     """Return the name of the function the named function converts to."""
    265     alias, need_conv = __aliases[funcname]
    266     return alias.name if need_conv else None
    267 
    268 
    269 def Categories(funcname):
    270     """Return all the categories of the named GL function."""
    271     api = __spec["api"]
    272     return [api.name]
    273