meson: only build imgui when needed
[mesa.git] / src / vulkan / util / gen_enum_to_str.py
index 8c11569b6aed3dda75079116efae832b3762151c..b65bc7f7ef64f166130fce073b7becc6b9be8d5d 100644 (file)
@@ -19,7 +19,7 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
-"""Create enum to string functions for vulking using vk.xml."""
+"""Create enum to string functions for vulkan using vk.xml."""
 
 from __future__ import print_function
 import argparse
@@ -29,8 +29,6 @@ import xml.etree.cElementTree as et
 
 from mako.template import Template
 
-VK_XML = os.path.join(os.path.dirname(__file__), '..', 'registry', 'vk.xml')
-
 COPYRIGHT = textwrap.dedent(u"""\
     * Copyright © 2017 Intel Corporation
     *
@@ -59,25 +57,94 @@ C_TEMPLATE = Template(textwrap.dedent(u"""\
      ${copyright}
      */
 
+    #include <string.h>
     #include <vulkan/vulkan.h>
+    #include <vulkan/vk_android_native_buffer.h>
     #include "util/macros.h"
     #include "vk_enum_to_str.h"
 
     % for enum in enums:
 
-        const char *
-        vk_${enum.name[2:]}_to_str(${enum.name} input)
-        {
-            switch(input) {
-            % for v in enum.values:
-                case ${v}:
-                    return "${v}";
-            % endfor
-            default:
-                unreachable("Undefined enum value.");
-            }
+      % if enum.guard:
+#ifdef ${enum.guard}
+      % endif
+    const char *
+    vk_${enum.name[2:]}_to_str(${enum.name} input)
+    {
+        #pragma GCC diagnostic push
+        #pragma GCC diagnostic ignored "-Wswitch"
+        switch(input) {
+        % for v in sorted(enum.values.keys()):
+            case ${v}:
+                return "${enum.values[v]}";
+        % endfor
+        }
+        #pragma GCC diagnostic pop
+        unreachable("Undefined enum value.");
+    }
+
+      % if enum.guard:
+#endif
+      % endif
+    %endfor
+
+    size_t vk_structure_type_size(const struct VkBaseInStructure *item)
+    {
+        #pragma GCC diagnostic push
+        #pragma GCC diagnostic ignored "-Wswitch"
+        switch(item->sType) {
+    % for struct in structs:
+        % if struct.extension is not None and struct.extension.define is not None:
+    #ifdef ${struct.extension.define}
+        case ${struct.stype}: return sizeof(${struct.name});
+    #endif
+        % else:
+        case ${struct.stype}: return sizeof(${struct.name});
+        % endif
+    %endfor
         }
-    %endfor"""),
+        #pragma GCC diagnostic pop
+        unreachable("Undefined struct type.");
+    }
+
+    void vk_load_instance_commands(VkInstance instance,
+                                   PFN_vkGetInstanceProcAddr gpa,
+                                   struct vk_instance_dispatch_table *table)
+    {
+        memset(table, 0, sizeof(*table));
+        table->GetInstanceProcAddr = gpa;
+    % for cmd in commands:
+        % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
+            % if cmd.extension is not None and cmd.extension.define is not None:
+    #ifdef ${cmd.extension.define}
+        table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
+    #endif
+            % else:
+        table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
+            % endif
+        % endif
+    %endfor
+    }
+
+    void vk_load_device_commands(VkDevice device,
+                                 PFN_vkGetDeviceProcAddr gpa,
+                                 struct vk_device_dispatch_table *table)
+    {
+        memset(table, 0, sizeof(*table));
+        table->GetDeviceProcAddr = gpa;
+    % for cmd in commands:
+        % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
+            % if cmd.extension is not None and cmd.extension.define is not None:
+    #ifdef ${cmd.extension.define}
+        table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
+    #endif
+            % else:
+        table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
+            % endif
+        % endif
+    %endfor
+    }
+    """),
     output_encoding='utf-8')
 
 H_TEMPLATE = Template(textwrap.dedent(u"""\
@@ -91,88 +158,270 @@ H_TEMPLATE = Template(textwrap.dedent(u"""\
     #define MESA_VK_ENUM_TO_STR_H
 
     #include <vulkan/vulkan.h>
+    #include <vulkan/vk_android_native_buffer.h>
+
+    #ifdef __cplusplus
+    extern "C" {
+    #endif
+
+    % for ext in extensions:
+    #define _${ext.name}_number (${ext.number})
+    % endfor
 
     % for enum in enums:
-        const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
+      % if enum.guard:
+#ifdef ${enum.guard}
+      % endif
+    const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
+      % if enum.guard:
+#endif
+      % endif
     % endfor
 
+    size_t vk_structure_type_size(const struct VkBaseInStructure *item);
+
+    struct vk_instance_dispatch_table {
+        PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+    % for cmd in commands:
+        % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
+            % if cmd.extension is not None and cmd.extension.define is not None:
+    #ifdef ${cmd.extension.define}
+        PFN_${cmd.name} ${cmd.name[2:]};
+    #endif
+            % else:
+        PFN_${cmd.name} ${cmd.name[2:]};
+            % endif
+        % endif
+    %endfor
+    };
+
+    struct vk_device_dispatch_table {
+        PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
+    % for cmd in commands:
+        % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
+            % if cmd.extension is not None and cmd.extension.define is not None:
+    #ifdef ${cmd.extension.define}
+        PFN_${cmd.name} ${cmd.name[2:]};
+    #endif
+            % else:
+        PFN_${cmd.name} ${cmd.name[2:]};
+            % endif
+        % endif
+    %endfor
+    };
+
+    void vk_load_instance_commands(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, struct vk_instance_dispatch_table *table);
+    void vk_load_device_commands(VkDevice device, PFN_vkGetDeviceProcAddr gpa, struct vk_device_dispatch_table *table);
+
+    #ifdef __cplusplus
+    } /* extern "C" */
+    #endif
+
     #endif"""),
     output_encoding='utf-8')
 
 
-class EnumFactory(object):
+class NamedFactory(object):
     """Factory for creating enums."""
 
     def __init__(self, type_):
         self.registry = {}
         self.type = type_
 
-    def __call__(self, name):
+    def __call__(self, name, **kwargs):
         try:
             return self.registry[name]
         except KeyError:
-            n = self.registry[name] = self.type(name)
+            n = self.registry[name] = self.type(name, **kwargs)
         return n
 
+    def get(self, name):
+        return self.registry.get(name)
+
+
+class VkExtension(object):
+    """Simple struct-like class representing extensions"""
+
+    def __init__(self, name, number=None, define=None):
+        self.name = name
+        self.number = number
+        self.define = define
+
 
 class VkEnum(object):
     """Simple struct-like class representing a single Vulkan Enum."""
 
     def __init__(self, name, values=None):
         self.name = name
-        self.values = values or []
+        self.extension = None
+        # Maps numbers to names
+        self.values = values or dict()
+        self.name_to_value = dict()
+        self.guard = None
+
+    def add_value(self, name, value=None,
+                  extnum=None, offset=None,
+                  error=False):
+        assert value is not None or extnum is not None
+        if value is None:
+            value = 1000000000 + (extnum - 1) * 1000 + offset
+            if error:
+                value = -value
+
+        self.name_to_value[name] = value
+        if value not in self.values:
+            self.values[value] = name
+        elif len(self.values[value]) > len(name):
+            self.values[value] = name
+
+    def add_value_from_xml(self, elem, extension=None):
+        self.extension = extension
+        if 'value' in elem.attrib:
+            self.add_value(elem.attrib['name'],
+                           value=int(elem.attrib['value'], base=0))
+        elif 'alias' in elem.attrib:
+            self.add_value(elem.attrib['name'],
+                           value=self.name_to_value[elem.attrib['alias']])
+        else:
+            error = 'dir' in elem.attrib and elem.attrib['dir'] == '-'
+            if 'extnumber' in elem.attrib:
+                extnum = int(elem.attrib['extnumber'])
+            else:
+                extnum = extension.number
+            self.add_value(elem.attrib['name'],
+                           extnum=extnum,
+                           offset=int(elem.attrib['offset']),
+                           error=error)
+
+    def set_guard(self, g):
+        self.guard = g
+
+
+class VkCommand(object):
+    """Simple struct-like class representing a single Vulkan command"""
+
+    def __init__(self, name, device_entrypoint=False):
+        self.name = name
+        self.device_entrypoint = device_entrypoint
+        self.extension = None
 
 
-def xml_parser(filename):
-    """Parse the XML file and return parsed data.
+class VkChainStruct(object):
+    """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType"""
+    def __init__(self, name, stype):
+        self.name = name
+        self.stype = stype
+        self.extension = None
 
-    This parser is a memory efficient iterative XML parser that returns a list
-    of VkEnum objects.
-    """
-    efactory = EnumFactory(VkEnum)
 
-    with open(filename, 'rb') as f:
-        context = iter(et.iterparse(f, events=('start', 'end')))
+def struct_get_stype(xml_node):
+    for member in xml_node.findall('./member'):
+        name = member.findall('./name')
+        if len(name) > 0 and name[0].text == "sType":
+            return member.get('values')
+    return None
 
-        # This gives the root element, since goal is to iterate over the
-        # elements without building a tree, this allows the root to be cleared
-        # (erase the elements) after the children have been processed.
-        _, root = next(context)
 
-        for event, elem in context:
-            if event == 'end' and elem.tag == 'enums':
-                type_ = elem.attrib.get('type')
-                if type_ == 'enum':
-                    enum = efactory(elem.attrib['name'])
-                    enum.values.extend([e.attrib['name'] for e in elem
-                                        if e.tag == 'enum'])
-            elif event == 'end' and elem.tag == 'extension':
-                if elem.attrib['supported'] != 'vulkan':
-                    continue
-                for e in elem.findall('.//enum[@extends][@offset]'):
-                    enum = efactory(e.attrib['extends'])
-                    enum.values.append(e.attrib['name'])
+def parse_xml(cmd_factory, enum_factory, ext_factory, struct_factory, filename):
+    """Parse the XML file. Accumulate results into the factories.
 
-            root.clear()
+    This parser is a memory efficient iterative XML parser that returns a list
+    of VkEnum objects.
+    """
 
-    return efactory.registry.values()
+    xml = et.parse(filename)
+
+    for enum_type in xml.findall('./enums[@type="enum"]'):
+        enum = enum_factory(enum_type.attrib['name'])
+        for value in enum_type.findall('./enum'):
+            enum.add_value_from_xml(value)
+
+    for value in xml.findall('./feature/require/enum[@extends]'):
+        enum = enum_factory.get(value.attrib['extends'])
+        if enum is not None:
+            enum.add_value_from_xml(value)
+
+    for command in xml.findall('./commands/command'):
+        name = command.find('./proto/name')
+        first_arg = command.find('./param/type')
+        # Some commands are alias KHR -> nonKHR, ignore those
+        if name is not None:
+            cmd_factory(name.text,
+                        device_entrypoint=(first_arg.text in ('VkDevice', 'VkCommandBuffer', 'VkQueue')))
+
+    for struct_type in xml.findall('./types/type[@category="struct"]'):
+        name = struct_type.attrib['name']
+        stype = struct_get_stype(struct_type)
+        if stype is not None:
+            struct_factory(name, stype=stype)
+
+    platform_define = {}
+    for platform in xml.findall('./platforms/platform'):
+        name = platform.attrib['name']
+        define = platform.attrib['protect']
+        platform_define[name] = define
+
+    for ext_elem in xml.findall('./extensions/extension[@supported="vulkan"]'):
+        define = None
+        if "platform" in ext_elem.attrib:
+            define = platform_define[ext_elem.attrib['platform']]
+        extension = ext_factory(ext_elem.attrib['name'],
+                                number=int(ext_elem.attrib['number']),
+                                define=define)
+
+        for value in ext_elem.findall('./require/enum[@extends]'):
+            enum = enum_factory.get(value.attrib['extends'])
+            if enum is not None:
+                enum.add_value_from_xml(value, extension)
+        for t in ext_elem.findall('./require/type'):
+            struct = struct_factory.get(t.attrib['name'])
+            if struct is not None:
+                struct.extension = extension
+
+        if define:
+            for value in ext_elem.findall('./require/type[@name]'):
+                enum = enum_factory.get(value.attrib['name'])
+                if enum is not None:
+                    enum.set_guard(define)
+
+        for t in ext_elem.findall('./require/command'):
+            command = cmd_factory.get(t.attrib['name'])
+            if command is not None:
+                command.extension = extension
 
 
 def main():
     parser = argparse.ArgumentParser()
+    parser.add_argument('--xml', required=True,
+                        help='Vulkan API XML files',
+                        action='append',
+                        dest='xml_files')
     parser.add_argument('--outdir',
                         help='Directory to put the generated files in',
                         required=True)
 
     args = parser.parse_args()
 
-    enums = xml_parser(VK_XML)
+    command_factory = NamedFactory(VkCommand)
+    enum_factory = NamedFactory(VkEnum)
+    ext_factory = NamedFactory(VkExtension)
+    struct_factory = NamedFactory(VkChainStruct)
+    for filename in args.xml_files:
+        parse_xml(command_factory, enum_factory, ext_factory, struct_factory, filename)
+    commands = sorted(command_factory.registry.values(), key=lambda e: e.name)
+    enums = sorted(enum_factory.registry.values(), key=lambda e: e.name)
+    extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name)
+    structs = sorted(struct_factory.registry.values(), key=lambda e: e.name)
+
     for template, file_ in [(C_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.c')),
                             (H_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.h'))]:
         with open(file_, 'wb') as f:
             f.write(template.render(
                 file=os.path.basename(__file__),
+                commands=commands,
                 enums=enums,
+                extensions=extensions,
+                structs=structs,
                 copyright=COPYRIGHT))