~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/vulkan/util/gen_enum_to_str.py

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright © 2017 Intel Corporation
2
 
 
3
 
# Permission is hereby granted, free of charge, to any person obtaining a copy
4
 
# of this software and associated documentation files (the "Software"), to deal
5
 
# in the Software without restriction, including without limitation the rights
6
 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
 
# copies of the Software, and to permit persons to whom the Software is
8
 
# furnished to do so, subject to the following conditions:
9
 
 
10
 
# The above copyright notice and this permission notice shall be included in
11
 
# all copies or substantial portions of the Software.
12
 
 
13
 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
 
# SOFTWARE.
20
 
 
21
 
"""Create enum to string functions for vulkan using vk.xml."""
22
 
 
23
 
import argparse
24
 
import functools
25
 
import os
26
 
import re
27
 
import textwrap
28
 
import xml.etree.ElementTree as et
29
 
 
30
 
from mako.template import Template
31
 
 
32
 
COPYRIGHT = textwrap.dedent(u"""\
33
 
    * Copyright © 2017 Intel Corporation
34
 
    *
35
 
    * Permission is hereby granted, free of charge, to any person obtaining a copy
36
 
    * of this software and associated documentation files (the "Software"), to deal
37
 
    * in the Software without restriction, including without limitation the rights
38
 
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39
 
    * copies of the Software, and to permit persons to whom the Software is
40
 
    * furnished to do so, subject to the following conditions:
41
 
    *
42
 
    * The above copyright notice and this permission notice shall be included in
43
 
    * all copies or substantial portions of the Software.
44
 
    *
45
 
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46
 
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47
 
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48
 
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49
 
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50
 
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
51
 
    * SOFTWARE.""")
52
 
 
53
 
C_TEMPLATE = Template(textwrap.dedent(u"""\
54
 
    /* Autogenerated file -- do not edit
55
 
     * generated by ${file}
56
 
     *
57
 
     ${copyright}
58
 
     */
59
 
 
60
 
    #include <string.h>
61
 
    #include <vulkan/vulkan.h>
62
 
    #include <vulkan/vk_android_native_buffer.h>
63
 
    #include <vulkan/vk_layer.h>
64
 
    #include "util/macros.h"
65
 
    #include "vk_enum_to_str.h"
66
 
 
67
 
    % for enum in enums:
68
 
 
69
 
      % if enum.guard:
70
 
#ifdef ${enum.guard}
71
 
      % endif
72
 
    const char *
73
 
    vk_${enum.name[2:]}_to_str(${enum.name} input)
74
 
    {
75
 
        switch((int64_t)input) {
76
 
    % for v in sorted(enum.values.keys()):
77
 
        case ${v}:
78
 
            return "${enum.values[v]}";
79
 
    % endfor
80
 
        case ${enum.max_enum_name}: return "${enum.max_enum_name}";
81
 
        default:
82
 
            return "Unknown ${enum.name} value.";
83
 
        }
84
 
    }
85
 
 
86
 
      % if enum.guard:
87
 
#endif
88
 
      % endif
89
 
    %endfor
90
 
 
91
 
    size_t vk_structure_type_size(const struct VkBaseInStructure *item)
92
 
    {
93
 
        switch((int)item->sType) {
94
 
    % for struct in structs:
95
 
        % if struct.extension is not None and struct.extension.define is not None:
96
 
    #ifdef ${struct.extension.define}
97
 
        case ${struct.stype}: return sizeof(${struct.name});
98
 
    #endif
99
 
        % else:
100
 
        case ${struct.stype}: return sizeof(${struct.name});
101
 
        % endif
102
 
    %endfor
103
 
        case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: return sizeof(VkLayerInstanceCreateInfo);
104
 
        case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: return sizeof(VkLayerDeviceCreateInfo);
105
 
        default:
106
 
            unreachable("Undefined struct type.");
107
 
        }
108
 
    }
109
 
 
110
 
    const char *
111
 
    vk_ObjectType_to_ObjectName(VkObjectType type)
112
 
    {
113
 
        switch((int)type) {
114
 
    % for object_type in sorted(object_types[0].enum_to_name.keys()):
115
 
        case ${object_type}:
116
 
            return "${object_types[0].enum_to_name[object_type]}";
117
 
    % endfor
118
 
        default:
119
 
            return "Unknown VkObjectType value.";
120
 
        }
121
 
    }
122
 
    """))
