"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/freedreno/vulkan/tu_entrypoints_gen.py" (16 Sep 2020, 16288 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "tu_entrypoints_gen.py" see the Fossies "Dox" file reference documentation.

    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 copy
   27 import functools
   28 import math
   29 import os
   30 import xml.etree.ElementTree as et
   31 
   32 from collections import OrderedDict, namedtuple
   33 from mako.template import Template
   34 
   35 from tu_extensions import VkVersion, MAX_API_VERSION, EXTENSIONS
   36 
   37 # We generate a static hash table for entry point lookup
   38 # (vkGetProcAddress). We use a linear congruential generator for our hash
   39 # function and a power-of-two size table. The prime numbers are determined
   40 # experimentally.
   41 
   42 # We currently don't use layers in tu, but keeping the ability for anv
   43 # anyways, so we can use it for device groups.
   44 LAYERS = [
   45     'tu'
   46 ]
   47 
   48 TEMPLATE_H = Template("""\
   49 /* This file generated from ${filename}, don't edit directly. */
   50 
   51 struct tu_dispatch_table {
   52    union {
   53       void *entrypoints[${len(entrypoints)}];
   54       struct {
   55       % for e in entrypoints:
   56         % if e.guard is not None:
   57 #ifdef ${e.guard}
   58           PFN_${e.name} ${e.name};
   59 #else
   60           void *${e.name};
   61 # endif
   62         % else:
   63           PFN_${e.name} ${e.name};
   64         % endif
   65       % endfor
   66       };
   67    };
   68 };
   69 
   70 % for e in entrypoints:
   71   % if e.alias:
   72     <% continue %>
   73   % endif
   74   % if e.guard is not None:
   75 #ifdef ${e.guard}
   76   % endif
   77   % for layer in LAYERS:
   78   VKAPI_ATTR ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()});
   79   % endfor
   80   % if e.guard is not None:
   81 #endif // ${e.guard}
   82   % endif
   83 % endfor
   84 """, output_encoding='utf-8')
   85 
   86 TEMPLATE_C = Template(u"""\
   87 /*
   88  * Copyright © 2015 Intel Corporation
   89  *
   90  * Permission is hereby granted, free of charge, to any person obtaining a
   91  * copy of this software and associated documentation files (the "Software"),
   92  * to deal in the Software without restriction, including without limitation
   93  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   94  * and/or sell copies of the Software, and to permit persons to whom the
   95  * Software is furnished to do so, subject to the following conditions:
   96  *
   97  * The above copyright notice and this permission notice (including the next
   98  * paragraph) shall be included in all copies or substantial portions of the
   99  * Software.
  100  *
  101  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  102  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  103  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  104  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  105  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  106  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  107  * IN THE SOFTWARE.
  108  */
  109 
  110 /* This file generated from ${filename}, don't edit directly. */
  111 
  112 #include "tu_private.h"
  113 
  114 struct string_map_entry {
  115    uint32_t name;
  116    uint32_t hash;
  117    uint32_t num;
  118 };
  119 
  120 /* We use a big string constant to avoid lots of relocations from the entry
  121  * point table to lots of little strings. The entries in the entry point table
  122  * store the index into this big string.
  123  */
  124 
  125 static const char strings[] =
  126 % for s in strmap.sorted_strings:
  127     "${s.string}\\0"
  128 % endfor
  129 ;
  130 
  131 static const struct string_map_entry string_map_entries[] = {
  132 % for s in strmap.sorted_strings:
  133     { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */
  134 % endfor
  135 };
  136 
  137 /* Hash table stats:
  138  * size ${len(strmap.sorted_strings)} entries
  139  * collisions entries:
  140 % for i in range(10):
  141  *     ${i}${'+' if i == 9 else ' '}     ${strmap.collisions[i]}
  142 % endfor
  143  */
  144 
  145 #define none 0xffff
  146 static const uint16_t string_map[${strmap.hash_size}] = {
  147 % for e in strmap.mapping:
  148     ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' },
  149 % endfor
  150 };
  151 
  152 /* Weak aliases for all potential implementations. These will resolve to
  153  * NULL if they're not defined, which lets the resolve_entrypoint() function
  154  * either pick the correct entry point.
  155  */
  156 
  157 % for layer in LAYERS:
  158   % for e in entrypoints:
  159     % if e.alias:
  160       <% continue %>
  161     % endif
  162     % if e.guard is not None:
  163 #ifdef ${e.guard}
  164     % endif
  165     ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak));
  166     % if e.guard is not None:
  167 #endif // ${e.guard}
  168     % endif
  169   % endfor
  170 
  171   const struct tu_dispatch_table ${layer}_layer = {
  172   % for e in entrypoints:
  173     % if e.guard is not None:
  174 #ifdef ${e.guard}
  175     % endif
  176     .${e.name} = ${e.prefixed_name(layer)},
  177     % if e.guard is not None:
  178 #endif // ${e.guard}
  179     % endif
  180   % endfor
  181   };
  182 % endfor
  183 
  184 static void * __attribute__ ((noinline))
  185 tu_resolve_entrypoint(uint32_t index)
  186 {
  187    return tu_layer.entrypoints[index];
  188 }
  189 
  190 /** Return true if the core version or extension in which the given entrypoint
  191  * is defined is enabled.
  192  *
  193  * If instance is NULL, we only allow the 3 commands explicitly allowed by the vk
  194  * spec.
  195  *
  196  * If device is NULL, all device extensions are considered enabled.
  197  */
  198 static bool
  199 tu_entrypoint_is_enabled(int index, uint32_t core_version,
  200                          const struct tu_instance_extension_table *instance,
  201                          const struct tu_device_extension_table *device)
  202 {
  203    switch (index) {
  204 % for e in entrypoints:
  205    case ${e.num}:
  206    % if not e.device_command:
  207       if (device) return false;
  208    % endif
  209    % if e.name == 'vkGetInstanceProcAddr' or e.name == 'vkCreateInstance' or e.name == 'vkEnumerateInstanceExtensionProperties' or e.name == 'vkEnumerateInstanceLayerProperties' or e.name == 'vkEnumerateInstanceVersion':
  210       return !device;
  211    % elif e.core_version:
  212       return instance && ${e.core_version.c_vk_version()} <= core_version;
  213    % elif e.extensions:
  214       % for ext in e.extensions:
  215          % if ext.type == 'instance':
  216       if (instance && instance->${ext.name[3:]}) return true;
  217          % else:
  218       if (instance && (!device || device->${ext.name[3:]})) return true;
  219          % endif
  220       %endfor
  221       return false;
  222    % else:
  223       return instance;
  224    % endif
  225 % endfor
  226    default:
  227       return false;
  228    }
  229 }
  230 
  231 static int
  232 tu_lookup_entrypoint(const char *name)
  233 {
  234    static const uint32_t prime_factor = ${strmap.prime_factor};
  235    static const uint32_t prime_step = ${strmap.prime_step};
  236    const struct string_map_entry *e;
  237    uint32_t hash, h;
  238    uint16_t i;
  239    const char *p;
  240 
  241    hash = 0;
  242    for (p = name; *p; p++)
  243        hash = hash * prime_factor + *p;
  244 
  245    h = hash;
  246    while (1) {
  247        i = string_map[h & ${strmap.hash_mask}];
  248        if (i == none)
  249           return -1;
  250        e = &string_map_entries[i];
  251        if (e->hash == hash && strcmp(name, strings + e->name) == 0)
  252            return e->num;
  253        h += prime_step;
  254    }
  255 
  256    return -1;
  257 }
  258 
  259 void *
  260 tu_lookup_entrypoint_unchecked(const char *name)
  261 {
  262    int index = tu_lookup_entrypoint(name);
  263    if (index < 0)
  264       return NULL;
  265    return tu_resolve_entrypoint(index);
  266 }
  267 
  268 void *
  269 tu_lookup_entrypoint_checked(const char *name,
  270                               uint32_t core_version,
  271                               const struct tu_instance_extension_table *instance,
  272                               const struct tu_device_extension_table *device)
  273 {
  274    int index = tu_lookup_entrypoint(name);
  275    if (index < 0 || !tu_entrypoint_is_enabled(index, core_version, instance, device))
  276       return NULL;
  277    return tu_resolve_entrypoint(index);
  278 }""", output_encoding='utf-8')
  279 
  280 U32_MASK = 2**32 - 1
  281 
  282 PRIME_FACTOR = 5024183
  283 PRIME_STEP = 19
  284 
  285 def round_to_pow2(x):
  286     return 2**int(math.ceil(math.log(x, 2)))
  287 
  288 class StringIntMapEntry(object):
  289     def __init__(self, string, num):
  290         self.string = string
  291         self.num = num
  292 
  293         # Calculate the same hash value that we will calculate in C.
  294         h = 0
  295         for c in string:
  296             h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK
  297         self.hash = h
  298 
  299         self.offset = None
  300 
  301 class StringIntMap(object):
  302     def __init__(self):
  303         self.baked = False
  304         self.strings = dict()
  305 
  306     def add_string(self, string, num):
  307         assert not self.baked
  308         assert string not in self.strings
  309         assert num >= 0 and num < 2**31
  310         self.strings[string] = StringIntMapEntry(string, num)
  311 
  312     def bake(self):
  313         self.sorted_strings = \
  314             sorted(self.strings.values(), key=lambda x: x.string)
  315         offset = 0
  316         for entry in self.sorted_strings:
  317             entry.offset = offset
  318             offset += len(entry.string) + 1
  319 
  320         # Save off some values that we'll need in C
  321         self.hash_size = round_to_pow2(len(self.strings) * 1.25)
  322         self.hash_mask = self.hash_size - 1
  323         self.prime_factor = PRIME_FACTOR
  324         self.prime_step = PRIME_STEP
  325 
  326         self.mapping = [-1] * self.hash_size
  327         self.collisions = [0] * 10
  328         for idx, s in enumerate(self.sorted_strings):
  329             level = 0
  330             h = s.hash
  331             while self.mapping[h & self.hash_mask] >= 0:
  332                 h = h + PRIME_STEP
  333                 level = level + 1
  334             self.collisions[min(level, 9)] += 1
  335             self.mapping[h & self.hash_mask] = idx
  336 
  337 EntrypointParam = namedtuple('EntrypointParam', 'type name decl')
  338 
  339 class EntrypointBase(object):
  340     def __init__(self, name):
  341         self.name = name
  342         self.alias = None
  343         self.guard = None
  344         self.enabled = False
  345         self.num = None
  346         # Extensions which require this entrypoint
  347         self.core_version = None
  348         self.extensions = []
  349 
  350 class Entrypoint(EntrypointBase):
  351     def __init__(self, name, return_type, params, guard = None):
  352         super(Entrypoint, self).__init__(name)
  353         self.return_type = return_type
  354         self.params = params
  355         self.guard = guard
  356         self.device_command = len(params) > 0 and (params[0].type == 'VkDevice' or params[0].type == 'VkQueue' or params[0].type == 'VkCommandBuffer')
  357 
  358     def prefixed_name(self, prefix):
  359         assert self.name.startswith('vk')
  360         return prefix + '_' + self.name[2:]
  361 
  362     def decl_params(self):
  363         return ', '.join(p.decl for p in self.params)
  364 
  365     def call_params(self):
  366         return ', '.join(p.name for p in self.params)
  367 
  368 class EntrypointAlias(EntrypointBase):
  369     def __init__(self, name, entrypoint):
  370         super(EntrypointAlias, self).__init__(name)
  371         self.alias = entrypoint
  372         self.device_command = entrypoint.device_command
  373 
  374     def prefixed_name(self, prefix):
  375         return self.alias.prefixed_name(prefix)
  376 
  377 def get_entrypoints(doc, entrypoints_to_defines, start_index):
  378     """Extract the entry points from the registry."""
  379     entrypoints = OrderedDict()
  380 
  381     for command in doc.findall('./commands/command'):
  382        if 'alias' in command.attrib:
  383            alias = command.attrib['name']
  384            target = command.attrib['alias']
  385            entrypoints[alias] = EntrypointAlias(alias, entrypoints[target])
  386        else:
  387            name = command.find('./proto/name').text
  388            ret_type = command.find('./proto/type').text
  389            params = [EntrypointParam(
  390                type = p.find('./type').text,
  391                name = p.find('./name').text,
  392                decl = ''.join(p.itertext())
  393            ) for p in command.findall('./param')]
  394            guard = entrypoints_to_defines.get(name)
  395            # They really need to be unique
  396            assert name not in entrypoints
  397            entrypoints[name] = Entrypoint(name, ret_type, params, guard)
  398 
  399     for feature in doc.findall('./feature'):
  400         assert feature.attrib['api'] == 'vulkan'
  401         version = VkVersion(feature.attrib['number'])
  402         if version > MAX_API_VERSION:
  403             continue
  404 
  405         for command in feature.findall('./require/command'):
  406             e = entrypoints[command.attrib['name']]
  407             e.enabled = True
  408             assert e.core_version is None
  409             e.core_version = version
  410 
  411     supported_exts = dict((ext.name, ext) for ext in EXTENSIONS)
  412     for extension in doc.findall('.extensions/extension'):
  413         ext_name = extension.attrib['name']
  414         if ext_name not in supported_exts:
  415             continue
  416 
  417         ext = supported_exts[ext_name]
  418         ext.type = extension.attrib['type']
  419 
  420         for command in extension.findall('./require/command'):
  421             e = entrypoints[command.attrib['name']]
  422             e.enabled = True
  423             assert e.core_version is None
  424             e.extensions.append(ext)
  425 
  426     # if the base command is not supported by the driver yet, don't alias aliases
  427     for e in entrypoints.values():
  428         if e.alias and not e.alias.enabled:
  429             e_clone = copy.deepcopy(e.alias)
  430             e_clone.enabled = True
  431             e_clone.name = e.name
  432             entrypoints[e.name] = e_clone
  433 
  434     return [e for e in entrypoints.values() if e.enabled]
  435 
  436 
  437 def get_entrypoints_defines(doc):
  438     """Maps entry points to extension defines."""
  439     entrypoints_to_defines = {}
  440 
  441     for extension in doc.findall('./extensions/extension[@protect]'):
  442         define = extension.attrib['protect']
  443 
  444         for entrypoint in extension.findall('./require/command'):
  445             fullname = entrypoint.attrib['name']
  446             entrypoints_to_defines[fullname] = define
  447 
  448     platform_define = {}
  449     for platform in doc.findall('./platforms/platform'):
  450         name = platform.attrib['name']
  451         define = platform.attrib['protect']
  452         platform_define[name] = define
  453 
  454     for extension in doc.findall('./extensions/extension[@platform]'):
  455         platform = extension.attrib['platform']
  456         define = platform_define[platform]
  457 
  458         for entrypoint in extension.findall('./require/command'):
  459             fullname = entrypoint.attrib['name']
  460             entrypoints_to_defines[fullname] = define
  461 
  462     return entrypoints_to_defines
  463 
  464 
  465 def gen_code(entrypoints):
  466     """Generate the C code."""
  467     strmap = StringIntMap()
  468     for e in entrypoints:
  469         strmap.add_string(e.name, e.num)
  470     strmap.bake()
  471 
  472     return TEMPLATE_C.render(entrypoints=entrypoints,
  473                              LAYERS=LAYERS,
  474                              strmap=strmap,
  475                              filename=os.path.basename(__file__))
  476 
  477 
  478 def main():
  479     parser = argparse.ArgumentParser()
  480     parser.add_argument('--outdir', help='Where to write the files.',
  481                         required=True)
  482     parser.add_argument('--xml',
  483                         help='Vulkan API XML file.',
  484                         required=True,
  485                         action='append',
  486                         dest='xml_files')
  487     args = parser.parse_args()
  488 
  489     entrypoints = []
  490 
  491     for filename in args.xml_files:
  492         doc = et.parse(filename)
  493         entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc),
  494                                        start_index=len(entrypoints))
  495 
  496     for num, e in enumerate(entrypoints):
  497         e.num = num
  498 
  499     # For outputting entrypoints.h we generate a tu_EntryPoint() prototype
  500     # per entry point.
  501     with open(os.path.join(args.outdir, 'tu_entrypoints.h'), 'wb') as f:
  502         f.write(TEMPLATE_H.render(entrypoints=entrypoints,
  503                                   LAYERS=LAYERS,
  504                                   filename=os.path.basename(__file__)))
  505     with open(os.path.join(args.outdir, 'tu_entrypoints.c'), 'wb') as f:
  506         f.write(gen_code(entrypoints))
  507 
  508 
  509 if __name__ == '__main__':
  510     main()