android: enable VK_ANDROID_native_buffer
[mesa.git] / src / intel / vulkan / anv_entrypoints_gen.py
1 # coding=utf-8
2 #
3 # Copyright © 2015, 2017 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 argparse
26 import functools
27 import math
28 import os
29 import xml.etree.cElementTree as et
30
31 from collections import OrderedDict, namedtuple
32 from mako.template import Template
33
34 from anv_extensions import *
35
36 # We generate a static hash table for entry point lookup
37 # (vkGetProcAddress). We use a linear congruential generator for our hash
38 # function and a power-of-two size table. The prime numbers are determined
39 # experimentally.
40
41 LAYERS = [
42 'anv',
43 'gen7',
44 'gen75',
45 'gen8',
46 'gen9',
47 'gen10',
48 'gen11',
49 ]
50
51 TEMPLATE_H = Template("""\
52 /* This file generated from ${filename}, don't edit directly. */
53
54 struct anv_dispatch_table {
55 union {
56 void *entrypoints[${len(entrypoints)}];
57 struct {
58 % for e in entrypoints:
59 % if e.guard is not None:
60 #ifdef ${e.guard}
61 PFN_${e.name} ${e.name};
62 #else
63 void *${e.name};
64 # endif
65 % else:
66 PFN_${e.name} ${e.name};
67 % endif
68 % endfor
69 };
70 };
71 };
72
73 %for layer in LAYERS:
74 extern const struct anv_dispatch_table ${layer}_dispatch_table;
75 %endfor
76 extern const struct anv_dispatch_table anv_tramp_dispatch_table;
77
78 % for e in entrypoints:
79 % if e.alias:
80 <% continue %>
81 % endif
82 % if e.guard is not None:
83 #ifdef ${e.guard}
84 % endif
85 % for layer in LAYERS:
86 ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()});
87 % endfor
88 % if e.guard is not None:
89 #endif // ${e.guard}
90 % endif
91 % endfor
92 """, output_encoding='utf-8')
93
94 TEMPLATE_C = Template(u"""\
95 /*
96 * Copyright © 2015 Intel Corporation
97 *
98 * Permission is hereby granted, free of charge, to any person obtaining a
99 * copy of this software and associated documentation files (the "Software"),
100 * to deal in the Software without restriction, including without limitation
101 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
102 * and/or sell copies of the Software, and to permit persons to whom the
103 * Software is furnished to do so, subject to the following conditions:
104 *
105 * The above copyright notice and this permission notice (including the next
106 * paragraph) shall be included in all copies or substantial portions of the
107 * Software.
108 *
109 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
110 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
111 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
112 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
113 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
114 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
115 * IN THE SOFTWARE.
116 */
117
118 /* This file generated from ${filename}, don't edit directly. */
119
120 #include "anv_private.h"
121
122 struct string_map_entry {
123 uint32_t name;
124 uint32_t hash;
125 uint32_t num;
126 };
127
128 /* We use a big string constant to avoid lots of reloctions from the entry
129 * point table to lots of little strings. The entries in the entry point table
130 * store the index into this big string.
131 */
132
133 static const char strings[] =
134 % for s in strmap.sorted_strings:
135 "${s.string}\\0"
136 % endfor
137 ;
138
139 static const struct string_map_entry string_map_entries[] = {
140 % for s in strmap.sorted_strings:
141 { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */
142 % endfor
143 };
144
145 /* Hash table stats:
146 * size ${len(strmap.sorted_strings)} entries
147 * collisions entries:
148 % for i in xrange(10):
149 * ${i}${'+' if i == 9 else ' '} ${strmap.collisions[i]}
150 % endfor
151 */
152
153 #define none 0xffff
154 static const uint16_t string_map[${strmap.hash_size}] = {
155 % for e in strmap.mapping:
156 ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' },
157 % endfor
158 };
159
160 static int
161 string_map_lookup(const char *str)
162 {
163 static const uint32_t prime_factor = ${strmap.prime_factor};
164 static const uint32_t prime_step = ${strmap.prime_step};
165 const struct string_map_entry *e;
166 uint32_t hash, h;
167 uint16_t i;
168 const char *p;
169
170 hash = 0;
171 for (p = str; *p; p++)
172 hash = hash * prime_factor + *p;
173
174 h = hash;
175 while (1) {
176 i = string_map[h & ${strmap.hash_mask}];
177 if (i == none)
178 return -1;
179 e = &string_map_entries[i];
180 if (e->hash == hash && strcmp(str, strings + e->name) == 0)
181 return e->num;
182 h += prime_step;
183 }
184
185 return -1;
186 }
187
188 /* Weak aliases for all potential implementations. These will resolve to
189 * NULL if they're not defined, which lets the resolve_entrypoint() function
190 * either pick the correct entry point.
191 */
192
193 % for layer in LAYERS:
194 % for e in entrypoints:
195 % if e.alias:
196 <% continue %>
197 % endif
198 % if e.guard is not None:
199 #ifdef ${e.guard}
200 % endif
201 ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak));
202 % if e.guard is not None:
203 #endif // ${e.guard}
204 % endif
205 % endfor
206
207 const struct anv_dispatch_table ${layer}_dispatch_table = {
208 % for e in entrypoints:
209 % if e.guard is not None:
210 #ifdef ${e.guard}
211 % endif
212 .${e.name} = ${e.prefixed_name(layer)},
213 % if e.guard is not None:
214 #endif // ${e.guard}
215 % endif
216 % endfor
217 };
218 % endfor
219
220
221 /** Trampoline entrypoints for all device functions */
222
223 % for e in entrypoints:
224 % if e.alias or not e.is_device_entrypoint():
225 <% continue %>
226 % endif
227 % if e.guard is not None:
228 #ifdef ${e.guard}
229 % endif
230 static ${e.return_type}
231 ${e.prefixed_name('anv_tramp')}(${e.decl_params()})
232 {
233 % if e.params[0].type == 'VkDevice':
234 ANV_FROM_HANDLE(anv_device, anv_device, ${e.params[0].name});
235 return anv_device->dispatch.${e.name}(${e.call_params()});
236 % elif e.params[0].type == 'VkCommandBuffer':
237 ANV_FROM_HANDLE(anv_cmd_buffer, anv_cmd_buffer, ${e.params[0].name});
238 return anv_cmd_buffer->device->dispatch.${e.name}(${e.call_params()});
239 % elif e.params[0].type == 'VkQueue':
240 ANV_FROM_HANDLE(anv_queue, anv_queue, ${e.params[0].name});
241 return anv_queue->device->dispatch.${e.name}(${e.call_params()});
242 % else:
243 assert(!"Unhandled device child trampoline case: ${e.params[0].type}");
244 % endif
245 }
246 % if e.guard is not None:
247 #endif // ${e.guard}
248 % endif
249 % endfor
250
251 const struct anv_dispatch_table anv_tramp_dispatch_table = {
252 % for e in entrypoints:
253 % if not e.is_device_entrypoint():
254 <% continue %>
255 % endif
256 % if e.guard is not None:
257 #ifdef ${e.guard}
258 % endif
259 .${e.name} = ${e.prefixed_name('anv_tramp')},
260 % if e.guard is not None:
261 #endif // ${e.guard}
262 % endif
263 % endfor
264 };
265
266
267 /** Return true if the core version or extension in which the given entrypoint
268 * is defined is enabled.
269 *
270 * If device is NULL, all device extensions are considered enabled.
271 */
272 bool
273 anv_entrypoint_is_enabled(int index, uint32_t core_version,
274 const struct anv_instance_extension_table *instance,
275 const struct anv_device_extension_table *device)
276 {
277 switch (index) {
278 % for e in entrypoints:
279 case ${e.num}:
280 /* ${e.name} */
281 % if e.core_version:
282 % if e.is_device_entrypoint():
283 return ${e.core_version.c_vk_version()} <= core_version;
284 % else:
285 return !device && ${e.core_version.c_vk_version()} <= core_version;
286 % endif
287 % elif e.extensions:
288 % for ext in e.extensions:
289 % if ext.type == 'instance':
290 if (!device && instance->${ext.name[3:]}) return true;
291 % else:
292 if (!device || device->${ext.name[3:]}) return true;
293 % endif
294 % endfor
295 return false;
296 % else:
297 return true;
298 % endif
299 % endfor
300 default:
301 return false;
302 }
303 }
304
305 static void * __attribute__ ((noinline))
306 anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
307 {
308 if (devinfo == NULL) {
309 return anv_dispatch_table.entrypoints[index];
310 }
311
312 const struct anv_dispatch_table *genX_table;
313 switch (devinfo->gen) {
314 case 11:
315 genX_table = &gen11_dispatch_table;
316 break;
317 case 10:
318 genX_table = &gen10_dispatch_table;
319 break;
320 case 9:
321 genX_table = &gen9_dispatch_table;
322 break;
323 case 8:
324 genX_table = &gen8_dispatch_table;
325 break;
326 case 7:
327 if (devinfo->is_haswell)
328 genX_table = &gen75_dispatch_table;
329 else
330 genX_table = &gen7_dispatch_table;
331 break;
332 default:
333 unreachable("unsupported gen\\n");
334 }
335
336 if (genX_table->entrypoints[index])
337 return genX_table->entrypoints[index];
338 else
339 return anv_dispatch_table.entrypoints[index];
340 }
341
342 int
343 anv_get_entrypoint_index(const char *name)
344 {
345 return string_map_lookup(name);
346 }
347
348 void *
349 anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name)
350 {
351 int idx = anv_get_entrypoint_index(name);
352 if (idx < 0)
353 return NULL;
354 return anv_resolve_entrypoint(devinfo, idx);
355 }""", output_encoding='utf-8')
356
357 U32_MASK = 2**32 - 1
358
359 PRIME_FACTOR = 5024183
360 PRIME_STEP = 19
361
362 class StringIntMapEntry(object):
363 def __init__(self, string, num):
364 self.string = string
365 self.num = num
366
367 # Calculate the same hash value that we will calculate in C.
368 h = 0
369 for c in string:
370 h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK
371 self.hash = h
372
373 self.offset = None
374
375 def round_to_pow2(x):
376 return 2**int(math.ceil(math.log(x, 2)))
377
378 class StringIntMap(object):
379 def __init__(self):
380 self.baked = False
381 self.strings = dict()
382
383 def add_string(self, string, num):
384 assert not self.baked
385 assert string not in self.strings
386 assert num >= 0 and num < 2**31
387 self.strings[string] = StringIntMapEntry(string, num)
388
389 def bake(self):
390 self.sorted_strings = \
391 sorted(self.strings.values(), key=lambda x: x.string)
392 offset = 0
393 for entry in self.sorted_strings:
394 entry.offset = offset
395 offset += len(entry.string) + 1
396
397 # Save off some values that we'll need in C
398 self.hash_size = round_to_pow2(len(self.strings) * 1.25)
399 self.hash_mask = self.hash_size - 1
400 self.prime_factor = PRIME_FACTOR
401 self.prime_step = PRIME_STEP
402
403 self.mapping = [-1] * self.hash_size
404 self.collisions = [0] * 10
405 for idx, s in enumerate(self.sorted_strings):
406 level = 0
407 h = s.hash
408 while self.mapping[h & self.hash_mask] >= 0:
409 h = h + PRIME_STEP
410 level = level + 1
411 self.collisions[min(level, 9)] += 1
412 self.mapping[h & self.hash_mask] = idx
413
414 EntrypointParam = namedtuple('EntrypointParam', 'type name decl')
415
416 class EntrypointBase(object):
417 def __init__(self, name):
418 self.name = name
419 self.alias = None
420 self.guard = None
421 self.enabled = False
422 self.num = None
423 # Extensions which require this entrypoint
424 self.core_version = None
425 self.extensions = []
426
427 class Entrypoint(EntrypointBase):
428 def __init__(self, name, return_type, params, guard = None):
429 super(Entrypoint, self).__init__(name)
430 self.return_type = return_type
431 self.params = params
432 self.guard = guard
433
434 def is_device_entrypoint(self):
435 return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue')
436
437 def prefixed_name(self, prefix):
438 assert self.name.startswith('vk')
439 return prefix + '_' + self.name[2:]
440
441 def decl_params(self):
442 return ', '.join(p.decl for p in self.params)
443
444 def call_params(self):
445 return ', '.join(p.name for p in self.params)
446
447 class EntrypointAlias(EntrypointBase):
448 def __init__(self, name, entrypoint):
449 super(EntrypointAlias, self).__init__(name)
450 self.alias = entrypoint
451
452 def is_device_entrypoint(self):
453 return self.alias.is_device_entrypoint()
454
455 def prefixed_name(self, prefix):
456 return self.alias.prefixed_name(prefix)
457
458 def get_entrypoints(doc, entrypoints_to_defines, start_index):
459 """Extract the entry points from the registry."""
460 entrypoints = OrderedDict()
461
462 for command in doc.findall('./commands/command'):
463 if 'alias' in command.attrib:
464 alias = command.attrib['name']
465 target = command.attrib['alias']
466 entrypoints[alias] = EntrypointAlias(alias, entrypoints[target])
467 else:
468 name = command.find('./proto/name').text
469 ret_type = command.find('./proto/type').text
470 params = [EntrypointParam(
471 type = p.find('./type').text,
472 name = p.find('./name').text,
473 decl = ''.join(p.itertext())
474 ) for p in command.findall('./param')]
475 guard = entrypoints_to_defines.get(name)
476 # They really need to be unique
477 assert name not in entrypoints
478 entrypoints[name] = Entrypoint(name, ret_type, params, guard)
479
480 for feature in doc.findall('./feature'):
481 assert feature.attrib['api'] == 'vulkan'
482 version = VkVersion(feature.attrib['number'])
483 if version > MAX_API_VERSION:
484 continue
485
486 for command in feature.findall('./require/command'):
487 e = entrypoints[command.attrib['name']]
488 e.enabled = True
489 assert e.core_version is None
490 e.core_version = version
491
492 supported_exts = dict((ext.name, ext) for ext in EXTENSIONS)
493 for extension in doc.findall('.extensions/extension'):
494 ext_name = extension.attrib['name']
495 if ext_name not in supported_exts:
496 continue
497
498 ext = supported_exts[ext_name]
499 ext.type = extension.attrib['type']
500
501 for command in extension.findall('./require/command'):
502 e = entrypoints[command.attrib['name']]
503 e.enabled = True
504 assert e.core_version is None
505 e.extensions.append(ext)
506
507 return [e for e in entrypoints.itervalues() if e.enabled]
508
509
510 def get_entrypoints_defines(doc):
511 """Maps entry points to extension defines."""
512 entrypoints_to_defines = {}
513
514 for extension in doc.findall('./extensions/extension[@platform]'):
515 platform = extension.attrib['platform']
516 define = 'VK_USE_PLATFORM_' + platform.upper() + '_KHR'
517
518 for entrypoint in extension.findall('./require/command'):
519 fullname = entrypoint.attrib['name']
520 entrypoints_to_defines[fullname] = define
521
522 return entrypoints_to_defines
523
524
525 def main():
526 parser = argparse.ArgumentParser()
527 parser.add_argument('--outdir', help='Where to write the files.',
528 required=True)
529 parser.add_argument('--xml',
530 help='Vulkan API XML file.',
531 required=True,
532 action='append',
533 dest='xml_files')
534 args = parser.parse_args()
535
536 entrypoints = []
537
538 for filename in args.xml_files:
539 doc = et.parse(filename)
540 entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc),
541 start_index=len(entrypoints))
542
543 # Manually add CreateDmaBufImageINTEL for which we don't have an extension
544 # defined.
545 entrypoints.append(Entrypoint('vkCreateDmaBufImageINTEL', 'VkResult', [
546 EntrypointParam('VkDevice', 'device', 'VkDevice device'),
547 EntrypointParam('VkDmaBufImageCreateInfo', 'pCreateInfo',
548 'const VkDmaBufImageCreateInfo* pCreateInfo'),
549 EntrypointParam('VkAllocationCallbacks', 'pAllocator',
550 'const VkAllocationCallbacks* pAllocator'),
551 EntrypointParam('VkDeviceMemory', 'pMem', 'VkDeviceMemory* pMem'),
552 EntrypointParam('VkImage', 'pImage', 'VkImage* pImage')
553 ]))
554
555 strmap = StringIntMap()
556 for num, e in enumerate(entrypoints):
557 strmap.add_string(e.name, num)
558 e.num = num
559 strmap.bake()
560
561 # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
562 # per entry point.
563 try:
564 with open(os.path.join(args.outdir, 'anv_entrypoints.h'), 'wb') as f:
565 f.write(TEMPLATE_H.render(entrypoints=entrypoints,
566 LAYERS=LAYERS,
567 filename=os.path.basename(__file__)))
568 with open(os.path.join(args.outdir, 'anv_entrypoints.c'), 'wb') as f:
569 f.write(TEMPLATE_C.render(entrypoints=entrypoints,
570 LAYERS=LAYERS,
571 strmap=strmap,
572 filename=os.path.basename(__file__)))
573 except Exception:
574 # In the even there's an error this imports some helpers from mako
575 # to print a useful stack trace and prints it, then exits with
576 # status 1, if python is run with debug; otherwise it just raises
577 # the exception
578 if __debug__:
579 import sys
580 from mako import exceptions
581 sys.stderr.write(exceptions.text_error_template().render() + '\n')
582 sys.exit(1)
583 raise
584
585
586 if __name__ == '__main__':
587 main()