1#!/usr/bin/python3 -i 2# 3# Copyright (c) 2015-2017 The Khronos Group Inc. 4# Copyright (c) 2015-2017 Valve Corporation 5# Copyright (c) 2015-2017 LunarG, Inc. 6# Copyright (c) 2015-2017 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 23import os,re,sys 24import xml.etree.ElementTree as etree 25from generator import * 26from collections import namedtuple 27 28# 29# HelperFileOutputGeneratorOptions - subclass of GeneratorOptions. 30class HelperFileOutputGeneratorOptions(GeneratorOptions): 31 def __init__(self, 32 filename = None, 33 directory = '.', 34 apiname = None, 35 profile = None, 36 versions = '.*', 37 emitversions = '.*', 38 defaultExtensions = None, 39 addExtensions = None, 40 removeExtensions = None, 41 sortProcedure = regSortFeatures, 42 prefixText = "", 43 genFuncPointers = True, 44 protectFile = True, 45 protectFeature = True, 46 protectProto = None, 47 protectProtoStr = None, 48 apicall = '', 49 apientry = '', 50 apientryp = '', 51 alignFuncParam = 0, 52 library_name = '', 53 helper_file_type = ''): 54 GeneratorOptions.__init__(self, filename, directory, apiname, profile, 55 versions, emitversions, defaultExtensions, 56 addExtensions, removeExtensions, sortProcedure) 57 self.prefixText = prefixText 58 self.genFuncPointers = genFuncPointers 59 self.protectFile = protectFile 60 self.protectFeature = protectFeature 61 self.protectProto = protectProto 62 self.protectProtoStr = protectProtoStr 63 self.apicall = apicall 64 self.apientry = apientry 65 self.apientryp = apientryp 66 self.alignFuncParam = alignFuncParam 67 self.library_name = library_name 68 self.helper_file_type = helper_file_type 69# 70# HelperFileOutputGenerator - subclass of OutputGenerator. Outputs Vulkan helper files 71class HelperFileOutputGenerator(OutputGenerator): 72 """Generate helper file based on XML element attributes""" 73 def __init__(self, 74 errFile = sys.stderr, 75 warnFile = sys.stderr, 76 diagFile = sys.stdout): 77 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 78 # Internal state - accumulators for different inner block text 79 self.enum_output = '' # string built up of enum string routines 80 self.struct_size_h_output = '' # string built up of struct size header output 81 self.struct_size_c_output = '' # string built up of struct size source output 82 # Internal state - accumulators for different inner block text 83 self.structNames = [] # List of Vulkan struct typenames 84 self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType 85 self.structMembers = [] # List of StructMemberData records for all Vulkan structs 86 self.object_types = [] # List of all handle types 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 92 # Named tuples to store struct and command data 93 self.StructType = namedtuple('StructType', ['name', 'value']) 94 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl']) 95 self.StructMemberData = namedtuple('StructMemberData', ['name', 'members', 'ifdef_protect']) 96 97 self.custom_construct_params = { 98 # safe_VkGraphicsPipelineCreateInfo needs to know if subpass has color and\or depth\stencil attachments to use its pointers 99 'VkGraphicsPipelineCreateInfo' : 100 ', const bool uses_color_attachment, const bool uses_depthstencil_attachment', 101 # safe_VkPipelineViewportStateCreateInfo needs to know if viewport and scissor is dynamic to use its pointers 102 'VkPipelineViewportStateCreateInfo' : 103 ', const bool is_dynamic_viewports, const bool is_dynamic_scissors', 104 } 105 # 106 # Called once at the beginning of each run 107 def beginFile(self, genOpts): 108 OutputGenerator.beginFile(self, genOpts) 109 # User-supplied prefix text, if any (list of strings) 110 self.helper_file_type = genOpts.helper_file_type 111 self.library_name = genOpts.library_name 112 # File Comment 113 file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' 114 file_comment += '// See helper_file_generator.py for modifications\n' 115 write(file_comment, file=self.outFile) 116 # Copyright Notice 117 copyright = '' 118 copyright += '\n' 119 copyright += '/***************************************************************************\n' 120 copyright += ' *\n' 121 copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n' 122 copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n' 123 copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n' 124 copyright += ' * Copyright (c) 2015-2017 Google Inc.\n' 125 copyright += ' *\n' 126 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 127 copyright += ' * you may not use this file except in compliance with the License.\n' 128 copyright += ' * You may obtain a copy of the License at\n' 129 copyright += ' *\n' 130 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 131 copyright += ' *\n' 132 copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 133 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 134 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 135 copyright += ' * See the License for the specific language governing permissions and\n' 136 copyright += ' * limitations under the License.\n' 137 copyright += ' *\n' 138 copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n' 139 copyright += ' * Author: Courtney Goeltzenleuchter <courtneygo@google.com>\n' 140 copyright += ' * Author: Tobin Ehlis <tobine@google.com>\n' 141 copyright += ' * Author: Chris Forbes <chrisforbes@google.com>\n' 142 copyright += ' * Author: John Zulauf<jzulauf@lunarg.com>\n' 143 copyright += ' *\n' 144 copyright += ' ****************************************************************************/\n' 145 write(copyright, file=self.outFile) 146 # 147 # Write generated file content to output file 148 def endFile(self): 149 dest_file = '' 150 dest_file += self.OutputDestFile() 151 # Remove blank lines at EOF 152 if dest_file.endswith('\n'): 153 dest_file = dest_file[:-1] 154 write(dest_file, file=self.outFile); 155 # Finish processing in superclass 156 OutputGenerator.endFile(self) 157 # 158 # Override parent class to be notified of the beginning of an extension 159 def beginFeature(self, interface, emit): 160 # Start processing in superclass 161 OutputGenerator.beginFeature(self, interface, emit) 162 if self.featureName == 'VK_VERSION_1_0': 163 return 164 nameElem = interface[0][1] 165 name = nameElem.get('name') 166 if 'EXTENSION_NAME' not in name: 167 print("Error in vk.xml file -- extension name is not available") 168 if interface.get('type') == 'instance': 169 self.instance_extension_info[name] = self.featureExtraProtect 170 else: 171 self.device_extension_info[name] = self.featureExtraProtect 172 # 173 # Override parent class to be notified of the end of an extension 174 def endFeature(self): 175 # Finish processing in superclass 176 OutputGenerator.endFeature(self) 177 # 178 # Grab group (e.g. C "enum" type) info to output for enum-string conversion helper 179 def genGroup(self, groupinfo, groupName): 180 OutputGenerator.genGroup(self, groupinfo, groupName) 181 groupElem = groupinfo.elem 182 # For enum_string_header 183 if self.helper_file_type == 'enum_string_header': 184 value_list = [] 185 for elem in groupElem.findall('enum'): 186 if elem.get('supported') != 'disabled': 187 item_name = elem.get('name') 188 value_list.append(item_name) 189 if value_list is not None: 190 self.enum_output += self.GenerateEnumStringConversion(groupName, value_list) 191 elif self.helper_file_type == 'object_types_header': 192 if groupName == 'VkDebugReportObjectTypeEXT': 193 for elem in groupElem.findall('enum'): 194 if elem.get('supported') != 'disabled': 195 item_name = elem.get('name') 196 self.debug_report_object_types.append(item_name) 197 elif groupName == 'VkObjectType': 198 for elem in groupElem.findall('enum'): 199 if elem.get('supported') != 'disabled': 200 item_name = elem.get('name') 201 self.core_object_types.append(item_name) 202 203 # 204 # Called for each type -- if the type is a struct/union, grab the metadata 205 def genType(self, typeinfo, name): 206 OutputGenerator.genType(self, typeinfo, name) 207 typeElem = typeinfo.elem 208 # If the type is a struct type, traverse the imbedded <member> tags generating a structure. 209 # Otherwise, emit the tag text. 210 category = typeElem.get('category') 211 if category == 'handle': 212 self.object_types.append(name) 213 elif (category == 'struct' or category == 'union'): 214 self.structNames.append(name) 215 self.genStruct(typeinfo, name) 216 # 217 # Generate a VkStructureType based on a structure typename 218 def genVkStructureType(self, typename): 219 # Add underscore between lowercase then uppercase 220 value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename) 221 # Change to uppercase 222 value = value.upper() 223 # Add STRUCTURE_TYPE_ 224 return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value) 225 # 226 # Check if the parameter passed in is a pointer 227 def paramIsPointer(self, param): 228 ispointer = False 229 for elem in param: 230 if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail: 231 ispointer = True 232 return ispointer 233 # 234 # Check if the parameter passed in is a static array 235 def paramIsStaticArray(self, param): 236 isstaticarray = 0 237 paramname = param.find('name') 238 if (paramname.tail is not None) and ('[' in paramname.tail): 239 isstaticarray = paramname.tail.count('[') 240 return isstaticarray 241 # 242 # Retrieve the type and name for a parameter 243 def getTypeNameTuple(self, param): 244 type = '' 245 name = '' 246 for elem in param: 247 if elem.tag == 'type': 248 type = noneStr(elem.text) 249 elif elem.tag == 'name': 250 name = noneStr(elem.text) 251 return (type, name) 252 # Extract length values from latexmath. Currently an inflexible solution that looks for specific 253 # patterns that are found in vk.xml. Will need to be updated when new patterns are introduced. 254 def parseLateXMath(self, source): 255 name = 'ERROR' 256 decoratedName = 'ERROR' 257 if 'mathit' in source: 258 # Matches expressions similar to 'latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]' 259 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) 260 if not match or match.group(1) != match.group(4): 261 raise 'Unrecognized latexmath expression' 262 name = match.group(2) 263 # Need to add 1 for ceiling function; otherwise, the allocated packet 264 # size will be less than needed during capture for some title which use 265 # this in VkPipelineMultisampleStateCreateInfo. based on ceiling function 266 # definition,it is '{0}%{1}?{0}/{1} + 1:{0}/{1}'.format(*match.group(2, 3)), 267 # its value <= '{}/{} + 1'. 268 if match.group(1) == 'ceil': 269 decoratedName = '{}/{} + 1'.format(*match.group(2, 3)) 270 else: 271 decoratedName = '{}/{}'.format(*match.group(2, 3)) 272 else: 273 # Matches expressions similar to 'latexmath : [dataSize \over 4]' 274 match = re.match(r'latexmath\s*\:\s*\[\s*(\w+)\s*\\over\s*(\d+)\s*\]', source) 275 name = match.group(1) 276 decoratedName = '{}/{}'.format(*match.group(1, 2)) 277 return name, decoratedName 278 # 279 # Retrieve the value of the len tag 280 def getLen(self, param): 281 result = None 282 len = param.attrib.get('len') 283 if len and len != 'null-terminated': 284 # For string arrays, 'len' can look like 'count,null-terminated', indicating that we 285 # have a null terminated array of strings. We strip the null-terminated from the 286 # 'len' field and only return the parameter specifying the string count 287 if 'null-terminated' in len: 288 result = len.split(',')[0] 289 else: 290 result = len 291 if 'latexmath' in len: 292 param_type, param_name = self.getTypeNameTuple(param) 293 len_name, result = self.parseLateXMath(len) 294 # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol 295 result = str(result).replace('::', '->') 296 return result 297 # 298 # Check if a structure is or contains a dispatchable (dispatchable = True) or 299 # non-dispatchable (dispatchable = False) handle 300 def TypeContainsObjectHandle(self, handle_type, dispatchable): 301 if dispatchable: 302 type_key = 'VK_DEFINE_HANDLE' 303 else: 304 type_key = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE' 305 handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']") 306 if handle is not None and handle.find('type').text == type_key: 307 return True 308 # if handle_type is a struct, search its members 309 if handle_type in self.structNames: 310 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == handle_type), None) 311 if member_index is not None: 312 for item in self.structMembers[member_index].members: 313 handle = self.registry.tree.find("types/type/[name='" + item.type + "'][@category='handle']") 314 if handle is not None and handle.find('type').text == type_key: 315 return True 316 return False 317 # 318 # Generate local ready-access data describing Vulkan structures and unions from the XML metadata 319 def genStruct(self, typeinfo, typeName): 320 OutputGenerator.genStruct(self, typeinfo, typeName) 321 members = typeinfo.elem.findall('.//member') 322 # Iterate over members once to get length parameters for arrays 323 lens = set() 324 for member in members: 325 len = self.getLen(member) 326 if len: 327 lens.add(len) 328 # Generate member info 329 membersInfo = [] 330 for member in members: 331 # Get the member's type and name 332 info = self.getTypeNameTuple(member) 333 type = info[0] 334 name = info[1] 335 cdecl = self.makeCParamDecl(member, 1) 336 # Process VkStructureType 337 if type == 'VkStructureType': 338 # Extract the required struct type value from the comments 339 # embedded in the original text defining the 'typeinfo' element 340 rawXml = etree.tostring(typeinfo.elem).decode('ascii') 341 result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml) 342 if result: 343 value = result.group(0) 344 else: 345 value = self.genVkStructureType(typeName) 346 # Store the required type value 347 self.structTypes[typeName] = self.StructType(name=name, value=value) 348 # Store pointer/array/string info 349 isstaticarray = self.paramIsStaticArray(member) 350 membersInfo.append(self.CommandParam(type=type, 351 name=name, 352 ispointer=self.paramIsPointer(member), 353 isstaticarray=isstaticarray, 354 isconst=True if 'const' in cdecl else False, 355 iscount=True if name in lens else False, 356 len=self.getLen(member), 357 extstructs=self.registry.validextensionstructs[typeName] if name == 'pNext' else None, 358 cdecl=cdecl)) 359 self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo, ifdef_protect=self.featureExtraProtect)) 360 # 361 # Enum_string_header: Create a routine to convert an enumerated value into a string 362 def GenerateEnumStringConversion(self, groupName, value_list): 363 outstring = '\n' 364 outstring += 'static inline const char* string_%s(%s input_value)\n' % (groupName, groupName) 365 outstring += '{\n' 366 outstring += ' switch ((%s)input_value)\n' % groupName 367 outstring += ' {\n' 368 for item in value_list: 369 outstring += ' case %s:\n' % item 370 outstring += ' return "%s";\n' % item 371 outstring += ' default:\n' 372 outstring += ' return "Unhandled %s";\n' % groupName 373 outstring += ' }\n' 374 outstring += '}\n' 375 return outstring 376 # 377 # Tack on a helper which, given an index into a VkPhysicalDeviceFeatures structure, will print the corresponding feature name 378 def DeIndexPhysDevFeatures(self): 379 pdev_members = None 380 for name, members, ifdef in self.structMembers: 381 if name == 'VkPhysicalDeviceFeatures': 382 pdev_members = members 383 break 384 deindex = '\n' 385 deindex += 'static const char * GetPhysDevFeatureString(uint32_t index) {\n' 386 deindex += ' const char * IndexToPhysDevFeatureString[] = {\n' 387 for feature in pdev_members: 388 deindex += ' "%s",\n' % feature.name 389 deindex += ' };\n\n' 390 deindex += ' return IndexToPhysDevFeatureString[index];\n' 391 deindex += '}\n' 392 return deindex 393 # 394 # Combine enum string helper header file preamble with body text and return 395 def GenerateEnumStringHelperHeader(self): 396 enum_string_helper_header = '\n' 397 enum_string_helper_header += '#pragma once\n' 398 enum_string_helper_header += '#ifdef _WIN32\n' 399 enum_string_helper_header += '#pragma warning( disable : 4065 )\n' 400 enum_string_helper_header += '#endif\n' 401 enum_string_helper_header += '\n' 402 enum_string_helper_header += '#include <vulkan/vulkan.h>\n' 403 enum_string_helper_header += '\n' 404 enum_string_helper_header += self.enum_output 405 enum_string_helper_header += self.DeIndexPhysDevFeatures() 406 return enum_string_helper_header 407 # 408 # struct_size_header: build function prototypes for header file 409 def GenerateStructSizeHeader(self): 410 outstring = '' 411 outstring += 'size_t get_struct_chain_size(const void* struct_ptr);\n' 412 outstring += 'size_t get_struct_size(const void* struct_ptr);\n' 413 for item in self.structMembers: 414 lower_case_name = item.name.lower() 415 if item.ifdef_protect != None: 416 outstring += '#ifdef %s\n' % item.ifdef_protect 417 outstring += 'size_t vk_size_%s(const %s* struct_ptr);\n' % (item.name.lower(), item.name) 418 if item.ifdef_protect != None: 419 outstring += '#endif // %s\n' % item.ifdef_protect 420 outstring += '#ifdef __cplusplus\n' 421 outstring += '}\n' 422 outstring += '#endif' 423 return outstring 424 # 425 # Combine struct size helper header file preamble with body text and return 426 def GenerateStructSizeHelperHeader(self): 427 struct_size_helper_header = '\n' 428 struct_size_helper_header += '#ifdef __cplusplus\n' 429 struct_size_helper_header += 'extern "C" {\n' 430 struct_size_helper_header += '#endif\n' 431 struct_size_helper_header += '\n' 432 struct_size_helper_header += '#include <stdio.h>\n' 433 struct_size_helper_header += '#include <stdlib.h>\n' 434 struct_size_helper_header += '#include <vulkan/vulkan.h>\n' 435 struct_size_helper_header += '\n' 436 struct_size_helper_header += '// Function Prototypes\n' 437 struct_size_helper_header += self.GenerateStructSizeHeader() 438 return struct_size_helper_header 439 # 440 # Helper function for declaring a counter variable only once 441 def DeclareCounter(self, string_var, declare_flag): 442 if declare_flag == False: 443 string_var += ' uint32_t i = 0;\n' 444 declare_flag = True 445 return string_var, declare_flag 446 # 447 # Build the header of the get_struct_chain_size function 448 def GenerateChainSizePreamble(self): 449 preamble = '\nsize_t get_struct_chain_size(const void* struct_ptr) {\n' 450 preamble += ' // Use VkApplicationInfo as struct until actual type is resolved\n' 451 preamble += ' VkApplicationInfo* pNext = (VkApplicationInfo*)struct_ptr;\n' 452 preamble += ' size_t struct_size = 0;\n' 453 preamble += ' while (pNext) {\n' 454 preamble += ' switch (pNext->sType) {\n' 455 return preamble 456 # 457 # Build the footer of the get_struct_chain_size function 458 def GenerateChainSizePostamble(self): 459 postamble = ' default:\n' 460 postamble += ' struct_size += 0;\n' 461 postamble += ' break;' 462 postamble += ' }\n' 463 postamble += ' pNext = (VkApplicationInfo*)pNext->pNext;\n' 464 postamble += ' }\n' 465 postamble += ' return struct_size;\n' 466 postamble += '}\n' 467 return postamble 468 # 469 # Build the header of the get_struct_size function 470 def GenerateStructSizePreamble(self): 471 preamble = '\nsize_t get_struct_size(const void* struct_ptr) {\n' 472 preamble += ' switch (((VkApplicationInfo*)struct_ptr)->sType) {\n' 473 return preamble 474 # 475 # Build the footer of the get_struct_size function 476 def GenerateStructSizePostamble(self): 477 postamble = ' default:\n' 478 postamble += ' return(0);\n' 479 postamble += ' }\n' 480 postamble += '}' 481 return postamble 482 # 483 # struct_size_helper source -- create bodies of struct size helper functions 484 def GenerateStructSizeSource(self): 485 # Construct the bodies of the struct size functions, get_struct_chain_size(), 486 # and get_struct_size() simultaneously 487 struct_size_funcs = '' 488 chain_size = self.GenerateChainSizePreamble() 489 struct_size = self.GenerateStructSizePreamble() 490 for item in self.structMembers: 491 struct_size_funcs += '\n' 492 lower_case_name = item.name.lower() 493 if item.ifdef_protect != None: 494 struct_size_funcs += '#ifdef %s\n' % item.ifdef_protect 495 struct_size += '#ifdef %s\n' % item.ifdef_protect 496 chain_size += '#ifdef %s\n' % item.ifdef_protect 497 if item.name in self.structTypes: 498 chain_size += ' case %s: {\n' % self.structTypes[item.name].value 499 chain_size += ' struct_size += vk_size_%s((%s*)pNext);\n' % (item.name.lower(), item.name) 500 chain_size += ' break;\n' 501 chain_size += ' }\n' 502 struct_size += ' case %s: \n' % self.structTypes[item.name].value 503 struct_size += ' return vk_size_%s((%s*)struct_ptr);\n' % (item.name.lower(), item.name) 504 struct_size_funcs += 'size_t vk_size_%s(const %s* struct_ptr) { \n' % (item.name.lower(), item.name) 505 struct_size_funcs += ' size_t struct_size = 0;\n' 506 struct_size_funcs += ' if (struct_ptr) {\n' 507 struct_size_funcs += ' struct_size = sizeof(%s);\n' % item.name 508 counter_declared = False 509 for member in item.members: 510 vulkan_type = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) 511 if member.ispointer == True: 512 if vulkan_type is not None: 513 # If this is another Vulkan structure call generated size function 514 if member.len is not None: 515 struct_size_funcs, counter_declared = self.DeclareCounter(struct_size_funcs, counter_declared) 516 struct_size_funcs += ' for (i = 0; i < struct_ptr->%s; i++) {\n' % member.len 517 struct_size_funcs += ' struct_size += vk_size_%s(&struct_ptr->%s[i]);\n' % (member.type.lower(), member.name) 518 struct_size_funcs += ' }\n' 519 else: 520 struct_size_funcs += ' struct_size += vk_size_%s(struct_ptr->%s);\n' % (member.type.lower(), member.name) 521 else: 522 if member.type == 'char': 523 # Deal with sizes of character strings 524 if member.len is not None: 525 struct_size_funcs, counter_declared = self.DeclareCounter(struct_size_funcs, counter_declared) 526 struct_size_funcs += ' for (i = 0; i < struct_ptr->%s; i++) {\n' % member.len 527 struct_size_funcs += ' struct_size += (sizeof(char*) + (sizeof(char) * (1 + strlen(struct_ptr->%s[i]))));\n' % (member.name) 528 struct_size_funcs += ' }\n' 529 else: 530 struct_size_funcs += ' struct_size += (struct_ptr->%s != NULL) ? sizeof(char)*(1+strlen(struct_ptr->%s)) : 0;\n' % (member.name, member.name) 531 else: 532 if member.len is not None: 533 # Avoid using 'sizeof(void)', which generates compile-time warnings/errors 534 checked_type = member.type 535 if checked_type == 'void': 536 checked_type = 'void*' 537 struct_size_funcs += ' struct_size += (struct_ptr->%s ) * sizeof(%s);\n' % (member.len, checked_type) 538 struct_size_funcs += ' }\n' 539 struct_size_funcs += ' return struct_size;\n' 540 struct_size_funcs += '}\n' 541 if item.ifdef_protect != None: 542 struct_size_funcs += '#endif // %s\n' % item.ifdef_protect 543 struct_size += '#endif // %s\n' % item.ifdef_protect 544 chain_size += '#endif // %s\n' % item.ifdef_protect 545 chain_size += self.GenerateChainSizePostamble() 546 struct_size += self.GenerateStructSizePostamble() 547 return_value = struct_size_funcs + chain_size + struct_size; 548 return return_value 549 # 550 # Combine struct size helper source file preamble with body text and return 551 def GenerateStructSizeHelperSource(self): 552 struct_size_helper_source = '\n' 553 struct_size_helper_source += '#include "vk_struct_size_helper.h"\n' 554 struct_size_helper_source += '#include <string.h>\n' 555 struct_size_helper_source += '#include <assert.h>\n' 556 struct_size_helper_source += '\n' 557 struct_size_helper_source += '// Function Definitions\n' 558 struct_size_helper_source += self.GenerateStructSizeSource() 559 return struct_size_helper_source 560 # 561 # Combine safe struct helper header file preamble with body text and return 562 def GenerateSafeStructHelperHeader(self): 563 safe_struct_helper_header = '\n' 564 safe_struct_helper_header += '#pragma once\n' 565 safe_struct_helper_header += '#include <vulkan/vulkan.h>\n' 566 safe_struct_helper_header += '\n' 567 safe_struct_helper_header += self.GenerateSafeStructHeader() 568 return safe_struct_helper_header 569 # 570 # safe_struct header: build function prototypes for header file 571 def GenerateSafeStructHeader(self): 572 safe_struct_header = '' 573 for item in self.structMembers: 574 if self.NeedSafeStruct(item) == True: 575 safe_struct_header += '\n' 576 if item.ifdef_protect != None: 577 safe_struct_header += '#ifdef %s\n' % item.ifdef_protect 578 safe_struct_header += 'struct safe_%s {\n' % (item.name) 579 for member in item.members: 580 if member.type in self.structNames: 581 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) 582 if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: 583 if member.ispointer: 584 safe_struct_header += ' safe_%s* %s;\n' % (member.type, member.name) 585 else: 586 safe_struct_header += ' safe_%s %s;\n' % (member.type, member.name) 587 continue 588 if member.len is not None and (self.TypeContainsObjectHandle(member.type, True) or self.TypeContainsObjectHandle(member.type, False)): 589 safe_struct_header += ' %s* %s;\n' % (member.type, member.name) 590 else: 591 safe_struct_header += '%s;\n' % member.cdecl 592 safe_struct_header += ' safe_%s(const %s* in_struct%s);\n' % (item.name, item.name, self.custom_construct_params.get(item.name, '')) 593 safe_struct_header += ' safe_%s(const safe_%s& src);\n' % (item.name, item.name) 594 safe_struct_header += ' safe_%s& operator=(const safe_%s& src);\n' % (item.name, item.name) 595 safe_struct_header += ' safe_%s();\n' % item.name 596 safe_struct_header += ' ~safe_%s();\n' % item.name 597 safe_struct_header += ' void initialize(const %s* in_struct%s);\n' % (item.name, self.custom_construct_params.get(item.name, '')) 598 safe_struct_header += ' void initialize(const safe_%s* src);\n' % (item.name) 599 safe_struct_header += ' %s *ptr() { return reinterpret_cast<%s *>(this); }\n' % (item.name, item.name) 600 safe_struct_header += ' %s const *ptr() const { return reinterpret_cast<%s const *>(this); }\n' % (item.name, item.name) 601 safe_struct_header += '};\n' 602 if item.ifdef_protect != None: 603 safe_struct_header += '#endif // %s\n' % item.ifdef_protect 604 return safe_struct_header 605 # 606 # Generate extension helper header file 607 def GenerateExtensionHelperHeader(self): 608 extension_helper_header = '\n' 609 extension_helper_header += '#ifndef VK_EXTENSION_HELPER_H_\n' 610 extension_helper_header += '#define VK_EXTENSION_HELPER_H_\n' 611 struct = '\n' 612 extension_helper_header += '#include <vulkan/vulkan.h>\n' 613 extension_helper_header += '#include <string.h>\n' 614 extension_helper_header += '#include <utility>\n' 615 extension_helper_header += '\n' 616 extension_dict = dict() 617 for type in ['Instance', 'Device']: 618 if type == 'Instance': 619 extension_dict = self.instance_extension_info 620 struct += 'struct InstanceExtensions { \n' 621 else: 622 extension_dict = self.device_extension_info 623 struct += 'struct DeviceExtensions : public InstanceExtensions { \n' 624 for ext_name, ifdef in extension_dict.items(): 625 bool_name = ext_name.lower() 626 bool_name = re.sub('_extension_name', '', bool_name) 627 struct += ' bool %s{false};\n' % bool_name 628 struct += '\n' 629 if type == 'Instance': 630 struct += ' void InitFromInstanceCreateInfo(const VkInstanceCreateInfo *pCreateInfo) {\n' 631 else: 632 struct += ' void InitFromDeviceCreateInfo(const InstanceExtensions *instance_extensions, const VkDeviceCreateInfo *pCreateInfo) {\n' 633 struct += '\n' 634 struct += ' static const std::pair<char const *, bool %sExtensions::*> known_extensions[]{\n' % type 635 for ext_name, ifdef in extension_dict.items(): 636 if ifdef is not None: 637 struct += '#ifdef %s\n' % ifdef 638 bool_name = ext_name.lower() 639 bool_name = re.sub('_extension_name', '', bool_name) 640 struct += ' {%s, &%sExtensions::%s},\n' % (ext_name, type, bool_name) 641 if ifdef is not None: 642 struct += '#endif\n' 643 struct += ' };\n' 644 struct += '\n' 645 struct += ' // Initialize struct data\n' 646 for ext_name, ifdef in self.instance_extension_info.items(): 647 bool_name = ext_name.lower() 648 bool_name = re.sub('_extension_name', '', bool_name) 649 if type == 'Device': 650 struct += ' %s = instance_extensions->%s;\n' % (bool_name, bool_name) 651 struct += '\n' 652 struct += ' for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {\n' 653 struct += ' for (auto ext : known_extensions) {\n' 654 struct += ' if (!strcmp(ext.first, pCreateInfo->ppEnabledExtensionNames[i])) {\n' 655 struct += ' this->*(ext.second) = true;\n' 656 struct += ' break;\n' 657 struct += ' }\n' 658 struct += ' }\n' 659 struct += ' }\n' 660 struct += ' }\n' 661 struct += '};\n' 662 struct += '\n' 663 # Output reference lists of instance/device extension names 664 struct += 'static const char * const k%sExtensionNames = \n' % type 665 for ext_name, ifdef in extension_dict.items(): 666 if ifdef is not None: 667 struct += '#ifdef %s\n' % ifdef 668 struct += ' %s\n' % ext_name 669 if ifdef is not None: 670 struct += '#endif\n' 671 struct += ';\n\n' 672 extension_helper_header += struct 673 extension_helper_header += '\n' 674 extension_helper_header += '#endif // VK_EXTENSION_HELPER_H_\n' 675 return extension_helper_header 676 # 677 # Combine object types helper header file preamble with body text and return 678 def GenerateObjectTypesHelperHeader(self): 679 object_types_helper_header = '\n' 680 object_types_helper_header += '#pragma once\n' 681 object_types_helper_header += '\n' 682 object_types_helper_header += '#include <vulkan/vulkan.h>\n\n' 683 object_types_helper_header += self.GenerateObjectTypesHeader() 684 return object_types_helper_header 685 # 686 # Object types header: create object enum type header file 687 def GenerateObjectTypesHeader(self): 688 object_types_header = '// Object Type enum for validation layer internal object handling\n' 689 object_types_header += 'typedef enum VulkanObjectType {\n' 690 object_types_header += ' kVulkanObjectTypeUnknown = 0,\n' 691 enum_num = 1 692 type_list = []; 693 694 # Output enum definition as each handle is processed, saving the names to use for the conversion routine 695 for item in self.object_types: 696 fixup_name = item[2:] 697 enum_entry = 'kVulkanObjectType%s' % fixup_name 698 object_types_header += ' ' + enum_entry 699 object_types_header += ' = %d,\n' % enum_num 700 enum_num += 1 701 type_list.append(enum_entry) 702 object_types_header += ' kVulkanObjectTypeMax = %d,\n' % enum_num 703 object_types_header += '} VulkanObjectType;\n\n' 704 705 # Output name string helper 706 object_types_header += '// Array of object name strings for OBJECT_TYPE enum conversion\n' 707 object_types_header += 'static const char * const object_string[kVulkanObjectTypeMax] = {\n' 708 object_types_header += ' "Unknown",\n' 709 for item in self.object_types: 710 fixup_name = item[2:] 711 object_types_header += ' "%s",\n' % fixup_name 712 object_types_header += '};\n' 713 714 # Output a conversion routine from the layer object definitions to the debug report definitions 715 object_types_header += '\n' 716 object_types_header += '// Helper array to get Vulkan VK_EXT_debug_report object type enum from the internal layers version\n' 717 object_types_header += 'const VkDebugReportObjectTypeEXT get_debug_report_enum[] = {\n' 718 object_types_header += ' VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // No Match\n' 719 for object_type in type_list: 720 search_type = object_type.replace("kVulkanObjectType", "").lower() 721 for vk_object_type in self.debug_report_object_types: 722 target_type = vk_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower() 723 target_type = target_type[:-4] 724 target_type = target_type.replace("_", "") 725 if search_type == target_type: 726 object_types_header += ' %s, // %s\n' % (vk_object_type, object_type) 727 break 728 object_types_header += '};\n' 729 730 # Output a conversion routine from the layer object definitions to the core object type definitions 731 object_types_header += '\n' 732 object_types_header += '// Helper array to get Official Vulkan VkObjectType enum from the internal layers version\n' 733 object_types_header += 'const VkObjectType get_object_type_enum[] = {\n' 734 object_types_header += ' VK_OBJECT_TYPE_UNKNOWN, // No Match\n' 735 for object_type in type_list: 736 search_type = object_type.replace("kVulkanObjectType", "").lower() 737 for vk_object_type in self.core_object_types: 738 target_type = vk_object_type.replace("VK_OBJECT_TYPE_", "").lower() 739 target_type = target_type.replace("_", "") 740 if search_type == target_type: 741 object_types_header += ' %s, // %s\n' % (vk_object_type, object_type) 742 break 743 object_types_header += '};\n' 744 745 return object_types_header 746 # 747 # Determine if a structure needs a safe_struct helper function 748 # That is, it has an sType or one of its members is a pointer 749 def NeedSafeStruct(self, structure): 750 if 'sType' == structure.name: 751 return True 752 for member in structure.members: 753 if member.ispointer == True: 754 return True 755 return False 756 # 757 # Combine safe struct helper source file preamble with body text and return 758 def GenerateSafeStructHelperSource(self): 759 safe_struct_helper_source = '\n' 760 safe_struct_helper_source += '#include "vk_safe_struct.h"\n' 761 safe_struct_helper_source += '#include <string.h>\n' 762 safe_struct_helper_source += '\n' 763 safe_struct_helper_source += self.GenerateSafeStructSource() 764 return safe_struct_helper_source 765 # 766 # safe_struct source -- create bodies of safe struct helper functions 767 def GenerateSafeStructSource(self): 768 safe_struct_body = [] 769 wsi_structs = ['VkXlibSurfaceCreateInfoKHR', 770 'VkXcbSurfaceCreateInfoKHR', 771 'VkWaylandSurfaceCreateInfoKHR', 772 'VkMirSurfaceCreateInfoKHR', 773 'VkAndroidSurfaceCreateInfoKHR', 774 'VkWin32SurfaceCreateInfoKHR' 775 ] 776 for item in self.structMembers: 777 if self.NeedSafeStruct(item) == False: 778 continue 779 if item.name in wsi_structs: 780 continue 781 if item.ifdef_protect != None: 782 safe_struct_body.append("#ifdef %s\n" % item.ifdef_protect) 783 ss_name = "safe_%s" % item.name 784 init_list = '' # list of members in struct constructor initializer 785 default_init_list = '' # Default constructor just inits ptrs to nullptr in initializer 786 init_func_txt = '' # Txt for initialize() function that takes struct ptr and inits members 787 construct_txt = '' # Body of constuctor as well as body of initialize() func following init_func_txt 788 destruct_txt = '' 789 790 custom_construct_txt = { 791 # VkWriteDescriptorSet is special case because pointers may be non-null but ignored 792 'VkWriteDescriptorSet' : 793 ' switch (descriptorType) {\n' 794 ' case VK_DESCRIPTOR_TYPE_SAMPLER:\n' 795 ' case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:\n' 796 ' case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:\n' 797 ' case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:\n' 798 ' case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:\n' 799 ' if (descriptorCount && in_struct->pImageInfo) {\n' 800 ' pImageInfo = new VkDescriptorImageInfo[descriptorCount];\n' 801 ' for (uint32_t i=0; i<descriptorCount; ++i) {\n' 802 ' pImageInfo[i] = in_struct->pImageInfo[i];\n' 803 ' }\n' 804 ' }\n' 805 ' break;\n' 806 ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:\n' 807 ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:\n' 808 ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:\n' 809 ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:\n' 810 ' if (descriptorCount && in_struct->pBufferInfo) {\n' 811 ' pBufferInfo = new VkDescriptorBufferInfo[descriptorCount];\n' 812 ' for (uint32_t i=0; i<descriptorCount; ++i) {\n' 813 ' pBufferInfo[i] = in_struct->pBufferInfo[i];\n' 814 ' }\n' 815 ' }\n' 816 ' break;\n' 817 ' case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:\n' 818 ' case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:\n' 819 ' if (descriptorCount && in_struct->pTexelBufferView) {\n' 820 ' pTexelBufferView = new VkBufferView[descriptorCount];\n' 821 ' for (uint32_t i=0; i<descriptorCount; ++i) {\n' 822 ' pTexelBufferView[i] = in_struct->pTexelBufferView[i];\n' 823 ' }\n' 824 ' }\n' 825 ' break;\n' 826 ' default:\n' 827 ' break;\n' 828 ' }\n', 829 'VkShaderModuleCreateInfo' : 830 ' if (in_struct->pCode) {\n' 831 ' pCode = reinterpret_cast<uint32_t *>(new uint8_t[codeSize]);\n' 832 ' memcpy((void *)pCode, (void *)in_struct->pCode, codeSize);\n' 833 ' }\n', 834 # VkGraphicsPipelineCreateInfo is special case because its pointers may be non-null but ignored 835 'VkGraphicsPipelineCreateInfo' : 836 ' if (stageCount && in_struct->pStages) {\n' 837 ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' 838 ' for (uint32_t i=0; i<stageCount; ++i) {\n' 839 ' pStages[i].initialize(&in_struct->pStages[i]);\n' 840 ' }\n' 841 ' }\n' 842 ' if (in_struct->pVertexInputState)\n' 843 ' pVertexInputState = new safe_VkPipelineVertexInputStateCreateInfo(in_struct->pVertexInputState);\n' 844 ' else\n' 845 ' pVertexInputState = NULL;\n' 846 ' if (in_struct->pInputAssemblyState)\n' 847 ' pInputAssemblyState = new safe_VkPipelineInputAssemblyStateCreateInfo(in_struct->pInputAssemblyState);\n' 848 ' else\n' 849 ' pInputAssemblyState = NULL;\n' 850 ' bool has_tessellation_stage = false;\n' 851 ' if (stageCount && pStages)\n' 852 ' for (uint32_t i=0; i<stageCount && !has_tessellation_stage; ++i)\n' 853 ' if (pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)\n' 854 ' has_tessellation_stage = true;\n' 855 ' if (in_struct->pTessellationState && has_tessellation_stage)\n' 856 ' pTessellationState = new safe_VkPipelineTessellationStateCreateInfo(in_struct->pTessellationState);\n' 857 ' else\n' 858 ' pTessellationState = NULL; // original pTessellationState pointer ignored\n' 859 ' bool has_rasterization = in_struct->pRasterizationState ? !in_struct->pRasterizationState->rasterizerDiscardEnable : false;\n' 860 ' if (in_struct->pViewportState && has_rasterization) {\n' 861 ' bool is_dynamic_viewports = false;\n' 862 ' bool is_dynamic_scissors = false;\n' 863 ' if (in_struct->pDynamicState && in_struct->pDynamicState->pDynamicStates) {\n' 864 ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_viewports; ++i)\n' 865 ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_VIEWPORT)\n' 866 ' is_dynamic_viewports = true;\n' 867 ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_scissors; ++i)\n' 868 ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_SCISSOR)\n' 869 ' is_dynamic_scissors = true;\n' 870 ' }\n' 871 ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(in_struct->pViewportState, is_dynamic_viewports, is_dynamic_scissors);\n' 872 ' } else\n' 873 ' pViewportState = NULL; // original pViewportState pointer ignored\n' 874 ' if (in_struct->pRasterizationState)\n' 875 ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(in_struct->pRasterizationState);\n' 876 ' else\n' 877 ' pRasterizationState = NULL;\n' 878 ' if (in_struct->pMultisampleState && has_rasterization)\n' 879 ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(in_struct->pMultisampleState);\n' 880 ' else\n' 881 ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' 882 ' // needs a tracked subpass state uses_depthstencil_attachment\n' 883 ' if (in_struct->pDepthStencilState && has_rasterization && uses_depthstencil_attachment)\n' 884 ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(in_struct->pDepthStencilState);\n' 885 ' else\n' 886 ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' 887 ' // needs a tracked subpass state usesColorAttachment\n' 888 ' if (in_struct->pColorBlendState && has_rasterization && uses_color_attachment)\n' 889 ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(in_struct->pColorBlendState);\n' 890 ' else\n' 891 ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' 892 ' if (in_struct->pDynamicState)\n' 893 ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(in_struct->pDynamicState);\n' 894 ' else\n' 895 ' pDynamicState = NULL;\n', 896 # VkPipelineViewportStateCreateInfo is special case because its pointers may be non-null but ignored 897 'VkPipelineViewportStateCreateInfo' : 898 ' if (in_struct->pViewports && !is_dynamic_viewports) {\n' 899 ' pViewports = new VkViewport[in_struct->viewportCount];\n' 900 ' memcpy ((void *)pViewports, (void *)in_struct->pViewports, sizeof(VkViewport)*in_struct->viewportCount);\n' 901 ' }\n' 902 ' else\n' 903 ' pViewports = NULL;\n' 904 ' if (in_struct->pScissors && !is_dynamic_scissors) {\n' 905 ' pScissors = new VkRect2D[in_struct->scissorCount];\n' 906 ' memcpy ((void *)pScissors, (void *)in_struct->pScissors, sizeof(VkRect2D)*in_struct->scissorCount);\n' 907 ' }\n' 908 ' else\n' 909 ' pScissors = NULL;\n', 910 # VkDescriptorSetLayoutBinding is special case because its pImmutableSamplers pointer may be non-null but ignored 911 'VkDescriptorSetLayoutBinding' : 912 ' const bool sampler_type = in_struct->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || in_struct->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n' 913 ' if (descriptorCount && in_struct->pImmutableSamplers && sampler_type) {\n' 914 ' pImmutableSamplers = new VkSampler[descriptorCount];\n' 915 ' for (uint32_t i=0; i<descriptorCount; ++i) {\n' 916 ' pImmutableSamplers[i] = in_struct->pImmutableSamplers[i];\n' 917 ' }\n' 918 ' }\n', 919 } 920 921 custom_copy_txt = { 922 # VkGraphicsPipelineCreateInfo is special case because it has custom construct parameters 923 'VkGraphicsPipelineCreateInfo' : 924 ' if (stageCount && src.pStages) {\n' 925 ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' 926 ' for (uint32_t i=0; i<stageCount; ++i) {\n' 927 ' pStages[i].initialize(&src.pStages[i]);\n' 928 ' }\n' 929 ' }\n' 930 ' if (src.pVertexInputState)\n' 931 ' pVertexInputState = new safe_VkPipelineVertexInputStateCreateInfo(*src.pVertexInputState);\n' 932 ' else\n' 933 ' pVertexInputState = NULL;\n' 934 ' if (src.pInputAssemblyState)\n' 935 ' pInputAssemblyState = new safe_VkPipelineInputAssemblyStateCreateInfo(*src.pInputAssemblyState);\n' 936 ' else\n' 937 ' pInputAssemblyState = NULL;\n' 938 ' bool has_tessellation_stage = false;\n' 939 ' if (stageCount && pStages)\n' 940 ' for (uint32_t i=0; i<stageCount && !has_tessellation_stage; ++i)\n' 941 ' if (pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)\n' 942 ' has_tessellation_stage = true;\n' 943 ' if (src.pTessellationState && has_tessellation_stage)\n' 944 ' pTessellationState = new safe_VkPipelineTessellationStateCreateInfo(*src.pTessellationState);\n' 945 ' else\n' 946 ' pTessellationState = NULL; // original pTessellationState pointer ignored\n' 947 ' bool has_rasterization = src.pRasterizationState ? !src.pRasterizationState->rasterizerDiscardEnable : false;\n' 948 ' if (src.pViewportState && has_rasterization) {\n' 949 ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(*src.pViewportState);\n' 950 ' } else\n' 951 ' pViewportState = NULL; // original pViewportState pointer ignored\n' 952 ' if (src.pRasterizationState)\n' 953 ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(*src.pRasterizationState);\n' 954 ' else\n' 955 ' pRasterizationState = NULL;\n' 956 ' if (src.pMultisampleState && has_rasterization)\n' 957 ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(*src.pMultisampleState);\n' 958 ' else\n' 959 ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' 960 ' if (src.pDepthStencilState && has_rasterization)\n' 961 ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(*src.pDepthStencilState);\n' 962 ' else\n' 963 ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' 964 ' if (src.pColorBlendState && has_rasterization)\n' 965 ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(*src.pColorBlendState);\n' 966 ' else\n' 967 ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' 968 ' if (src.pDynamicState)\n' 969 ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(*src.pDynamicState);\n' 970 ' else\n' 971 ' pDynamicState = NULL;\n', 972 # VkPipelineViewportStateCreateInfo is special case because it has custom construct parameters 973 'VkPipelineViewportStateCreateInfo' : 974 ' if (src.pViewports) {\n' 975 ' pViewports = new VkViewport[src.viewportCount];\n' 976 ' memcpy ((void *)pViewports, (void *)src.pViewports, sizeof(VkViewport)*src.viewportCount);\n' 977 ' }\n' 978 ' else\n' 979 ' pViewports = NULL;\n' 980 ' if (src.pScissors) {\n' 981 ' pScissors = new VkRect2D[src.scissorCount];\n' 982 ' memcpy ((void *)pScissors, (void *)src.pScissors, sizeof(VkRect2D)*src.scissorCount);\n' 983 ' }\n' 984 ' else\n' 985 ' pScissors = NULL;\n', 986 } 987 988 custom_destruct_txt = {'VkShaderModuleCreateInfo' : 989 ' if (pCode)\n' 990 ' delete[] reinterpret_cast<const uint8_t *>(pCode);\n' } 991 992 for member in item.members: 993 m_type = member.type 994 if member.type in self.structNames: 995 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) 996 if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: 997 m_type = 'safe_%s' % member.type 998 if member.ispointer and 'safe_' not in m_type and self.TypeContainsObjectHandle(member.type, False) == False: 999 # Ptr types w/o a safe_struct, for non-null case need to allocate new ptr and copy data in 1000 if m_type in ['void', 'char']: 1001 # For these exceptions just copy initial value over for now 1002 init_list += '\n %s(in_struct->%s),' % (member.name, member.name) 1003 init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) 1004 else: 1005 default_init_list += '\n %s(nullptr),' % (member.name) 1006 init_list += '\n %s(nullptr),' % (member.name) 1007 init_func_txt += ' %s = nullptr;\n' % (member.name) 1008 if 'pNext' != member.name and 'void' not in m_type: 1009 if not member.isstaticarray and (member.len is None or '/' in member.len): 1010 construct_txt += ' if (in_struct->%s) {\n' % member.name 1011 construct_txt += ' %s = new %s(*in_struct->%s);\n' % (member.name, m_type, member.name) 1012 construct_txt += ' }\n' 1013 destruct_txt += ' if (%s)\n' % member.name 1014 destruct_txt += ' delete %s;\n' % member.name 1015 else: 1016 construct_txt += ' if (in_struct->%s) {\n' % member.name 1017 construct_txt += ' %s = new %s[in_struct->%s];\n' % (member.name, m_type, member.len) 1018 construct_txt += ' memcpy ((void *)%s, (void *)in_struct->%s, sizeof(%s)*in_struct->%s);\n' % (member.name, member.name, m_type, member.len) 1019 construct_txt += ' }\n' 1020 destruct_txt += ' if (%s)\n' % member.name 1021 destruct_txt += ' delete[] %s;\n' % member.name 1022 elif member.isstaticarray or member.len is not None: 1023 if member.len is None: 1024 # Extract length of static array by grabbing val between [] 1025 static_array_size = re.match(r"[^[]*\[([^]]*)\]", member.cdecl) 1026 construct_txt += ' for (uint32_t i=0; i<%s; ++i) {\n' % static_array_size.group(1) 1027 construct_txt += ' %s[i] = in_struct->%s[i];\n' % (member.name, member.name) 1028 construct_txt += ' }\n' 1029 else: 1030 # Init array ptr to NULL 1031 default_init_list += '\n %s(nullptr),' % member.name 1032 init_list += '\n %s(nullptr),' % member.name 1033 init_func_txt += ' %s = nullptr;\n' % member.name 1034 array_element = 'in_struct->%s[i]' % member.name 1035 if member.type in self.structNames: 1036 member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) 1037 if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: 1038 array_element = '%s(&in_struct->safe_%s[i])' % (member.type, member.name) 1039 construct_txt += ' if (%s && in_struct->%s) {\n' % (member.len, member.name) 1040 construct_txt += ' %s = new %s[%s];\n' % (member.name, m_type, member.len) 1041 destruct_txt += ' if (%s)\n' % member.name 1042 destruct_txt += ' delete[] %s;\n' % member.name 1043 construct_txt += ' for (uint32_t i=0; i<%s; ++i) {\n' % (member.len) 1044 if 'safe_' in m_type: 1045 construct_txt += ' %s[i].initialize(&in_struct->%s[i]);\n' % (member.name, member.name) 1046 else: 1047 construct_txt += ' %s[i] = %s;\n' % (member.name, array_element) 1048 construct_txt += ' }\n' 1049 construct_txt += ' }\n' 1050 elif member.ispointer == True: 1051 construct_txt += ' if (in_struct->%s)\n' % member.name 1052 construct_txt += ' %s = new %s(in_struct->%s);\n' % (member.name, m_type, member.name) 1053 construct_txt += ' else\n' 1054 construct_txt += ' %s = NULL;\n' % member.name 1055 destruct_txt += ' if (%s)\n' % member.name 1056 destruct_txt += ' delete %s;\n' % member.name 1057 elif 'safe_' in m_type: 1058 init_list += '\n %s(&in_struct->%s),' % (member.name, member.name) 1059 init_func_txt += ' %s.initialize(&in_struct->%s);\n' % (member.name, member.name) 1060 else: 1061 init_list += '\n %s(in_struct->%s),' % (member.name, member.name) 1062 init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) 1063 if '' != init_list: 1064 init_list = init_list[:-1] # hack off final comma 1065 if item.name in custom_construct_txt: 1066 construct_txt = custom_construct_txt[item.name] 1067 if item.name in custom_destruct_txt: 1068 destruct_txt = custom_destruct_txt[item.name] 1069 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)) 1070 if '' != default_init_list: 1071 default_init_list = " :%s" % (default_init_list[:-1]) 1072 safe_struct_body.append("\n%s::%s()%s\n{}" % (ss_name, ss_name, default_init_list)) 1073 # Create slight variation of init and construct txt for copy constructor that takes a src object reference vs. struct ptr 1074 copy_construct_init = init_func_txt.replace('in_struct->', 'src.') 1075 copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line 1076 copy_construct_txt = copy_construct_txt.replace('(in_struct->', '(*src.') # Pass object to copy constructors 1077 copy_construct_txt = copy_construct_txt.replace('in_struct->', 'src.') # Modify remaining struct refs for src object 1078 if item.name in custom_copy_txt: 1079 copy_construct_txt = custom_copy_txt[item.name] 1080 copy_assign_txt = ' if (&src == this) return *this;\n\n' + destruct_txt + '\n' + copy_construct_init + copy_construct_txt + '\n return *this;' 1081 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 1082 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 1083 safe_struct_body.append("\n%s::~%s()\n{\n%s}" % (ss_name, ss_name, destruct_txt)) 1084 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)) 1085 # Copy initializer uses same txt as copy constructor but has a ptr and not a reference 1086 init_copy = copy_construct_init.replace('src.', 'src->') 1087 init_construct = copy_construct_txt.replace('src.', 'src->') 1088 safe_struct_body.append("\nvoid %s::initialize(const %s* src)\n{\n%s%s}" % (ss_name, ss_name, init_copy, init_construct)) 1089 if item.ifdef_protect != None: 1090 safe_struct_body.append("#endif // %s\n" % item.ifdef_protect) 1091 return "\n".join(safe_struct_body) 1092 # 1093 # Generate the type map 1094 def GenerateTypeMapHelperHeader(self): 1095 prefix = 'Lvl' 1096 fprefix = 'lvl_' 1097 typemap = prefix + 'TypeMap' 1098 idmap = prefix + 'STypeMap' 1099 type_member = 'Type' 1100 id_member = 'kSType' 1101 id_decl = 'static const VkStructureType ' 1102 generic_header = prefix + 'GenericHeader' 1103 typename_func = fprefix + 'typename' 1104 idname_func = fprefix + 'stype_name' 1105 find_func = fprefix + 'find_in_chain' 1106 init_func = fprefix + 'init_struct' 1107 1108 explanatory_comment = '\n'.join(( 1109 '// These empty generic templates are specialized for each type with sType', 1110 '// members and for each sType -- providing a two way map between structure', 1111 '// types and sTypes')) 1112 1113 empty_typemap = 'template <typename T> struct ' + typemap + ' {};' 1114 typemap_format = 'template <> struct {template}<{typename}> {{\n' 1115 typemap_format += ' {id_decl}{id_member} = {id_value};\n' 1116 typemap_format += '}};\n' 1117 1118 empty_idmap = 'template <VkStructureType id> struct ' + idmap + ' {};' 1119 idmap_format = ''.join(( 1120 'template <> struct {template}<{id_value}> {{\n', 1121 ' typedef {typename} {typedef};\n', 1122 '}};\n')) 1123 1124 # Define the utilities (here so any renaming stays consistent), if this grows large, refactor to a fixed .h file 1125 utilities_format = '\n'.join(( 1126 '// Header "base class" for pNext chain traversal', 1127 'struct {header} {{', 1128 ' VkStructureType sType;', 1129 ' const {header} *pNext;', 1130 '}};', 1131 '', 1132 '// Find an entry of the given type in the pNext chain', 1133 'template <typename T> const T *{find_func}(const void *next) {{', 1134 ' const {header} *current = reinterpret_cast<const {header} *>(next);', 1135 ' const T *found = nullptr;', 1136 ' while (current) {{', 1137 ' if ({type_map}<T>::{id_member} == current->sType) {{', 1138 ' found = reinterpret_cast<const T*>(current);', 1139 ' current = nullptr;', 1140 ' }} else {{', 1141 ' current = current->pNext;', 1142 ' }}', 1143 ' }}', 1144 ' return found;', 1145 '}}', 1146 '', 1147 '// Init the header of an sType struct with pNext', 1148 'template <typename T> T {init_func}(void *p_next) {{', 1149 ' T out = {{}};', 1150 ' out.sType = {type_map}<T>::kSType;', 1151 ' out.pNext = p_next;', 1152 ' return out;', 1153 '}}', 1154 '', 1155 '// Init the header of an sType struct', 1156 'template <typename T> T {init_func}() {{', 1157 ' T out = {{}};', 1158 ' out.sType = {type_map}<T>::kSType;', 1159 ' return out;', 1160 '}}', 1161 1162 '')) 1163 1164 code = [] 1165 1166 # Generate header 1167 code.append('\n'.join(( 1168 '#pragma once', 1169 '#include <vulkan/vulkan.h>\n', 1170 explanatory_comment, '', 1171 empty_idmap, 1172 empty_typemap, ''))) 1173 1174 # Generate the specializations for each type and stype 1175 for item in self.structMembers: 1176 typename = item.name 1177 info = self.structTypes.get(typename) 1178 if not info: 1179 continue 1180 1181 if item.ifdef_protect != None: 1182 code.append('#ifdef %s' % item.ifdef_protect) 1183 1184 code.append('// Map type {} to id {}'.format(typename, info.value)) 1185 code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value, 1186 id_decl=id_decl, id_member=id_member)) 1187 code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, typedef=type_member)) 1188 1189 if item.ifdef_protect != None: 1190 code.append('#endif // %s' % item.ifdef_protect) 1191 1192 # Generate utilities for all types 1193 code.append('\n'.join(( 1194 utilities_format.format(id_member=id_member, id_map=idmap, type_map=typemap, 1195 type_member=type_member, header=generic_header, typename_func=typename_func, idname_func=idname_func, 1196 find_func=find_func, init_func=init_func), '' 1197 ))) 1198 1199 return "\n".join(code) 1200 1201 # 1202 # Create a helper file and return it as a string 1203 def OutputDestFile(self): 1204 if self.helper_file_type == 'enum_string_header': 1205 return self.GenerateEnumStringHelperHeader() 1206 elif self.helper_file_type == 'struct_size_header': 1207 return self.GenerateStructSizeHelperHeader() 1208 elif self.helper_file_type == 'struct_size_source': 1209 return self.GenerateStructSizeHelperSource() 1210 elif self.helper_file_type == 'safe_struct_header': 1211 return self.GenerateSafeStructHelperHeader() 1212 elif self.helper_file_type == 'safe_struct_source': 1213 return self.GenerateSafeStructHelperSource() 1214 elif self.helper_file_type == 'object_types_header': 1215 return self.GenerateObjectTypesHelperHeader() 1216 elif self.helper_file_type == 'extension_helper_header': 1217 return self.GenerateExtensionHelperHeader() 1218 elif self.helper_file_type == 'typemap_helper_header': 1219 return self.GenerateTypeMapHelperHeader() 1220 else: 1221 return 'Bad Helper File Generator Option %s' % self.helper_file_type 1222 1223