From 414f5e0e14e5f2e90b688344660751803935c6f2 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen Date: Sun, 11 Feb 2018 13:12:33 +0100 Subject: [PATCH] radv: Reword radv_entrypoints_gen.py With a big inspiration from anv as always ... Reviewed-by: Dave Airlie --- src/amd/vulkan/radv_entrypoints_gen.py | 162 ++++++++++++++++--------- 1 file changed, 106 insertions(+), 56 deletions(-) diff --git a/src/amd/vulkan/radv_entrypoints_gen.py b/src/amd/vulkan/radv_entrypoints_gen.py index c981c0be13a..f7a791967b9 100644 --- a/src/amd/vulkan/radv_entrypoints_gen.py +++ b/src/amd/vulkan/radv_entrypoints_gen.py @@ -27,6 +27,7 @@ import functools import os import xml.etree.cElementTree as et +from collections import OrderedDict, namedtuple from mako.template import Template from radv_extensions import * @@ -36,6 +37,12 @@ from radv_extensions import * # function and a power-of-two size table. The prime numbers are determined # experimentally. +# We currently don't use layers in radv, but keeping the ability for anv +# anyways, so we can use it for device groups. +LAYERS = [ + 'radv' +] + TEMPLATE_H = Template("""\ /* This file generated from ${filename}, don't edit directly. */ @@ -43,28 +50,30 @@ struct radv_dispatch_table { union { void *entrypoints[${len(entrypoints)}]; struct { - % for _, name, _, _, _, guard in entrypoints: - % if guard is not None: -#ifdef ${guard} - PFN_vk${name} ${name}; + % for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + PFN_${e.name} ${e.name}; #else - void *${name}; + void *${e.name}; # endif % else: - PFN_vk${name} ${name}; + PFN_${e.name} ${e.name}; % endif % endfor }; }; }; -% for type_, name, args, num, h, guard in entrypoints: - % if guard is not None: -#ifdef ${guard} +% for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} % endif - ${type_} radv_${name}(${args}); - % if guard is not None: -#endif // ${guard} + % for layer in LAYERS: + ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}); + % endfor + % if e.guard is not None: +#endif // ${e.guard} % endif % endfor """, output_encoding='utf-8') @@ -108,14 +117,14 @@ struct radv_entrypoint { */ static const char strings[] = -% for _, name, _, _, _, _ in entrypoints: - "vk${name}\\0" +% for e in entrypoints: + "${e.name}\\0" % endfor ; static const struct radv_entrypoint entrypoints[] = { -% for _, name, _, num, h, _ in entrypoints: - [${num}] = { ${offsets[num]}, ${'{:0=#8x}'.format(h)} }, /* vk${name} */ +% for e in entrypoints: + [${e.num}] = { ${offsets[e.num]}, ${'{:0=#8x}'.format(e.get_c_hash())} }, /* ${e.name} */ % endfor }; @@ -124,25 +133,25 @@ static const struct radv_entrypoint entrypoints[] = { * either pick the correct entry point. */ -% for layer in ['radv']: - % for type_, name, args, _, _, guard in entrypoints: - % if guard is not None: -#ifdef ${guard} +% for layer in LAYERS: + % for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} % endif - ${type_} ${layer}_${name}(${args}) __attribute__ ((weak)); - % if guard is not None: -#endif // ${guard} + ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak)); + % if e.guard is not None: +#endif // ${e.guard} % endif % endfor const struct radv_dispatch_table ${layer}_layer = { - % for _, name, args, _, _, guard in entrypoints: - % if guard is not None: -#ifdef ${guard} + % for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} % endif - .${name} = ${layer}_${name}, - % if guard is not None: -#endif // ${guard} + .${e.name} = ${e.prefixed_name(layer)}, + % if e.guard is not None: +#endif // ${e.guard} % endif % endfor }; @@ -212,53 +221,88 @@ HASH_MASK = HASH_SIZE - 1 PRIME_FACTOR = 5024183 PRIME_STEP = 19 - def cal_hash(name): """Calculate the same hash value that Mesa will calculate in C.""" return functools.reduce( lambda h, c: (h * PRIME_FACTOR + ord(c)) & U32_MASK, name, 0) +EntrypointParam = namedtuple('EntrypointParam', 'type name decl') + +class Entrypoint(object): + def __init__(self, name, return_type, params, guard = None): + self.name = name + self.return_type = return_type + self.params = params + self.guard = guard + self.enabled = False + self.num = None + # Extensions which require this entrypoint + self.core_version = None + self.extension = None + + def prefixed_name(self, prefix): + assert self.name.startswith('vk') + return prefix + '_' + self.name[2:] + + def decl_params(self): + return ', '.join(p.decl for p in self.params) + + def call_params(self): + return ', '.join(p.name for p in self.params) + + def get_c_hash(self): + return cal_hash(self.name) def get_entrypoints(doc, entrypoints_to_defines, start_index): """Extract the entry points from the registry.""" - entrypoints = [] + entrypoints = OrderedDict() + + for command in doc.findall('./commands/command'): + ret_type = command.find('./proto/type').text + fullname = command.find('./proto/name').text + params = [EntrypointParam( + type = p.find('./type').text, + name = p.find('./name').text, + decl = ''.join(p.itertext()) + ) for p in command.findall('./param')] + guard = entrypoints_to_defines.get(fullname) + # They really need to be unique + assert fullname not in entrypoints + entrypoints[fullname] = Entrypoint(fullname, ret_type, params, guard) enabled_commands = set() for feature in doc.findall('./feature'): assert feature.attrib['api'] == 'vulkan' - if VkVersion(feature.attrib['number']) > MAX_API_VERSION: + version = VkVersion(feature.attrib['number']) + if version > MAX_API_VERSION: continue for command in feature.findall('./require/command'): - enabled_commands.add(command.attrib['name']) + e = entrypoints[command.attrib['name']] + e.enabled = True + assert e.core_version is None + e.core_version = version - supported = set(ext.name for ext in EXTENSIONS) + supported_exts = dict((ext.name, ext) for ext in EXTENSIONS) for extension in doc.findall('.extensions/extension'): - if extension.attrib['name'] not in supported: + ext_name = extension.attrib['name'] + if ext_name not in supported_exts: continue if extension.attrib['supported'] != 'vulkan': continue - for command in extension.findall('./require/command'): - enabled_commands.add(command.attrib['name']) - - index = start_index - for command in doc.findall('./commands/command'): - type = command.find('./proto/type').text - fullname = command.find('./proto/name').text + ext = supported_exts[ext_name] + ext.type = extension.attrib['type'] - if fullname not in enabled_commands: - continue - - shortname = fullname[2:] - params = (''.join(p.itertext()) for p in command.findall('./param')) - params = ', '.join(params) - guard = entrypoints_to_defines.get(fullname) - entrypoints.append((type, shortname, params, index, cal_hash(fullname), guard)) - index += 1 + for command in extension.findall('./require/command'): + e = entrypoints[command.attrib['name']] + e.enabled = True + assert e.core_version is None + assert e.extension is None + e.extension = ext - return entrypoints + return [e for e in entrypoints.itervalues() if e.enabled] def get_entrypoints_defines(doc): @@ -279,14 +323,15 @@ def gen_code(entrypoints): """Generate the C code.""" i = 0 offsets = [] - for _, name, _, _, _, _ in entrypoints: + for e in entrypoints: offsets.append(i) - i += 2 + len(name) + 1 + i += len(e.name) + 1 mapping = [NONE] * HASH_SIZE collisions = [0] * 10 - for _, name, _, num, h, _ in entrypoints: + for e in entrypoints: level = 0 + h = e.get_c_hash() while mapping[h & HASH_MASK] != NONE: h = h + PRIME_STEP level = level + 1 @@ -294,9 +339,10 @@ def gen_code(entrypoints): collisions[9] += 1 else: collisions[level] += 1 - mapping[h & HASH_MASK] = num + mapping[h & HASH_MASK] = e.num return TEMPLATE_C.render(entrypoints=entrypoints, + LAYERS=LAYERS, offsets=offsets, collisions=collisions, mapping=mapping, @@ -326,10 +372,14 @@ def main(): entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc), start_index=len(entrypoints)) + for num, e in enumerate(entrypoints): + e.num = num + # For outputting entrypoints.h we generate a radv_EntryPoint() prototype # per entry point. with open(os.path.join(args.outdir, 'radv_entrypoints.h'), 'wb') as f: f.write(TEMPLATE_H.render(entrypoints=entrypoints, + LAYERS=LAYERS, filename=os.path.basename(__file__))) with open(os.path.join(args.outdir, 'radv_entrypoints.c'), 'wb') as f: f.write(gen_code(entrypoints)) -- 2.30.2