1#!/usr/bin/python3 -i 2# 3# Copyright (c) 2015-2019 The Khronos Group Inc. 4# Copyright (c) 2015-2019 Valve Corporation 5# Copyright (c) 2015-2019 LunarG, Inc. 6# Copyright (c) 2015-2019 Google Inc. 7# 8# Licensed under the Apache License, Version 2.0 (the "License"); 9# you may not use this file except in compliance with the License. 10# You may obtain a copy of the License at 11# 12# http://www.apache.org/licenses/LICENSE-2.0 13# 14# Unless required by applicable law or agreed to in writing, software 15# distributed under the License is distributed on an "AS IS" BASIS, 16# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17# See the License for the specific language governing permissions and 18# limitations under the License. 19# 20# Author: Mark Lobodzinski <mark@lunarg.com> 21# Author: Tobin Ehlis <tobine@google.com> 22# Author: John Zulauf <jzulauf@lunarg.com> 23 24import os,re,sys 25import xml.etree.ElementTree as etree 26from generator import * 27from collections import namedtuple 28from common_codegen import * 29 30# 31# HelperFileOutputGeneratorOptions - subclass of GeneratorOptions. 32class HelperFileOutputGeneratorOptions(GeneratorOptions): 33 def __init__(self, 34 conventions = None, 35 filename = None, 36 directory = '.', 37 apiname = None, 38 profile = None, 39 versions = '.*', 40 emitversions = '.*', 41 defaultExtensions = None, 42 addExtensions = None, 43 removeExtensions = None, 44 emitExtensions = None, 45 sortProcedure = regSortFeatures, 46 prefixText = "", 47 genFuncPointers = True, 48 protectFile = True, 49 protectFeature = True, 50 apicall = '', 51 apientry = '', 52 apientryp = '', 53 alignFuncParam = 0, 54 library_name = '', 55 expandEnumerants = True, 56 helper_file_type = ''): 57 GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile, 58 versions, emitversions, defaultExtensions, 59 addExtensions, removeExtensions, emitExtensions, sortProcedure) 60 self.prefixText = prefixText 61 self.genFuncPointers = genFuncPointers 62 self.protectFile = protectFile 63 self.protectFeature = protectFeature 64 self.apicall = apicall 65 self.apientry = apientry 66 self.apientryp = apientryp 67 self.alignFuncParam = alignFuncParam 68 self.library_name = library_name 69 self.helper_file_type = helper_file_type 70# 71# HelperFileOutputGenerator - subclass of OutputGenerator. Outputs Vulkan helper files 72class HelperFileOutputGenerator(OutputGenerator): 73 """Generate helper file based on XML element attributes""" 74 def __init__(self, 75 errFile = sys.stderr, 76 warnFile = sys.stderr, 77 diagFile = sys.stdout): 78 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 79 # Internal state - accumulators for different inner block text 80 self.enum_output = '' # string built up of enum string routines 81 # Internal state - accumulators for different inner block text 82 self.structNames = [] # List of Vulkan struct typenames 83 self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType 84 self.structMembers = [] # List of StructMemberData records for all Vulkan structs 85 self.object_types = [] # List of all handle types 86 self.object_type_aliases = [] # Aliases to handles types (for handles that were extensions) 87 self.debug_report_object_types = [] # Handy copy of debug_report_object_type enum data 88 self.core_object_types = [] # Handy copy of core_object_type enum data 89 self.device_extension_info = dict() # Dict of device extension name defines and ifdef values 90 self.instance_extension_info = dict() # Dict of instance extension name defines and ifdef values 91 self.structextends_list = [] # List of structs which extend another struct via pNext 92 93 94 # Named tuples to store struct and command data 95 self.StructType = namedtuple('StructType', ['name', 'value']) 96 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl']) 97 self.StructMemberData = namedtuple('StructMemberData', ['name', 'members', 'ifdef_protect']) 98 99 self.custom_construct_params = { 100 # safe_VkGraphicsPipelineCreateInfo needs to know if subpass has color and\or depth\stencil attachments to use its pointers 101 'VkGraphicsPipelineCreateInfo' : 102 ', const bool uses_color_attachment, const bool uses_depthstencil_attachment', 103 # safe_VkPipelineViewportStateCreateInfo needs to know if viewport and scissor is dynamic to use its pointers 104 'VkPipelineViewportStateCreateInfo' : 105 ', const bool is_dynamic_viewports, const bool is_dynamic_scissors', 106 } 107 # 108 # Called once at the beginning of each run 109 def beginFile(self, genOpts): 110 OutputGenerator.beginFile(self, genOpts) 111 # Initialize members that require the tree 112 self.handle_types = GetHandleTypes(self.registry.tree) 113 # User-supplied prefix text, if any (list of strings) 114 self.helper_file_type = genOpts.helper_file_type 115 self.library_name = genOpts.library_name 116 # File Comment 117 file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' 118 file_comment += '// See helper_file_generator.py for modifications\n' 119 write(file_comment, file=self.outFile) 120 # Copyright Notice 121 copyright = '' 122 copyright += '\n' 123 copyright += '/***************************************************************************\n' 124 copyright += ' *\n' 125 copyright += ' * Copyright (c) 2015-2019 The Khronos Group Inc.\n' 126 copyright += ' * Copyright (c) 2015-2019 Valve Corporation\n' 127 copyright += ' * Copyright (c) 2015-2019 LunarG, Inc.\n' 128 copyright += ' * Copyright (c) 2015-2019 Google Inc.\n' 129 copyright += ' *\n' 130 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 131 copyright += ' * you may not use this file except in compliance with the License.\n' 132 copyright += ' * You may obtain a copy of the License at\n' 133 copyright += ' *\n' 134 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 135 copyright += ' *\n' 136 copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 137 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 138 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 139 copyright += ' * See the License for the specific language governing permissions and\n' 140 copyright += ' * limitations under the License.\n' 141 copyright += ' *\n' 142 copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n' 143 copyright += ' * Author: Courtney Goeltzenleuchter <courtneygo@google.com>\n' 144 copyright += ' * Author: Tobin Ehlis <tobine@google.com>\n' 145 copyright += ' * Author: Chris Forbes <chrisforbes@google.com>\n' 146 copyright += ' * Author: John Zulauf<jzulauf@lunarg.com>\n' 147 copyright += ' *\n' 148 copyright += ' ****************************************************************************/\n' 149 write(copyright, file=self.outFile) 150 # 151 # Write generated file content to output file 152 def endFile(self): 153 dest_file = '' 154 dest_file += self.OutputDestFile() 155 # Remove blank lines at EOF 156 if dest_file.endswith('\n'): 157 dest_file = dest_file[:-1] 158 write(dest_file, file=self.outFile); 159 # Finish processing in superclass 160 OutputGenerator.endFile(self) 161 # 162 # Override parent class to be notified of the beginning of an extension 163 def beginFeature(self, interface, emit): 164 # Start processing in superclass 165 OutputGenerator.beginFeature(self, interface, emit) 166 self.featureExtraProtect = GetFeatureProtect(interface) 167 168 if self.featureName == 'VK_VERSION_1_0' or self.featureName == 'VK_VERSION_1_1': 169 return 170 name = self.featureName 171 nameElem = interface[0][1] 172 name_define = nameElem.get('name') 173 if 'EXTENSION_NAME' not in name_define: 174 print("Error in vk.xml file -- extension name is not available") 175 requires = interface.get('requires') 176 if requires is not None: 177 required_extensions = requires.split(',') 178 else: 179 required_extensions = list() 180 info = { 'define': name_define, 'ifdef':self.featureExtraProtect, 'reqs':required_extensions } 181 if interface.get('type') == 'instance': 182 self.instance_extension_info[name] = info 183 else: 184 self.device_extension_info[name] = info 185 186 # 187 # Override parent class to be notified of the end of an extension 188 def endFeature(self): 189 # Finish processing in superclass 190 OutputGenerator.endFeature(self) 191 # 192 # Grab group (e.g. C "enum" type) info to output for enum-string conversion helper 193 def genGroup(self, groupinfo, groupName, alias): 194 OutputGenerator.genGroup(self, groupinfo, groupName, alias) 195 groupElem = groupinfo.elem 196 # For enum_string_header 197 if self.helper_file_type == 'enum_string_header': 198 value_set = set() 199 for elem in groupElem.findall('enum'): 200 if elem.get('supported') != 'disabled' and elem.get('alias') is None: 201 value_set.add(elem.get('name')) 202 if value_set != set(): 203 self.enum_output += self.GenerateEnumStringConversion(groupName, value_set) 204 elif self.helper_file_type == 'object_types_header': 205 if groupName == 'VkDebugReportObjectTypeEXT': 206 for elem in groupElem.findall('enum'): 207 if elem.get('supported') != 'disabled': 208 if elem.get('alias') is None: # TODO: Strangely the "alias" fn parameter does not work 209 item_name = elem.get('name') 210 if self.debug_report_object_types.count(item_name) == 0: # TODO: Strangely there are duplicates 211 self.debug_report_object_types.append(item_name) 212 elif groupName == 'VkObjectType': 213 for elem in groupElem.findall('enum'): 214 if elem.get('supported') != 'disabled': 215 if elem.get('alias') is None: # TODO: Strangely the "alias" fn parameter does not work 216 item_name = elem.get('name') 217 self.core_object_types.append(item_name) 218 219 # 220 # Called for each type -- if the type is a struct/union, grab the metadata 221 def genType(self, typeinfo, name, alias): 222 OutputGenerator.genType(self, typeinfo, name, alias) 223 typeElem = typeinfo.elem 224 # If the type is a struct type, traverse the imbedded <member> tags generating a structure. 225 # Otherwise, emit the tag text. 226 category = typeElem.get('category') 227 if category == 'handle': 228 if alias: 229 self.object_type_aliases.append((name,alias)) 230 else: 231 self.object_types.append(name) 232 elif (category == 'struct' or category == 'union'): 233 self.structNames.append(name) 234 self.genStruct(typeinfo, name, alias) 235 # 236 # Check if the parameter passed in is a pointer 237 def paramIsPointer(self, param): 238 ispointer = False 239 for elem in param: 240 if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail: 241 ispointer = True 242 return ispointer 243 # 244 # Check if the parameter passed in is a static array 245 def paramIsStaticArray(self, param): 246 isstaticarray = 0 247 paramname = param.find('name') 248 if (paramname.tail is not None) and ('[' in paramname.tail): 249 isstaticarray = paramname.tail.count('[') 250 return isstaticarray 251 # 252 # Retrieve the type and name for a parameter 253 def getTypeNameTuple(self, param): 254 type = '' 255 name = '' 256 for elem in param: 257 if elem.tag == 'type': 258 type = noneStr(elem.text) 259 elif elem.tag == 'name': 260 name = noneStr(elem.text) 261 return (type, name) 262 # Extract length values from latexmath. Currently an inflexible solution that looks for specific 263 # patterns that are found in vk.xml. Will need to be updated when new patterns are introduced. 264 def parseLateXMath(self, source): 265 name = 'ERROR' 266 decoratedName = 'ERROR' 267 if 'mathit' in source: 268 # Matches expressions similar to 'latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]' 269 match = re.match(r'latexmath\s*\:\s*\[\s*\\l(\w+)\s*\{\s*\\mathit\s*\{\s*(\w+)\s*\}\s*\\over\s*(\d+)\s*\}\s*\\r(\w+)\s*\]', source) 270 if not match or match.group(1) != match.group(4): 271 raise 'Unrecognized latexmath expression' 272 name = match.group(2) 273 # Need to add 1 for ceiling function; otherwise, the allocated packet 274 # size will be less than needed during capture for some title which use 275 # this in VkPipelineMultisampleStateCreateInfo. based on ceiling function 276 # definition,it is '{0}%{1}?{0}/{1} + 1:{0}/{1}'.format(*match.group(2, 3)), 277 # its value <= '{}/{} + 1'. 278 if match.group(1) == 'ceil': 279 decoratedName = '{}/{} + 1'.format(*match.group(2, 3)) 280 else: 281 decoratedName = '{}/{}'.format(*match.group(2, 3)) 282 else: 283 # Matches expressions similar to 'latexmath : [dataSize \over 4]' 284 match = re.match(r'latexmath\s*\:\s*\[\s*(\\textrm\{)?(\w+)\}?\s*\\over\s*(\d+)\s*\]', source) 285 name = match.group(2) 286 decoratedName = '{}/{}'.format(*match.group(2, 3)) 287 return name, decoratedName 288 # 289 # Retrieve the value of the len tag 290 def getLen(self, param): 291 result = None 292 len = param.attrib.get('len') 293 if len and len != 'null-terminated': 294 # For string arrays, 'len' can look like 'count,null-terminated', indicating that we 295 # have a null terminated array of strings. We strip the null-terminated from the 296 # 'len' field and only return the parameter specifying the string count 297 if 'null-terminated' in len: 298 result = len.split(',')[0] 299 else: 300 result = len 301 if 'latexmath' in len: 302 param_type, param_name = self.getTypeNameTuple(param) 303 len_name, result = self.parseLateXMath(len) 304 # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol 305 result = str(result).replace('::', '->') 306 return result 307 # 308 # Check if a structure is or contains a dispatchable (dispatchable = True) or 309 # non-dispatchable (dispatchable = False) handle 310 def TypeContainsObjectHandle(self, handle_type, dispatchable): 311 if dispatchable: 312 type_check = self.handle_types.IsDispatchable 313 else: 314 type_check = self.handle_types.IsNonDispatchable 315 if type_check(handle_type): 316 return True 317 # if handle_type is a struct, search its members 318 if handle_type in self.structNames: 319 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == handle_type), None) 320 if member_index is not None: 321 for item in self.structMembers[member_index].members: 322 if type_check(item.type): 323 return True 324 return False 325 # 326 # Generate local ready-access data describing Vulkan structures and unions from the XML metadata 327 def genStruct(self, typeinfo, typeName, alias): 328 OutputGenerator.genStruct(self, typeinfo, typeName, alias) 329 members = typeinfo.elem.findall('.//member') 330 # Iterate over members once to get length parameters for arrays 331 lens = set() 332 for member in members: 333 len = self.getLen(member) 334 if len: 335 lens.add(len) 336 # Generate member info 337 membersInfo = [] 338 for member in members: 339 # Get the member's type and name 340 info = self.getTypeNameTuple(member) 341 type = info[0] 342 name = info[1] 343 cdecl = self.makeCParamDecl(member, 1) 344 # Process VkStructureType 345 if type == 'VkStructureType': 346 # Extract the required struct type value from the comments 347 # embedded in the original text defining the 'typeinfo' element 348 rawXml = etree.tostring(typeinfo.elem).decode('ascii') 349 result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml) 350 if result: 351 value = result.group(0) 352 # Store the required type value 353 self.structTypes[typeName] = self.StructType(name=name, value=value) 354 # Store pointer/array/string info 355 isstaticarray = self.paramIsStaticArray(member) 356 structextends = False 357 membersInfo.append(self.CommandParam(type=type, 358 name=name, 359 ispointer=self.paramIsPointer(member), 360 isstaticarray=isstaticarray, 361 isconst=True if 'const' in cdecl else False, 362 iscount=True if name in lens else False, 363 len=self.getLen(member), 364 extstructs=self.registry.validextensionstructs[typeName] if name == 'pNext' else None, 365 cdecl=cdecl)) 366 # If this struct extends another, keep its name in list for further processing 367 if typeinfo.elem.attrib.get('structextends') is not None: 368 self.structextends_list.append(typeName) 369 self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo, ifdef_protect=self.featureExtraProtect)) 370 # 371 # Enum_string_header: Create a routine to convert an enumerated value into a string 372 def GenerateEnumStringConversion(self, groupName, value_list): 373 outstring = '\n' 374 if self.featureExtraProtect is not None: 375 outstring += '\n#ifdef %s\n\n' % self.featureExtraProtect 376 outstring += 'static inline const char* string_%s(%s input_value)\n' % (groupName, groupName) 377 outstring += '{\n' 378 outstring += ' switch ((%s)input_value)\n' % groupName 379 outstring += ' {\n' 380 # Emit these in a repeatable order so file is generated with the same contents each time. 381 # This helps compiler caching systems like ccache. 382 for item in sorted(value_list): 383 outstring += ' case %s:\n' % item 384 outstring += ' return "%s";\n' % item 385 outstring += ' default:\n' 386 outstring += ' return "Unhandled %s";\n' % groupName 387 outstring += ' }\n' 388 outstring += '}\n' 389 390 bitsIndex = groupName.find('Bits') 391 if (bitsIndex != -1): 392 outstring += '\n' 393 flagsName = groupName[0:bitsIndex] + "s" + groupName[bitsIndex+4:] 394 outstring += 'static inline std::string string_%s(%s input_value)\n' % (flagsName, flagsName) 395 outstring += '{\n' 396 outstring += ' std::string ret;\n' 397 outstring += ' int index = 0;\n' 398 outstring += ' while(input_value) {\n' 399 outstring += ' if (input_value & 1) {\n' 400 outstring += ' if( !ret.empty()) ret.append("|");\n' 401 outstring += ' ret.append(string_%s(static_cast<%s>(1 << index)));\n' % (groupName, groupName) 402 outstring += ' }\n' 403 outstring += ' ++index;\n' 404 outstring += ' input_value >>= 1;\n' 405 outstring += ' }\n' 406 outstring += ' if( ret.empty()) ret.append(string_%s(static_cast<%s>(0)));\n' % (groupName, groupName) 407 outstring += ' return ret;\n' 408 outstring += '}\n' 409 410 if self.featureExtraProtect is not None: 411 outstring += '#endif // %s\n' % self.featureExtraProtect 412 return outstring 413 # 414 # Tack on a helper which, given an index into a VkPhysicalDeviceFeatures structure, will print the corresponding feature name 415 def DeIndexPhysDevFeatures(self): 416 pdev_members = None 417 for name, members, ifdef in self.structMembers: 418 if name == 'VkPhysicalDeviceFeatures': 419 pdev_members = members 420 break 421 deindex = '\n' 422 deindex += 'static inline const char * GetPhysDevFeatureString(uint32_t index) {\n' 423 deindex += ' const char * IndexToPhysDevFeatureString[] = {\n' 424 for feature in pdev_members: 425 deindex += ' "%s",\n' % feature.name 426 deindex += ' };\n\n' 427 deindex += ' return IndexToPhysDevFeatureString[index];\n' 428 deindex += '}\n' 429 return deindex 430 # 431 # Combine enum string helper header file preamble with body text and return 432 def GenerateEnumStringHelperHeader(self): 433 enum_string_helper_header = '\n' 434 enum_string_helper_header += '#pragma once\n' 435 enum_string_helper_header += '#ifdef _WIN32\n' 436 enum_string_helper_header += '#pragma warning( disable : 4065 )\n' 437 enum_string_helper_header += '#endif\n' 438 enum_string_helper_header += '\n' 439 enum_string_helper_header += '#include <string>\n' 440 enum_string_helper_header += '#include <vulkan/vulkan.h>\n' 441 enum_string_helper_header += '\n' 442 enum_string_helper_header += self.enum_output 443 enum_string_helper_header += self.DeIndexPhysDevFeatures() 444 return enum_string_helper_header 445 # 446 # Helper function for declaring a counter variable only once 447 def DeclareCounter(self, string_var, declare_flag): 448 if declare_flag == False: 449 string_var += ' uint32_t i = 0;\n' 450 declare_flag = True 451 return string_var, declare_flag 452 # 453 # Combine safe struct helper header file preamble with body text and return 454 def GenerateSafeStructHelperHeader(self): 455 safe_struct_helper_header = '\n' 456 safe_struct_helper_header += '#pragma once\n' 457 safe_struct_helper_header += '#include <vulkan/vulkan.h>\n' 458 safe_struct_helper_header += '\n' 459 safe_struct_helper_header += 'void *SafePnextCopy(const void *pNext);\n' 460 safe_struct_helper_header += 'void FreePnextChain(const void *pNext);\n' 461 safe_struct_helper_header += 'char *SafeStringCopy(const char *in_string);\n' 462 safe_struct_helper_header += '\n' 463 safe_struct_helper_header += self.GenerateSafeStructHeader() 464 return safe_struct_helper_header 465 # 466 # safe_struct header: build function prototypes for header file 467 def GenerateSafeStructHeader(self): 468 safe_struct_header = '' 469 for item in self.structMembers: 470 if self.NeedSafeStruct(item) == True: 471 safe_struct_header += '\n' 472 if item.ifdef_protect is not None: 473 safe_struct_header += '#ifdef %s\n' % item.ifdef_protect 474 safe_struct_header += 'struct safe_%s {\n' % (item.name) 475 for member in item.members: 476 if member.type in self.structNames: 477 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) 478 if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: 479 if member.ispointer: 480 safe_struct_header += ' safe_%s* %s;\n' % (member.type, member.name) 481 else: 482 safe_struct_header += ' safe_%s %s;\n' % (member.type, member.name) 483 continue 484 if member.len is not None and (self.TypeContainsObjectHandle(member.type, True) or self.TypeContainsObjectHandle(member.type, False)): 485 safe_struct_header += ' %s* %s;\n' % (member.type, member.name) 486 else: 487 safe_struct_header += '%s;\n' % member.cdecl 488 safe_struct_header += ' safe_%s(const %s* in_struct%s);\n' % (item.name, item.name, self.custom_construct_params.get(item.name, '')) 489 safe_struct_header += ' safe_%s(const safe_%s& src);\n' % (item.name, item.name) 490 safe_struct_header += ' safe_%s& operator=(const safe_%s& src);\n' % (item.name, item.name) 491 safe_struct_header += ' safe_%s();\n' % item.name 492 safe_struct_header += ' ~safe_%s();\n' % item.name 493 safe_struct_header += ' void initialize(const %s* in_struct%s);\n' % (item.name, self.custom_construct_params.get(item.name, '')) 494 safe_struct_header += ' void initialize(const safe_%s* src);\n' % (item.name) 495 safe_struct_header += ' %s *ptr() { return reinterpret_cast<%s *>(this); }\n' % (item.name, item.name) 496 safe_struct_header += ' %s const *ptr() const { return reinterpret_cast<%s const *>(this); }\n' % (item.name, item.name) 497 safe_struct_header += '};\n' 498 if item.ifdef_protect is not None: 499 safe_struct_header += '#endif // %s\n' % item.ifdef_protect 500 return safe_struct_header 501 # 502 # Generate extension helper header file 503 def GenerateExtensionHelperHeader(self): 504 505 V_1_1_level_feature_set = [ 506 'VK_VERSION_1_1', 507 ] 508 509 V_1_0_instance_extensions_promoted_to_V_1_1_core = [ 510 'vk_khr_device_group_creation', 511 'vk_khr_external_fence_capabilities', 512 'vk_khr_external_memory_capabilities', 513 'vk_khr_external_semaphore_capabilities', 514 'vk_khr_get_physical_device_properties_2', 515 ] 516 517 V_1_0_device_extensions_promoted_to_V_1_1_core = [ 518 'vk_khr_16bit_storage', 519 'vk_khr_bind_memory_2', 520 'vk_khr_dedicated_allocation', 521 'vk_khr_descriptor_update_template', 522 'vk_khr_device_group', 523 'vk_khr_external_fence', 524 'vk_khr_external_memory', 525 'vk_khr_external_semaphore', 526 'vk_khr_get_memory_requirements_2', 527 'vk_khr_maintenance1', 528 'vk_khr_maintenance2', 529 'vk_khr_maintenance3', 530 'vk_khr_multiview', 531 'vk_khr_relaxed_block_layout', 532 'vk_khr_sampler_ycbcr_conversion', 533 'vk_khr_shader_draw_parameters', 534 'vk_khr_storage_buffer_storage_class', 535 'vk_khr_variable_pointers', 536 ] 537 538 output = [ 539 '', 540 '#ifndef VK_EXTENSION_HELPER_H_', 541 '#define VK_EXTENSION_HELPER_H_', 542 '#include <unordered_set>', 543 '#include <string>', 544 '#include <unordered_map>', 545 '#include <utility>', 546 '#include <set>', 547 '#include <vector>', 548 '', 549 '#include <vulkan/vulkan.h>', 550 ''] 551 552 def guarded(ifdef, value): 553 if ifdef is not None: 554 return '\n'.join([ '#ifdef %s' % ifdef, value, '#endif' ]) 555 else: 556 return value 557 558 for type in ['Instance', 'Device']: 559 struct_type = '%sExtensions' % type 560 if type == 'Instance': 561 extension_dict = self.instance_extension_info 562 promoted_ext_list = V_1_0_instance_extensions_promoted_to_V_1_1_core 563 struct_decl = 'struct %s {' % struct_type 564 instance_struct_type = struct_type 565 else: 566 extension_dict = self.device_extension_info 567 promoted_ext_list = V_1_0_device_extensions_promoted_to_V_1_1_core 568 struct_decl = 'struct %s : public %s {' % (struct_type, instance_struct_type) 569 570 extension_items = sorted(extension_dict.items()) 571 572 field_name = { ext_name: re.sub('_extension_name', '', info['define'].lower()) for ext_name, info in extension_items } 573 574 if type == 'Instance': 575 instance_field_name = field_name 576 instance_extension_dict = extension_dict 577 else: 578 # Get complete field name and extension data for both Instance and Device extensions 579 field_name.update(instance_field_name) 580 extension_dict = extension_dict.copy() # Don't modify the self.<dict> we're pointing to 581 extension_dict.update(instance_extension_dict) 582 583 # Output the data member list 584 struct = [struct_decl] 585 struct.extend([ ' bool vk_feature_version_1_1{false};']) 586 struct.extend([ ' bool %s{false};' % field_name[ext_name] for ext_name, info in extension_items]) 587 588 # Construct the extension information map -- mapping name to data member (field), and required extensions 589 # The map is contained within a static function member for portability reasons. 590 info_type = '%sInfo' % type 591 info_map_type = '%sMap' % info_type 592 req_type = '%sReq' % type 593 req_vec_type = '%sVec' % req_type 594 struct.extend([ 595 '', 596 ' struct %s {' % req_type, 597 ' const bool %s::* enabled;' % struct_type, 598 ' const char *name;', 599 ' };', 600 ' typedef std::vector<%s> %s;' % (req_type, req_vec_type), 601 ' struct %s {' % info_type, 602 ' %s(bool %s::* state_, const %s requires_): state(state_), requires(requires_) {}' % ( info_type, struct_type, req_vec_type), 603 ' bool %s::* state;' % struct_type, 604 ' %s requires;' % req_vec_type, 605 ' };', 606 '', 607 ' typedef std::unordered_map<std::string,%s> %s;' % (info_type, info_map_type), 608 ' static const %s &get_info(const char *name) {' %info_type, 609 ' static const %s info_map = {' % info_map_type ]) 610 struct.extend([ 611 ' std::make_pair("VK_VERSION_1_1", %sInfo(&%sExtensions::vk_feature_version_1_1, {})),' % (type, type)]) 612 613 field_format = '&' + struct_type + '::%s' 614 req_format = '{' + field_format+ ', %s}' 615 req_indent = '\n ' 616 req_join = ',' + req_indent 617 info_format = (' std::make_pair(%s, ' + info_type + '(' + field_format + ', {%s})),') 618 def format_info(ext_name, info): 619 reqs = req_join.join([req_format % (field_name[req], extension_dict[req]['define']) for req in info['reqs']]) 620 return info_format % (info['define'], field_name[ext_name], '{%s}' % (req_indent + reqs) if reqs else '') 621 622 struct.extend([guarded(info['ifdef'], format_info(ext_name, info)) for ext_name, info in extension_items]) 623 struct.extend([ 624 ' };', 625 '', 626 ' static const %s empty_info {nullptr, %s()};' % (info_type, req_vec_type), 627 ' %s::const_iterator info = info_map.find(name);' % info_map_type, 628 ' if ( info != info_map.cend()) {', 629 ' return info->second;', 630 ' }', 631 ' return empty_info;', 632 ' }', 633 '']) 634 635 if type == 'Instance': 636 struct.extend([ 637 ' uint32_t NormalizeApiVersion(uint32_t specified_version) {', 638 ' uint32_t api_version = (specified_version < VK_API_VERSION_1_1) ? VK_API_VERSION_1_0 : VK_API_VERSION_1_1;', 639 ' return api_version;', 640 ' }', 641 '', 642 ' uint32_t InitFromInstanceCreateInfo(uint32_t requested_api_version, const VkInstanceCreateInfo *pCreateInfo) {']) 643 else: 644 struct.extend([ 645 ' %s() = default;' % struct_type, 646 ' %s(const %s& instance_ext) : %s(instance_ext) {}' % (struct_type, instance_struct_type, instance_struct_type), 647 '', 648 ' uint32_t InitFromDeviceCreateInfo(const %s *instance_extensions, uint32_t requested_api_version,' % instance_struct_type, 649 ' const VkDeviceCreateInfo *pCreateInfo) {', 650 ' // Initialize: this to defaults, base class fields to input.', 651 ' assert(instance_extensions);', 652 ' *this = %s(*instance_extensions);' % struct_type, 653 '']), 654 struct.extend([ 655 '', 656 ' static const std::vector<const char *> V_1_1_promoted_%s_apis = {' % type.lower() ]) 657 struct.extend([' %s_EXTENSION_NAME,' % ext_name.upper() for ext_name in promoted_ext_list]) 658 struct.extend([' "VK_VERSION_1_1",']) 659 struct.extend([ 660 ' };', 661 '', 662 ' // Initialize struct data, robust to invalid pCreateInfo', 663 ' if (pCreateInfo->ppEnabledExtensionNames) {', 664 ' for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {', 665 ' if (!pCreateInfo->ppEnabledExtensionNames[i]) continue;', 666 ' auto info = get_info(pCreateInfo->ppEnabledExtensionNames[i]);', 667 ' if(info.state) this->*(info.state) = true;', 668 ' }', 669 ' }', 670 ' uint32_t api_version = NormalizeApiVersion(requested_api_version);', 671 ' if (api_version >= VK_API_VERSION_1_1) {', 672 ' for (auto promoted_ext : V_1_1_promoted_%s_apis) {' % type.lower(), 673 ' auto info = get_info(promoted_ext);', 674 ' assert(info.state);', 675 ' if (info.state) this->*(info.state) = true;', 676 ' }', 677 ' }', 678 ' return api_version;', 679 ' }', 680 '};']) 681 682 # Output reference lists of instance/device extension names 683 struct.extend(['', 'static const std::set<std::string> k%sExtensionNames = {' % type]) 684 struct.extend([guarded(info['ifdef'], ' %s,' % info['define']) for ext_name, info in extension_items]) 685 struct.extend(['};', '']) 686 output.extend(struct) 687 688 output.extend(['', '#endif // VK_EXTENSION_HELPER_H_']) 689 return '\n'.join(output) 690 # 691 # Combine object types helper header file preamble with body text and return 692 def GenerateObjectTypesHelperHeader(self): 693 object_types_helper_header = '\n' 694 object_types_helper_header += '#pragma once\n' 695 object_types_helper_header += '\n' 696 object_types_helper_header += self.GenerateObjectTypesHeader() 697 return object_types_helper_header 698 # 699 # Object types header: create object enum type header file 700 def GenerateObjectTypesHeader(self): 701 object_types_header = '#include "cast_utils.h"\n' 702 object_types_header += '\n' 703 object_types_header += '// Object Type enum for validation layer internal object handling\n' 704 object_types_header += 'typedef enum VulkanObjectType {\n' 705 object_types_header += ' kVulkanObjectTypeUnknown = 0,\n' 706 enum_num = 1 707 type_list = []; 708 enum_entry_map = {} 709 non_dispatchable = {} 710 dispatchable = {} 711 object_type_info = {} 712 713 # Output enum definition as each handle is processed, saving the names to use for the conversion routine 714 for item in self.object_types: 715 fixup_name = item[2:] 716 enum_entry = 'kVulkanObjectType%s' % fixup_name 717 enum_entry_map[item] = enum_entry 718 object_types_header += ' ' + enum_entry 719 object_types_header += ' = %d,\n' % enum_num 720 enum_num += 1 721 type_list.append(enum_entry) 722 object_type_info[enum_entry] = { 'VkType': item } 723 # We'll want lists of the dispatchable and non dispatchable handles below with access to the same info 724 if self.handle_types.IsNonDispatchable(item): 725 non_dispatchable[item] = enum_entry 726 else: 727 dispatchable[item] = enum_entry 728 729 object_types_header += ' kVulkanObjectTypeMax = %d,\n' % enum_num 730 object_types_header += ' // Aliases for backwards compatibilty of "promoted" types\n' 731 for (name, alias) in self.object_type_aliases: 732 fixup_name = name[2:] 733 object_types_header += ' kVulkanObjectType{} = {},\n'.format(fixup_name, enum_entry_map[alias]) 734 object_types_header += '} VulkanObjectType;\n\n' 735 736 # Output name string helper 737 object_types_header += '// Array of object name strings for OBJECT_TYPE enum conversion\n' 738 object_types_header += 'static const char * const object_string[kVulkanObjectTypeMax] = {\n' 739 object_types_header += ' "VkNonDispatchableHandle",\n' 740 for item in self.object_types: 741 object_types_header += ' "%s",\n' % item 742 object_types_header += '};\n' 743 744 # Helpers to create unified dict key from k<Name>, VK_OBJECT_TYPE_<Name>, and VK_DEBUG_REPORT_OBJECT_TYPE_<Name> 745 def dro_to_key(raw_key): return re.search('^VK_DEBUG_REPORT_OBJECT_TYPE_(.*)_EXT$', raw_key).group(1).lower().replace("_","") 746 def vko_to_key(raw_key): return re.search('^VK_OBJECT_TYPE_(.*)', raw_key).group(1).lower().replace("_","") 747 def kenum_to_key(raw_key): return re.search('^kVulkanObjectType(.*)', raw_key).group(1).lower() 748 749 dro_dict = {dro_to_key(dro) : dro for dro in self.debug_report_object_types} 750 vko_dict = {vko_to_key(vko) : vko for vko in self.core_object_types} 751 752 # Output a conversion routine from the layer object definitions to the debug report definitions 753 object_types_header += '\n' 754 object_types_header += '// Helper array to get Vulkan VK_EXT_debug_report object type enum from the internal layers version\n' 755 object_types_header += 'const VkDebugReportObjectTypeEXT get_debug_report_enum[] = {\n' 756 object_types_header += ' VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // kVulkanObjectTypeUnknown\n' # no unknown handle, so this must be here explicitly 757 758 for object_type in type_list: 759 # VK_DEBUG_REPORT is not updated anymore; there might be missing object types 760 kenum_type = dro_dict.get(kenum_to_key(object_type), 'VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT') 761 object_types_header += ' %s, // %s\n' % (kenum_type, object_type) 762 object_type_info[object_type]['DbgType'] = kenum_type 763 object_types_header += '};\n' 764 765 # Output a conversion routine from the layer object definitions to the core object type definitions 766 # This will intentionally *fail* for unmatched types as the VK_OBJECT_TYPE list should match the kVulkanObjectType list 767 object_types_header += '\n' 768 object_types_header += '// Helper array to get Official Vulkan VkObjectType enum from the internal layers version\n' 769 object_types_header += 'const VkObjectType get_object_type_enum[] = {\n' 770 object_types_header += ' VK_OBJECT_TYPE_UNKNOWN, // kVulkanObjectTypeUnknown\n' # no unknown handle, so must be here explicitly 771 772 for object_type in type_list: 773 kenum_type = vko_dict[kenum_to_key(object_type)] 774 object_types_header += ' %s, // %s\n' % (kenum_type, object_type) 775 object_type_info[object_type]['VkoType'] = kenum_type 776 object_types_header += '};\n' 777 778 # Create a functions to convert between VkDebugReportObjectTypeEXT and VkObjectType 779 object_types_header += '\n' 780 object_types_header += 'static inline VkObjectType convertDebugReportObjectToCoreObject(VkDebugReportObjectTypeEXT debug_report_obj) {\n' 781 object_types_header += ' switch (debug_report_obj) {\n' 782 for dr_object_type in self.debug_report_object_types: 783 object_types_header += ' case %s: return %s;\n' % (dr_object_type, vko_dict[dro_to_key(dr_object_type)]) 784 object_types_header += ' default: return VK_OBJECT_TYPE_UNKNOWN;\n' 785 object_types_header += ' }\n' 786 object_types_header += '}\n' 787 788 object_types_header += '\n' 789 object_types_header += 'static inline VkDebugReportObjectTypeEXT convertCoreObjectToDebugReportObject(VkObjectType core_report_obj) {\n' 790 object_types_header += ' switch (core_report_obj) {\n' 791 for core_object_type in self.core_object_types: 792 # VK_DEBUG_REPORT is not updated anymore; there might be missing object types 793 dr_object_type = dro_dict.get(vko_to_key(core_object_type)) 794 if dr_object_type is not None: 795 object_types_header += ' case %s: return %s;\n' % (core_object_type, dr_object_type) 796 object_types_header += ' default: return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n' 797 object_types_header += ' }\n' 798 object_types_header += '}\n' 799 800 # 801 object_types_header += '\n' 802 traits_format = Outdent(''' 803 template <> struct VkHandleInfo<{vk_type}> {{ 804 static const VulkanObjectType kVulkanObjectType = {obj_type}; 805 static const VkDebugReportObjectTypeEXT kDebugReportObjectType = {dbg_type}; 806 static const VkObjectType kVkObjectType = {vko_type}; 807 static const char* Typename() {{ 808 return "{vk_type}"; 809 }} 810 }}; 811 template <> struct VulkanObjectTypeInfo<{obj_type}> {{ 812 typedef {vk_type} Type; 813 }}; 814 ''') 815 816 object_types_header += Outdent(''' 817 // Traits objects from each type statically map from Vk<handleType> to the various enums 818 template <typename VkType> struct VkHandleInfo {}; 819 template <VulkanObjectType id> struct VulkanObjectTypeInfo {}; 820 821 // The following line must match the vulkan_core.h condition guarding VK_DEFINE_NON_DISPATCHABLE_HANDLE 822 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || \ 823 defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) 824 #define TYPESAFE_NONDISPATCHABLE_HANDLES 825 #else 826 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkNonDispatchableHandle) 827 ''') +'\n' 828 object_types_header += traits_format.format(vk_type='VkNonDispatchableHandle', obj_type='kVulkanObjectTypeUnknown', 829 dbg_type='VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT', 830 vko_type='VK_OBJECT_TYPE_UNKNOWN') + '\n' 831 object_types_header += '#endif // VK_DEFINE_HANDLE logic duplication\n' 832 833 for vk_type, object_type in sorted(dispatchable.items()): 834 info = object_type_info[object_type] 835 object_types_header += traits_format.format(vk_type=vk_type, obj_type=object_type, dbg_type=info['DbgType'], 836 vko_type=info['VkoType']) 837 object_types_header += '#ifdef TYPESAFE_NONDISPATCHABLE_HANDLES\n' 838 for vk_type, object_type in sorted(non_dispatchable.items()): 839 info = object_type_info[object_type] 840 object_types_header += traits_format.format(vk_type=vk_type, obj_type=object_type, dbg_type=info['DbgType'], 841 vko_type=info['VkoType']) 842 object_types_header += '#endif // TYPESAFE_NONDISPATCHABLE_HANDLES\n' 843 844 object_types_header += Outdent(''' 845 struct VulkanTypedHandle { 846 uint64_t handle; 847 VulkanObjectType type; 848 template <typename Handle> 849 VulkanTypedHandle(Handle handle_, VulkanObjectType type_) : 850 handle(CastToUint64(handle_)), 851 type(type_) { 852 #ifdef TYPESAFE_NONDISPATCHABLE_HANDLES 853 // For 32 bit it's not always safe to check for traits <-> type 854 // as all non-dispatchable handles have the same type-id and thus traits, 855 // but on 64 bit we can validate the passed type matches the passed handle 856 assert(type == VkHandleInfo<Handle>::kVulkanObjectType); 857 #endif // TYPESAFE_NONDISPATCHABLE_HANDLES 858 } 859 template <typename Handle> 860 Handle Cast() const { 861 #ifdef TYPESAFE_NONDISPATCHABLE_HANDLES 862 assert(type == VkHandleInfo<Handle>::kVulkanObjectType); 863 #endif // TYPESAFE_NONDISPATCHABLE_HANDLES 864 return CastFromUint64<Handle>(handle); 865 } 866 VulkanTypedHandle() : 867 handle(VK_NULL_HANDLE), 868 type(kVulkanObjectTypeUnknown) {} 869 }; ''') +'\n' 870 871 return object_types_header 872 # 873 # Generate pNext handling function 874 def build_safe_struct_utility_funcs(self): 875 # Construct Safe-struct helper functions 876 877 string_copy_proc = '\n\n' 878 string_copy_proc += 'char *SafeStringCopy(const char *in_string) {\n' 879 string_copy_proc += ' if (nullptr == in_string) return nullptr;\n' 880 string_copy_proc += ' char* dest = new char[std::strlen(in_string) + 1];\n' 881 string_copy_proc += ' return std::strcpy(dest, in_string);\n' 882 string_copy_proc += '}\n' 883 884 build_pnext_proc = '\n' 885 build_pnext_proc += 'void *SafePnextCopy(const void *pNext) {\n' 886 build_pnext_proc += ' if (!pNext) return nullptr;\n' 887 build_pnext_proc += '\n' 888 build_pnext_proc += ' void *safe_pNext;\n' 889 build_pnext_proc += ' const VkBaseOutStructure *header = reinterpret_cast<const VkBaseOutStructure *>(pNext);\n' 890 build_pnext_proc += '\n' 891 build_pnext_proc += ' switch (header->sType) {\n' 892 # Add special-case code to copy beloved secret loader structs 893 build_pnext_proc += ' // Special-case Loader Instance Struct passed to/from layer in pNext chain\n' 894 build_pnext_proc += ' case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: {\n' 895 build_pnext_proc += ' VkLayerInstanceCreateInfo *struct_copy = new VkLayerInstanceCreateInfo;\n' 896 build_pnext_proc += ' // TODO: Uses original VkLayerInstanceLink* chain, which should be okay for our uses\n' 897 build_pnext_proc += ' memcpy(struct_copy, pNext, sizeof(VkLayerInstanceCreateInfo));\n' 898 build_pnext_proc += ' struct_copy->pNext = SafePnextCopy(header->pNext);\n' 899 build_pnext_proc += ' safe_pNext = struct_copy;\n' 900 build_pnext_proc += ' break;\n' 901 build_pnext_proc += ' }\n' 902 build_pnext_proc += ' // Special-case Loader Device Struct passed to/from layer in pNext chain\n' 903 build_pnext_proc += ' case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: {\n' 904 build_pnext_proc += ' VkLayerDeviceCreateInfo *struct_copy = new VkLayerDeviceCreateInfo;\n' 905 build_pnext_proc += ' // TODO: Uses original VkLayerDeviceLink*, which should be okay for our uses\n' 906 build_pnext_proc += ' memcpy(struct_copy, pNext, sizeof(VkLayerDeviceCreateInfo));\n' 907 build_pnext_proc += ' struct_copy->pNext = SafePnextCopy(header->pNext);\n' 908 build_pnext_proc += ' safe_pNext = struct_copy;\n' 909 build_pnext_proc += ' break;\n' 910 build_pnext_proc += ' }\n' 911 912 free_pnext_proc = '\n' 913 free_pnext_proc += 'void FreePnextChain(const void *pNext) {\n' 914 free_pnext_proc += ' if (!pNext) return;\n' 915 free_pnext_proc += '\n' 916 free_pnext_proc += ' auto header = reinterpret_cast<const VkBaseOutStructure *>(pNext);\n' 917 free_pnext_proc += '\n' 918 free_pnext_proc += ' switch (header->sType) {\n' 919 free_pnext_proc += ' // Special-case Loader Instance Struct passed to/from layer in pNext chain\n' 920 free_pnext_proc += ' case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n' 921 free_pnext_proc += ' FreePnextChain(header->pNext);\n' 922 free_pnext_proc += ' delete reinterpret_cast<const VkLayerInstanceCreateInfo *>(pNext);\n' 923 free_pnext_proc += ' break;\n' 924 free_pnext_proc += ' // Special-case Loader Device Struct passed to/from layer in pNext chain\n' 925 free_pnext_proc += ' case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n' 926 free_pnext_proc += ' FreePnextChain(header->pNext);\n' 927 free_pnext_proc += ' delete reinterpret_cast<const VkLayerDeviceCreateInfo *>(pNext);\n' 928 free_pnext_proc += ' break;\n' 929 930 chain_structs = tuple(s for s in self.structMembers if s.name in self.structextends_list) 931 ifdefs = sorted({cs.ifdef_protect for cs in chain_structs}, key = lambda i : i if i is not None else '') 932 for ifdef in ifdefs: 933 if ifdef is not None: 934 build_pnext_proc += '#ifdef %s\n' % ifdef 935 free_pnext_proc += '#ifdef %s\n' % ifdef 936 937 assorted_chain_structs = tuple(s for s in chain_structs if s.ifdef_protect == ifdef) 938 for struct in assorted_chain_structs: 939 build_pnext_proc += ' case %s:\n' % self.structTypes[struct.name].value 940 build_pnext_proc += ' safe_pNext = new safe_%s(reinterpret_cast<const %s *>(pNext));\n' % (struct.name, struct.name) 941 build_pnext_proc += ' break;\n' 942 943 free_pnext_proc += ' case %s:\n' % self.structTypes[struct.name].value 944 free_pnext_proc += ' delete reinterpret_cast<const safe_%s *>(header);\n' % struct.name 945 free_pnext_proc += ' break;\n' 946 947 if ifdef is not None: 948 build_pnext_proc += '#endif // %s\n' % ifdef 949 free_pnext_proc += '#endif // %s\n' % ifdef 950 951 build_pnext_proc += ' default: // Encountered an unknown sType -- skip (do not copy) this entry in the chain\n' 952 build_pnext_proc += ' safe_pNext = SafePnextCopy(header->pNext);\n' 953 build_pnext_proc += ' break;\n' 954 build_pnext_proc += ' }\n' 955 build_pnext_proc += '\n' 956 build_pnext_proc += ' return safe_pNext;\n' 957 build_pnext_proc += '}\n' 958 959 free_pnext_proc += ' default: // Encountered an unknown sType -- panic, there should be none such in safe chain\n' 960 free_pnext_proc += ' assert(false);\n' 961 free_pnext_proc += ' FreePnextChain(header->pNext);\n' 962 free_pnext_proc += ' break;\n' 963 free_pnext_proc += ' }\n' 964 free_pnext_proc += '}\n' 965 966 pnext_procs = string_copy_proc + build_pnext_proc + free_pnext_proc 967 return pnext_procs 968 # 969 # Determine if a structure needs a safe_struct helper function 970 # That is, it has an sType or one of its members is a pointer 971 def NeedSafeStruct(self, structure): 972 if 'VkBase' in structure.name: 973 return False 974 if 'sType' == structure.name: 975 return True 976 for member in structure.members: 977 if member.ispointer == True: 978 return True 979 return False 980 # 981 # Combine safe struct helper source file preamble with body text and return 982 def GenerateSafeStructHelperSource(self): 983 safe_struct_helper_source = '\n' 984 safe_struct_helper_source += '#include "vk_safe_struct.h"\n' 985 safe_struct_helper_source += '\n' 986 safe_struct_helper_source += '#include <string.h>\n' 987 safe_struct_helper_source += '#include <cassert>\n' 988 safe_struct_helper_source += '#include <cstring>\n' 989 safe_struct_helper_source += '\n' 990 safe_struct_helper_source += '#include <vulkan/vk_layer.h>\n' 991 safe_struct_helper_source += '\n' 992 safe_struct_helper_source += self.GenerateSafeStructSource() 993 safe_struct_helper_source += self.build_safe_struct_utility_funcs() 994 995 return safe_struct_helper_source 996 # 997 # safe_struct source -- create bodies of safe struct helper functions 998 def GenerateSafeStructSource(self): 999 safe_struct_body = [] 1000 wsi_structs = ['VkXlibSurfaceCreateInfoKHR', 1001 'VkXcbSurfaceCreateInfoKHR', 1002 'VkWaylandSurfaceCreateInfoKHR', 1003 'VkAndroidSurfaceCreateInfoKHR', 1004 'VkWin32SurfaceCreateInfoKHR' 1005 ] 1006 1007 # For abstract types just want to save the pointer away 1008 # since we cannot make a copy. 1009 abstract_types = ['AHardwareBuffer', 1010 'ANativeWindow', 1011 ] 1012 for item in self.structMembers: 1013 if self.NeedSafeStruct(item) == False: 1014 continue 1015 if item.name in wsi_structs: 1016 continue 1017 if item.ifdef_protect is not None: 1018 safe_struct_body.append("#ifdef %s\n" % item.ifdef_protect) 1019 ss_name = "safe_%s" % item.name 1020 init_list = '' # list of members in struct constructor initializer 1021 default_init_list = '' # Default constructor just inits ptrs to nullptr in initializer 1022 init_func_txt = '' # Txt for initialize() function that takes struct ptr and inits members 1023 construct_txt = '' # Body of constuctor as well as body of initialize() func following init_func_txt 1024 destruct_txt = '' 1025 1026 custom_construct_txt = { 1027 # VkWriteDescriptorSet is special case because pointers may be non-null but ignored 1028 'VkWriteDescriptorSet' : 1029 ' switch (descriptorType) {\n' 1030 ' case VK_DESCRIPTOR_TYPE_SAMPLER:\n' 1031 ' case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:\n' 1032 ' case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:\n' 1033 ' case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:\n' 1034 ' case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:\n' 1035 ' if (descriptorCount && in_struct->pImageInfo) {\n' 1036 ' pImageInfo = new VkDescriptorImageInfo[descriptorCount];\n' 1037 ' for (uint32_t i = 0; i < descriptorCount; ++i) {\n' 1038 ' pImageInfo[i] = in_struct->pImageInfo[i];\n' 1039 ' }\n' 1040 ' }\n' 1041 ' break;\n' 1042 ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:\n' 1043 ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:\n' 1044 ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:\n' 1045 ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:\n' 1046 ' if (descriptorCount && in_struct->pBufferInfo) {\n' 1047 ' pBufferInfo = new VkDescriptorBufferInfo[descriptorCount];\n' 1048 ' for (uint32_t i = 0; i < descriptorCount; ++i) {\n' 1049 ' pBufferInfo[i] = in_struct->pBufferInfo[i];\n' 1050 ' }\n' 1051 ' }\n' 1052 ' break;\n' 1053 ' case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:\n' 1054 ' case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:\n' 1055 ' if (descriptorCount && in_struct->pTexelBufferView) {\n' 1056 ' pTexelBufferView = new VkBufferView[descriptorCount];\n' 1057 ' for (uint32_t i = 0; i < descriptorCount; ++i) {\n' 1058 ' pTexelBufferView[i] = in_struct->pTexelBufferView[i];\n' 1059 ' }\n' 1060 ' }\n' 1061 ' break;\n' 1062 ' default:\n' 1063 ' break;\n' 1064 ' }\n', 1065 'VkShaderModuleCreateInfo' : 1066 ' if (in_struct->pCode) {\n' 1067 ' pCode = reinterpret_cast<uint32_t *>(new uint8_t[codeSize]);\n' 1068 ' memcpy((void *)pCode, (void *)in_struct->pCode, codeSize);\n' 1069 ' }\n', 1070 # VkGraphicsPipelineCreateInfo is special case because its pointers may be non-null but ignored 1071 'VkGraphicsPipelineCreateInfo' : 1072 ' if (stageCount && in_struct->pStages) {\n' 1073 ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' 1074 ' for (uint32_t i = 0; i < stageCount; ++i) {\n' 1075 ' pStages[i].initialize(&in_struct->pStages[i]);\n' 1076 ' }\n' 1077 ' }\n' 1078 ' if (in_struct->pVertexInputState)\n' 1079 ' pVertexInputState = new safe_VkPipelineVertexInputStateCreateInfo(in_struct->pVertexInputState);\n' 1080 ' else\n' 1081 ' pVertexInputState = NULL;\n' 1082 ' if (in_struct->pInputAssemblyState)\n' 1083 ' pInputAssemblyState = new safe_VkPipelineInputAssemblyStateCreateInfo(in_struct->pInputAssemblyState);\n' 1084 ' else\n' 1085 ' pInputAssemblyState = NULL;\n' 1086 ' bool has_tessellation_stage = false;\n' 1087 ' if (stageCount && pStages)\n' 1088 ' for (uint32_t i = 0; i < stageCount && !has_tessellation_stage; ++i)\n' 1089 ' if (pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)\n' 1090 ' has_tessellation_stage = true;\n' 1091 ' if (in_struct->pTessellationState && has_tessellation_stage)\n' 1092 ' pTessellationState = new safe_VkPipelineTessellationStateCreateInfo(in_struct->pTessellationState);\n' 1093 ' else\n' 1094 ' pTessellationState = NULL; // original pTessellationState pointer ignored\n' 1095 ' bool has_rasterization = in_struct->pRasterizationState ? !in_struct->pRasterizationState->rasterizerDiscardEnable : false;\n' 1096 ' if (in_struct->pViewportState && has_rasterization) {\n' 1097 ' bool is_dynamic_viewports = false;\n' 1098 ' bool is_dynamic_scissors = false;\n' 1099 ' if (in_struct->pDynamicState && in_struct->pDynamicState->pDynamicStates) {\n' 1100 ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_viewports; ++i)\n' 1101 ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_VIEWPORT)\n' 1102 ' is_dynamic_viewports = true;\n' 1103 ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_scissors; ++i)\n' 1104 ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_SCISSOR)\n' 1105 ' is_dynamic_scissors = true;\n' 1106 ' }\n' 1107 ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(in_struct->pViewportState, is_dynamic_viewports, is_dynamic_scissors);\n' 1108 ' } else\n' 1109 ' pViewportState = NULL; // original pViewportState pointer ignored\n' 1110 ' if (in_struct->pRasterizationState)\n' 1111 ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(in_struct->pRasterizationState);\n' 1112 ' else\n' 1113 ' pRasterizationState = NULL;\n' 1114 ' if (in_struct->pMultisampleState && has_rasterization)\n' 1115 ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(in_struct->pMultisampleState);\n' 1116 ' else\n' 1117 ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' 1118 ' // needs a tracked subpass state uses_depthstencil_attachment\n' 1119 ' if (in_struct->pDepthStencilState && has_rasterization && uses_depthstencil_attachment)\n' 1120 ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(in_struct->pDepthStencilState);\n' 1121 ' else\n' 1122 ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' 1123 ' // needs a tracked subpass state usesColorAttachment\n' 1124 ' if (in_struct->pColorBlendState && has_rasterization && uses_color_attachment)\n' 1125 ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(in_struct->pColorBlendState);\n' 1126 ' else\n' 1127 ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' 1128 ' if (in_struct->pDynamicState)\n' 1129 ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(in_struct->pDynamicState);\n' 1130 ' else\n' 1131 ' pDynamicState = NULL;\n', 1132 # VkPipelineViewportStateCreateInfo is special case because its pointers may be non-null but ignored 1133 'VkPipelineViewportStateCreateInfo' : 1134 ' if (in_struct->pViewports && !is_dynamic_viewports) {\n' 1135 ' pViewports = new VkViewport[in_struct->viewportCount];\n' 1136 ' memcpy ((void *)pViewports, (void *)in_struct->pViewports, sizeof(VkViewport)*in_struct->viewportCount);\n' 1137 ' }\n' 1138 ' else\n' 1139 ' pViewports = NULL;\n' 1140 ' if (in_struct->pScissors && !is_dynamic_scissors) {\n' 1141 ' pScissors = new VkRect2D[in_struct->scissorCount];\n' 1142 ' memcpy ((void *)pScissors, (void *)in_struct->pScissors, sizeof(VkRect2D)*in_struct->scissorCount);\n' 1143 ' }\n' 1144 ' else\n' 1145 ' pScissors = NULL;\n', 1146 # VkDescriptorSetLayoutBinding is special case because its pImmutableSamplers pointer may be non-null but ignored 1147 'VkDescriptorSetLayoutBinding' : 1148 ' const bool sampler_type = in_struct->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || in_struct->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n' 1149 ' if (descriptorCount && in_struct->pImmutableSamplers && sampler_type) {\n' 1150 ' pImmutableSamplers = new VkSampler[descriptorCount];\n' 1151 ' for (uint32_t i = 0; i < descriptorCount; ++i) {\n' 1152 ' pImmutableSamplers[i] = in_struct->pImmutableSamplers[i];\n' 1153 ' }\n' 1154 ' }\n', 1155 } 1156 1157 custom_copy_txt = { 1158 # VkGraphicsPipelineCreateInfo is special case because it has custom construct parameters 1159 'VkGraphicsPipelineCreateInfo' : 1160 ' pNext = SafePnextCopy(src.pNext);\n' 1161 ' if (stageCount && src.pStages) {\n' 1162 ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' 1163 ' for (uint32_t i = 0; i < stageCount; ++i) {\n' 1164 ' pStages[i].initialize(&src.pStages[i]);\n' 1165 ' }\n' 1166 ' }\n' 1167 ' if (src.pVertexInputState)\n' 1168 ' pVertexInputState = new safe_VkPipelineVertexInputStateCreateInfo(*src.pVertexInputState);\n' 1169 ' else\n' 1170 ' pVertexInputState = NULL;\n' 1171 ' if (src.pInputAssemblyState)\n' 1172 ' pInputAssemblyState = new safe_VkPipelineInputAssemblyStateCreateInfo(*src.pInputAssemblyState);\n' 1173 ' else\n' 1174 ' pInputAssemblyState = NULL;\n' 1175 ' bool has_tessellation_stage = false;\n' 1176 ' if (stageCount && pStages)\n' 1177 ' for (uint32_t i = 0; i < stageCount && !has_tessellation_stage; ++i)\n' 1178 ' if (pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)\n' 1179 ' has_tessellation_stage = true;\n' 1180 ' if (src.pTessellationState && has_tessellation_stage)\n' 1181 ' pTessellationState = new safe_VkPipelineTessellationStateCreateInfo(*src.pTessellationState);\n' 1182 ' else\n' 1183 ' pTessellationState = NULL; // original pTessellationState pointer ignored\n' 1184 ' bool has_rasterization = src.pRasterizationState ? !src.pRasterizationState->rasterizerDiscardEnable : false;\n' 1185 ' if (src.pViewportState && has_rasterization) {\n' 1186 ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(*src.pViewportState);\n' 1187 ' } else\n' 1188 ' pViewportState = NULL; // original pViewportState pointer ignored\n' 1189 ' if (src.pRasterizationState)\n' 1190 ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(*src.pRasterizationState);\n' 1191 ' else\n' 1192 ' pRasterizationState = NULL;\n' 1193 ' if (src.pMultisampleState && has_rasterization)\n' 1194 ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(*src.pMultisampleState);\n' 1195 ' else\n' 1196 ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' 1197 ' if (src.pDepthStencilState && has_rasterization)\n' 1198 ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(*src.pDepthStencilState);\n' 1199 ' else\n' 1200 ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' 1201 ' if (src.pColorBlendState && has_rasterization)\n' 1202 ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(*src.pColorBlendState);\n' 1203 ' else\n' 1204 ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' 1205 ' if (src.pDynamicState)\n' 1206 ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(*src.pDynamicState);\n' 1207 ' else\n' 1208 ' pDynamicState = NULL;\n', 1209 # VkPipelineViewportStateCreateInfo is special case because it has custom construct parameters 1210 'VkPipelineViewportStateCreateInfo' : 1211 ' pNext = SafePnextCopy(src.pNext);\n' 1212 ' if (src.pViewports) {\n' 1213 ' pViewports = new VkViewport[src.viewportCount];\n' 1214 ' memcpy ((void *)pViewports, (void *)src.pViewports, sizeof(VkViewport)*src.viewportCount);\n' 1215 ' }\n' 1216 ' else\n' 1217 ' pViewports = NULL;\n' 1218 ' if (src.pScissors) {\n' 1219 ' pScissors = new VkRect2D[src.scissorCount];\n' 1220 ' memcpy ((void *)pScissors, (void *)src.pScissors, sizeof(VkRect2D)*src.scissorCount);\n' 1221 ' }\n' 1222 ' else\n' 1223 ' pScissors = NULL;\n', 1224 } 1225 1226 custom_destruct_txt = {'VkShaderModuleCreateInfo' : 1227 ' if (pCode)\n' 1228 ' delete[] reinterpret_cast<const uint8_t *>(pCode);\n' } 1229 copy_pnext = '' 1230 copy_strings = '' 1231 for member in item.members: 1232 m_type = member.type 1233 if member.name == 'pNext': 1234 copy_pnext = ' pNext = SafePnextCopy(in_struct->pNext);\n' 1235 if member.type in self.structNames: 1236 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) 1237 if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: 1238 m_type = 'safe_%s' % member.type 1239 if member.ispointer and 'safe_' not in m_type and self.TypeContainsObjectHandle(member.type, False) == False: 1240 # Ptr types w/o a safe_struct, for non-null case need to allocate new ptr and copy data in 1241 if m_type in ['void', 'char']: 1242 if member.name != 'pNext': 1243 if m_type == 'char': 1244 # Create deep copies of strings 1245 if member.len: 1246 copy_strings += ' char **tmp_%s = new char *[in_struct->%s];\n' % (member.name, member.len) 1247 copy_strings += ' for (uint32_t i = 0; i < %s; ++i) {\n' % member.len 1248 copy_strings += ' tmp_%s[i] = SafeStringCopy(in_struct->%s[i]);\n' % (member.name, member.name) 1249 copy_strings += ' }\n' 1250 copy_strings += ' %s = tmp_%s;\n' % (member.name, member.name) 1251 1252 destruct_txt += ' if (%s) {\n' % member.name 1253 destruct_txt += ' for (uint32_t i = 0; i < %s; ++i) {\n' % member.len 1254 destruct_txt += ' delete [] %s[i];\n' % member.name 1255 destruct_txt += ' }\n' 1256 destruct_txt += ' delete [] %s;\n' % member.name 1257 destruct_txt += ' }\n' 1258 else: 1259 copy_strings += ' %s = SafeStringCopy(in_struct->%s);\n' % (member.name, member.name) 1260 destruct_txt += ' if (%s) delete [] %s;\n' % (member.name, member.name) 1261 else: 1262 # For these exceptions just copy initial value over for now 1263 init_list += '\n %s(in_struct->%s),' % (member.name, member.name) 1264 init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) 1265 default_init_list += '\n %s(nullptr),' % (member.name) 1266 else: 1267 default_init_list += '\n %s(nullptr),' % (member.name) 1268 init_list += '\n %s(nullptr),' % (member.name) 1269 if m_type in abstract_types: 1270 construct_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) 1271 else: 1272 init_func_txt += ' %s = nullptr;\n' % (member.name) 1273 if not member.isstaticarray and (member.len is None or '/' in member.len): 1274 construct_txt += ' if (in_struct->%s) {\n' % member.name 1275 construct_txt += ' %s = new %s(*in_struct->%s);\n' % (member.name, m_type, member.name) 1276 construct_txt += ' }\n' 1277 destruct_txt += ' if (%s)\n' % member.name 1278 destruct_txt += ' delete %s;\n' % member.name 1279 else: 1280 construct_txt += ' if (in_struct->%s) {\n' % member.name 1281 construct_txt += ' %s = new %s[in_struct->%s];\n' % (member.name, m_type, member.len) 1282 construct_txt += ' memcpy ((void *)%s, (void *)in_struct->%s, sizeof(%s)*in_struct->%s);\n' % (member.name, member.name, m_type, member.len) 1283 construct_txt += ' }\n' 1284 destruct_txt += ' if (%s)\n' % member.name 1285 destruct_txt += ' delete[] %s;\n' % member.name 1286 elif member.isstaticarray or member.len is not None: 1287 if member.len is None: 1288 # Extract length of static array by grabbing val between [] 1289 static_array_size = re.match(r"[^[]*\[([^]]*)\]", member.cdecl) 1290 construct_txt += ' for (uint32_t i = 0; i < %s; ++i) {\n' % static_array_size.group(1) 1291 construct_txt += ' %s[i] = in_struct->%s[i];\n' % (member.name, member.name) 1292 construct_txt += ' }\n' 1293 else: 1294 # Init array ptr to NULL 1295 default_init_list += '\n %s(nullptr),' % member.name 1296 init_list += '\n %s(nullptr),' % member.name 1297 init_func_txt += ' %s = nullptr;\n' % member.name 1298 array_element = 'in_struct->%s[i]' % member.name 1299 if member.type in self.structNames: 1300 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) 1301 if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: 1302 array_element = '%s(&in_struct->safe_%s[i])' % (member.type, member.name) 1303 construct_txt += ' if (%s && in_struct->%s) {\n' % (member.len, member.name) 1304 construct_txt += ' %s = new %s[%s];\n' % (member.name, m_type, member.len) 1305 destruct_txt += ' if (%s)\n' % member.name 1306 destruct_txt += ' delete[] %s;\n' % member.name 1307 construct_txt += ' for (uint32_t i = 0; i < %s; ++i) {\n' % (member.len) 1308 if 'safe_' in m_type: 1309 construct_txt += ' %s[i].initialize(&in_struct->%s[i]);\n' % (member.name, member.name) 1310 else: 1311 construct_txt += ' %s[i] = %s;\n' % (member.name, array_element) 1312 construct_txt += ' }\n' 1313 construct_txt += ' }\n' 1314 elif member.ispointer == True: 1315 default_init_list += '\n %s(nullptr),' % (member.name) 1316 init_list += '\n %s(nullptr),' % (member.name) 1317 init_func_txt += ' %s = nullptr;\n' % (member.name) 1318 construct_txt += ' if (in_struct->%s)\n' % member.name 1319 construct_txt += ' %s = new %s(in_struct->%s);\n' % (member.name, m_type, member.name) 1320 destruct_txt += ' if (%s)\n' % member.name 1321 destruct_txt += ' delete %s;\n' % member.name 1322 elif 'safe_' in m_type: 1323 init_list += '\n %s(&in_struct->%s),' % (member.name, member.name) 1324 init_func_txt += ' %s.initialize(&in_struct->%s);\n' % (member.name, member.name) 1325 else: 1326 init_list += '\n %s(in_struct->%s),' % (member.name, member.name) 1327 init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) 1328 if '' != init_list: 1329 init_list = init_list[:-1] # hack off final comma 1330 1331 1332 if item.name in custom_construct_txt: 1333 construct_txt = custom_construct_txt[item.name] 1334 1335 construct_txt = copy_pnext + copy_strings + construct_txt 1336 1337 if item.name in custom_destruct_txt: 1338 destruct_txt = custom_destruct_txt[item.name] 1339 1340 if copy_pnext: 1341 destruct_txt += ' if (pNext)\n FreePnextChain(pNext);\n' 1342 1343 safe_struct_body.append("\n%s::%s(const %s* in_struct%s) :%s\n{\n%s}" % (ss_name, ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_list, construct_txt)) 1344 if '' != default_init_list: 1345 default_init_list = " :%s" % (default_init_list[:-1]) 1346 safe_struct_body.append("\n%s::%s()%s\n{}" % (ss_name, ss_name, default_init_list)) 1347 # Create slight variation of init and construct txt for copy constructor that takes a src object reference vs. struct ptr 1348 copy_construct_init = init_func_txt.replace('in_struct->', 'src.') 1349 copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line 1350 copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line 1351 copy_construct_txt = re.sub('(new \\w+)\\(in_struct->', '\\1(*src.', construct_txt) # Pass object to copy constructors 1352 copy_construct_txt = copy_construct_txt.replace('in_struct->', 'src.') # Modify remaining struct refs for src object 1353 if item.name in custom_copy_txt: 1354 copy_construct_txt = custom_copy_txt[item.name] 1355 copy_assign_txt = ' if (&src == this) return *this;\n\n' + destruct_txt + '\n' + copy_construct_init + copy_construct_txt + '\n return *this;' 1356 safe_struct_body.append("\n%s::%s(const %s& src)\n{\n%s%s}" % (ss_name, ss_name, ss_name, copy_construct_init, copy_construct_txt)) # Copy constructor 1357 safe_struct_body.append("\n%s& %s::operator=(const %s& src)\n{\n%s\n}" % (ss_name, ss_name, ss_name, copy_assign_txt)) # Copy assignment operator 1358 safe_struct_body.append("\n%s::~%s()\n{\n%s}" % (ss_name, ss_name, destruct_txt)) 1359 safe_struct_body.append("\nvoid %s::initialize(const %s* in_struct%s)\n{\n%s%s}" % (ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_func_txt, construct_txt)) 1360 # Copy initializer uses same txt as copy constructor but has a ptr and not a reference 1361 init_copy = copy_construct_init.replace('src.', 'src->') 1362 init_construct = copy_construct_txt.replace('src.', 'src->') 1363 safe_struct_body.append("\nvoid %s::initialize(const %s* src)\n{\n%s%s}" % (ss_name, ss_name, init_copy, init_construct)) 1364 if item.ifdef_protect is not None: 1365 safe_struct_body.append("#endif // %s\n" % item.ifdef_protect) 1366 return "\n".join(safe_struct_body) 1367 # 1368 # Generate the type map 1369 def GenerateTypeMapHelperHeader(self): 1370 prefix = 'Lvl' 1371 fprefix = 'lvl_' 1372 typemap = prefix + 'TypeMap' 1373 idmap = prefix + 'STypeMap' 1374 type_member = 'Type' 1375 id_member = 'kSType' 1376 id_decl = 'static const VkStructureType ' 1377 generic_header = 'VkBaseOutStructure' 1378 typename_func = fprefix + 'typename' 1379 idname_func = fprefix + 'stype_name' 1380 find_func = fprefix + 'find_in_chain' 1381 init_func = fprefix + 'init_struct' 1382 1383 explanatory_comment = '\n'.join(( 1384 '// These empty generic templates are specialized for each type with sType', 1385 '// members and for each sType -- providing a two way map between structure', 1386 '// types and sTypes')) 1387 1388 empty_typemap = 'template <typename T> struct ' + typemap + ' {};' 1389 typemap_format = 'template <> struct {template}<{typename}> {{\n' 1390 typemap_format += ' {id_decl}{id_member} = {id_value};\n' 1391 typemap_format += '}};\n' 1392 1393 empty_idmap = 'template <VkStructureType id> struct ' + idmap + ' {};' 1394 idmap_format = ''.join(( 1395 'template <> struct {template}<{id_value}> {{\n', 1396 ' typedef {typename} {typedef};\n', 1397 '}};\n')) 1398 1399 # Define the utilities (here so any renaming stays consistent), if this grows large, refactor to a fixed .h file 1400 utilities_format = '\n'.join(( 1401 '// Find an entry of the given type in the pNext chain', 1402 'template <typename T> const T *{find_func}(const void *next) {{', 1403 ' const {header} *current = reinterpret_cast<const {header} *>(next);', 1404 ' const T *found = nullptr;', 1405 ' while (current) {{', 1406 ' if ({type_map}<T>::{id_member} == current->sType) {{', 1407 ' found = reinterpret_cast<const T*>(current);', 1408 ' current = nullptr;', 1409 ' }} else {{', 1410 ' current = current->pNext;', 1411 ' }}', 1412 ' }}', 1413 ' return found;', 1414 '}}', 1415 '', 1416 '// Init the header of an sType struct with pNext', 1417 'template <typename T> T {init_func}(void *p_next) {{', 1418 ' T out = {{}};', 1419 ' out.sType = {type_map}<T>::kSType;', 1420 ' out.pNext = p_next;', 1421 ' return out;', 1422 '}}', 1423 '', 1424 '// Init the header of an sType struct', 1425 'template <typename T> T {init_func}() {{', 1426 ' T out = {{}};', 1427 ' out.sType = {type_map}<T>::kSType;', 1428 ' return out;', 1429 '}}', 1430 1431 '')) 1432 1433 code = [] 1434 1435 # Generate header 1436 code.append('\n'.join(( 1437 '#pragma once', 1438 '#include <vulkan/vulkan.h>\n', 1439 explanatory_comment, '', 1440 empty_idmap, 1441 empty_typemap, ''))) 1442 1443 # Generate the specializations for each type and stype 1444 for item in self.structMembers: 1445 typename = item.name 1446 info = self.structTypes.get(typename) 1447 if not info: 1448 continue 1449 1450 if item.ifdef_protect is not None: 1451 code.append('#ifdef %s' % item.ifdef_protect) 1452 1453 code.append('// Map type {} to id {}'.format(typename, info.value)) 1454 code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value, 1455 id_decl=id_decl, id_member=id_member)) 1456 code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, typedef=type_member)) 1457 1458 if item.ifdef_protect is not None: 1459 code.append('#endif // %s' % item.ifdef_protect) 1460 1461 # Generate utilities for all types 1462 code.append('\n'.join(( 1463 utilities_format.format(id_member=id_member, id_map=idmap, type_map=typemap, 1464 type_member=type_member, header=generic_header, typename_func=typename_func, idname_func=idname_func, 1465 find_func=find_func, init_func=init_func), '' 1466 ))) 1467 1468 return "\n".join(code) 1469 1470 # 1471 # Create a helper file and return it as a string 1472 def OutputDestFile(self): 1473 if self.helper_file_type == 'enum_string_header': 1474 return self.GenerateEnumStringHelperHeader() 1475 elif self.helper_file_type == 'safe_struct_header': 1476 return self.GenerateSafeStructHelperHeader() 1477 elif self.helper_file_type == 'safe_struct_source': 1478 return self.GenerateSafeStructHelperSource() 1479 elif self.helper_file_type == 'object_types_header': 1480 return self.GenerateObjectTypesHelperHeader() 1481 elif self.helper_file_type == 'extension_helper_header': 1482 return self.GenerateExtensionHelperHeader() 1483 elif self.helper_file_type == 'typemap_helper_header': 1484 return self.GenerateTypeMapHelperHeader() 1485 else: 1486 return 'Bad Helper File Generator Option %s' % self.helper_file_type 1487