#!/usr/bin/env python3 # # This file is part of libplacebo. # # libplacebo is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # libplacebo is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with libplacebo. If not, see . import os.path import re import sys import xml.etree.ElementTree as ET try: import jinja2 except ModuleNotFoundError: print('Module \'jinja2\' not found, please install \'python3-Jinja2\' or ' 'an equivalent package on your system! Alternatively, run ' '`git submodule update --init` followed by `meson --wipe`.', file=sys.stderr) sys.exit(1) TEMPLATE = jinja2.Environment( loader = jinja2.FileSystemLoader(searchpath=os.path.dirname(__file__)), trim_blocks=True, ).get_template('utils_gen.c.j2') class Obj(object): def __init__(self, **kwargs): self.__dict__.update(kwargs) class VkXML(ET.ElementTree): def blacklist_block(self, req): for t in req.iterfind('type'): self.blacklist_types.add(t.attrib['name']) for e in req.iterfind('enum'): self.blacklist_enums.add(e.attrib['name']) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.blacklist_types = set() self.blacklist_enums = set() for f in self.iterfind('feature'): # Feature block for non-Vulkan API if not 'vulkan' in f.attrib['api'].split(','): for r in f.iterfind('require'): self.blacklist_block(r) for e in self.iterfind('extensions/extension'): # Entire extension is unsupported on vulkan or platform-specifid if not 'vulkan' in e.attrib['supported'].split(',') or 'platform' in e.attrib: for r in e.iterfind('require'): self.blacklist_block(r) continue # Only individual blocks are API-specific for r in e.iterfind('require[@api]'): if not 'vulkan' in r.attrib['api'].split(','): self.blacklist_block(r) def findall_enum(self, name): for e in self.iterfind('enums[@name="{0}"]/enum'.format(name)): if not 'alias' in e.attrib: if not e.attrib['name'] in self.blacklist_enums: yield e for e in self.iterfind('.//enum[@extends="{0}"]'.format(name)): if not 'alias' in e.attrib: if not e.attrib['name'] in self.blacklist_enums: yield e def findall_type(self, category): for t in self.iterfind('types/type[@category="{0}"]'.format(category)): name = t.attrib.get('name') or t.find('name').text if name in self.blacklist_types: continue yield t def get_vkenum(registry, enum): for e in registry.findall_enum(enum): yield e.attrib['name'] def get_vkobjects(registry): for t in registry.findall_type('handle'): if 'objtypeenum' in t.attrib: yield Obj(enum = t.attrib['objtypeenum'], name = t.find('name').text) def get_vkstructs(registry): for t in registry.findall_type('struct'): stype = None for m in t.iterfind('member'): if m.find('name').text == 'sType': stype = m break if stype is not None and 'values' in stype.attrib: yield Obj(stype = stype.attrib['values'], name = t.attrib['name']) def get_vkaccess(registry): access = Obj(read = 0, write = 0) for e in registry.findall_enum('VkAccessFlagBits2'): if '_READ_' in e.attrib['name']: access.read |= 1 << int(e.attrib['bitpos']) if '_WRITE_' in e.attrib['name']: access.write |= 1 << int(e.attrib['bitpos']) return access def get_vkexts(registry): for e in registry.iterfind('extensions/extension'): promoted_ver = None if res := re.match(r'VK_VERSION_(\d)_(\d)', e.attrib.get('promotedto', '')): promoted_ver = 'VK_API_VERSION_{0}_{1}'.format(res[1], res[2]) yield Obj(name = e.attrib['name'], promoted_ver = promoted_ver) def get_vkfeatures(registry): structs = []; featuremap = {}; # features -> [struct] for t in registry.findall_type('struct'): sname = t.attrib['name'] is_base = sname == 'VkPhysicalDeviceFeatures' extends = t.attrib.get('structextends', []) if is_base: sname = 'VkPhysicalDeviceFeatures2' stype = 'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2' elif not 'VkPhysicalDeviceFeatures2' in extends: continue features = [] for f in t.iterfind('member'): if f.find('type').text == 'VkStructureType': stype = f.attrib['values'] elif f.find('type').text == 'VkBool32': fname = f.find('name').text if is_base: fname = 'features.' + fname features.append(Obj(name = fname)) core_ver = None if res := re.match(r'VkPhysicalDeviceVulkan(\d)(\d)Features', sname): core_ver = 'VK_API_VERSION_{0}_{1}'.format(res[1], res[2]) struct = Obj(name = sname, stype = stype, core_ver = core_ver, is_base = is_base, features = features) structs.append(struct) for f in features: featuremap.setdefault(f.name, []).append(struct) for s in structs: for f in s.features: f.replacements = featuremap[f.name] core_ver = next(( r.core_ver for r in f.replacements if r.core_ver ), None) for r in f.replacements: if not r.core_ver: r.max_ver = core_ver yield from structs def find_registry_xml(datadir): registry_paths = [ '{0}/vulkan/registry/vk.xml'.format(datadir), '$MINGW_PREFIX/share/vulkan/registry/vk.xml', '%VULKAN_SDK%/share/vulkan/registry/vk.xml', '$VULKAN_SDK/share/vulkan/registry/vk.xml', '/usr/share/vulkan/registry/vk.xml', ] for p in registry_paths: path = os.path.expandvars(p) if os.path.isfile(path): print('Found vk.xml: {0}'.format(path)) return path print('Could not find the vulkan registry (vk.xml), please specify its ' 'location manually using the -Dvulkan-registry=/path/to/vk.xml ' 'option!', file=sys.stderr) sys.exit(1) if __name__ == '__main__': assert len(sys.argv) == 4 datadir = sys.argv[1] xmlfile = sys.argv[2] outfile = sys.argv[3] if not xmlfile or xmlfile == '': xmlfile = find_registry_xml(datadir) registry = VkXML(ET.parse(xmlfile)) with open(outfile, 'w') as f: f.write(TEMPLATE.render( vkresults = get_vkenum(registry, 'VkResult'), vkformats = get_vkenum(registry, 'VkFormat'), vkspaces = get_vkenum(registry, 'VkColorSpaceKHR'), vkhandles = get_vkenum(registry, 'VkExternalMemoryHandleTypeFlagBits'), vkalphas = get_vkenum(registry, 'VkCompositeAlphaFlagBitsKHR'), vktransforms = get_vkenum(registry, 'VkSurfaceTransformFlagBitsKHR'), vkobjects = get_vkobjects(registry), vkstructs = get_vkstructs(registry), vkaccess = get_vkaccess(registry), vkexts = get_vkexts(registry), vkfeatures = get_vkfeatures(registry), ))