tu: Force gl_Layer to 0 when necessary
[mesa.git] / src / freedreno / vulkan / tu_entrypoints_gen.py
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()