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 25import sys 26import 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 33none = 0xffff 34hash_size = 256 35u32_mask = 2**32 - 1 36hash_mask = hash_size - 1 37 38prime_factor = 5024183 39prime_step = 19 40 41def hash(name): 42 h = 0; 43 for c in name: 44 h = (h * prime_factor + ord(c)) & u32_mask 45 46 return h 47 48def print_guard_start(guard): 49 if guard is not None: 50 print "#ifdef {0}".format(guard) 51 52def print_guard_end(guard): 53 if guard is not None: 54 print "#endif // {0}".format(guard) 55 56opt_header = False 57opt_code = False 58 59if (sys.argv[1] == "header"): 60 opt_header = True 61 sys.argv.pop() 62elif (sys.argv[1] == "code"): 63 opt_code = True 64 sys.argv.pop() 65 66# Extract the entry points from the registry 67def 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 84def 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 95doc = ET.parse(sys.stdin) 96entrypoints = get_entrypoints(doc, get_entrypoints_defines(doc)) 97 98# Manually add CreateDmaBufImageINTEL for which we don't have an extension 99# defined. 100entrypoints.append(('VkResult', 'CreateDmaBufImageINTEL', 101 'VkDevice device, ' + 102 'const VkDmaBufImageCreateInfo* pCreateInfo, ' + 103 'const VkAllocationCallbacks* pAllocator,' + 104 'VkDeviceMemory* pMem,' + 105 'VkImage* pImage', len(entrypoints), 106 hash('vkCreateDmaBufImageINTEL'), None)) 107 108# For outputting entrypoints.h we generate a anv_EntryPoint() prototype 109# per entry point. 110 111if opt_header: 112 print "/* This file generated from vk_gen.py, don't edit directly. */\n" 113 114 print "struct anv_dispatch_table {" 115 print " union {" 116 print " void *entrypoints[%d];" % len(entrypoints) 117 print " struct {" 118 119 for type, name, args, num, h, guard in entrypoints: 120 if guard is not None: 121 print "#ifdef {0}".format(guard) 122 print " PFN_vk{0} {0};".format(name) 123 print "#else" 124 print " void *{0};".format(name) 125 print "#endif" 126 else: 127 print " PFN_vk{0} {0};".format(name) 128 print " };\n" 129 print " };\n" 130 print "};\n" 131 132 print "void anv_set_dispatch_devinfo(const struct gen_device_info *info);\n" 133 134 for type, name, args, num, h, guard in entrypoints: 135 print_guard_start(guard) 136 print "%s anv_%s(%s);" % (type, name, args) 137 print "%s gen7_%s(%s);" % (type, name, args) 138 print "%s gen75_%s(%s);" % (type, name, args) 139 print "%s gen8_%s(%s);" % (type, name, args) 140 print "%s gen9_%s(%s);" % (type, name, args) 141 print_guard_end(guard) 142 exit() 143 144 145 146print """/* 147 * Copyright © 2015 Intel Corporation 148 * 149 * Permission is hereby granted, free of charge, to any person obtaining a 150 * copy of this software and associated documentation files (the "Software"), 151 * to deal in the Software without restriction, including without limitation 152 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 153 * and/or sell copies of the Software, and to permit persons to whom the 154 * Software is furnished to do so, subject to the following conditions: 155 * 156 * The above copyright notice and this permission notice (including the next 157 * paragraph) shall be included in all copies or substantial portions of the 158 * Software. 159 * 160 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 162 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 163 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 164 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 165 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 166 * IN THE SOFTWARE. 167 */ 168 169/* DO NOT EDIT! This is a generated file. */ 170 171#include "anv_private.h" 172 173struct anv_entrypoint { 174 uint32_t name; 175 uint32_t hash; 176}; 177 178/* We use a big string constant to avoid lots of reloctions from the entry 179 * point table to lots of little strings. The entries in the entry point table 180 * store the index into this big string. 181 */ 182 183static const char strings[] =""" 184 185offsets = [] 186i = 0; 187for type, name, args, num, h, guard in entrypoints: 188 print " \"vk%s\\0\"" % name 189 offsets.append(i) 190 i += 2 + len(name) + 1 191print " ;" 192 193# Now generate the table of all entry points 194 195print "\nstatic const struct anv_entrypoint entrypoints[] = {" 196for type, name, args, num, h, guard in entrypoints: 197 print " { %5d, 0x%08x }," % (offsets[num], h) 198print "};\n" 199 200print """ 201 202/* Weak aliases for all potential implementations. These will resolve to 203 * NULL if they're not defined, which lets the resolve_entrypoint() function 204 * either pick the correct entry point. 205 */ 206""" 207 208for layer in [ "anv", "gen7", "gen75", "gen8", "gen9" ]: 209 for type, name, args, num, h, guard in entrypoints: 210 print_guard_start(guard) 211 print "%s %s_%s(%s) __attribute__ ((weak));" % (type, layer, name, args) 212 print_guard_end(guard) 213 print "\nconst struct anv_dispatch_table %s_layer = {" % layer 214 for type, name, args, num, h, guard in entrypoints: 215 print_guard_start(guard) 216 print " .%s = %s_%s," % (name, layer, name) 217 print_guard_end(guard) 218 print "};\n" 219 220print """ 221static void * __attribute__ ((noinline)) 222anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index) 223{ 224 if (devinfo == NULL) { 225 return anv_layer.entrypoints[index]; 226 } 227 228 switch (devinfo->gen) { 229 case 9: 230 if (gen9_layer.entrypoints[index]) 231 return gen9_layer.entrypoints[index]; 232 /* fall through */ 233 case 8: 234 if (gen8_layer.entrypoints[index]) 235 return gen8_layer.entrypoints[index]; 236 /* fall through */ 237 case 7: 238 if (devinfo->is_haswell && gen75_layer.entrypoints[index]) 239 return gen75_layer.entrypoints[index]; 240 241 if (gen7_layer.entrypoints[index]) 242 return gen7_layer.entrypoints[index]; 243 /* fall through */ 244 case 0: 245 return anv_layer.entrypoints[index]; 246 default: 247 unreachable("unsupported gen\\n"); 248 } 249} 250""" 251 252# Now generate the hash table used for entry point look up. This is a 253# uint16_t table of entry point indices. We use 0xffff to indicate an entry 254# in the hash table is empty. 255 256map = [none for f in xrange(hash_size)] 257collisions = [0 for f in xrange(10)] 258for type, name, args, num, h, guard in entrypoints: 259 level = 0 260 while map[h & hash_mask] != none: 261 h = h + prime_step 262 level = level + 1 263 if level > 9: 264 collisions[9] += 1 265 else: 266 collisions[level] += 1 267 map[h & hash_mask] = num 268 269print "/* Hash table stats:" 270print " * size %d entries" % hash_size 271print " * collisions entries" 272for i in xrange(10): 273 if (i == 9): 274 plus = "+" 275 else: 276 plus = " " 277 278 print " * %2d%s %4d" % (i, plus, collisions[i]) 279print " */\n" 280 281print "#define none 0x%04x\n" % none 282 283print "static const uint16_t map[] = {" 284for i in xrange(0, hash_size, 8): 285 print " ", 286 for j in xrange(i, i + 8): 287 if map[j] & 0xffff == 0xffff: 288 print " none,", 289 else: 290 print "0x%04x," % (map[j] & 0xffff), 291 print 292 293print "};" 294 295# Finally we generate the hash table lookup function. The hash function and 296# linear probing algorithm matches the hash table generated above. 297 298print """ 299void * 300anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name) 301{ 302 static const uint32_t prime_factor = %d; 303 static const uint32_t prime_step = %d; 304 const struct anv_entrypoint *e; 305 uint32_t hash, h, i; 306 const char *p; 307 308 hash = 0; 309 for (p = name; *p; p++) 310 hash = hash * prime_factor + *p; 311 312 h = hash; 313 do { 314 i = map[h & %d]; 315 if (i == none) 316 return NULL; 317 e = &entrypoints[i]; 318 h += prime_step; 319 } while (e->hash != hash); 320 321 if (strcmp(name, strings + e->name) != 0) 322 return NULL; 323 324 return anv_resolve_entrypoint(devinfo, i); 325} 326""" % (prime_factor, prime_step, hash_mask) 327