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
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;
75 % for e in entrypoints:
76 % if e.guard is not None:
79 % for layer in LAYERS:
80 ${e.return_type} ${e.prefixed_name(layer)}(${e.params});
82 % if e.guard is not None:
86 """, output_encoding
='utf-8')
88 TEMPLATE_C
= Template(u
"""\
90 * Copyright © 2015 Intel Corporation
92 * Permission is hereby granted, free of charge, to any person obtaining a
93 * copy of this software and associated documentation files (the "Software"),
94 * to deal in the Software without restriction, including without limitation
95 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
96 * and/or sell copies of the Software, and to permit persons to whom the
97 * Software is furnished to do so, subject to the following conditions:
99 * The above copyright notice and this permission notice (including the next
100 * paragraph) shall be included in all copies or substantial portions of the
103 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
104 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
105 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
106 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
107 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
108 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
112 /* This file generated from ${filename}, don't edit directly. */
114 #include "anv_private.h"
116 struct anv_entrypoint {
121 /* We use a big string constant to avoid lots of reloctions from the entry
122 * point table to lots of little strings. The entries in the entry point table
123 * store the index into this big string.
126 static const char strings[] =
127 % for e in entrypoints:
132 static const struct anv_entrypoint entrypoints[] = {
133 % for e in entrypoints:
134 [${e.num}] = { ${offsets[e.num]}, ${'{:0=#8x}'.format(e.get_c_hash())} }, /* ${e.name} */
138 /* Weak aliases for all potential implementations. These will resolve to
139 * NULL if they're not defined, which lets the resolve_entrypoint() function
140 * either pick the correct entry point.
143 % for layer in LAYERS:
144 % for e in entrypoints:
145 % if e.guard is not None:
148 ${e.return_type} ${e.prefixed_name(layer)}(${e.params}) __attribute__ ((weak));
149 % if e.guard is not None:
154 const struct anv_dispatch_table ${layer}_dispatch_table = {
155 % for e in entrypoints:
156 % if e.guard is not None:
159 .${e.name} = ${e.prefixed_name(layer)},
160 % if e.guard is not None:
167 /** Return true if the core version or extension in which the given entrypoint
168 * is defined is enabled.
170 * If device is NULL, all device extensions are considered enabled.
173 anv_entrypoint_is_enabled(int index, uint32_t core_version,
174 const struct anv_instance_extension_table *instance,
175 const struct anv_device_extension_table *device)
178 % for e in entrypoints:
181 return ${e.core_version.c_vk_version()} <= core_version;
183 % if e.extension.type == 'instance':
184 return instance->${e.extension.name[3:]};
186 return !device || device->${e.extension.name[3:]};
197 static void * __attribute__ ((noinline))
198 anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
200 if (devinfo == NULL) {
201 return anv_dispatch_table.entrypoints[index];
204 const struct anv_dispatch_table *genX_table;
205 switch (devinfo->gen) {
207 genX_table = &gen10_dispatch_table;
210 genX_table = &gen9_dispatch_table;
213 genX_table = &gen8_dispatch_table;
216 if (devinfo->is_haswell)
217 genX_table = &gen75_dispatch_table;
219 genX_table = &gen7_dispatch_table;
222 unreachable("unsupported gen\\n");
225 if (genX_table->entrypoints[index])
226 return genX_table->entrypoints[index];
228 return anv_dispatch_table.entrypoints[index];
232 * size ${hash_size} entries
233 * collisions entries:
234 % for i in xrange(10):
235 * ${i}${'+' if i == 9 else ''} ${collisions[i]}
239 #define none ${'{:#x}'.format(none)}
240 static const uint16_t map[] = {
241 % for i in xrange(0, hash_size, 8):
242 % for j in xrange(i, i + 8):
243 ## This is 6 because the 0x is counted in the length
244 % if mapping[j] & 0xffff == 0xffff:
247 ${'{:0=#6x}'.format(mapping[j] & 0xffff)},
254 anv_get_entrypoint_index(const char *name)
256 static const uint32_t prime_factor = ${prime_factor};
257 static const uint32_t prime_step = ${prime_step};
258 const struct anv_entrypoint *e;
263 for (p = name; *p; p++)
264 hash = hash * prime_factor + *p;
268 i = map[h & ${hash_mask}];
273 } while (e->hash != hash);
275 if (strcmp(name, strings + e->name) != 0)
282 anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name)
284 int idx = anv_get_entrypoint_index(name);
287 return anv_resolve_entrypoint(devinfo, idx);
288 }""", output_encoding
='utf-8')
293 HASH_MASK
= HASH_SIZE
- 1
295 PRIME_FACTOR
= 5024183
300 """Calculate the same hash value that Mesa will calculate in C."""
301 return functools
.reduce(
302 lambda h
, c
: (h
* PRIME_FACTOR
+ ord(c
)) & U32_MASK
, name
, 0)
304 class Entrypoint(object):
305 def __init__(self
, name
, return_type
, params
, guard
= None):
307 self
.return_type
= return_type
308 self
.params
= ', '.join(params
)
312 # Extensions which require this entrypoint
313 self
.core_version
= None
314 self
.extension
= None
316 def prefixed_name(self
, prefix
):
317 assert self
.name
.startswith('vk')
318 return prefix
+ '_' + self
.name
[2:]
320 def get_c_hash(self
):
321 return cal_hash(self
.name
)
323 def get_entrypoints(doc
, entrypoints_to_defines
, start_index
):
324 """Extract the entry points from the registry."""
325 entrypoints
= OrderedDict()
327 for command
in doc
.findall('./commands/command'):
328 ret_type
= command
.find('./proto/type').text
329 fullname
= command
.find('./proto/name').text
330 params
= (''.join(p
.itertext()) for p
in command
.findall('./param'))
331 guard
= entrypoints_to_defines
.get(fullname
)
332 # They really need to be unique
333 assert fullname
not in entrypoints
334 entrypoints
[fullname
] = Entrypoint(fullname
, ret_type
, params
, guard
)
336 enabled_commands
= set()
337 for feature
in doc
.findall('./feature'):
338 assert feature
.attrib
['api'] == 'vulkan'
339 version
= VkVersion(feature
.attrib
['number'])
340 if version
> MAX_API_VERSION
:
343 for command
in feature
.findall('./require/command'):
344 e
= entrypoints
[command
.attrib
['name']]
346 assert e
.core_version
is None
347 e
.core_version
= version
349 supported_exts
= dict((ext
.name
, ext
) for ext
in EXTENSIONS
)
350 for extension
in doc
.findall('.extensions/extension'):
351 ext_name
= extension
.attrib
['name']
352 if ext_name
not in supported_exts
:
355 if extension
.attrib
['supported'] != 'vulkan':
358 ext
= supported_exts
[ext_name
]
359 ext
.type = extension
.attrib
['type']
361 for command
in extension
.findall('./require/command'):
362 e
= entrypoints
[command
.attrib
['name']]
364 assert e
.core_version
is None
365 assert e
.extension
is None
368 return [e
for e
in entrypoints
.itervalues() if e
.enabled
]
371 def get_entrypoints_defines(doc
):
372 """Maps entry points to extension defines."""
373 entrypoints_to_defines
= {}
375 for extension
in doc
.findall('./extensions/extension[@protect]'):
376 define
= extension
.attrib
['protect']
378 for entrypoint
in extension
.findall('./require/command'):
379 fullname
= entrypoint
.attrib
['name']
380 entrypoints_to_defines
[fullname
] = define
382 return entrypoints_to_defines
385 def gen_code(entrypoints
):
386 """Generate the C code."""
389 for e
in entrypoints
:
393 mapping
= [NONE
] * HASH_SIZE
394 collisions
= [0] * 10
395 for e
in entrypoints
:
398 while mapping
[h
& HASH_MASK
] != NONE
:
404 collisions
[level
] += 1
405 mapping
[h
& HASH_MASK
] = e
.num
407 return TEMPLATE_C
.render(entrypoints
=entrypoints
,
410 collisions
=collisions
,
413 prime_step
=PRIME_STEP
,
414 prime_factor
=PRIME_FACTOR
,
417 filename
=os
.path
.basename(__file__
))
421 parser
= argparse
.ArgumentParser()
422 parser
.add_argument('--outdir', help='Where to write the files.',
424 parser
.add_argument('--xml',
425 help='Vulkan API XML file.',
429 args
= parser
.parse_args()
433 for filename
in args
.xml_files
:
434 doc
= et
.parse(filename
)
435 entrypoints
+= get_entrypoints(doc
, get_entrypoints_defines(doc
),
436 start_index
=len(entrypoints
))
438 # Manually add CreateDmaBufImageINTEL for which we don't have an extension
440 entrypoints
.append(Entrypoint('vkCreateDmaBufImageINTEL', 'VkResult',
442 'const VkDmaBufImageCreateInfo* pCreateInfo',
443 'const VkAllocationCallbacks* pAllocator',
444 'VkDeviceMemory* pMem',
447 for num
, e
in enumerate(entrypoints
):
450 # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
453 with
open(os
.path
.join(args
.outdir
, 'anv_entrypoints.h'), 'wb') as f
:
454 f
.write(TEMPLATE_H
.render(entrypoints
=entrypoints
,
456 filename
=os
.path
.basename(__file__
)))
457 with
open(os
.path
.join(args
.outdir
, 'anv_entrypoints.c'), 'wb') as f
:
458 f
.write(gen_code(entrypoints
))
460 # In the even there's an error this imports some helpers from mako
461 # to print a useful stack trace and prints it, then exits with
462 # status 1, if python is run with debug; otherwise it just raises
466 from mako
import exceptions
467 sys
.stderr
.write(exceptions
.text_error_template().render() + '\n')
472 if __name__
== '__main__':