123
 
 
124
 
H_TEMPLATE = Template(textwrap.dedent(u"""\
125
 
    /* Autogenerated file -- do not edit
126
 
     * generated by ${file}
127
 
     *
128
 
     ${copyright}
129
 
     */
130
 
 
131
 
    #ifndef MESA_VK_ENUM_TO_STR_H
132
 
    #define MESA_VK_ENUM_TO_STR_H
133
 
 
134
 
    #include <vulkan/vulkan.h>
135
 
    #include <vulkan/vk_android_native_buffer.h>
136
 
 
137
 
    #ifdef __cplusplus
138
 
    extern "C" {
139
 
    #endif
140
 
 
141
 
    % for enum in enums:
142
 
      % if enum.guard:
143
 
#ifdef ${enum.guard}
144
 
      % endif
145
 
    const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
146
 
      % if enum.guard:
147
 
#endif
148
 
      % endif
149
 
    % endfor
150
 
 
151
 
    size_t vk_structure_type_size(const struct VkBaseInStructure *item);
152
 
 
153
 
    const char * vk_ObjectType_to_ObjectName(VkObjectType type);
154
 
 
155
 
    #ifdef __cplusplus
156
 
    } /* extern "C" */
157
 
    #endif
158
 
 
159
 
    #endif"""))
160
 
 
161
 
 
162
 
H_DEFINE_TEMPLATE = Template(textwrap.dedent(u"""\
163
 
    /* Autogenerated file -- do not edit
164
 
     * generated by ${file}
165
 
     *
166
 
     ${copyright}
167
 
     */
168
 
 
169
 
    #ifndef MESA_VK_ENUM_DEFINES_H
170
 
    #define MESA_VK_ENUM_DEFINES_H
171
 
 
172
 
    #include <vulkan/vulkan.h>
173
 
    #include <vulkan/vk_android_native_buffer.h>
174
 
 
175
 
    #ifdef __cplusplus
176
 
    extern "C" {
177
 
    #endif
178
 
 
179
 
    % for ext in extensions:
180
 
    #define _${ext.name}_number (${ext.number})
181
 
    % endfor
182
 
 
183
 
    % for enum in bitmasks:
184
 
      % if enum.bitwidth > 32:
185
 
        <% continue %>
186
 
      % endif
187
 
      % if enum.guard:
188
 
#ifdef ${enum.guard}
189
 
      % endif
190
 
    #define ${enum.all_bits_name()} ${hex(enum.all_bits_value())}u
191
 
      % if enum.guard:
192
 
#endif
193
 
      % endif
194
 
    % endfor
195
 
 
196
 
    % for enum in bitmasks:
197
 
      % if enum.bitwidth < 64:
198
 
        <% continue %>
199
 
      % endif
200
 
    /* Redefine bitmask values of ${enum.name} */
201
 
      % if enum.guard:
202
 
#ifdef ${enum.guard}
203
 
      % endif
204
 
      % for n, v in enum.name_to_value.items():
205
 
    #define ${n} (${hex(v)}ULL)
206
 
      % endfor
207
 
      % if enum.guard:
208
 
#endif
209
 
      % endif
210
 
    % endfor
211
 
 
212
 
    #ifdef __cplusplus
213
 
    } /* extern "C" */
214
 
    #endif
215
 
 
216
 
    #endif"""))
217
 
 
218
 
 
219
 
class NamedFactory(object):
220
 
    """Factory for creating enums."""
221
 
 
222
 
    def __init__(self, type_):
