1# coding=utf-8 2# -*- Mode: Python; py-indent-offset: 4 -*- 3# 4# Copyright © 2012 Intel Corporation 5# 6# Based on code by Kristian Høgsberg <krh@bitplanet.net>, 7# extracted from mesa/main/get.c 8# 9# Permission is hereby granted, free of charge, to any person obtaining a 10# copy of this software and associated documentation files (the "Software"), 11# to deal in the Software without restriction, including without limitation 12# on the rights to use, copy, modify, merge, publish, distribute, sub 13# license, and/or sell copies of the Software, and to permit persons to whom 14# the Software is furnished to do so, subject to the following conditions: 15# 16# The above copyright notice and this permission notice (including the next 17# paragraph) shall be included in all copies or substantial portions of the 18# Software. 19# 20# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26# IN THE SOFTWARE. 27 28# Generate a C header file containing hash tables of glGet parameter 29# names for each GL API. The generated file is to be included by glGet.c 30 31from __future__ import print_function 32 33import os, sys, getopt 34from collections import defaultdict 35import get_hash_params 36 37param_desc_file = os.path.join(os.path.dirname(__file__), "get_hash_params.py") 38 39GLAPI = os.path.join(os.path.dirname(__file__), "..", "..", "mapi", "glapi", "gen") 40sys.path.insert(0, GLAPI) 41import gl_XML 42 43prime_factor = 89 44prime_step = 281 45hash_table_size = 1024 46 47gl_apis=set(["GL", "GL_CORE", "GLES", "GLES2", "GLES3", "GLES31", "GLES32"]) 48 49def 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 54def 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 61def api_name(api): 62 return "API_OPEN%s" % api 63 64# This must match gl_api enum in src/mesa/main/mtypes.h 65api_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 75def api_index(api): 76 return api_enum.index(api) 77 78def table_name(api): 79 return "table_" + api_name(api) 80 81def 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 97def 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) 116def merge_tables(tables): 117 merged_tables = [] 118 for api, indices in sorted(tables.items()): 119 matching_table = list(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 128def 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 136def die(msg): 137 sys.stderr.write("%s: %s\n" % (program, msg)) 138 exit(1) 139 140program = os.path.basename(sys.argv[0]) 141 142def 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 193def show_usage(): 194 sys.stderr.write( 195"""Usage: %s [OPTIONS] 196 -f <file> specify GL API XML file 197""" % (program)) 198 exit(1) 199 200if __name__ == '__main__': 201 try: 202 (opts, args) = getopt.getopt(sys.argv[1:], "f:") 203 except Exception: 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