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