Add ES 3 handling to get.c and get_hash_generator.py
[mesa.git] / src / mesa / main / get_hash_generator.py
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 Høgsberg <krh@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"])
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 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 ]
72
73 def api_index(api):
74 return api_enum.index(api)
75
76 def table_name(api):
77 return "table_" + api_name(api)
78
79 def print_table(api, table):
80 print "static table_t %s = {" % (table_name(api))
81
82 # convert sparse (index, value) table into a dense table
83 dense_table = [0] * hash_table_size
84 for i, v in table:
85 dense_table[i] = v
86
87 row_size = 4
88 for i in range(0, hash_table_size, row_size):
89 row = dense_table[i : i + row_size]
90 idx_val = ["%4d" % v for v in row]
91 print " " * 4 + ", ".join(idx_val) + ","
92
93 print "};\n"
94
95 def print_tables(tables):
96 for table in tables:
97 print_table(table["apis"][0], table["indices"])
98
99 dense_tables = ['NULL'] * len(api_enum)
100 for table in tables:
101 tname = table_name(table["apis"][0])
102 for api in table["apis"]:
103 i = api_index(api)
104 dense_tables[i] = "&%s" % (tname)
105
106 print "static table_t *table_set[] = {"
107 for expr in dense_tables:
108 print " %s," % expr
109 print "};\n"
110
111 print "#define table(api) (*table_set[api])"
112
113 # Merge tables with matching parameter lists (i.e. GL and GL_CORE)
114 def merge_tables(tables):
115 merged_tables = []
116 for api, indices in sorted(tables.items()):
117 matching_table = filter(lambda mt:mt["indices"] == indices,
118 merged_tables)
119 if matching_table:
120 matching_table[0]["apis"].append(api)
121 else:
122 merged_tables.append({"apis": [api], "indices": indices})
123
124 return merged_tables
125
126 def add_to_hash_table(table, hash_val, value):
127 while True:
128 index = hash_val & (hash_table_size - 1)
129 if index not in table:
130 table[index] = value
131 break
132 hash_val += prime_step
133
134 def die(msg):
135 sys.stderr.write("%s: %s\n" % (program, msg))
136 exit(1)
137
138 program = os.path.basename(sys.argv[0])
139
140 def generate_hash_tables(enum_list, enabled_apis, param_descriptors):
141 tables = defaultdict(lambda:{})
142
143 # the first entry should be invalid, so that get.c:find_value can use
144 # its index for the 'enum not found' condition.
145 params = [[0, ""]]
146
147 for param_block in param_descriptors:
148 if set(["apis", "params"]) != set(param_block):
149 die("missing fields (%s) in param descriptor file (%s)" %
150 (", ".join(set(["apis", "params"]) - set(param_block)),
151 param_desc_file))
152
153 valid_apis = set(param_block["apis"])
154 if valid_apis - gl_apis:
155 die("unknown API(s) in param descriptor file (%s): %s\n" %
156 (param_desc_file, ",".join(valid_apis - gl_apis)))
157
158 if not (valid_apis & enabled_apis):
159 continue
160
161 valid_apis &= enabled_apis
162
163 for param in param_block["params"]:
164 enum_name = param[0]
165 enum_val = enum_list[enum_name].value
166 hash_val = enum_val * prime_factor
167
168 for api in valid_apis:
169 add_to_hash_table(tables[api], hash_val, len(params))
170 # Also add GLES2 items to the GLES3 hash table
171 if api == "GLES2":
172 add_to_hash_table(tables["GLES3"], hash_val, len(params))
173
174 params.append(["GL_" + enum_name, param[1]])
175
176 sorted_tables={}
177 for api, indices in tables.items():
178 sorted_tables[api] = sorted(indices.items())
179
180 return params, merge_tables(sorted_tables)
181
182 def opt_to_apis(feature):
183 _map = {"ES1": "GLES", "ES2": "GLES2", "GL": "GL"}
184 if feature not in _map:
185 return None
186
187 apis = set([_map[feature]])
188 if "GL" in apis:
189 apis.add("GL_CORE")
190 if "GLES2" in apis:
191 apis.add("GLES3")
192
193 return apis
194
195 def show_usage():
196 sys.stderr.write(
197 """Usage: %s [OPTIONS]
198 -f <file> specify GL API XML file
199 -a [GL|ES1|ES2] specify APIs to generate hash tables for
200 """ % (program))
201 exit(1)
202
203 if __name__ == '__main__':
204 try:
205 (opts, args) = getopt.getopt(sys.argv[1:], "f:a:")
206 except Exception,e:
207 show_usage()
208
209 if len(args) != 0:
210 show_usage()
211
212 enabled_apis = set([])
213 api_desc_file = ""
214
215 for opt_name, opt_val in opts:
216 if opt_name == "-f":
217 api_desc_file = opt_val
218 if opt_name == "-a":
219 apis = opt_to_apis(opt_val.upper())
220 if not apis:
221 die("invalid API %s\n" % opt_val)
222
223 enabled_apis |= apis
224
225 if not api_desc_file:
226 die("missing descriptor file (-f)\n")
227
228 if len(enabled_apis) == 0:
229 die("need at least a single enabled API\n")
230
231 try:
232 api_desc = gl_XML.parse_GL_API(api_desc_file)
233 except Exception:
234 die("couldn't parse API specification file %s\n" % api_desc_file)
235
236 (params, hash_tables) = generate_hash_tables(api_desc.enums_by_name,
237 enabled_apis, get_hash_params.descriptor)
238
239 print_header()
240 print_params(params)
241 print_tables(hash_tables)