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