Home | History | Annotate | Download | only in main
      1 #!/usr/bin/python2
      2 # coding=utf-8
      3 # -*- Mode: Python; py-indent-offset: 4 -*-
      4 #
      5 # Copyright  2012 Intel Corporation
      6 #
      7 # Based on code by Kristian Hgsberg <krh (at] bitplanet.net>,
      8 #   extracted from mesa/main/get.c
      9 #
     10 # Permission is hereby granted, free of charge, to any person obtaining a
     11 # copy of this software and associated documentation files (the "Software"),
     12 # to deal in the Software without restriction, including without limitation
     13 # on the rights to use, copy, modify, merge, publish, distribute, sub
     14 # license, and/or sell copies of the Software, and to permit persons to whom
     15 # the Software is furnished to do so, subject to the following conditions:
     16 #
     17 # The above copyright notice and this permission notice (including the next
     18 # paragraph) shall be included in all copies or substantial portions of the
     19 # Software.
     20 #
     21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     22 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     23 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
     24 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     25 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     26 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     27 # IN THE SOFTWARE.
     28 
     29 # Generate a C header file containing hash tables of glGet parameter
     30 # names for each GL API. The generated file is to be included by glGet.c
     31 
     32 import os, sys, imp, getopt
     33 from collections import defaultdict
     34 import get_hash_params
     35 
     36 cur_dir = os.path.dirname(sys.argv[0])
     37 param_desc_file = "%s/get_hash_params.py" % cur_dir
     38 
     39 GLAPI = "%s/../../mapi/glapi/gen" % cur_dir
     40 sys.path.append(GLAPI)
     41 import gl_XML
     42 
     43 prime_factor = 89
     44 prime_step = 281
     45 hash_table_size = 1024
     46 
     47 gl_apis=set(["GL", "GL_CORE", "GLES", "GLES2", "GLES3", "GLES31", "GLES32"])
     48 
     49 def print_header():
     50    print "typedef const unsigned short table_t[%d];\n" % (hash_table_size)
     51    print "static const int prime_factor = %d, prime_step = %d;\n" % \
     52           (prime_factor, prime_step)
     53 
     54 def print_params(params):
     55    print "static const struct value_desc values[] = {"
     56    for p in params:
     57       print "    { %s, %s }," % (p[0], p[1])
     58 
     59    print "};\n"
     60 
     61 def api_name(api):
     62    return "API_OPEN%s" % api
     63 
     64 # This must match gl_api enum in src/mesa/main/mtypes.h
     65 api_enum = [
     66    'GL',
     67    'GLES',
     68    'GLES2',
     69    'GL_CORE',
     70    'GLES3', # Not in gl_api enum in mtypes.h
     71    'GLES31', # Not in gl_api enum in mtypes.h
     72    'GLES32', # Not in gl_api enum in mtypes.h
     73 ]
     74 
     75 def api_index(api):
     76     return api_enum.index(api)
     77 
     78 def table_name(api):
     79    return "table_" + api_name(api)
     80 
     81 def print_table(api, table):
     82    print "static table_t %s = {" % (table_name(api))
     83 
     84    # convert sparse (index, value) table into a dense table
     85    dense_table = [0] * hash_table_size
     86    for i, v in table:
     87       dense_table[i] = v
     88 
     89    row_size = 4
     90    for i in range(0, hash_table_size, row_size):
     91       row = dense_table[i : i + row_size]
     92       idx_val = ["%4d" % v for v in row]
     93       print " " * 4 + ", ".join(idx_val) + ","
     94 
     95    print "};\n"
     96 
     97 def print_tables(tables):
     98    for table in tables:
     99       print_table(table["apis"][0], table["indices"])
    100 
    101    dense_tables = ['NULL'] * len(api_enum)
    102    for table in tables:
    103       tname = table_name(table["apis"][0])
    104       for api in table["apis"]:
    105          i = api_index(api)
    106          dense_tables[i] = "&%s" % (tname)
    107 
    108    print "static table_t *table_set[] = {"
    109    for expr in dense_tables:
    110       print "   %s," % expr
    111    print "};\n"
    112 
    113    print "#define table(api) (*table_set[api])"
    114 
    115 # Merge tables with matching parameter lists (i.e. GL and GL_CORE)
    116 def merge_tables(tables):
    117    merged_tables = []
    118    for api, indices in sorted(tables.items()):
    119       matching_table = filter(lambda mt:mt["indices"] == indices,
    120                               merged_tables)
    121       if matching_table:
    122          matching_table[0]["apis"].append(api)
    123       else:
    124          merged_tables.append({"apis": [api], "indices": indices})
    125 
    126    return merged_tables
    127 
    128 def add_to_hash_table(table, hash_val, value):
    129    while True:
    130       index = hash_val & (hash_table_size - 1)
    131       if index not in table:
    132          table[index] = value
    133          break
    134       hash_val += prime_step
    135 
    136 def die(msg):
    137    sys.stderr.write("%s: %s\n" % (program, msg))
    138    exit(1)
    139 
    140 program = os.path.basename(sys.argv[0])
    141 
    142 def generate_hash_tables(enum_list, enabled_apis, param_descriptors):
    143    tables = defaultdict(lambda:{})
    144 
    145    # the first entry should be invalid, so that get.c:find_value can use
    146    # its index for the 'enum not found' condition.
    147    params = [[0, ""]]
    148 
    149    for param_block in param_descriptors:
    150       if set(["apis", "params"]) != set(param_block):
    151          die("missing fields (%s) in param descriptor file (%s)" %
    152                (", ".join(set(["apis", "params"]) - set(param_block)),
    153                 param_desc_file))
    154 
    155       valid_apis = set(param_block["apis"])
    156       if valid_apis - gl_apis:
    157          die("unknown API(s) in param descriptor file (%s): %s\n" %
    158                (param_desc_file, ",".join(valid_apis - gl_apis)))
    159 
    160       if not (valid_apis & enabled_apis):
    161          continue
    162 
    163       valid_apis &= enabled_apis
    164 
    165       for param in param_block["params"]:
    166          enum_name = param[0]
    167          enum_val = enum_list[enum_name].value
    168          hash_val = enum_val * prime_factor
    169 
    170          for api in valid_apis:
    171             add_to_hash_table(tables[api], hash_val, len(params))
    172             # Also add GLES2 items to the GLES3+ hash tables
    173             if api == "GLES2":
    174                add_to_hash_table(tables["GLES3"], hash_val, len(params))
    175                add_to_hash_table(tables["GLES31"], hash_val, len(params))
    176                add_to_hash_table(tables["GLES32"], hash_val, len(params))
    177             # Also add GLES3 items to the GLES31+ hash tables
    178             if api == "GLES3":
    179                add_to_hash_table(tables["GLES31"], hash_val, len(params))
    180                add_to_hash_table(tables["GLES32"], hash_val, len(params))
    181             # Also add GLES31 items to the GLES32+ hash tables
    182             if api == "GLES31":
    183                add_to_hash_table(tables["GLES32"], hash_val, len(params))
    184          params.append(["GL_" + enum_name, param[1]])
    185 
    186    sorted_tables={}
    187    for api, indices in tables.items():
    188       sorted_tables[api] = sorted(indices.items())
    189 
    190    return params, merge_tables(sorted_tables)
    191 
    192 
    193 def show_usage():
    194    sys.stderr.write(
    195 """Usage: %s [OPTIONS]
    196   -f <file>          specify GL API XML file
    197 """ % (program))
    198    exit(1)
    199 
    200 if __name__ == '__main__':
    201    try:
    202       (opts, args) = getopt.getopt(sys.argv[1:], "f:")
    203    except Exception,e:
    204       show_usage()
    205 
    206    if len(args) != 0:
    207       show_usage()
    208 
    209    api_desc_file = ""
    210 
    211    for opt_name, opt_val in opts:
    212       if opt_name == "-f":
    213          api_desc_file = opt_val
    214 
    215    if not api_desc_file:
    216       die("missing descriptor file (-f)\n")
    217 
    218    # generate the code for all APIs
    219    enabled_apis = set(["GLES", "GLES2", "GLES3", "GLES31", "GLES32",
    220                        "GL", "GL_CORE"])
    221 
    222    try:
    223       api_desc = gl_XML.parse_GL_API(api_desc_file)
    224    except Exception:
    225       die("couldn't parse API specification file %s\n" % api_desc_file)
    226 
    227    (params, hash_tables) = generate_hash_tables(api_desc.enums_by_name,
    228                               enabled_apis, get_hash_params.descriptor)
    229 
    230    print_header()
    231    print_params(params)
    232    print_tables(hash_tables)
    233