223
 
        self.registry = {}
224
 
        self.type = type_
225
 
 
226
 
    def __call__(self, name, **kwargs):
227
 
        try:
228
 
            return self.registry[name]
229
 
        except KeyError:
230
 
            n = self.registry[name] = self.type(name, **kwargs)
231
 
        return n
232
 
 
233
 
    def get(self, name):
234
 
        return self.registry.get(name)
235
 
 
236
 
 
237
 
class VkExtension(object):
238
 
    """Simple struct-like class representing extensions"""
239
 
 
240
 
    def __init__(self, name, number=None, define=None):
241
 
        self.name = name
242
 
        self.number = number
243
 
        self.define = define
244
 
 
245
 
 
246
 
def CamelCase_to_SHOUT_CASE(s):
247
 
   return (s[:1] + re.sub(r'(?<![A-Z])([A-Z])', r'_\1', s[1:])).upper()
248
 
 
249
 
def compute_max_enum_name(s):
250
 
    max_enum_name = CamelCase_to_SHOUT_CASE(s)
251
 
    last_prefix = max_enum_name.rsplit('_', 1)[-1]
252
 
    # Those special prefixes need to be always at the end
253
 
    if last_prefix in ['AMD', 'EXT', 'INTEL', 'KHR', 'NV'] :
254
 
        max_enum_name = "_".join(max_enum_name.split('_')[:-1])
255
 
        max_enum_name = max_enum_name + "_MAX_ENUM_" + last_prefix
256
 
    else:
257
 
        max_enum_name = max_enum_name + "_MAX_ENUM"
258
 
 
259
 
    return max_enum_name
260
 
 
261
 
class VkEnum(object):
262
 
    """Simple struct-like class representing a single Vulkan Enum."""
263
 
 
264
 
    def __init__(self, name, bitwidth=32, values=None):
265
 
        self.name = name
266
 
        self.max_enum_name = compute_max_enum_name(name)
267
 
        self.bitwidth = bitwidth
268
 
        self.extension = None
269
 
        # Maps numbers to names
270
 
        self.values = values or dict()
271
 
        self.name_to_value = dict()
272
 
        self.guard = None
273
 
        self.name_to_alias_list = {}
274
 
 
275
 
    def all_bits_name(self):
276
 
        assert self.name.startswith('Vk')
277
 
        assert re.search(r'FlagBits[A-Z]*$', self.name)
278
 
 
279
 
        return 'VK_ALL_' + CamelCase_to_SHOUT_CASE(self.name[2:])
280
 
 
281
 
    def all_bits_value(self):
282
 
        return functools.reduce(lambda a,b: a | b, self.values.keys(), 0)
283
 
 
284
 
    def add_value(self, name, value=None,
285
 
                  extnum=None, offset=None, alias=None,
286
 
                  error=False):
287
 
        if alias is not None:
288
 
            assert value is None and offset is None
289
 
            if alias not in self.name_to_value:
290
 
                # We don't have this alias yet.  Just record the alias and
291
 
                # we'll deal with it later.
292
 
                alias_list = self.name_to_alias_list.setdefault(alias, [])
293
 
                alias_list.append(name);
294
 
                return
295
 
 
296
 
            # Use the value from the alias
297
 
            value = self.name_to_value[alias]
298
 
 
299
 
        assert value is not None or extnum is not None
300
 
        if value is None:
301
 
            value = 1000000000 + (extnum - 1) * 1000 + offset
302
 
            if error:
303
 
                value = -value
304
 
 
305
 
        self.name_to_value[name] = value
306
 
        if value not in self.values:
307
 
            self.values[value] = name
308
 
        elif len(self.values[value]) > len(name):
309
 
            self.values[value] = name
310
 
 
311
 
        # Now that the value has been fully added, resolve aliases, if any.
312
 
        if name in self.name_to_alias_list:
313
 
            for alias in self.name_to_alias_list[name]:
