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