python: Stop using the Python 2 exception syntax
[mesa.git] / src / mesa / main / get_hash_generator.py
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
31 from __future__ import print_function
32
33 import os, sys, imp, getopt
34 from collections import defaultdict
35 import get_hash_params
36
37 cur_dir = os.path.dirname(sys.argv[0])
38 param_desc_file = "%s/get_hash_params.py" % cur_dir
39
40 GLAPI = "%s/../../mapi/glapi/gen" % cur_dir
41 sys.path.append(GLAPI)
42 import gl_XML
43
44 prime_factor = 89
45 prime_step = 281
46 hash_table_size = 1024
47
48 gl_apis=set(["GL", "GL_CORE", "GLES", "GLES2", "GLES3", "GLES31", "GLES32"])
49
50 def print_header():
51 print("typedef const unsigned short table_t[%d];\n" % (hash_table_size))
52 print("static const int prime_factor = %d, prime_step = %d;\n" % \
53 (prime_factor, prime_step))
54
55 def print_params(params):
56 print("static const struct value_desc values[] = {")
57 for p in params:
58 print(" { %s, %s }," % (p[0], p[1]))
59
60 print("};\n")
61
62 def api_name(api):
63 return "API_OPEN%s" % api
64
65 # This must match gl_api enum in src/mesa/main/mtypes.h
66 api_enum = [
67 'GL',
68 'GLES',
69 'GLES2',
70 'GL_CORE',
71 'GLES3', # Not in gl_api enum in mtypes.h
72 'GLES31', # Not in gl_api enum in mtypes.h
73 'GLES32', # Not in gl_api enum in mtypes.h
74 ]
75
76 def api_index(api):
77 return api_enum.index(api)
78
79 def table_name(api):
80 return "table_" + api_name(api)
81
82 def print_table(api, table):
83 print("static table_t %s = {" % (table_name(api)))
84
85 # convert sparse (index, value) table into a dense table
86 dense_table = [0] * hash_table_size
87 for i, v in table:
88 dense_table[i] = v
89
90 row_size = 4
91 for i in range(0, hash_table_size, row_size):
92 row = dense_table[i : i + row_size]
93 idx_val = ["%4d" % v for v in row]
94 print(" " * 4 + ", ".join(idx_val) + ",")
95
96 print("};\n")
97
98 def print_tables(tables):
99 for table in tables:
100 print_table(table["apis"][0], table["indices"])
101
102 dense_tables = ['NULL'] * len(api_enum)
103 for table in tables:
104 tname = table_name(table["apis"][0])
105 for api in table["apis"]:
106 i = api_index(api)
107 dense_tables[i] = "&%s" % (tname)
108
109 print("static table_t *table_set[] = {")
110 for expr in dense_tables:
111 print(" %s," % expr)
112 print("};\n")
113
114 print("#define table(api) (*table_set[api])")
115
116 # Merge tables with matching parameter lists (i.e. GL and GL_CORE)
117 def merge_tables(tables):
118 merged_tables = []
119 for api, indices in sorted(tables.items()):
120 matching_table = filter(lambda mt:mt["indices"] == indices,
121 merged_tables)
122 if matching_table:
123 matching_table[0]["apis"].append(api)
124 else:
125 merged_tables.append({"apis": [api], "indices": indices})
126
127 return merged_tables
128
129 def add_to_hash_table(table, hash_val, value):
130 while True:
131 index = hash_val & (hash_table_size - 1)
132 if index not in table:
133 table[index] = value
134 break
135 hash_val += prime_step
136
137 def die(msg):
138 sys.stderr.write("%s: %s\n" % (program, msg))
139 exit(1)
140
141 program = os.path.basename(sys.argv[0])
142
143 def generate_hash_tables(enum_list, enabled_apis, param_descriptors):
144 tables = defaultdict(lambda:{})
145
146 # the first entry should be invalid, so that get.c:find_value can use
147 # its index for the 'enum not found' condition.
148 params = [[0, ""]]
149
150 for param_block in param_descriptors:
151 if set(["apis", "params"]) != set(param_block):
152 die("missing fields (%s) in param descriptor file (%s)" %
153 (", ".join(set(["apis", "params"]) - set(param_block)),
154 param_desc_file))
155
156 valid_apis = set(param_block["apis"])
157 if valid_apis - gl_apis:
158 die("unknown API(s) in param descriptor file (%s): %s\n" %
159 (param_desc_file, ",".join(valid_apis - gl_apis)))
160
161 if not (valid_apis & enabled_apis):
162 continue
163
164 valid_apis &= enabled_apis
165
166 for param in param_block["params"]:
167 enum_name = param[0]
168 enum_val = enum_list[enum_name].value
169 hash_val = enum_val * prime_factor
170
171 for api in valid_apis:
172 add_to_hash_table(tables[api], hash_val, len(params))
173 # Also add GLES2 items to the GLES3+ hash tables
174 if api == "GLES2":
175 add_to_hash_table(tables["GLES3"], hash_val, len(params))
176 add_to_hash_table(tables["GLES31"], hash_val, len(params))
177 add_to_hash_table(tables["GLES32"], hash_val, len(params))
178 # Also add GLES3 items to the GLES31+ hash tables
179 if api == "GLES3":
180 add_to_hash_table(tables["GLES31"], hash_val, len(params))
181 add_to_hash_table(tables["GLES32"], hash_val, len(params))
182 # Also add GLES31 items to the GLES32+ hash tables
183 if api == "GLES31":
184 add_to_hash_table(tables["GLES32"], hash_val, len(params))
185 params.append(["GL_" + enum_name, param[1]])
186
187 sorted_tables={}
188 for api, indices in tables.items():
189 sorted_tables[api] = sorted(indices.items())
190
191 return params, merge_tables(sorted_tables)
192
193
194 def show_usage():
195 sys.stderr.write(
196 """Usage: %s [OPTIONS]
197 -f <file> specify GL API XML file
198 """ % (program))
199 exit(1)
200
201 if __name__ == '__main__':
202 try:
203 (opts, args) = getopt.getopt(sys.argv[1:], "f:")
204 except Exception:
205 show_usage()
206
207 if len(args) != 0:
208 show_usage()
209
210 api_desc_file = ""
211
212 for opt_name, opt_val in opts:
213 if opt_name == "-f":
214 api_desc_file = opt_val
215
216 if not api_desc_file:
217 die("missing descriptor file (-f)\n")
218
219 # generate the code for all APIs
220 enabled_apis = set(["GLES", "GLES2", "GLES3", "GLES31", "GLES32",
221 "GL", "GL_CORE"])
222
223 try:
224 api_desc = gl_XML.parse_GL_API(api_desc_file)
225 except Exception:
226 die("couldn't parse API specification file %s\n" % api_desc_file)
227
228 (params, hash_tables) = generate_hash_tables(api_desc.enums_by_name,
229 enabled_apis, get_hash_params.descriptor)
230
231 print_header()
232 print_params(params)
233 print_tables(hash_tables)