1# Copyright 2020 Intel Corporation 2# 3# Permission is hereby granted, free of charge, to any person obtaining a 4# copy of this software and associated documentation files (the 5# "Software"), to deal in the Software without restriction, including 6# without limitation the rights to use, copy, modify, merge, publish, 7# distribute, sub license, and/or sell copies of the Software, and to 8# permit persons to whom the Software is furnished to do so, subject to 9# the following conditions: 10# 11# The above copyright notice and this permission notice (including the 12# next paragraph) shall be included in all copies or substantial portions 13# of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 18# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 19# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23import xml.etree.ElementTree as et 24 25from collections import OrderedDict, namedtuple 26 27# Mesa-local imports must be declared in meson variable 28# '{file_without_suffix}_depend_files'. 29from vk_extensions import Extension, VkVersion 30 31EntrypointParam = namedtuple('EntrypointParam', 'type name decl len') 32 33class EntrypointBase: 34 def __init__(self, name): 35 assert name.startswith('vk') 36 self.name = name[2:] 37 self.alias = None 38 self.guard = None 39 self.entry_table_index = None 40 # Extensions which require this entrypoint 41 self.core_version = None 42 self.extensions = [] 43 44 def prefixed_name(self, prefix): 45 return prefix + '_' + self.name 46 47class Entrypoint(EntrypointBase): 48 def __init__(self, name, return_type, params, guard=None): 49 super(Entrypoint, self).__init__(name) 50 self.return_type = return_type 51 self.params = params 52 self.guard = guard 53 self.aliases = [] 54 self.disp_table_index = None 55 56 def is_physical_device_entrypoint(self): 57 return self.params[0].type in ('VkPhysicalDevice', ) 58 59 def is_device_entrypoint(self): 60 return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue') 61 62 def decl_params(self, start=0): 63 return ', '.join(p.decl for p in self.params[start:]) 64 65 def call_params(self, start=0): 66 return ', '.join(p.name for p in self.params[start:]) 67 68class EntrypointAlias(EntrypointBase): 69 def __init__(self, name, entrypoint): 70 super(EntrypointAlias, self).__init__(name) 71 self.alias = entrypoint 72 entrypoint.aliases.append(self) 73 74 def is_physical_device_entrypoint(self): 75 return self.alias.is_physical_device_entrypoint() 76 77 def is_device_entrypoint(self): 78 return self.alias.is_device_entrypoint() 79 80 def prefixed_name(self, prefix): 81 return self.alias.prefixed_name(prefix) 82 83 @property 84 def params(self): 85 return self.alias.params 86 87 @property 88 def return_type(self): 89 return self.alias.return_type 90 91 @property 92 def disp_table_index(self): 93 return self.alias.disp_table_index 94 95 def decl_params(self): 96 return self.alias.decl_params() 97 98 def call_params(self): 99 return self.alias.call_params() 100 101def get_entrypoints(doc, entrypoints_to_defines): 102 """Extract the entry points from the registry.""" 103 entrypoints = OrderedDict() 104 105 for command in doc.findall('./commands/command'): 106 if 'alias' in command.attrib: 107 alias = command.attrib['name'] 108 target = command.attrib['alias'] 109 entrypoints[alias] = EntrypointAlias(alias, entrypoints[target]) 110 else: 111 name = command.find('./proto/name').text 112 ret_type = command.find('./proto/type').text 113 params = [EntrypointParam( 114 type=p.find('./type').text, 115 name=p.find('./name').text, 116 decl=''.join(p.itertext()), 117 len=p.attrib.get('len', None) 118 ) for p in command.findall('./param')] 119 guard = entrypoints_to_defines.get(name) 120 # They really need to be unique 121 assert name not in entrypoints 122 entrypoints[name] = Entrypoint(name, ret_type, params, guard) 123 124 for feature in doc.findall('./feature'): 125 assert feature.attrib['api'] == 'vulkan' 126 version = VkVersion(feature.attrib['number']) 127 for command in feature.findall('./require/command'): 128 e = entrypoints[command.attrib['name']] 129 assert e.core_version is None 130 e.core_version = version 131 132 for extension in doc.findall('.extensions/extension'): 133 if extension.attrib['supported'] != 'vulkan': 134 continue 135 136 ext_name = extension.attrib['name'] 137 138 ext = Extension(ext_name, 1, True) 139 ext.type = extension.attrib['type'] 140 141 for command in extension.findall('./require/command'): 142 e = entrypoints[command.attrib['name']] 143 assert e.core_version is None 144 e.extensions.append(ext) 145 146 return entrypoints.values() 147 148 149def get_entrypoints_defines(doc): 150 """Maps entry points to extension defines.""" 151 entrypoints_to_defines = {} 152 153 platform_define = {} 154 for platform in doc.findall('./platforms/platform'): 155 name = platform.attrib['name'] 156 define = platform.attrib['protect'] 157 platform_define[name] = define 158 159 for extension in doc.findall('./extensions/extension[@platform]'): 160 platform = extension.attrib['platform'] 161 define = platform_define[platform] 162 163 for entrypoint in extension.findall('./require/command'): 164 fullname = entrypoint.attrib['name'] 165 entrypoints_to_defines[fullname] = define 166 167 return entrypoints_to_defines 168 169def get_entrypoints_from_xml(xml_files): 170 entrypoints = [] 171 172 for filename in xml_files: 173 doc = et.parse(filename) 174 entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc)) 175 176 return entrypoints 177