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