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