314
 
                self.add_value(alias, value)
315
 
            del self.name_to_alias_list[name]
316
 
 
317
 
    def add_value_from_xml(self, elem, extension=None):
318
 
        self.extension = extension
319
 
        if 'value' in elem.attrib:
320
 
            self.add_value(elem.attrib['name'],
321
 
                           value=int(elem.attrib['value'], base=0))
322
 
        elif 'bitpos' in elem.attrib:
323
 
            self.add_value(elem.attrib['name'],
324
 
                           value=(1 << int(elem.attrib['bitpos'], base=0)))
325
 
        elif 'alias' in elem.attrib:
326
 
            self.add_value(elem.attrib['name'], alias=elem.attrib['alias'])
327
 
        else:
328
 
            error = 'dir' in elem.attrib and elem.attrib['dir'] == '-'
329
 
            if 'extnumber' in elem.attrib:
330
 
                extnum = int(elem.attrib['extnumber'])
331
 
            else:
332
 
                extnum = extension.number
333
 
            self.add_value(elem.attrib['name'],
334
 
                           extnum=extnum,
335
 
                           offset=int(elem.attrib['offset']),
336
 
                           error=error)
337
 
 
338
 
    def set_guard(self, g):
339
 
        self.guard = g
340
 
 
341
 
 
342
 
class VkChainStruct(object):
343
 
    """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType"""
344
 
    def __init__(self, name, stype):
345
 
        self.name = name
346
 
        self.stype = stype
347
 
        self.extension = None
348
 
 
349
 
 
350
 
def struct_get_stype(xml_node):
351
 
    for member in xml_node.findall('./member'):
352
 
        name = member.findall('./name')
353
 
        if len(name) > 0 and name[0].text == "sType":
354
 
            return member.get('values')
355
 
    return None
356
 
 
357
 
class VkObjectType(object):
358
 
    """Simple struct-like class representing a single Vulkan object type"""
359
 
    def __init__(self, name):
360
 
        self.name = name
361
 
        self.enum_to_name = dict()
362
 
 
363
 
 
364
 
def parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory,
365
 
              obj_type_factory, filename):
366
 
    """Parse the XML file. Accumulate results into the factories.
367
 
 
368
 
    This parser is a memory efficient iterative XML parser that returns a list
369
 
    of VkEnum objects.
370
 
    """
371
 
 
372
 
    xml = et.parse(filename)
373
 
 
374
 
    for enum_type in xml.findall('./enums[@type="enum"]'):
375
 
        enum = enum_factory(enum_type.attrib['name'])
376
 
        for value in enum_type.findall('./enum'):
377
 
            enum.add_value_from_xml(value)
378
 
 
379
 
    # For bitmask we only add the Enum selected for convenience.
380
 
    for enum_type in xml.findall('./enums[@type="bitmask"]'):
381
 
        bitwidth = int(enum_type.attrib.get('bitwidth', 32))
382
 
        enum = bitmask_factory(enum_type.attrib['name'], bitwidth=bitwidth)
383
 
        for value in enum_type.findall('./enum'):
384
 
            enum.add_value_from_xml(value)
385
 
 
386
 
    for value in xml.findall('./feature/require/enum[@extends]'):
387
 
        extends = value.attrib['extends']
388
 
        enum = enum_factory.get(extends)
389
 
        if enum is not None:
390
 
            enum.add_value_from_xml(value)
391
 
        enum = bitmask_factory.get(extends)
392
 
        if enum is not None:
393
 
            enum.add_value_from_xml(value)
394
 
 
395
 
    for struct_type in xml.findall('./types/type[@category="struct"]'):
396
 
        name = struct_type.attrib['name']
397
 
        stype = struct_get_stype(struct_type)
398
 
        if stype is not None:
399
 
            struct_factory(name, stype=stype)
400
 
 
401
 
    platform_define = {}
402
 
    for platform in xml.findall('./platforms/platform'):
