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