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