anv: Support VkPhysicalDeviceShaderDrawParameterFeatures
[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 % else:
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 % endif
240 }
241 % if e.guard is not None:
242 #endif // ${e.guard}
243 % endif
244 % endfor
245
246 const struct anv_dispatch_table anv_tramp_dispatch_table = {
247 % for e in entrypoints:
248 % if not e.is_device_entrypoint():
249 <% continue %>
250 % endif
251 % if e.guard is not None:
252 #ifdef ${e.guard}
253 % endif
254 .${e.name} = ${e.prefixed_name('anv_tramp')},
255 % if e.guard is not None:
256 #endif // ${e.guard}
257 % endif
258 % endfor
259 };
260
261
262 /** Return true if the core version or extension in which the given entrypoint
263 * is defined is enabled.
264 *
265 * If device is NULL, all device extensions are considered enabled.
266 */
267 bool
268 anv_entrypoint_is_enabled(int index, uint32_t core_version,
269 const struct anv_instance_extension_table *instance,
270 const struct anv_device_extension_table *device)
271 {
272 switch (index) {
273 % for e in entrypoints:
274 case ${e.num}:
275 /* ${e.name} */
276 % if e.core_version:
277 return ${e.core_version.c_vk_version()} <= core_version;
278 % elif e.extensions:
279 % for ext in e.extensions:
280 % if ext.type == 'instance':
281 if (!device && instance->${ext.name[3:]}) return true;
282 % else:
283 if (!device || device->${ext.name[3:]}) return true;
284 % endif
285 % endfor
286 return false;
287 % else:
288 return true;
289 % endif
290 % endfor
291 default:
292 return false;
293 }
294 }
295
296 static void * __attribute__ ((noinline))
297 anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
298 {
299 if (devinfo == NULL) {
300 return anv_dispatch_table.entrypoints[index];
301 }
302
303 const struct anv_dispatch_table *genX_table;
304 switch (devinfo->gen) {
305 case 11:
306 genX_table = &gen11_dispatch_table;
307 break;
308 case 10:
309 genX_table = &gen10_dispatch_table;
310 break;
311 case 9:
312 genX_table = &gen9_dispatch_table;
313 break;
314 case 8:
315 genX_table = &gen8_dispatch_table;
316 break;
317 case 7:
318 if (devinfo->is_haswell)
319 genX_table = &gen75_dispatch_table;
320 else
321 genX_table = &gen7_dispatch_table;
322 break;
323 default:
324 unreachable("unsupported gen\\n");
325 }
326
327 if (genX_table->entrypoints[index])
328 return genX_table->entrypoints[index];
329 else
330 return anv_dispatch_table.entrypoints[index];
331 }
332
333 int
334 anv_get_entrypoint_index(const char *name)
335 {
336 return string_map_lookup(name);
337 }
338
339 void *
340 anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name)
341 {
342 int idx = anv_get_entrypoint_index(name);
343 if (idx < 0)
344 return NULL;
345 return anv_resolve_entrypoint(devinfo, idx);
346 }""", output_encoding='utf-8')
347
348 U32_MASK = 2**32 - 1
349
350 PRIME_FACTOR = 5024183
351 PRIME_STEP = 19
352
353 class StringIntMapEntry(object):
354 def __init__(self, string, num):
355 self.string = string
356 self.num = num
357
358 # Calculate the same hash value that we will calculate in C.
359 h = 0
360 for c in string:
361 h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK
362 self.hash = h
363
364 self.offset = None
365
366 def round_to_pow2(x):
367 return 2**int(math.ceil(math.log(x, 2)))
368
369 class StringIntMap(object):
370 def __init__(self):
371 self.baked = False
372 self.strings = dict()
373
374 def add_string(self, string, num):
375 assert not self.baked
376 assert string not in self.strings
377 assert num >= 0 and num < 2**31
378 self.strings[string] = StringIntMapEntry(string, num)
379
380 def bake(self):
381 self.sorted_strings = \
382 sorted(self.strings.values(), key=lambda x: x.string)
383 offset = 0
384 for entry in self.sorted_strings:
385 entry.offset = offset
386 offset += len(entry.string) + 1
387
388 # Save off some values that we'll need in C
389 self.hash_size = round_to_pow2(len(self.strings) * 1.25)
390 self.hash_mask = self.hash_size - 1
391 self.prime_factor = PRIME_FACTOR
392 self.prime_step = PRIME_STEP
393
394 self.mapping = [-1] * self.hash_size
395 self.collisions = [0] * 10
396 for idx, s in enumerate(self.sorted_strings):
397 level = 0
398 h = s.hash
399 while self.mapping[h & self.hash_mask] >= 0:
400 h = h + PRIME_STEP
401 level = level + 1
402 self.collisions[min(level, 9)] += 1
403 self.mapping[h & self.hash_mask] = idx
404
405 EntrypointParam = namedtuple('EntrypointParam', 'type name decl')
406
407 class EntrypointBase(object):
408 def __init__(self, name):
409 self.name = name
410 self.alias = None
411 self.guard = None
412 self.enabled = False
413 self.num = None
414 # Extensions which require this entrypoint
415 self.core_version = None
416 self.extensions = []
417
418 class Entrypoint(EntrypointBase):
419 def __init__(self, name, return_type, params, guard = None):
420 super(Entrypoint, self).__init__(name)
421 self.return_type = return_type
422 self.params = params
423 self.guard = guard
424
425 def is_device_entrypoint(self):
426 return self.params[0].type in ('VkDevice', 'VkCommandBuffer')
427
428 def prefixed_name(self, prefix):
429 assert self.name.startswith('vk')
430 return prefix + '_' + self.name[2:]
431
432 def decl_params(self):
433 return ', '.join(p.decl for p in self.params)
434
435 def call_params(self):
436 return ', '.join(p.name for p in self.params)
437
438 class EntrypointAlias(EntrypointBase):
439 def __init__(self, name, entrypoint):
440 super(EntrypointAlias, self).__init__(name)
441 self.alias = entrypoint
442
443 def is_device_entrypoint(self):
444 return self.alias.is_device_entrypoint()
445
446 def prefixed_name(self, prefix):
447 return self.alias.prefixed_name(prefix)
448
449 def get_entrypoints(doc, entrypoints_to_defines, start_index):
450 """Extract the entry points from the registry."""
451 entrypoints = OrderedDict()
452
453 for command in doc.findall('./commands/command'):
454 if 'alias' in command.attrib:
455 alias = command.attrib['name']
456 target = command.attrib['alias']
457 entrypoints[alias] = EntrypointAlias(alias, entrypoints[target])
458 else:
459 name = command.find('./proto/name').text
460 ret_type = command.find('./proto/type').text
461 params = [EntrypointParam(
462 type = p.find('./type').text,
463 name = p.find('./name').text,
464 decl = ''.join(p.itertext())
465 ) for p in command.findall('./param')]
466 guard = entrypoints_to_defines.get(name)
467 # They really need to be unique
468 assert name not in entrypoints
469 entrypoints[name] = Entrypoint(name, ret_type, params, guard)
470
471 for feature in doc.findall('./feature'):
472 assert feature.attrib['api'] == 'vulkan'
473 version = VkVersion(feature.attrib['number'])
474 if version > MAX_API_VERSION:
475 continue
476
477 for command in feature.findall('./require/command'):
478 e = entrypoints[command.attrib['name']]
479 e.enabled = True
480 assert e.core_version is None
481 e.core_version = version
482
483 supported_exts = dict((ext.name, ext) for ext in EXTENSIONS)
484 for extension in doc.findall('.extensions/extension'):
485 ext_name = extension.attrib['name']
486 if ext_name not in supported_exts:
487 continue
488
489 if extension.attrib['supported'] != 'vulkan':
490 continue
491
492 ext = supported_exts[ext_name]
493 ext.type = extension.attrib['type']
494
495 for command in extension.findall('./require/command'):
496 e = entrypoints[command.attrib['name']]
497 e.enabled = True
498 assert e.core_version is None
499 e.extensions.append(ext)
500
501 return [e for e in entrypoints.itervalues() if e.enabled]
502
503
504 def get_entrypoints_defines(doc):
505 """Maps entry points to extension defines."""
506 entrypoints_to_defines = {}
507
508 for extension in doc.findall('./extensions/extension[@platform]'):
509 platform = extension.attrib['platform']
510 define = 'VK_USE_PLATFORM_' + platform.upper() + '_KHR'
511
512 for entrypoint in extension.findall('./require/command'):
513 fullname = entrypoint.attrib['name']
514 entrypoints_to_defines[fullname] = define
515
516 return entrypoints_to_defines
517
518
519 def main():
520 parser = argparse.ArgumentParser()
521 parser.add_argument('--outdir', help='Where to write the files.',
522 required=True)
523 parser.add_argument('--xml',
524 help='Vulkan API XML file.',
525 required=True,
526 action='append',
527 dest='xml_files')
528 args = parser.parse_args()
529
530 entrypoints = []
531
532 for filename in args.xml_files:
533 doc = et.parse(filename)
534 entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc),
535 start_index=len(entrypoints))
536
537 # Manually add CreateDmaBufImageINTEL for which we don't have an extension
538 # defined.
539 entrypoints.append(Entrypoint('vkCreateDmaBufImageINTEL', 'VkResult', [
540 EntrypointParam('VkDevice', 'device', 'VkDevice device'),
541 EntrypointParam('VkDmaBufImageCreateInfo', 'pCreateInfo',
542 'const VkDmaBufImageCreateInfo* pCreateInfo'),
543 EntrypointParam('VkAllocationCallbacks', 'pAllocator',
544 'const VkAllocationCallbacks* pAllocator'),
545 EntrypointParam('VkDeviceMemory', 'pMem', 'VkDeviceMemory* pMem'),
546 EntrypointParam('VkImage', 'pImage', 'VkImage* pImage')
547 ]))
548
549 strmap = StringIntMap()
550 for num, e in enumerate(entrypoints):
551 strmap.add_string(e.name, num)
552 e.num = num
553 strmap.bake()
554
555 # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
556 # per entry point.
557 try:
558 with open(os.path.join(args.outdir, 'anv_entrypoints.h'), 'wb') as f:
559 f.write(TEMPLATE_H.render(entrypoints=entrypoints,
560 LAYERS=LAYERS,
561 filename=os.path.basename(__file__)))
562 with open(os.path.join(args.outdir, 'anv_entrypoints.c'), 'wb') as f:
563 f.write(TEMPLATE_C.render(entrypoints=entrypoints,
564 LAYERS=LAYERS,
565 strmap=strmap,
566 filename=os.path.basename(__file__)))
567 except Exception:
568 # In the even there's an error this imports some helpers from mako
569 # to print a useful stack trace and prints it, then exits with
570 # status 1, if python is run with debug; otherwise it just raises
571 # the exception
572 if __debug__:
573 import sys
574 from mako import exceptions
575 sys.stderr.write(exceptions.text_error_template().render() + '\n')
576 sys.exit(1)
577 raise
578
579
580 if __name__ == '__main__':
581 main()