1COPYRIGHT=u""" 2/* Copyright © 2021 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23""" 24 25import argparse 26import os 27from collections import OrderedDict, namedtuple 28import xml.etree.ElementTree as et 29 30from mako.template import Template 31 32TEMPLATE_C = Template(COPYRIGHT + """ 33/* This file generated from ${filename}, don't edit directly. */ 34 35#include "vk_log.h" 36#include "vk_physical_device.h" 37#include "vk_util.h" 38 39static VkResult 40check_physical_device_features(struct vk_physical_device *physical_device, 41 const VkPhysicalDeviceFeatures *supported, 42 const VkPhysicalDeviceFeatures *enabled, 43 const char *struct_name) 44{ 45% for flag in pdev_features: 46 if (enabled->${flag} && !supported->${flag}) 47 return vk_errorf(physical_device, VK_ERROR_FEATURE_NOT_PRESENT, 48 "%s.%s not supported", struct_name, "${flag}"); 49% endfor 50 51 return VK_SUCCESS; 52} 53 54VkResult 55vk_physical_device_check_device_features(struct vk_physical_device *physical_device, 56 const VkDeviceCreateInfo *pCreateInfo) 57{ 58 VkPhysicalDevice vk_physical_device = 59 vk_physical_device_to_handle(physical_device); 60 61 /* Query the device what kind of features are supported. */ 62 VkPhysicalDeviceFeatures2 supported_features2 = { 63 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, 64 }; 65 66% for f in features: 67 ${f.name} supported_${f.name} = { .pNext = NULL }; 68% endfor 69 70 vk_foreach_struct_const(feat, pCreateInfo->pNext) { 71 VkBaseOutStructure *supported = NULL; 72 switch (feat->sType) { 73% for f in features: 74 case ${f.vk_type}: 75 supported = (VkBaseOutStructure *) &supported_${f.name}; 76 break; 77% endfor 78 default: 79 break; 80 } 81 82 /* Not a feature struct. */ 83 if (!supported) 84 continue; 85 86 /* Check for cycles in the list */ 87 if (supported->pNext != NULL || supported->sType != 0) 88 return VK_ERROR_UNKNOWN; 89 90 supported->sType = feat->sType; 91 __vk_append_struct(&supported_features2, supported); 92 } 93 94 physical_device->dispatch_table.GetPhysicalDeviceFeatures2( 95 vk_physical_device, &supported_features2); 96 97 if (pCreateInfo->pEnabledFeatures) { 98 VkResult result = 99 check_physical_device_features(physical_device, 100 &supported_features2.features, 101 pCreateInfo->pEnabledFeatures, 102 "VkPhysicalDeviceFeatures"); 103 if (result != VK_SUCCESS) 104 return result; 105 } 106 107 /* Iterate through additional feature structs */ 108 vk_foreach_struct_const(feat, pCreateInfo->pNext) { 109 /* Check each feature boolean for given structure. */ 110 switch (feat->sType) { 111 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: { 112 const VkPhysicalDeviceFeatures2 *features2 = (const void *)feat; 113 VkResult result = 114 check_physical_device_features(physical_device, 115 &supported_features2.features, 116 &features2->features, 117 "VkPhysicalDeviceFeatures2.features"); 118 if (result != VK_SUCCESS) 119 return result; 120 break; 121 } 122% for f in features: 123 case ${f.vk_type} : { 124 ${f.name} *a = &supported_${f.name}; 125 ${f.name} *b = (${f.name} *) feat; 126% for flag in f.vk_flags: 127 if (b->${flag} && !a->${flag}) 128 return vk_errorf(physical_device, VK_ERROR_FEATURE_NOT_PRESENT, 129 "%s.%s not supported", "${f.name}", "${flag}"); 130% endfor 131 break; 132 } 133% endfor 134 default: 135 break; 136 } 137 } // for each extension structure 138 return VK_SUCCESS; 139} 140 141""", output_encoding='utf-8') 142 143Feature = namedtuple('Feature', 'name vk_type vk_flags') 144 145def get_pdev_features(doc): 146 for _type in doc.findall('./types/type'): 147 if _type.attrib.get('name') != 'VkPhysicalDeviceFeatures': 148 continue 149 150 flags = [] 151 152 for p in _type.findall('./member'): 153 assert p.find('./type').text == 'VkBool32' 154 flags.append(p.find('./name').text) 155 156 return flags 157 158 return None 159 160def get_features(doc): 161 features = OrderedDict() 162 163 provisional_structs = set() 164 165 # we want to ignore struct types that are part of provisional extensions 166 for _extension in doc.findall('./extensions/extension'): 167 if _extension.attrib.get('provisional') != 'true': 168 continue 169 for p in _extension.findall('./require/type'): 170 provisional_structs.add(p.attrib.get('name')) 171 172 # parse all struct types where structextends VkPhysicalDeviceFeatures2 173 for _type in doc.findall('./types/type'): 174 if _type.attrib.get('category') != 'struct': 175 continue 176 if _type.attrib.get('structextends') != 'VkPhysicalDeviceFeatures2,VkDeviceCreateInfo': 177 continue 178 if _type.attrib.get('name') in provisional_structs: 179 continue 180 181 # find Vulkan structure type 182 for elem in _type: 183 if "STRUCTURE_TYPE" in str(elem.attrib): 184 s_type = elem.attrib.get('values') 185 186 # collect a list of feature flags 187 flags = [] 188 189 for p in _type.findall('./member'): 190 m_name = p.find('./name').text 191 if m_name == 'pNext': 192 pass 193 elif m_name == 'sType': 194 s_type = p.attrib.get('values') 195 else: 196 assert p.find('./type').text == 'VkBool32' 197 flags.append(m_name) 198 199 feat = Feature(name=_type.attrib.get('name'), vk_type=s_type, vk_flags=flags) 200 features[_type.attrib.get('name')] = feat 201 202 return features.values() 203 204def get_features_from_xml(xml_files): 205 pdev_features = None 206 features = [] 207 208 for filename in xml_files: 209 doc = et.parse(filename) 210 features += get_features(doc) 211 if not pdev_features: 212 pdev_features = get_pdev_features(doc) 213 214 return pdev_features, features 215 216 217def main(): 218 parser = argparse.ArgumentParser() 219 parser.add_argument('--out-c', required=True, help='Output C file.') 220 parser.add_argument('--xml', 221 help='Vulkan API XML file.', 222 required=True, action='append', dest='xml_files') 223 args = parser.parse_args() 224 225 pdev_features, features = get_features_from_xml(args.xml_files) 226 227 environment = { 228 'filename': os.path.basename(__file__), 229 'pdev_features': pdev_features, 230 'features': features, 231 } 232 233 try: 234 with open(args.out_c, 'wb') as f: 235 f.write(TEMPLATE_C.render(**environment)) 236 except Exception: 237 # In the event there's an error, this imports some helpers from mako 238 # to print a useful stack trace and prints it, then exits with 239 # status 1, if python is run with debug; otherwise it just raises 240 # the exception 241 import sys 242 from mako import exceptions 243 print(exceptions.text_error_template().render(), file=sys.stderr) 244 sys.exit(1) 245 246if __name__ == '__main__': 247 main() 248