anv: anv_entrypoints_gen.py: use a main function
[mesa.git] / src / intel / vulkan / anv_entrypoints_gen.py
1 # coding=utf-8
2 #
3 # Copyright © 2015, 2017 Intel Corporation
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 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # 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 NONINFRINGEMENT. IN NO EVENT SHALL
19 # THE AUTHORS OR COPYRIGHT HOLDERS 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
25 import sys
26 import textwrap
27 import xml.etree.ElementTree as ET
28
29 max_api_version = 1.0
30
31 supported_extensions = [
32 'VK_KHR_descriptor_update_template',
33 'VK_KHR_get_physical_device_properties2',
34 'VK_KHR_maintenance1',
35 'VK_KHR_push_descriptor',
36 'VK_KHR_sampler_mirror_clamp_to_edge',
37 'VK_KHR_shader_draw_parameters',
38 'VK_KHR_surface',
39 'VK_KHR_swapchain',
40 'VK_KHR_wayland_surface',
41 'VK_KHR_xcb_surface',
42 'VK_KHR_xlib_surface',
43 ]
44
45 # We generate a static hash table for entry point lookup
46 # (vkGetProcAddress). We use a linear congruential generator for our hash
47 # function and a power-of-two size table. The prime numbers are determined
48 # experimentally.
49
50 none = 0xffff
51 hash_size = 256
52 u32_mask = 2**32 - 1
53 hash_mask = hash_size - 1
54
55 prime_factor = 5024183
56 prime_step = 19
57
58 def hash(name):
59 h = 0;
60 for c in name:
61 h = (h * prime_factor + ord(c)) & u32_mask
62
63 return h
64
65 def print_guard_start(guard):
66 if guard is not None:
67 print "#ifdef {0}".format(guard)
68
69 def print_guard_end(guard):
70 if guard is not None:
71 print "#endif // {0}".format(guard)
72
73 opt_header = False
74 opt_code = False
75
76 if (sys.argv[1] == "header"):
77 opt_header = True
78 sys.argv.pop()
79 elif (sys.argv[1] == "code"):
80 opt_code = True
81 sys.argv.pop()
82
83 # Extract the entry points from the registry
84 def get_entrypoints(doc, entrypoints_to_defines):
85 entrypoints = []
86
87 enabled_commands = set()
88 for feature in doc.findall('./feature'):
89 assert feature.attrib['api'] == 'vulkan'
90 if float(feature.attrib['number']) > max_api_version:
91 continue
92
93 for command in feature.findall('./require/command'):
94 enabled_commands.add(command.attrib['name'])
95
96 for extension in doc.findall('.extensions/extension'):
97 if extension.attrib['name'] not in supported_extensions:
98 continue
99
100 assert extension.attrib['supported'] == 'vulkan'
101 for command in extension.findall('./require/command'):
102 enabled_commands.add(command.attrib['name'])
103
104 index = 0
105 for command in doc.findall('./commands/command'):
106 type = command.find('./proto/type').text
107 fullname = command.find('./proto/name').text
108
109 if fullname not in enabled_commands:
110 continue
111
112 shortname = fullname[2:]
113 params = map(lambda p: "".join(p.itertext()), command.findall('./param'))
114 params = ', '.join(params)
115 if fullname in entrypoints_to_defines:
116 guard = entrypoints_to_defines[fullname]
117 else:
118 guard = None
119 entrypoints.append((type, shortname, params, index, hash(fullname), guard))
120 index += 1
121
122 return entrypoints
123
124 # Maps entry points to extension defines
125 def get_entrypoints_defines(doc):
126 entrypoints_to_defines = {}
127 extensions = doc.findall('./extensions/extension')
128 for extension in extensions:
129 define = extension.get('protect')
130 entrypoints = extension.findall('./require/command')
131 for entrypoint in entrypoints:
132 fullname = entrypoint.get('name')
133 entrypoints_to_defines[fullname] = define
134 return entrypoints_to_defines
135
136
137 def main():
138 doc = ET.parse(sys.stdin)
139 entrypoints = get_entrypoints(doc, get_entrypoints_defines(doc))
140
141 # Manually add CreateDmaBufImageINTEL for which we don't have an extension
142 # defined.
143 entrypoints.append(('VkResult', 'CreateDmaBufImageINTEL',
144 'VkDevice device, ' +
145 'const VkDmaBufImageCreateInfo* pCreateInfo, ' +
146 'const VkAllocationCallbacks* pAllocator,' +
147 'VkDeviceMemory* pMem,' +
148 'VkImage* pImage', len(entrypoints),
149 hash('vkCreateDmaBufImageINTEL'), None))
150
151 # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
152 # per entry point.
153
154 if opt_header:
155 print "/* This file generated from vk_gen.py, don't edit directly. */\n"
156
157 print "struct anv_dispatch_table {"
158 print " union {"
159 print " void *entrypoints[%d];" % len(entrypoints)
160 print " struct {"
161
162 for type, name, args, num, h, guard in entrypoints:
163 if guard is not None:
164 print "#ifdef {0}".format(guard)
165 print " PFN_vk{0} {0};".format(name)
166 print "#else"
167 print " void *{0};".format(name)
168 print "#endif"
169 else:
170 print " PFN_vk{0} {0};".format(name)
171 print " };\n"
172 print " };\n"
173 print "};\n"
174
175 print "void anv_set_dispatch_devinfo(const struct gen_device_info *info);\n"
176
177 for type, name, args, num, h, guard in entrypoints:
178 print_guard_start(guard)
179 print "%s anv_%s(%s);" % (type, name, args)
180 print "%s gen7_%s(%s);" % (type, name, args)
181 print "%s gen75_%s(%s);" % (type, name, args)
182 print "%s gen8_%s(%s);" % (type, name, args)
183 print "%s gen9_%s(%s);" % (type, name, args)
184 print_guard_end(guard)
185 exit()
186
187
188
189 print textwrap.dedent("""\
190 /*
191 * Copyright © 2015 Intel Corporation
192 *
193 * Permission is hereby granted, free of charge, to any person obtaining a
194 * copy of this software and associated documentation files (the "Software"),
195 * to deal in the Software without restriction, including without limitation
196 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
197 * and/or sell copies of the Software, and to permit persons to whom the
198 * Software is furnished to do so, subject to the following conditions:
199 *
200 * The above copyright notice and this permission notice (including the next
201 * paragraph) shall be included in all copies or substantial portions of the
202 * Software.
203 *
204 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
205 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
206 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
207 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
209 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
210 * IN THE SOFTWARE.
211 */
212
213 /* DO NOT EDIT! This is a generated file. */
214
215 #include "anv_private.h"
216
217 struct anv_entrypoint {
218 uint32_t name;
219 uint32_t hash;
220 };
221
222 /* We use a big string constant to avoid lots of reloctions from the entry
223 * point table to lots of little strings. The entries in the entry point table
224 * store the index into this big string.
225 */
226
227 static const char strings[] =""")
228
229 offsets = []
230 i = 0;
231 for type, name, args, num, h, guard in entrypoints:
232 print " \"vk%s\\0\"" % name
233 offsets.append(i)
234 i += 2 + len(name) + 1
235 print " ;"
236
237 # Now generate the table of all entry points
238
239 print "\nstatic const struct anv_entrypoint entrypoints[] = {"
240 for type, name, args, num, h, guard in entrypoints:
241 print " { %5d, 0x%08x }," % (offsets[num], h)
242 print "};\n"
243
244 print textwrap.dedent("""
245
246 /* Weak aliases for all potential implementations. These will resolve to
247 * NULL if they're not defined, which lets the resolve_entrypoint() function
248 * either pick the correct entry point.
249 */
250 """)
251
252 for layer in [ "anv", "gen7", "gen75", "gen8", "gen9" ]:
253 for type, name, args, num, h, guard in entrypoints:
254 print_guard_start(guard)
255 print "%s %s_%s(%s) __attribute__ ((weak));" % (type, layer, name, args)
256 print_guard_end(guard)
257 print "\nconst struct anv_dispatch_table %s_layer = {" % layer
258 for type, name, args, num, h, guard in entrypoints:
259 print_guard_start(guard)
260 print " .%s = %s_%s," % (name, layer, name)
261 print_guard_end(guard)
262 print "};\n"
263
264 print textwrap.dedent("""
265 static void * __attribute__ ((noinline))
266 anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
267 {
268 if (devinfo == NULL) {
269 return anv_layer.entrypoints[index];
270 }
271
272 switch (devinfo->gen) {
273 case 9:
274 if (gen9_layer.entrypoints[index])
275 return gen9_layer.entrypoints[index];
276 /* fall through */
277 case 8:
278 if (gen8_layer.entrypoints[index])
279 return gen8_layer.entrypoints[index];
280 /* fall through */
281 case 7:
282 if (devinfo->is_haswell && gen75_layer.entrypoints[index])
283 return gen75_layer.entrypoints[index];
284
285 if (gen7_layer.entrypoints[index])
286 return gen7_layer.entrypoints[index];
287 /* fall through */
288 case 0:
289 return anv_layer.entrypoints[index];
290 default:
291 unreachable("unsupported gen\\n");
292 }
293 }
294 """)
295
296 # Now generate the hash table used for entry point look up. This is a
297 # uint16_t table of entry point indices. We use 0xffff to indicate an entry
298 # in the hash table is empty.
299
300 map = [none for f in xrange(hash_size)]
301 collisions = [0 for f in xrange(10)]
302 for type, name, args, num, h, guard in entrypoints:
303 level = 0
304 while map[h & hash_mask] != none:
305 h = h + prime_step
306 level = level + 1
307 if level > 9:
308 collisions[9] += 1
309 else:
310 collisions[level] += 1
311 map[h & hash_mask] = num
312
313 print "/* Hash table stats:"
314 print " * size %d entries" % hash_size
315 print " * collisions entries"
316 for i in xrange(10):
317 if (i == 9):
318 plus = "+"
319 else:
320 plus = " "
321
322 print " * %2d%s %4d" % (i, plus, collisions[i])
323 print " */\n"
324
325 print "#define none 0x%04x\n" % none
326
327 print "static const uint16_t map[] = {"
328 for i in xrange(0, hash_size, 8):
329 print " ",
330 for j in xrange(i, i + 8):
331 if map[j] & 0xffff == 0xffff:
332 print " none,",
333 else:
334 print "0x%04x," % (map[j] & 0xffff),
335 print
336
337 print "};"
338
339 # Finally we generate the hash table lookup function. The hash function and
340 # linear probing algorithm matches the hash table generated above.
341
342 print textwrap.dedent("""
343 void *
344 anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name)
345 {
346 static const uint32_t prime_factor = %d;
347 static const uint32_t prime_step = %d;
348 const struct anv_entrypoint *e;
349 uint32_t hash, h, i;
350 const char *p;
351
352 hash = 0;
353 for (p = name; *p; p++)
354 hash = hash * prime_factor + *p;
355
356 h = hash;
357 do {
358 i = map[h & %d];
359 if (i == none)
360 return NULL;
361 e = &entrypoints[i];
362 h += prime_step;
363 } while (e->hash != hash);
364
365 if (strcmp(name, strings + e->name) != 0)
366 return NULL;
367
368 return anv_resolve_entrypoint(devinfo, i);
369 }
370 """) % (prime_factor, prime_step, hash_mask)
371
372
373 if __name__ == '__main__':
374 main()