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