3 # Copyright © 2015, 2017 Intel Corporation
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:
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
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
28 import xml
.etree
.cElementTree
as et
30 from collections
import OrderedDict
, namedtuple
31 from mako
.template
import Template
33 from anv_extensions
import *
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
49 TEMPLATE_H
= Template("""\
50 /* This file generated from ${filename}, don't edit directly. */
52 struct anv_dispatch_table {
54 void *entrypoints[${len(entrypoints)}];
56 % for e in entrypoints:
57 % if e.guard is not None:
59 PFN_${e.name} ${e.name};
64 PFN_${e.name} ${e.name};
72 extern const struct anv_dispatch_table ${layer}_dispatch_table;
74 extern const struct anv_dispatch_table anv_tramp_dispatch_table;
76 % for e in entrypoints:
77 % if e.guard is not None:
80 % for layer in LAYERS:
81 ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()});
83 % if e.guard is not None:
87 """, output_encoding
='utf-8')
89 TEMPLATE_C
= Template(u
"""\
91 * Copyright © 2015 Intel Corporation
93 * Permission is hereby granted, free of charge, to any person obtaining a
94 * copy of this software and associated documentation files (the "Software"),
95 * to deal in the Software without restriction, including without limitation
96 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
97 * and/or sell copies of the Software, and to permit persons to whom the
98 * Software is furnished to do so, subject to the following conditions:
100 * The above copyright notice and this permission notice (including the next
101 * paragraph) shall be included in all copies or substantial portions of the
104 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
105 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
106 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
107 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
108 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
109 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
113 /* This file generated from ${filename}, don't edit directly. */
115 #include "anv_private.h"
117 struct anv_entrypoint {
122 /* We use a big string constant to avoid lots of reloctions from the entry
123 * point table to lots of little strings. The entries in the entry point table
124 * store the index into this big string.
127 static const char strings[] =
128 % for e in entrypoints:
133 static const struct anv_entrypoint entrypoints[] = {
134 % for e in entrypoints:
135 [${e.num}] = { ${offsets[e.num]}, ${'{:0=#8x}'.format(e.get_c_hash())} }, /* ${e.name} */
139 /* Weak aliases for all potential implementations. These will resolve to
140 * NULL if they're not defined, which lets the resolve_entrypoint() function
141 * either pick the correct entry point.
144 % for layer in LAYERS:
145 % for e in entrypoints:
146 % if e.guard is not None:
149 ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak));
150 % if e.guard is not None:
155 const struct anv_dispatch_table ${layer}_dispatch_table = {
156 % for e in entrypoints:
157 % if e.guard is not None:
160 .${e.name} = ${e.prefixed_name(layer)},
161 % if e.guard is not None:
169 /** Trampoline entrypoints for all device functions */
171 % for e in entrypoints:
172 % if e.params[0].type not in ('VkDevice', 'VkCommandBuffer'):
175 % if e.guard is not None:
178 static ${e.return_type}
179 ${e.prefixed_name('anv_tramp')}(${e.decl_params()})
181 % if e.params[0].type == 'VkDevice':
182 ANV_FROM_HANDLE(anv_device, anv_device, ${e.params[0].name});
183 return anv_device->dispatch.${e.name}(${e.call_params()});
185 ANV_FROM_HANDLE(anv_cmd_buffer, anv_cmd_buffer, ${e.params[0].name});
186 return anv_cmd_buffer->device->dispatch.${e.name}(${e.call_params()});
189 % if e.guard is not None:
194 const struct anv_dispatch_table anv_tramp_dispatch_table = {
195 % for e in entrypoints:
196 % if e.params[0].type not in ('VkDevice', 'VkCommandBuffer'):
199 % if e.guard is not None:
202 .${e.name} = ${e.prefixed_name('anv_tramp')},
203 % if e.guard is not None:
210 /** Return true if the core version or extension in which the given entrypoint
211 * is defined is enabled.
213 * If device is NULL, all device extensions are considered enabled.
216 anv_entrypoint_is_enabled(int index, uint32_t core_version,
217 const struct anv_instance_extension_table *instance,
218 const struct anv_device_extension_table *device)
221 % for e in entrypoints:
224 return ${e.core_version.c_vk_version()} <= core_version;
226 % if e.extension.type == 'instance':
227 return instance->${e.extension.name[3:]};
229 return !device || device->${e.extension.name[3:]};
240 static void * __attribute__ ((noinline))
241 anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
243 if (devinfo == NULL) {
244 return anv_dispatch_table.entrypoints[index];
247 const struct anv_dispatch_table *genX_table;
248 switch (devinfo->gen) {
250 genX_table = &gen10_dispatch_table;
253 genX_table = &gen9_dispatch_table;
256 genX_table = &gen8_dispatch_table;
259 if (devinfo->is_haswell)
260 genX_table = &gen75_dispatch_table;
262 genX_table = &gen7_dispatch_table;
265 unreachable("unsupported gen\\n");
268 if (genX_table->entrypoints[index])
269 return genX_table->entrypoints[index];
271 return anv_dispatch_table.entrypoints[index];
275 * size ${hash_size} entries
276 * collisions entries:
277 % for i in xrange(10):
278 * ${i}${'+' if i == 9 else ''} ${collisions[i]}
282 #define none ${'{:#x}'.format(none)}
283 static const uint16_t map[] = {
284 % for i in xrange(0, hash_size, 8):
285 % for j in xrange(i, i + 8):
286 ## This is 6 because the 0x is counted in the length
287 % if mapping[j] & 0xffff == 0xffff:
290 ${'{:0=#6x}'.format(mapping[j] & 0xffff)},
297 anv_get_entrypoint_index(const char *name)
299 static const uint32_t prime_factor = ${prime_factor};
300 static const uint32_t prime_step = ${prime_step};
301 const struct anv_entrypoint *e;
306 for (p = name; *p; p++)
307 hash = hash * prime_factor + *p;
311 i = map[h & ${hash_mask}];
316 } while (e->hash != hash);
318 if (strcmp(name, strings + e->name) != 0)
325 anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name)
327 int idx = anv_get_entrypoint_index(name);
330 return anv_resolve_entrypoint(devinfo, idx);
331 }""", output_encoding
='utf-8')
336 HASH_MASK
= HASH_SIZE
- 1
338 PRIME_FACTOR
= 5024183
343 """Calculate the same hash value that Mesa will calculate in C."""
344 return functools
.reduce(
345 lambda h
, c
: (h
* PRIME_FACTOR
+ ord(c
)) & U32_MASK
, name
, 0)
347 EntrypointParam
= namedtuple('EntrypointParam', 'type name decl')
349 class Entrypoint(object):
350 def __init__(self
, name
, return_type
, params
, guard
= None):
352 self
.return_type
= return_type
357 # Extensions which require this entrypoint
358 self
.core_version
= None
359 self
.extension
= None
361 def prefixed_name(self
, prefix
):
362 assert self
.name
.startswith('vk')
363 return prefix
+ '_' + self
.name
[2:]
365 def decl_params(self
):
366 return ', '.join(p
.decl
for p
in self
.params
)
368 def call_params(self
):
369 return ', '.join(p
.name
for p
in self
.params
)
371 def get_c_hash(self
):
372 return cal_hash(self
.name
)
374 def get_entrypoints(doc
, entrypoints_to_defines
, start_index
):
375 """Extract the entry points from the registry."""
376 entrypoints
= OrderedDict()
378 for command
in doc
.findall('./commands/command'):
379 ret_type
= command
.find('./proto/type').text
380 fullname
= command
.find('./proto/name').text
381 params
= [EntrypointParam(
382 type = p
.find('./type').text
,
383 name
= p
.find('./name').text
,
384 decl
= ''.join(p
.itertext())
385 ) for p
in command
.findall('./param')]
386 guard
= entrypoints_to_defines
.get(fullname
)
387 # They really need to be unique
388 assert fullname
not in entrypoints
389 entrypoints
[fullname
] = Entrypoint(fullname
, ret_type
, params
, guard
)
391 enabled_commands
= set()
392 for feature
in doc
.findall('./feature'):
393 assert feature
.attrib
['api'] == 'vulkan'
394 version
= VkVersion(feature
.attrib
['number'])
395 if version
> MAX_API_VERSION
:
398 for command
in feature
.findall('./require/command'):
399 e
= entrypoints
[command
.attrib
['name']]
401 assert e
.core_version
is None
402 e
.core_version
= version
404 supported_exts
= dict((ext
.name
, ext
) for ext
in EXTENSIONS
)
405 for extension
in doc
.findall('.extensions/extension'):
406 ext_name
= extension
.attrib
['name']
407 if ext_name
not in supported_exts
:
410 if extension
.attrib
['supported'] != 'vulkan':
413 ext
= supported_exts
[ext_name
]
414 ext
.type = extension
.attrib
['type']
416 for command
in extension
.findall('./require/command'):
417 e
= entrypoints
[command
.attrib
['name']]
419 assert e
.core_version
is None
420 assert e
.extension
is None
423 return [e
for e
in entrypoints
.itervalues() if e
.enabled
]
426 def get_entrypoints_defines(doc
):
427 """Maps entry points to extension defines."""
428 entrypoints_to_defines
= {}
430 for extension
in doc
.findall('./extensions/extension[@protect]'):
431 define
= extension
.attrib
['protect']
433 for entrypoint
in extension
.findall('./require/command'):
434 fullname
= entrypoint
.attrib
['name']
435 entrypoints_to_defines
[fullname
] = define
437 return entrypoints_to_defines
440 def gen_code(entrypoints
):
441 """Generate the C code."""
444 for e
in entrypoints
:
448 mapping
= [NONE
] * HASH_SIZE
449 collisions
= [0] * 10
450 for e
in entrypoints
:
453 while mapping
[h
& HASH_MASK
] != NONE
:
459 collisions
[level
] += 1
460 mapping
[h
& HASH_MASK
] = e
.num
462 return TEMPLATE_C
.render(entrypoints
=entrypoints
,
465 collisions
=collisions
,
468 prime_step
=PRIME_STEP
,
469 prime_factor
=PRIME_FACTOR
,
472 filename
=os
.path
.basename(__file__
))
476 parser
= argparse
.ArgumentParser()
477 parser
.add_argument('--outdir', help='Where to write the files.',
479 parser
.add_argument('--xml',
480 help='Vulkan API XML file.',
484 args
= parser
.parse_args()
488 for filename
in args
.xml_files
:
489 doc
= et
.parse(filename
)
490 entrypoints
+= get_entrypoints(doc
, get_entrypoints_defines(doc
),
491 start_index
=len(entrypoints
))
493 # Manually add CreateDmaBufImageINTEL for which we don't have an extension
495 entrypoints
.append(Entrypoint('vkCreateDmaBufImageINTEL', 'VkResult', [
496 EntrypointParam('VkDevice', 'device', 'VkDevice device'),
497 EntrypointParam('VkDmaBufImageCreateInfo', 'pCreateInfo',
498 'const VkDmaBufImageCreateInfo* pCreateInfo'),
499 EntrypointParam('VkAllocationCallbacks', 'pAllocator',
500 'const VkAllocationCallbacks* pAllocator'),
501 EntrypointParam('VkDeviceMemory', 'pMem', 'VkDeviceMemory* pMem'),
502 EntrypointParam('VkImage', 'pImage', 'VkImage* pImage')
505 for num
, e
in enumerate(entrypoints
):
508 # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
511 with
open(os
.path
.join(args
.outdir
, 'anv_entrypoints.h'), 'wb') as f
:
512 f
.write(TEMPLATE_H
.render(entrypoints
=entrypoints
,
514 filename
=os
.path
.basename(__file__
)))
515 with
open(os
.path
.join(args
.outdir
, 'anv_entrypoints.c'), 'wb') as f
:
516 f
.write(gen_code(entrypoints
))
518 # In the even there's an error this imports some helpers from mako
519 # to print a useful stack trace and prints it, then exits with
520 # status 1, if python is run with debug; otherwise it just raises
524 from mako
import exceptions
525 sys
.stderr
.write(exceptions
.text_error_template().render() + '\n')
530 if __name__
== '__main__':