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