• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# encoding=utf-8
2# Copyright © 2017 Intel Corporation
3
4# Permission is hereby granted, free of charge, to any person obtaining a copy
5# of this software and associated documentation files (the "Software"), to deal
6# in the Software without restriction, including without limitation the rights
7# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8# copies of the Software, and to permit persons to whom the Software is
9# furnished to do so, subject to the following conditions:
10
11# The above copyright notice and this permission notice shall be included in
12# all copies or substantial portions of the Software.
13
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20# SOFTWARE.
21
22"""Create enum to string functions for vulkan using vk.xml."""
23
24from __future__ import print_function
25import argparse
26import os
27import textwrap
28import xml.etree.cElementTree as et
29
30from mako.template import Template
31
32COPYRIGHT = 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
53C_TEMPLATE = Template(textwrap.dedent(u"""\
54    /* Autogenerated file -- do not edit
55     * generated by ${file}
56     *
57     ${copyright}
58     */
59
60    #include <vulkan/vulkan.h>
61    #include <vulkan/vk_android_native_buffer.h>
62    #include "util/macros.h"
63    #include "vk_enum_to_str.h"
64
65    % for enum in enums:
66
67    const char *
68    vk_${enum.name[2:]}_to_str(${enum.name} input)
69    {
70        switch(input) {
71        % for v in sorted(enum.values.keys()):
72            % if enum.values[v] in FOREIGN_ENUM_VALUES:
73
74            #pragma GCC diagnostic push
75            #pragma GCC diagnostic ignored "-Wswitch"
76            % endif
77            case ${v}:
78                return "${enum.values[v]}";
79            % if enum.values[v] in FOREIGN_ENUM_VALUES:
80            #pragma GCC diagnostic pop
81
82            % endif
83        % endfor
84        default:
85            unreachable("Undefined enum value.");
86        }
87    }
88    %endfor"""),
89    output_encoding='utf-8')
90
91H_TEMPLATE = Template(textwrap.dedent(u"""\
92    /* Autogenerated file -- do not edit
93     * generated by ${file}
94     *
95     ${copyright}
96     */
97
98    #ifndef MESA_VK_ENUM_TO_STR_H
99    #define MESA_VK_ENUM_TO_STR_H
100
101    #include <vulkan/vulkan.h>
102    #include <vulkan/vk_android_native_buffer.h>
103
104    % for ext in extensions:
105    #define _${ext.name}_number (${ext.number})
106    % endfor
107
108    % for enum in enums:
109    const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
110    % endfor
111
112    #endif"""),
113    output_encoding='utf-8')
114
115# These enums are defined outside their respective enum blocks, and thus cause
116# -Wswitch warnings.
117FOREIGN_ENUM_VALUES = [
118    "VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID",
119]
120
121
122class NamedFactory(object):
123    """Factory for creating enums."""
124
125    def __init__(self, type_):
126        self.registry = {}
127        self.type = type_
128
129    def __call__(self, name, **kwargs):
130        try:
131            return self.registry[name]
132        except KeyError:
133            n = self.registry[name] = self.type(name, **kwargs)
134        return n
135
136    def get(self, name):
137        return self.registry.get(name)
138
139
140class VkExtension(object):
141    """Simple struct-like class representing extensions"""
142
143    def __init__(self, name, number=None):
144        self.name = name
145        self.number = number
146
147
148class VkEnum(object):
149    """Simple struct-like class representing a single Vulkan Enum."""
150
151    def __init__(self, name, values=None):
152        self.name = name
153        # Maps numbers to names
154        self.values = values or dict()
155
156    def add_value(self, name, value=None,
157                  extension=None, offset=None,
158                  error=False):
159        assert value is not None or extension is not None
160        if value is None:
161            value = 1000000000 + (extension.number - 1) * 1000 + offset
162            if error:
163                value = -value
164
165        if value not in self.values:
166            self.values[value] = name
167
168
169def parse_xml(enum_factory, ext_factory, filename):
170    """Parse the XML file. Accumulate results into the factories.
171
172    This parser is a memory efficient iterative XML parser that returns a list
173    of VkEnum objects.
174    """
175
176    xml = et.parse(filename)
177
178    for enum_type in xml.findall('./enums[@type="enum"]'):
179        enum = enum_factory(enum_type.attrib['name'])
180        for value in enum_type.findall('./enum'):
181            enum.add_value(value.attrib['name'],
182                           value=int(value.attrib['value']))
183
184    for ext_elem in xml.findall('./extensions/extension[@supported="vulkan"]'):
185        extension = ext_factory(ext_elem.attrib['name'],
186                                number=int(ext_elem.attrib['number']))
187
188        for value in ext_elem.findall('./require/enum[@extends]'):
189            enum = enum_factory.get(value.attrib['extends'])
190            if enum is None:
191                continue
192            if 'value' in value.attrib:
193                enum.add_value(value.attrib['name'],
194                               value=int(value.attrib['value']))
195            else:
196                error = 'dir' in value.attrib and value.attrib['dir'] == '-'
197                enum.add_value(value.attrib['name'],
198                               extension=extension,
199                               offset=int(value.attrib['offset']),
200                               error=error)
201
202
203def main():
204    parser = argparse.ArgumentParser()
205    parser.add_argument('--xml', required=True,
206                        help='Vulkan API XML files',
207                        action='append',
208                        dest='xml_files')
209    parser.add_argument('--outdir',
210                        help='Directory to put the generated files in',
211                        required=True)
212
213    args = parser.parse_args()
214
215    enum_factory = NamedFactory(VkEnum)
216    ext_factory = NamedFactory(VkExtension)
217    for filename in args.xml_files:
218        parse_xml(enum_factory, ext_factory, filename)
219    enums = sorted(enum_factory.registry.values(), key=lambda e: e.name)
220    extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name)
221
222    for template, file_ in [(C_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.c')),
223                            (H_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.h'))]:
224        with open(file_, 'wb') as f:
225            f.write(template.render(
226                file=os.path.basename(__file__),
227                enums=enums,
228                extensions=extensions,
229                copyright=COPYRIGHT,
230                FOREIGN_ENUM_VALUES=FOREIGN_ENUM_VALUES))
231
232
233if __name__ == '__main__':
234    main()
235