Home | History | Annotate | Download | only in vulkan
      1 # coding=utf-8
      2 #
      3 # Copyright  2015 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 sys
     26 import xml.etree.ElementTree as ET
     27 
     28 # We generate a static hash table for entry point lookup
     29 # (vkGetProcAddress). We use a linear congruential generator for our hash
     30 # function and a power-of-two size table. The prime numbers are determined
     31 # experimentally.
     32 
     33 none = 0xffff
     34 hash_size = 256
     35 u32_mask = 2**32 - 1
     36 hash_mask = hash_size - 1
     37 
     38 prime_factor = 5024183
     39 prime_step = 19
     40 
     41 def hash(name):
     42     h = 0;
     43     for c in name:
     44         h = (h * prime_factor + ord(c)) & u32_mask
     45 
     46     return h
     47 
     48 def print_guard_start(guard):
     49     if guard is not None:
     50         print "#ifdef {0}".format(guard)
     51 
     52 def print_guard_end(guard):
     53     if guard is not None:
     54         print "#endif // {0}".format(guard)
     55 
     56 opt_header = False
     57 opt_code = False
     58 
     59 if (sys.argv[1] == "header"):
     60     opt_header = True
     61     sys.argv.pop()
     62 elif (sys.argv[1] == "code"):
     63     opt_code = True
     64     sys.argv.pop()
     65 
     66 # Extract the entry points from the registry
     67 def get_entrypoints(doc, entrypoints_to_defines):
     68     entrypoints = []
     69     commands = doc.findall('./commands/command')
     70     for i, command in enumerate(commands):
     71         type = command.find('./proto/type').text
     72         fullname = command.find('./proto/name').text
     73         shortname = fullname[2:]
     74         params = map(lambda p: "".join(p.itertext()), command.findall('./param'))
     75         params = ', '.join(params)
     76         if fullname in entrypoints_to_defines:
     77             guard = entrypoints_to_defines[fullname]
     78         else:
     79             guard = None
     80         entrypoints.append((type, shortname, params, i, hash(fullname), guard))
     81     return entrypoints
     82 
     83 # Maps entry points to extension defines
     84 def get_entrypoints_defines(doc):
     85     entrypoints_to_defines = {}
     86     extensions = doc.findall('./extensions/extension')
     87     for extension in extensions:
     88         define = extension.get('protect')
     89         entrypoints = extension.findall('./require/command')
     90         for entrypoint in entrypoints:
     91             fullname = entrypoint.get('name')
     92             entrypoints_to_defines[fullname] = define
     93     return entrypoints_to_defines
     94 
     95 doc = ET.parse(sys.stdin)
     96 entrypoints = get_entrypoints(doc, get_entrypoints_defines(doc))
     97 
     98 # For outputting entrypoints.h we generate a radv_EntryPoint() prototype
     99 # per entry point.
    100 
    101 if opt_header:
    102     print "/* This file generated from vk_gen.py, don't edit directly. */\n"
    103 
    104     print "struct radv_dispatch_table {"
    105     print "   union {"
    106     print "      void *entrypoints[%d];" % len(entrypoints)
    107     print "      struct {"
    108 
    109     for type, name, args, num, h, guard in entrypoints:
    110         if guard is not None:
    111             print "#ifdef {0}".format(guard)
    112             print "         PFN_vk{0} {0};".format(name)
    113             print "#else"
    114             print "         void *{0};".format(name)
    115             print "#endif"
    116         else:
    117             print "         PFN_vk{0} {0};".format(name)
    118     print "      };\n"
    119     print "   };\n"
    120     print "};\n"
    121 
    122     for type, name, args, num, h, guard in entrypoints:
    123         print_guard_start(guard)
    124         print "%s radv_%s(%s);" % (type, name, args)
    125         print_guard_end(guard)
    126     exit()
    127 
    128 
    129 
    130 print """/*
    131  * Copyright  2015 Intel Corporation
    132  *
    133  * Permission is hereby granted, free of charge, to any person obtaining a
    134  * copy of this software and associated documentation files (the "Software"),
    135  * to deal in the Software without restriction, including without limitation
    136  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    137  * and/or sell copies of the Software, and to permit persons to whom the
    138  * Software is furnished to do so, subject to the following conditions:
    139  *
    140  * The above copyright notice and this permission notice (including the next
    141  * paragraph) shall be included in all copies or substantial portions of the
    142  * Software.
    143  *
    144  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    145  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    146  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
    147  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    148  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    149  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    150  * IN THE SOFTWARE.
    151  */
    152 
    153 /* DO NOT EDIT! This is a generated file. */
    154 
    155 #include "radv_private.h"
    156 
    157 struct radv_entrypoint {
    158    uint32_t name;
    159    uint32_t hash;
    160 };
    161 
    162 /* We use a big string constant to avoid lots of reloctions from the entry
    163  * point table to lots of little strings. The entries in the entry point table
    164  * store the index into this big string.
    165  */
    166 
    167 static const char strings[] ="""
    168 
    169 offsets = []
    170 i = 0;
    171 for type, name, args, num, h, guard in entrypoints:
    172     print "   \"vk%s\\0\"" % name
    173     offsets.append(i)
    174     i += 2 + len(name) + 1
    175 print "   ;"
    176 
    177 # Now generate the table of all entry points
    178 
    179 print "\nstatic const struct radv_entrypoint entrypoints[] = {"
    180 for type, name, args, num, h, guard in entrypoints:
    181     print "   { %5d, 0x%08x }," % (offsets[num], h)
    182 print "};\n"
    183 
    184 print """
    185 
    186 /* Weak aliases for all potential implementations. These will resolve to
    187  * NULL if they're not defined, which lets the resolve_entrypoint() function
    188  * either pick the correct entry point.
    189  */
    190 """
    191 
    192 for layer in [ "radv" ]:
    193     for type, name, args, num, h, guard in entrypoints:
    194         print_guard_start(guard)
    195         print "%s %s_%s(%s) __attribute__ ((weak));" % (type, layer, name, args)
    196         print_guard_end(guard)
    197     print "\nconst struct radv_dispatch_table %s_layer = {" % layer
    198     for type, name, args, num, h, guard in entrypoints:
    199         print_guard_start(guard)
    200         print "   .%s = %s_%s," % (name, layer, name)
    201         print_guard_end(guard)
    202     print "};\n"
    203 
    204 print """
    205 
    206 void * __attribute__ ((noinline))
    207 radv_resolve_entrypoint(uint32_t index)
    208 {
    209    return radv_layer.entrypoints[index];
    210 }
    211 """
    212 
    213 # Now generate the hash table used for entry point look up.  This is a
    214 # uint16_t table of entry point indices. We use 0xffff to indicate an entry
    215 # in the hash table is empty.
    216 
    217 map = [none for f in xrange(hash_size)]
    218 collisions = [0 for f in xrange(10)]
    219 for type, name, args, num, h, guard in entrypoints:
    220     level = 0
    221     while map[h & hash_mask] != none:
    222         h = h + prime_step
    223         level = level + 1
    224     if level > 9:
    225         collisions[9] += 1
    226     else:
    227         collisions[level] += 1
    228     map[h & hash_mask] = num
    229 
    230 print "/* Hash table stats:"
    231 print " * size %d entries" % hash_size
    232 print " * collisions  entries"
    233 for i in xrange(10):
    234     if (i == 9):
    235         plus = "+"
    236     else:
    237         plus = " "
    238 
    239     print " *     %2d%s     %4d" % (i, plus, collisions[i])
    240 print " */\n"
    241 
    242 print "#define none 0x%04x\n" % none
    243 
    244 print "static const uint16_t map[] = {"
    245 for i in xrange(0, hash_size, 8):
    246     print "   ",
    247     for j in xrange(i, i + 8):
    248         if map[j] & 0xffff == 0xffff:
    249             print "  none,",
    250         else:
    251             print "0x%04x," % (map[j] & 0xffff),
    252     print
    253 
    254 print "};"    
    255 
    256 # Finally we generate the hash table lookup function.  The hash function and
    257 # linear probing algorithm matches the hash table generated above.
    258 
    259 print """
    260 void *
    261 radv_lookup_entrypoint(const char *name)
    262 {
    263    static const uint32_t prime_factor = %d;
    264    static const uint32_t prime_step = %d;
    265    const struct radv_entrypoint *e;
    266    uint32_t hash, h, i;
    267    const char *p;
    268 
    269    hash = 0;
    270    for (p = name; *p; p++)
    271       hash = hash * prime_factor + *p;
    272 
    273    h = hash;
    274    do {
    275       i = map[h & %d];
    276       if (i == none)
    277          return NULL;
    278       e = &entrypoints[i];
    279       h += prime_step;
    280    } while (e->hash != hash);
    281 
    282    if (strcmp(name, strings + e->name) != 0)
    283       return NULL;
    284 
    285    return radv_resolve_entrypoint(i);
    286 }
    287 """ % (prime_factor, prime_step, hash_mask)
    288