403
 
        name = platform.attrib['name']
404
 
        define = platform.attrib['protect']
405
 
        platform_define[name] = define
406
 
 
407
 
    for ext_elem in xml.findall('./extensions/extension[@supported="vulkan"]'):
408
 
        define = None
409
 
        if "platform" in ext_elem.attrib:
410
 
            define = platform_define[ext_elem.attrib['platform']]
411
 
        extension = ext_factory(ext_elem.attrib['name'],
412
 
                                number=int(ext_elem.attrib['number']),
413
 
                                define=define)
414
 
 
415
 
        for value in ext_elem.findall('./require/enum[@extends]'):
416
 
            extends = value.attrib['extends']
417
 
            enum = enum_factory.get(extends)
418
 
            if enum is not None:
419
 
                enum.add_value_from_xml(value, extension)
420
 
            enum = bitmask_factory.get(extends)
421
 
            if enum is not None:
422
 
                enum.add_value_from_xml(value, extension)
423
 
        for t in ext_elem.findall('./require/type'):
424
 
            struct = struct_factory.get(t.attrib['name'])
425
 
            if struct is not None:
426
 
                struct.extension = extension
427
 
 
428
 
        if define:
429
 
            for value in ext_elem.findall('./require/type[@name]'):
430
 
                enum = enum_factory.get(value.attrib['name'])
431
 
                if enum is not None:
432
 
                    enum.set_guard(define)
433
 
 
434
 
    obj_types = obj_type_factory("VkObjectType")
435
 
    for object_type in xml.findall('./types/type[@category="handle"]'):
436
 
        for object_name in object_type.findall('./name'):
437
 
            # Convert to int to avoid undefined enums
438
 
            enum = object_type.attrib['objtypeenum']
439
 
            enum_val = enum_factory.get("VkObjectType").name_to_value[enum]
440
 
            obj_types.enum_to_name[enum_val] = object_name.text
441
 
 
442
 
 
443
 
def main():
444
 
    parser = argparse.ArgumentParser()
445
 
    parser.add_argument('--xml', required=True,
446
 
                        help='Vulkan API XML files',
447
 
                        action='append',
448
 
                        dest='xml_files')
449
 
    parser.add_argument('--outdir',
450
 
                        help='Directory to put the generated files in',
451
 
                        required=True)
452
 
 
453
 
    args = parser.parse_args()
454
 
 
455
 
    enum_factory = NamedFactory(VkEnum)
456
 
    ext_factory = NamedFactory(VkExtension)
457
 
    struct_factory = NamedFactory(VkChainStruct)
458
 
    obj_type_factory = NamedFactory(VkObjectType)
459
 
    bitmask_factory = NamedFactory(VkEnum)
460
 
 
461
 
    for filename in args.xml_files:
462
 
        parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory,
463
 
                  obj_type_factory, filename)
464
 
    enums = sorted(enum_factory.registry.values(), key=lambda e: e.name)
465
 
    extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name)
466
 
    structs = sorted(struct_factory.registry.values(), key=lambda e: e.name)
467
 
    bitmasks = sorted(bitmask_factory.registry.values(), key=lambda e: e.name)
468
 
    object_types = sorted(obj_type_factory.registry.values(), key=lambda e: e.name)
469
 
 
470
 
    for template, file_ in [(C_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.c')),
471
 
                            (H_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.h')),
472
 
                            (H_DEFINE_TEMPLATE, os.path.join(args.outdir, 'vk_enum_defines.h'))]:
473
 
        with open(file_, 'w', encoding='utf-8') as f:
474
 
            f.write(template.render(
475
 
                file=os.path.basename(__file__),
476
 
                enums=enums,
477
 
                extensions=extensions,
478
 
                structs=structs,
479
 
                bitmasks=bitmasks,
480
 
                object_types=object_types,
481
 
                copyright=COPYRIGHT))
482
 
 
483
 
 
484
 
if __name__ == '__main__':
485
 
    main()