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