xref: /aosp_15_r20/external/mesa3d/src/vulkan/util/vk_dispatch_table_gen.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1COPYRIGHT = """\
2/*
3 * Copyright 2020 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
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25"""
26
27import argparse
28import math
29import os
30
31from mako.template import Template
32
33# Mesa-local imports must be declared in meson variable
34# '{file_without_suffix}_depend_files'.
35from vk_entrypoints import get_entrypoints_from_xml
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
42TEMPLATE_H = Template(COPYRIGHT + """\
43/* This file generated from ${filename}, don't edit directly. */
44
45#ifndef VK_DISPATCH_TABLE_H
46#define VK_DISPATCH_TABLE_H
47
48#include "vulkan/vulkan.h"
49#include "vulkan/vk_android_native_buffer.h"
50
51#include "vk_extensions.h"
52
53/* Windows api conflict */
54#ifdef _WIN32
55#include <windows.h>
56#ifdef CreateSemaphore
57#undef CreateSemaphore
58#endif
59#ifdef CreateEvent
60#undef CreateEvent
61#endif
62#endif
63
64#ifdef __cplusplus
65extern "C" {
66#endif
67
68#ifdef _MSC_VER
69VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void);
70#endif
71
72<%def name="dispatch_table(entrypoints)">
73% for e in entrypoints:
74  % if e.alias:
75    <% continue %>
76  % endif
77  % if e.guard is not None:
78#ifdef ${e.guard}
79  % endif
80  % if e.aliases:
81    union {
82        PFN_vk${e.name} ${e.name};
83      % for a in e.aliases:
84        PFN_vk${a.name} ${a.name};
85      % endfor
86    };
87  % else:
88    PFN_vk${e.name} ${e.name};
89  % endif
90  % if e.guard is not None:
91#else
92    % if e.aliases:
93    union {
94        PFN_vkVoidFunction ${e.name};
95      % for a in e.aliases:
96        PFN_vkVoidFunction ${a.name};
97      % endfor
98    };
99    % else:
100    PFN_vkVoidFunction ${e.name};
101    % endif
102#endif
103  % endif
104% endfor
105</%def>
106
107<%def name="entrypoint_table(type, entrypoints)">
108struct vk_${type}_entrypoint_table {
109% for e in entrypoints:
110  % if e.guard is not None:
111#ifdef ${e.guard}
112  % endif
113    PFN_vk${e.name} ${e.name};
114  % if e.guard is not None:
115#else
116    PFN_vkVoidFunction ${e.name};
117# endif
118  % endif
119% endfor
120};
121</%def>
122
123struct vk_instance_dispatch_table {
124  ${dispatch_table(instance_entrypoints)}
125};
126
127struct vk_physical_device_dispatch_table {
128  ${dispatch_table(physical_device_entrypoints)}
129};
130
131struct vk_device_dispatch_table {
132  ${dispatch_table(device_entrypoints)}
133};
134
135struct vk_dispatch_table {
136    union {
137        struct {
138            struct vk_instance_dispatch_table instance;
139            struct vk_physical_device_dispatch_table physical_device;
140            struct vk_device_dispatch_table device;
141        };
142
143        struct {
144            ${dispatch_table(instance_entrypoints)}
145            ${dispatch_table(physical_device_entrypoints)}
146            ${dispatch_table(device_entrypoints)}
147        };
148    };
149};
150
151${entrypoint_table('instance', instance_entrypoints)}
152${entrypoint_table('physical_device', physical_device_entrypoints)}
153${entrypoint_table('device', device_entrypoints)}
154
155<%def name="uncompacted_dispatch_table(entrypoints)">
156% for e in entrypoints:
157  % if e.alias:
158    <% continue %>
159  % endif
160  % if e.guard is not None:
161#ifdef ${e.guard}
162  % endif
163    PFN_vk${e.name} ${e.name};
164  % if e.aliases:
165    % for a in e.aliases:
166    PFN_vk${a.name} ${a.name};
167    % endfor
168  % endif
169  % if e.guard is not None:
170#else
171    PFN_vkVoidFunction ${e.name};
172    % if e.aliases:
173      % for a in e.aliases:
174        PFN_vkVoidFunction ${a.name};
175      % endfor
176    % endif
177#endif
178  % endif
179% endfor
180</%def>
181
182
183struct vk_instance_uncompacted_dispatch_table {
184  ${uncompacted_dispatch_table(instance_entrypoints)}
185};
186
187struct vk_physical_device_uncompacted_dispatch_table {
188  ${uncompacted_dispatch_table(physical_device_entrypoints)}
189};
190
191struct vk_device_uncompacted_dispatch_table {
192  ${uncompacted_dispatch_table(device_entrypoints)}
193};
194
195struct vk_uncompacted_dispatch_table {
196    union {
197        struct {
198            struct vk_instance_uncompacted_dispatch_table instance;
199            struct vk_physical_device_uncompacted_dispatch_table physical_device;
200            struct vk_device_uncompacted_dispatch_table device;
201        };
202
203        struct {
204            ${uncompacted_dispatch_table(instance_entrypoints)}
205            ${uncompacted_dispatch_table(physical_device_entrypoints)}
206            ${uncompacted_dispatch_table(device_entrypoints)}
207        };
208    };
209};
210
211void
212vk_instance_dispatch_table_load(struct vk_instance_dispatch_table *table,
213                                PFN_vkGetInstanceProcAddr gpa,
214                                VkInstance instance);
215void
216vk_physical_device_dispatch_table_load(struct vk_physical_device_dispatch_table *table,
217                                       PFN_vkGetInstanceProcAddr gpa,
218                                       VkInstance instance);
219void
220vk_device_dispatch_table_load(struct vk_device_dispatch_table *table,
221                              PFN_vkGetDeviceProcAddr gpa,
222                              VkDevice device);
223
224void
225vk_instance_uncompacted_dispatch_table_load(struct vk_instance_uncompacted_dispatch_table *table,
226                                PFN_vkGetInstanceProcAddr gpa,
227                                VkInstance instance);
228void
229vk_physical_device_uncompacted_dispatch_table_load(struct vk_physical_device_uncompacted_dispatch_table *table,
230                                       PFN_vkGetInstanceProcAddr gpa,
231                                       VkInstance instance);
232void
233vk_device_uncompacted_dispatch_table_load(struct vk_device_uncompacted_dispatch_table *table,
234                              PFN_vkGetDeviceProcAddr gpa,
235                              VkDevice device);
236
237void vk_instance_dispatch_table_from_entrypoints(
238    struct vk_instance_dispatch_table *dispatch_table,
239    const struct vk_instance_entrypoint_table *entrypoint_table,
240    bool overwrite);
241
242void vk_physical_device_dispatch_table_from_entrypoints(
243    struct vk_physical_device_dispatch_table *dispatch_table,
244    const struct vk_physical_device_entrypoint_table *entrypoint_table,
245    bool overwrite);
246
247void vk_device_dispatch_table_from_entrypoints(
248    struct vk_device_dispatch_table *dispatch_table,
249    const struct vk_device_entrypoint_table *entrypoint_table,
250    bool overwrite);
251
252PFN_vkVoidFunction
253vk_instance_dispatch_table_get(const struct vk_instance_dispatch_table *table,
254                               const char *name);
255
256PFN_vkVoidFunction
257vk_physical_device_dispatch_table_get(const struct vk_physical_device_dispatch_table *table,
258                                      const char *name);
259
260PFN_vkVoidFunction
261vk_device_dispatch_table_get(const struct vk_device_dispatch_table *table,
262                             const char *name);
263
264PFN_vkVoidFunction
265vk_instance_dispatch_table_get_if_supported(
266    const struct vk_instance_dispatch_table *table,
267    const char *name,
268    uint32_t core_version,
269    const struct vk_instance_extension_table *instance_exts);
270
271PFN_vkVoidFunction
272vk_physical_device_dispatch_table_get_if_supported(
273    const struct vk_physical_device_dispatch_table *table,
274    const char *name,
275    uint32_t core_version,
276    const struct vk_instance_extension_table *instance_exts);
277
278PFN_vkVoidFunction
279vk_device_dispatch_table_get_if_supported(
280    const struct vk_device_dispatch_table *table,
281    const char *name,
282    uint32_t core_version,
283    const struct vk_instance_extension_table *instance_exts,
284    const struct vk_device_extension_table *device_exts);
285
286#ifdef __cplusplus
287}
288#endif
289
290#endif /* VK_DISPATCH_TABLE_H */
291""")
292
293TEMPLATE_C = Template(COPYRIGHT + """\
294/* This file generated from ${filename}, don't edit directly. */
295
296#include "vk_dispatch_table.h"
297
298#include "util/macros.h"
299#include "string.h"
300
301<%def name="load_dispatch_table(type, VkType, ProcAddr, entrypoints)">
302void
303vk_${type}_dispatch_table_load(struct vk_${type}_dispatch_table *table,
304                               PFN_vk${ProcAddr} gpa,
305                               ${VkType} obj)
306{
307% if type != 'physical_device':
308    table->${ProcAddr} = gpa;
309% endif
310% for e in entrypoints:
311  % if e.alias or e.name == '${ProcAddr}':
312    <% continue %>
313  % endif
314  % if e.guard is not None:
315#ifdef ${e.guard}
316  % endif
317    table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${e.name}");
318  % for a in e.aliases:
319    if (table->${e.name} == NULL) {
320        table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${a.name}");
321    }
322  % endfor
323  % if e.guard is not None:
324#endif
325  % endif
326% endfor
327}
328</%def>
329
330${load_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr',
331                      instance_entrypoints)}
332
333${load_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr',
334                      physical_device_entrypoints)}
335
336${load_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr',
337                      device_entrypoints)}
338
339<%def name="load_uncompacted_dispatch_table(type, VkType, ProcAddr, entrypoints)">
340void
341vk_${type}_uncompacted_dispatch_table_load(struct vk_${type}_uncompacted_dispatch_table *table,
342                               PFN_vk${ProcAddr} gpa,
343                               ${VkType} obj)
344{
345% if type != 'physical_device':
346    table->${ProcAddr} = gpa;
347% endif
348% for e in entrypoints:
349  % if e.alias or e.name == '${ProcAddr}':
350    <% continue %>
351  % endif
352  % if e.guard is not None:
353#ifdef ${e.guard}
354  % endif
355    table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${e.name}");
356  % for a in e.aliases:
357    table->${a.name} = (PFN_vk${a.name}) gpa(obj, "vk${a.name}");
358    if (table->${e.name} && !table->${a.name})
359       table->${a.name} = (PFN_vk${a.name}) table->${e.name};
360    if (!table->${e.name})
361       table->${e.name} = (PFN_vk${e.name}) table->${a.name};
362  % endfor
363  % if e.guard is not None:
364#endif
365  % endif
366% endfor
367}
368</%def>
369
370${load_uncompacted_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr',
371                      instance_entrypoints)}
372
373${load_uncompacted_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr',
374                      physical_device_entrypoints)}
375
376${load_uncompacted_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr',
377                      device_entrypoints)}
378
379
380struct string_map_entry {
381   uint32_t name;
382   uint32_t hash;
383   uint32_t num;
384};
385
386/* We use a big string constant to avoid lots of reloctions from the entry
387 * point table to lots of little strings. The entries in the entry point table
388 * store the index into this big string.
389 */
390
391<%def name="strmap(strmap, prefix)">
392static const char ${prefix}_strings[] =
393% for s in strmap.sorted_strings:
394    "${s.string}\\0"
395% endfor
396;
397
398static const struct string_map_entry ${prefix}_string_map_entries[] = {
399% for s in strmap.sorted_strings:
400    { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */
401% endfor
402};
403
404/* Hash table stats:
405 * size ${len(strmap.sorted_strings)} entries
406 * collisions entries:
407% for i in range(10):
408 *     ${i}${'+' if i == 9 else ' '}     ${strmap.collisions[i]}
409% endfor
410 */
411
412#define none 0xffff
413static const uint16_t ${prefix}_string_map[${strmap.hash_size}] = {
414% for e in strmap.mapping:
415    ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' },
416% endfor
417};
418
419static int
420${prefix}_string_map_lookup(const char *str)
421{
422    static const uint32_t prime_factor = ${strmap.prime_factor};
423    static const uint32_t prime_step = ${strmap.prime_step};
424    const struct string_map_entry *e;
425    uint32_t hash, h;
426    uint16_t i;
427    const char *p;
428
429    hash = 0;
430    for (p = str; *p; p++)
431        hash = hash * prime_factor + *p;
432
433    h = hash;
434    while (1) {
435        i = ${prefix}_string_map[h & ${strmap.hash_mask}];
436        if (i == none)
437           return -1;
438        e = &${prefix}_string_map_entries[i];
439        if (e->hash == hash && strcmp(str, ${prefix}_strings + e->name) == 0)
440            return e->num;
441        h += prime_step;
442    }
443
444    return -1;
445}
446</%def>
447
448${strmap(instance_strmap, 'instance')}
449${strmap(physical_device_strmap, 'physical_device')}
450${strmap(device_strmap, 'device')}
451
452<% assert len(instance_entrypoints) < 2**8 %>
453static const uint8_t instance_compaction_table[] = {
454% for e in instance_entrypoints:
455    ${e.disp_table_index},
456% endfor
457};
458
459<% assert len(physical_device_entrypoints) < 2**8 %>
460static const uint8_t physical_device_compaction_table[] = {
461% for e in physical_device_entrypoints:
462    ${e.disp_table_index},
463% endfor
464};
465
466<% assert len(device_entrypoints) < 2**16 %>
467static const uint16_t device_compaction_table[] = {
468% for e in device_entrypoints:
469    ${e.disp_table_index},
470% endfor
471};
472
473static bool
474vk_instance_entrypoint_is_enabled(int index, uint32_t core_version,
475                                  const struct vk_instance_extension_table *instance)
476{
477   switch (index) {
478% for e in instance_entrypoints:
479   case ${e.entry_table_index}:
480      /* ${e.name} */
481   % if e.core_version:
482      return ${e.core_version.c_vk_version()} <= core_version;
483   % elif e.extensions:
484     % for ext in e.extensions:
485        % if ext.type == 'instance':
486      if (instance->${ext.name[3:]}) return true;
487        % else:
488      /* All device extensions are considered enabled at the instance level */
489      return true;
490        % endif
491     % endfor
492      return false;
493   % else:
494      return true;
495   % endif
496% endfor
497   default:
498      return false;
499   }
500}
501
502/** Return true if the core version or extension in which the given entrypoint
503 * is defined is enabled.
504 *
505 * If device is NULL, all device extensions are considered enabled.
506 */
507static bool
508vk_physical_device_entrypoint_is_enabled(int index, uint32_t core_version,
509                                         const struct vk_instance_extension_table *instance)
510{
511   switch (index) {
512% for e in physical_device_entrypoints:
513   case ${e.entry_table_index}:
514      /* ${e.name} */
515   % if e.core_version:
516      return ${e.core_version.c_vk_version()} <= core_version;
517   % elif e.extensions:
518     % for ext in e.extensions:
519        % if ext.type == 'instance':
520      if (instance->${ext.name[3:]}) return true;
521        % else:
522      /* All device extensions are considered enabled at the instance level */
523      return true;
524        % endif
525     % endfor
526      return false;
527   % else:
528      return true;
529   % endif
530% endfor
531   default:
532      return false;
533   }
534}
535
536/** Return true if the core version or extension in which the given entrypoint
537 * is defined is enabled.
538 *
539 * If device is NULL, all device extensions are considered enabled.
540 */
541static bool
542vk_device_entrypoint_is_enabled(int index, uint32_t core_version,
543                                const struct vk_instance_extension_table *instance,
544                                const struct vk_device_extension_table *device)
545{
546   switch (index) {
547% for e in device_entrypoints:
548   case ${e.entry_table_index}:
549      /* ${e.name} */
550   % if e.core_version:
551      return ${e.core_version.c_vk_version()} <= core_version;
552   % elif e.extensions:
553     % for ext in e.extensions:
554        % if ext.type == 'instance':
555      if (instance->${ext.name[3:]}) return true;
556        % else:
557      if (!device || device->${ext.name[3:]}) return true;
558        % endif
559     % endfor
560      return false;
561   % else:
562      return true;
563   % endif
564% endfor
565   default:
566      return false;
567   }
568}
569
570#ifdef _MSC_VER
571VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void)
572{
573   unreachable("Entrypoint not implemented");
574}
575
576static const void *get_function_target(const void *func)
577{
578   const uint8_t *address = func;
579#ifdef _M_X64
580   /* Incremental linking may indirect through relative jump */
581   if (*address == 0xE9)
582   {
583      /* Compute JMP target if the first byte is opcode 0xE9 */
584      uint32_t offset;
585      memcpy(&offset, address + 1, 4);
586      address += offset + 5;
587   }
588#else
589   /* Add other platforms here if necessary */
590#endif
591   return address;
592}
593
594static bool vk_function_is_stub(PFN_vkVoidFunction func)
595{
596   return (func == vk_entrypoint_stub) || (get_function_target(func) == get_function_target(vk_entrypoint_stub));
597}
598#endif
599
600<%def name="dispatch_table_from_entrypoints(type)">
601void vk_${type}_dispatch_table_from_entrypoints(
602    struct vk_${type}_dispatch_table *dispatch_table,
603    const struct vk_${type}_entrypoint_table *entrypoint_table,
604    bool overwrite)
605{
606    PFN_vkVoidFunction *disp = (PFN_vkVoidFunction *)dispatch_table;
607    PFN_vkVoidFunction *entry = (PFN_vkVoidFunction *)entrypoint_table;
608
609    if (overwrite) {
610        memset(dispatch_table, 0, sizeof(*dispatch_table));
611        for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) {
612#ifdef _MSC_VER
613            assert(entry[i] != NULL);
614            if (vk_function_is_stub(entry[i]))
615#else
616            if (entry[i] == NULL)
617#endif
618                continue;
619            unsigned disp_index = ${type}_compaction_table[i];
620            assert(disp[disp_index] == NULL);
621            disp[disp_index] = entry[i];
622        }
623    } else {
624        for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) {
625            unsigned disp_index = ${type}_compaction_table[i];
626#ifdef _MSC_VER
627            assert(entry[i] != NULL);
628            if (disp[disp_index] == NULL && !vk_function_is_stub(entry[i]))
629#else
630            if (disp[disp_index] == NULL)
631#endif
632                disp[disp_index] = entry[i];
633        }
634    }
635}
636</%def>
637
638${dispatch_table_from_entrypoints('instance')}
639${dispatch_table_from_entrypoints('physical_device')}
640${dispatch_table_from_entrypoints('device')}
641
642<%def name="lookup_funcs(type)">
643static PFN_vkVoidFunction
644vk_${type}_dispatch_table_get_for_entry_index(
645    const struct vk_${type}_dispatch_table *table, int entry_index)
646{
647    assert(entry_index < ARRAY_SIZE(${type}_compaction_table));
648    int disp_index = ${type}_compaction_table[entry_index];
649    return ((PFN_vkVoidFunction *)table)[disp_index];
650}
651
652PFN_vkVoidFunction
653vk_${type}_dispatch_table_get(
654    const struct vk_${type}_dispatch_table *table, const char *name)
655{
656    int entry_index = ${type}_string_map_lookup(name);
657    if (entry_index < 0)
658        return NULL;
659
660    return vk_${type}_dispatch_table_get_for_entry_index(table, entry_index);
661}
662</%def>
663
664${lookup_funcs('instance')}
665${lookup_funcs('physical_device')}
666${lookup_funcs('device')}
667
668PFN_vkVoidFunction
669vk_instance_dispatch_table_get_if_supported(
670    const struct vk_instance_dispatch_table *table,
671    const char *name,
672    uint32_t core_version,
673    const struct vk_instance_extension_table *instance_exts)
674{
675    int entry_index = instance_string_map_lookup(name);
676    if (entry_index < 0)
677        return NULL;
678
679    if (!vk_instance_entrypoint_is_enabled(entry_index, core_version,
680                                           instance_exts))
681        return NULL;
682
683    return vk_instance_dispatch_table_get_for_entry_index(table, entry_index);
684}
685
686PFN_vkVoidFunction
687vk_physical_device_dispatch_table_get_if_supported(
688    const struct vk_physical_device_dispatch_table *table,
689    const char *name,
690    uint32_t core_version,
691    const struct vk_instance_extension_table *instance_exts)
692{
693    int entry_index = physical_device_string_map_lookup(name);
694    if (entry_index < 0)
695        return NULL;
696
697    if (!vk_physical_device_entrypoint_is_enabled(entry_index, core_version,
698                                                  instance_exts))
699        return NULL;
700
701    return vk_physical_device_dispatch_table_get_for_entry_index(table, entry_index);
702}
703
704PFN_vkVoidFunction
705vk_device_dispatch_table_get_if_supported(
706    const struct vk_device_dispatch_table *table,
707    const char *name,
708    uint32_t core_version,
709    const struct vk_instance_extension_table *instance_exts,
710    const struct vk_device_extension_table *device_exts)
711{
712    int entry_index = device_string_map_lookup(name);
713    if (entry_index < 0)
714        return NULL;
715
716    if (!vk_device_entrypoint_is_enabled(entry_index, core_version,
717                                         instance_exts, device_exts))
718        return NULL;
719
720    return vk_device_dispatch_table_get_for_entry_index(table, entry_index);
721}
722""")
723
724U32_MASK = 2**32 - 1
725
726PRIME_FACTOR = 5024183
727PRIME_STEP = 19
728
729class StringIntMapEntry:
730    def __init__(self, string, num):
731        self.string = string
732        self.num = num
733
734        # Calculate the same hash value that we will calculate in C.
735        h = 0
736        for c in string:
737            h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK
738        self.hash = h
739
740        self.offset = None
741
742def round_to_pow2(x):
743    return 2**int(math.ceil(math.log(x, 2)))
744
745class StringIntMap:
746    def __init__(self):
747        self.baked = False
748        self.strings = {}
749
750    def add_string(self, string, num):
751        assert not self.baked
752        assert string not in self.strings
753        assert 0 <= num < 2**31
754        self.strings[string] = StringIntMapEntry(string, num)
755
756    def bake(self):
757        self.sorted_strings = \
758            sorted(self.strings.values(), key=lambda x: x.string)
759        offset = 0
760        for entry in self.sorted_strings:
761            entry.offset = offset
762            offset += len(entry.string) + 1
763
764        # Save off some values that we'll need in C
765        self.hash_size = round_to_pow2(len(self.strings) * 1.25)
766        self.hash_mask = self.hash_size - 1
767        self.prime_factor = PRIME_FACTOR
768        self.prime_step = PRIME_STEP
769
770        self.mapping = [-1] * self.hash_size
771        self.collisions = [0] * 10
772        for idx, s in enumerate(self.sorted_strings):
773            level = 0
774            h = s.hash
775            while self.mapping[h & self.hash_mask] >= 0:
776                h = h + PRIME_STEP
777                level = level + 1
778            self.collisions[min(level, 9)] += 1
779            self.mapping[h & self.hash_mask] = idx
780
781def main():
782    parser = argparse.ArgumentParser()
783    parser.add_argument('--out-c', help='Output C file.')
784    parser.add_argument('--out-h', help='Output H file.')
785    parser.add_argument('--beta', required=True, help='Enable beta extensions.')
786    parser.add_argument('--xml',
787                        help='Vulkan API XML file.',
788                        required=True,
789                        action='append',
790                        dest='xml_files')
791    args = parser.parse_args()
792
793    entrypoints = get_entrypoints_from_xml(args.xml_files, args.beta)
794
795    device_entrypoints = []
796    physical_device_entrypoints = []
797    instance_entrypoints = []
798    for e in entrypoints:
799        if e.is_device_entrypoint():
800            device_entrypoints.append(e)
801        elif e.is_physical_device_entrypoint():
802            physical_device_entrypoints.append(e)
803        else:
804            instance_entrypoints.append(e)
805
806    for i, e in enumerate(e for e in device_entrypoints if not e.alias):
807        e.disp_table_index = i
808
809    device_strmap = StringIntMap()
810    for i, e in enumerate(device_entrypoints):
811        e.entry_table_index = i
812        device_strmap.add_string("vk" + e.name, e.entry_table_index)
813    device_strmap.bake()
814
815    for i, e in enumerate(e for e in physical_device_entrypoints if not e.alias):
816        e.disp_table_index = i
817
818    physical_device_strmap = StringIntMap()
819    for i, e in enumerate(physical_device_entrypoints):
820        e.entry_table_index = i
821        physical_device_strmap.add_string("vk" + e.name, e.entry_table_index)
822    physical_device_strmap.bake()
823
824    for i, e in enumerate(e for e in instance_entrypoints if not e.alias):
825        e.disp_table_index = i
826
827    instance_strmap = StringIntMap()
828    for i, e in enumerate(instance_entrypoints):
829        e.entry_table_index = i
830        instance_strmap.add_string("vk" + e.name, e.entry_table_index)
831    instance_strmap.bake()
832
833    # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
834    # per entry point.
835    try:
836        if args.out_h:
837            with open(args.out_h, 'w', encoding='utf-8') as f:
838                f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints,
839                                          physical_device_entrypoints=physical_device_entrypoints,
840                                          device_entrypoints=device_entrypoints,
841                                          filename=os.path.basename(__file__)))
842        if args.out_c:
843            with open(args.out_c, 'w', encoding='utf-8') as f:
844                f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints,
845                                          physical_device_entrypoints=physical_device_entrypoints,
846                                          device_entrypoints=device_entrypoints,
847                                          instance_strmap=instance_strmap,
848                                          physical_device_strmap=physical_device_strmap,
849                                          device_strmap=device_strmap,
850                                          filename=os.path.basename(__file__)))
851    except Exception:
852        # In the event there's an error, this imports some helpers from mako
853        # to print a useful stack trace and prints it, then exits with
854        # status 1, if python is run with debug; otherwise it just raises
855        # the exception
856        import sys
857        from mako import exceptions
858        print(exceptions.text_error_template().render(), file=sys.stderr)
859        sys.exit(1)
860
861
862if __name__ == '__main__':
863    main()
864