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