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