1#!/usr/bin/python3 -i 2# 3# Copyright (c) 2015-2020 The Khronos Group Inc. 4# Copyright (c) 2015-2020 Valve Corporation 5# Copyright (c) 2015-2020 LunarG, Inc. 6# Copyright (c) 2015-2020 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: Dave Houlton <daveh@lunarg.com> 22 23import os,re,sys,string,json 24import xml.etree.ElementTree as etree 25from generator import * 26from collections import namedtuple 27from common_codegen import * 28 29# This is a workaround to use a Python 2.7 and 3.x compatible syntax. 30from io import open 31 32# ObjectTrackerGeneratorOptions - subclass of GeneratorOptions. 33# 34# Adds options used by ObjectTrackerOutputGenerator objects during 35# object_tracker layer generation. 36# 37# Additional members 38# prefixText - list of strings to prefix generated header with 39# (usually a copyright statement + calling convention macros). 40# protectFile - True if multiple inclusion protection should be 41# generated (based on the filename) around the entire header. 42# protectFeature - True if #ifndef..#endif protection should be 43# generated around a feature interface in the header file. 44# genFuncPointers - True if function pointer typedefs should be 45# generated 46# protectProto - If conditional protection should be generated 47# around prototype declarations, set to either '#ifdef' 48# to require opt-in (#ifdef protectProtoStr) or '#ifndef' 49# to require opt-out (#ifndef protectProtoStr). Otherwise 50# set to None. 51# protectProtoStr - #ifdef/#ifndef symbol to use around prototype 52# declarations, if protectProto is set 53# apicall - string to use for the function declaration prefix, 54# such as APICALL on Windows. 55# apientry - string to use for the calling convention macro, 56# in typedefs, such as APIENTRY. 57# apientryp - string to use for the calling convention macro 58# in function pointer typedefs, such as APIENTRYP. 59# indentFuncProto - True if prototype declarations should put each 60# parameter on a separate line 61# indentFuncPointer - True if typedefed function pointers should put each 62# parameter on a separate line 63# alignFuncParam - if nonzero and parameters are being put on a 64# separate line, align parameter names at the specified column 65class ObjectTrackerGeneratorOptions(GeneratorOptions): 66 def __init__(self, 67 conventions = None, 68 filename = None, 69 directory = '.', 70 genpath = None, 71 apiname = None, 72 profile = None, 73 versions = '.*', 74 emitversions = '.*', 75 defaultExtensions = None, 76 addExtensions = None, 77 removeExtensions = None, 78 emitExtensions = None, 79 sortProcedure = regSortFeatures, 80 prefixText = "", 81 genFuncPointers = True, 82 protectFile = True, 83 protectFeature = True, 84 apicall = '', 85 apientry = '', 86 apientryp = '', 87 indentFuncProto = True, 88 indentFuncPointer = False, 89 alignFuncParam = 0, 90 expandEnumerants = True, 91 valid_usage_path = ''): 92 GeneratorOptions.__init__(self, 93 conventions = conventions, 94 filename = filename, 95 directory = directory, 96 genpath = genpath, 97 apiname = apiname, 98 profile = profile, 99 versions = versions, 100 emitversions = emitversions, 101 defaultExtensions = defaultExtensions, 102 addExtensions = addExtensions, 103 removeExtensions = removeExtensions, 104 emitExtensions = emitExtensions, 105 sortProcedure = sortProcedure) 106 self.prefixText = prefixText 107 self.genFuncPointers = genFuncPointers 108 self.protectFile = protectFile 109 self.protectFeature = protectFeature 110 self.apicall = apicall 111 self.apientry = apientry 112 self.apientryp = apientryp 113 self.indentFuncProto = indentFuncProto 114 self.indentFuncPointer = indentFuncPointer 115 self.alignFuncParam = alignFuncParam 116 self.expandEnumerants = expandEnumerants 117 self.valid_usage_path = valid_usage_path 118 119 120# ObjectTrackerOutputGenerator - subclass of OutputGenerator. 121# Generates object_tracker layer object validation code 122# 123# ---- methods ---- 124# ObjectTrackerOutputGenerator(errFile, warnFile, diagFile) - args as for OutputGenerator. Defines additional internal state. 125# ---- methods overriding base class ---- 126# beginFile(genOpts) 127# endFile() 128# beginFeature(interface, emit) 129# endFeature() 130# genCmd(cmdinfo) 131# genStruct() 132# genType() 133class ObjectTrackerOutputGenerator(OutputGenerator): 134 """Generate ObjectTracker code based on XML element attributes""" 135 # This is an ordered list of sections in the header file. 136 ALL_SECTIONS = ['command'] 137 def __init__(self, 138 errFile = sys.stderr, 139 warnFile = sys.stderr, 140 diagFile = sys.stdout): 141 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 142 self.INDENT_SPACES = 4 143 self.prototypes = [] 144 self.instance_extensions = [] 145 self.device_extensions = [] 146 # Commands which are not autogenerated but still intercepted 147 self.no_autogen_list = [ 148 'vkDestroyInstance', 149 'vkCreateInstance', 150 'vkCreateDevice', 151 'vkEnumeratePhysicalDevices', 152 'vkGetPhysicalDeviceQueueFamilyProperties', 153 'vkGetPhysicalDeviceQueueFamilyProperties2', 154 'vkGetPhysicalDeviceQueueFamilyProperties2KHR', 155 'vkGetDeviceQueue', 156 'vkGetDeviceQueue2', 157 'vkCreateDescriptorSetLayout', 158 'vkDestroyDescriptorPool', 159 'vkDestroyCommandPool', 160 'vkAllocateCommandBuffers', 161 'vkAllocateDescriptorSets', 162 'vkFreeDescriptorSets', 163 'vkFreeCommandBuffers', 164 'vkUpdateDescriptorSets', 165 'vkBeginCommandBuffer', 166 'vkGetDescriptorSetLayoutSupport', 167 'vkGetDescriptorSetLayoutSupportKHR', 168 'vkDestroySwapchainKHR', 169 'vkGetSwapchainImagesKHR', 170 'vkCmdPushDescriptorSetKHR', 171 'vkDestroyDevice', 172 'vkResetDescriptorPool', 173 'vkGetPhysicalDeviceDisplayPropertiesKHR', 174 'vkGetPhysicalDeviceDisplayProperties2KHR', 175 'vkGetDisplayModePropertiesKHR', 176 'vkGetDisplayModeProperties2KHR', 177 'vkCreateFramebuffer', 178 'vkSetDebugUtilsObjectNameEXT', 179 'vkSetDebugUtilsObjectTagEXT', 180 'vkCreateDescriptorUpdateTemplate', 181 'vkCreateDescriptorUpdateTemplateKHR', 182 183 ] 184 # These VUIDS are not implicit, but are best handled in this layer. Codegen for vkDestroy calls will generate a key 185 # which is translated here into a good VU. Saves ~40 checks. 186 self.manual_vuids = dict() 187 self.manual_vuids = { 188 "fence-compatalloc": "\"VUID-vkDestroyFence-fence-01121\"", 189 "fence-nullalloc": "\"VUID-vkDestroyFence-fence-01122\"", 190 "event-compatalloc": "\"VUID-vkDestroyEvent-event-01146\"", 191 "event-nullalloc": "\"VUID-vkDestroyEvent-event-01147\"", 192 "buffer-compatalloc": "\"VUID-vkDestroyBuffer-buffer-00923\"", 193 "buffer-nullalloc": "\"VUID-vkDestroyBuffer-buffer-00924\"", 194 "image-compatalloc": "\"VUID-vkDestroyImage-image-01001\"", 195 "image-nullalloc": "\"VUID-vkDestroyImage-image-01002\"", 196 "shaderModule-compatalloc": "\"VUID-vkDestroyShaderModule-shaderModule-01092\"", 197 "shaderModule-nullalloc": "\"VUID-vkDestroyShaderModule-shaderModule-01093\"", 198 "pipeline-compatalloc": "\"VUID-vkDestroyPipeline-pipeline-00766\"", 199 "pipeline-nullalloc": "\"VUID-vkDestroyPipeline-pipeline-00767\"", 200 "sampler-compatalloc": "\"VUID-vkDestroySampler-sampler-01083\"", 201 "sampler-nullalloc": "\"VUID-vkDestroySampler-sampler-01084\"", 202 "renderPass-compatalloc": "\"VUID-vkDestroyRenderPass-renderPass-00874\"", 203 "renderPass-nullalloc": "\"VUID-vkDestroyRenderPass-renderPass-00875\"", 204 "descriptorUpdateTemplate-compatalloc": "\"VUID-vkDestroyDescriptorUpdateTemplate-descriptorSetLayout-00356\"", 205 "descriptorUpdateTemplate-nullalloc": "\"VUID-vkDestroyDescriptorUpdateTemplate-descriptorSetLayout-00357\"", 206 "imageView-compatalloc": "\"VUID-vkDestroyImageView-imageView-01027\"", 207 "imageView-nullalloc": "\"VUID-vkDestroyImageView-imageView-01028\"", 208 "pipelineCache-compatalloc": "\"VUID-vkDestroyPipelineCache-pipelineCache-00771\"", 209 "pipelineCache-nullalloc": "\"VUID-vkDestroyPipelineCache-pipelineCache-00772\"", 210 "pipelineLayout-compatalloc": "\"VUID-vkDestroyPipelineLayout-pipelineLayout-00299\"", 211 "pipelineLayout-nullalloc": "\"VUID-vkDestroyPipelineLayout-pipelineLayout-00300\"", 212 "descriptorSetLayout-compatalloc": "\"VUID-vkDestroyDescriptorSetLayout-descriptorSetLayout-00284\"", 213 "descriptorSetLayout-nullalloc": "\"VUID-vkDestroyDescriptorSetLayout-descriptorSetLayout-00285\"", 214 "semaphore-compatalloc": "\"VUID-vkDestroySemaphore-semaphore-01138\"", 215 "semaphore-nullalloc": "\"VUID-vkDestroySemaphore-semaphore-01139\"", 216 "queryPool-compatalloc": "\"VUID-vkDestroyQueryPool-queryPool-00794\"", 217 "queryPool-nullalloc": "\"VUID-vkDestroyQueryPool-queryPool-00795\"", 218 "bufferView-compatalloc": "\"VUID-vkDestroyBufferView-bufferView-00937\"", 219 "bufferView-nullalloc": "\"VUID-vkDestroyBufferView-bufferView-00938\"", 220 "surface-compatalloc": "\"VUID-vkDestroySurfaceKHR-surface-01267\"", 221 "surface-nullalloc": "\"VUID-vkDestroySurfaceKHR-surface-01268\"", 222 "framebuffer-compatalloc": "\"VUID-vkDestroyFramebuffer-framebuffer-00893\"", 223 "framebuffer-nullalloc": "\"VUID-vkDestroyFramebuffer-framebuffer-00894\"", 224 "VkGraphicsPipelineCreateInfo-basePipelineHandle": "\"VUID-VkGraphicsPipelineCreateInfo-flags-00722\"", 225 "VkComputePipelineCreateInfo-basePipelineHandle": "\"VUID-VkComputePipelineCreateInfo-flags-00697\"", 226 "VkRayTracingPipelineCreateInfoNV-basePipelineHandle": "\"VUID-VkRayTracingPipelineCreateInfoNV-flags-03421\"", 227 "VkRayTracingPipelineCreateInfoKHR-basePipelineHandle": "\"VUID-VkRayTracingPipelineCreateInfoKHR-flags-03421\"", 228 } 229 230 # Commands shadowed by interface functions and are not implemented 231 self.interface_functions = [ 232 ] 233 self.headerVersion = None 234 # Internal state - accumulators for different inner block text 235 self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) 236 self.cmd_list = [] # list of commands processed to maintain ordering 237 self.cmd_info_dict = {} # Per entry-point data for code generation and validation 238 self.structMembers = [] # List of StructMemberData records for all Vulkan structs 239 self.extension_structs = [] # List of all structs or sister-structs containing handles 240 # A sister-struct may contain no handles but shares <validextensionstructs> with one that does 241 self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType 242 self.struct_member_dict = dict() 243 # Named tuples to store struct and command data 244 self.StructType = namedtuple('StructType', ['name', 'value']) 245 self.CmdInfoData = namedtuple('CmdInfoData', ['name', 'cmdinfo', 'members', 'extra_protect', 'alias', 'iscreate', 'isdestroy', 'allocator']) 246 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'isconst', 'isoptional', 'iscount', 'iscreate', 'len', 'extstructs', 'cdecl', 'islocal']) 247 self.StructMemberData = namedtuple('StructMemberData', ['name', 'members']) 248 self.object_types = [] # List of all handle types 249 self.valid_vuids = set() # Set of all valid VUIDs 250 self.vuid_dict = dict() # VUID dictionary (from JSON) 251 # 252 # Check if the parameter passed in is optional 253 def paramIsOptional(self, param): 254 # See if the handle is optional 255 isoptional = False 256 # Simple, if it's optional, return true 257 optString = param.attrib.get('optional') 258 if optString: 259 if optString == 'true': 260 isoptional = True 261 elif ',' in optString: 262 opts = [] 263 for opt in optString.split(','): 264 val = opt.strip() 265 if val == 'true': 266 opts.append(True) 267 elif val == 'false': 268 opts.append(False) 269 else: 270 print('Unrecognized len attribute value',val) 271 isoptional = opts 272 if not isoptional: 273 # Matching logic in parameter validation and ValidityOutputGenerator.isHandleOptional 274 optString = param.attrib.get('noautovalidity') 275 if optString and optString == 'true': 276 if param.attrib.get('len'): 277 isoptional = [True, True] 278 else: 279 isoptional = True 280 return isoptional 281 # 282 # Get VUID identifier from implicit VUID tag 283 def GetVuid(self, parent, suffix): 284 vuid_string = 'VUID-%s-%s' % (parent, suffix) 285 vuid = "kVUIDUndefined" 286 if '->' in vuid_string: 287 return vuid 288 if vuid_string in self.valid_vuids: 289 vuid = "\"%s\"" % vuid_string 290 else: 291 alias = self.cmd_info_dict[parent].alias if parent in self.cmd_info_dict else None 292 if alias: 293 alias_string = 'VUID-%s-%s' % (alias, suffix) 294 if alias_string in self.valid_vuids: 295 vuid = "\"%s\"" % alias_string 296 return vuid 297 # 298 # Increases indent by 4 spaces and tracks it globally 299 def incIndent(self, indent): 300 inc = ' ' * self.INDENT_SPACES 301 if indent: 302 return indent + inc 303 return inc 304 # 305 # Decreases indent by 4 spaces and tracks it globally 306 def decIndent(self, indent): 307 if indent and (len(indent) > self.INDENT_SPACES): 308 return indent[:-self.INDENT_SPACES] 309 return '' 310 # 311 # Override makeProtoName to drop the "vk" prefix 312 def makeProtoName(self, name, tail): 313 return self.genOpts.apientry + name[2:] + tail 314 # 315 # Check if the parameter passed in is a pointer to an array 316 def paramIsArray(self, param): 317 return param.attrib.get('len') is not None 318 319 # 320 # Generate the object tracker undestroyed object validation function 321 def GenReportFunc(self): 322 output_func = '' 323 for objtype in ['instance', 'device']: 324 upper_objtype = objtype.capitalize(); 325 output_func += 'bool ObjectLifetimes::ReportUndestroyed%sObjects(Vk%s %s, const std::string& error_code) const {\n' % (upper_objtype, upper_objtype, objtype) 326 output_func += ' bool skip = false;\n' 327 if objtype == 'device': 328 output_func += ' skip |= ReportLeaked%sObjects(%s, kVulkanObjectTypeCommandBuffer, error_code);\n' % (upper_objtype, objtype) 329 for handle in self.object_types: 330 if self.handle_types.IsNonDispatchable(handle) and not self.is_aliased_type[handle]: 331 if (objtype == 'device' and self.handle_parents.IsParentDevice(handle)) or (objtype == 'instance' and not self.handle_parents.IsParentDevice(handle)): 332 comment_prefix = '' 333 if (handle == 'VkDisplayKHR' or handle == 'VkDisplayModeKHR'): 334 comment_prefix = '// No destroy API -- do not report: ' 335 output_func += ' %sskip |= ReportLeaked%sObjects(%s, %s, error_code);\n' % (comment_prefix, upper_objtype, objtype, self.GetVulkanObjType(handle)) 336 output_func += ' return skip;\n' 337 output_func += '}\n' 338 return output_func 339 340 # 341 # Generate the object tracker undestroyed object destruction function 342 def GenDestroyFunc(self): 343 output_func = '' 344 for objtype in ['instance', 'device']: 345 upper_objtype = objtype.capitalize(); 346 output_func += 'void ObjectLifetimes::DestroyLeaked%sObjects() {\n' % upper_objtype 347 if objtype == 'device': 348 output_func += ' DestroyUndestroyedObjects(kVulkanObjectTypeCommandBuffer);\n' 349 for handle in self.object_types: 350 if self.handle_types.IsNonDispatchable(handle) and not self.is_aliased_type[handle]: 351 if (objtype == 'device' and self.handle_parents.IsParentDevice(handle)) or (objtype == 'instance' and not self.handle_parents.IsParentDevice(handle)): 352 output_func += ' DestroyUndestroyedObjects(%s);\n' % self.GetVulkanObjType(handle) 353 output_func += '}\n' 354 355 return output_func 356 357 # 358 # Walk the JSON-derived dict and find all "vuid" key values 359 def ExtractVUIDs(self, d): 360 if hasattr(d, 'items'): 361 for k, v in d.items(): 362 if k == "vuid": 363 yield v 364 elif isinstance(v, dict): 365 for s in self.ExtractVUIDs(v): 366 yield s 367 elif isinstance (v, list): 368 for l in v: 369 for s in self.ExtractVUIDs(l): 370 yield s 371 # 372 # Separate content for validation source and header files 373 def otwrite(self, dest, formatstring): 374 if 'object_tracker.h' in self.genOpts.filename and (dest == 'hdr' or dest == 'both'): 375 write(formatstring, file=self.outFile) 376 elif 'object_tracker.cpp' in self.genOpts.filename and (dest == 'cpp' or dest == 'both'): 377 write(formatstring, file=self.outFile) 378 379 # 380 # Called at beginning of processing as file is opened 381 def beginFile(self, genOpts): 382 OutputGenerator.beginFile(self, genOpts) 383 384 # Initialize members that require the tree 385 self.handle_types = GetHandleTypes(self.registry.tree) 386 self.handle_parents = GetHandleParents(self.registry.tree) 387 self.type_categories = GetTypeCategories(self.registry.tree) 388 self.is_aliased_type = GetHandleAliased(self.registry.tree) 389 390 header_file = (genOpts.filename == 'object_tracker.h') 391 source_file = (genOpts.filename == 'object_tracker.cpp') 392 393 if not header_file and not source_file: 394 print("Error: Output Filenames have changed, update generator source.\n") 395 sys.exit(1) 396 397 self.valid_usage_path = genOpts.valid_usage_path 398 vu_json_filename = os.path.join(self.valid_usage_path + os.sep, 'validusage.json') 399 if os.path.isfile(vu_json_filename): 400 json_file = open(vu_json_filename, 'r', encoding='utf-8') 401 self.vuid_dict = json.load(json_file) 402 json_file.close() 403 if len(self.vuid_dict) == 0: 404 print("Error: Could not find, or error loading %s/validusage.json\n", vu_json_filename) 405 sys.exit(1) 406 407 # Build a set of all vuid text strings found in validusage.json 408 for json_vuid_string in self.ExtractVUIDs(self.vuid_dict): 409 self.valid_vuids.add(json_vuid_string) 410 411 # File Comment 412 file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' 413 file_comment += '// See object_tracker_generator.py for modifications\n' 414 self.otwrite('both', file_comment) 415 # Copyright Statement 416 copyright = '' 417 copyright += '\n' 418 copyright += '/***************************************************************************\n' 419 copyright += ' *\n' 420 copyright += ' * Copyright (c) 2015-2020 The Khronos Group Inc.\n' 421 copyright += ' * Copyright (c) 2015-2020 Valve Corporation\n' 422 copyright += ' * Copyright (c) 2015-2020 LunarG, Inc.\n' 423 copyright += ' * Copyright (c) 2015-2020 Google Inc.\n' 424 copyright += ' *\n' 425 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 426 copyright += ' * you may not use this file except in compliance with the License.\n' 427 copyright += ' * You may obtain a copy of the License at\n' 428 copyright += ' *\n' 429 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 430 copyright += ' *\n' 431 copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 432 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 433 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 434 copyright += ' * See the License for the specific language governing permissions and\n' 435 copyright += ' * limitations under the License.\n' 436 copyright += ' *\n' 437 copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n' 438 copyright += ' * Author: Dave Houlton <daveh@lunarg.com>\n' 439 copyright += ' *\n' 440 copyright += ' ****************************************************************************/\n' 441 self.otwrite('both', copyright) 442 self.newline() 443 self.otwrite('cpp', '#include "chassis.h"') 444 self.otwrite('cpp', '#include "object_lifetime_validation.h"') 445 446 # 447 # Now that the data is all collected and complete, generate and output the object validation routines 448 def endFile(self): 449 self.struct_member_dict = dict(self.structMembers) 450 # Generate the list of APIs that might need to handle wrapped extension structs 451 # self.GenerateCommandWrapExtensionList() 452 self.WrapCommands() 453 # Build undestroyed objects reporting function 454 report_func = self.GenReportFunc() 455 self.newline() 456 # Build undestroyed objects destruction function 457 destroy_func = self.GenDestroyFunc() 458 self.otwrite('cpp', '\n') 459 self.otwrite('cpp', '// ObjectTracker undestroyed objects validation function') 460 self.otwrite('cpp', '%s' % report_func) 461 self.otwrite('cpp', '%s' % destroy_func) 462 # Actually write the interface to the output file. 463 if (self.emit): 464 self.newline() 465 if self.featureExtraProtect is not None: 466 prot = '#ifdef %s' % self.featureExtraProtect 467 self.otwrite('both', '%s' % prot) 468 # Write the object_tracker code to the file 469 if self.sections['command']: 470 source = ('\n'.join(self.sections['command'])) 471 self.otwrite('both', '%s' % source) 472 if (self.featureExtraProtect is not None): 473 prot = '\n#endif // %s', self.featureExtraProtect 474 self.otwrite('both', prot) 475 else: 476 self.otwrite('both', '\n') 477 478 479 self.otwrite('hdr', 'void PostCallRecordDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator);') 480 self.otwrite('hdr', 'void PreCallRecordResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);') 481 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties);') 482 self.otwrite('hdr', 'void PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers);') 483 self.otwrite('hdr', 'void PreCallRecordFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets);') 484 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties);') 485 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties);') 486 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkDisplayPropertiesKHR *pProperties, VkResult result);') 487 self.otwrite('hdr', 'void PostCallRecordGetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties, VkResult result);') 488 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkDisplayProperties2KHR *pProperties, VkResult result);') 489 self.otwrite('hdr', 'void PostCallRecordGetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties, VkResult result);') 490 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties, VkResult result);') 491 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlaneProperties2KHR* pProperties, VkResult result);') 492 OutputGenerator.endFile(self) 493 # 494 # Processing point at beginning of each extension definition 495 def beginFeature(self, interface, emit): 496 # Start processing in superclass 497 OutputGenerator.beginFeature(self, interface, emit) 498 self.headerVersion = None 499 self.featureExtraProtect = GetFeatureProtect(interface) 500 501 if interface.tag == 'extension': 502 white_list_entry = [] 503 if (self.featureExtraProtect is not None): 504 white_list_entry += [ '#ifdef %s' % self.featureExtraProtect ] 505 white_list_entry += [ '"%s"' % self.featureName ] 506 if (self.featureExtraProtect is not None): 507 white_list_entry += [ '#endif' ] 508 featureType = interface.get('type') 509 if featureType == 'instance': 510 self.instance_extensions += white_list_entry 511 elif featureType == 'device': 512 self.device_extensions += white_list_entry 513 # 514 # Processing point at end of each extension definition 515 def endFeature(self): 516 # Finish processing in superclass 517 OutputGenerator.endFeature(self) 518 # 519 # Process enums, structs, etc. 520 def genType(self, typeinfo, name, alias): 521 OutputGenerator.genType(self, typeinfo, name, alias) 522 typeElem = typeinfo.elem 523 # If the type is a struct type, traverse the imbedded <member> tags generating a structure. 524 # Otherwise, emit the tag text. 525 category = typeElem.get('category') 526 if (category == 'struct' or category == 'union'): 527 self.genStruct(typeinfo, name, alias) 528 if category == 'handle': 529 self.object_types.append(name) 530 # 531 # Append a definition to the specified section 532 def appendSection(self, section, text): 533 # self.sections[section].append('SECTION: ' + section + '\n') 534 self.sections[section].append(text) 535 # 536 # Check if the parameter passed in is a pointer 537 def paramIsPointer(self, param): 538 ispointer = False 539 for elem in param: 540 if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail: 541 ispointer = True 542 return ispointer 543 # 544 # Retrieve the type and name for a parameter 545 def getTypeNameTuple(self, param): 546 type = '' 547 name = '' 548 for elem in param: 549 if elem.tag == 'type': 550 type = noneStr(elem.text) 551 elif elem.tag == 'name': 552 name = noneStr(elem.text) 553 return (type, name) 554 # 555 # Retrieve the value of the len tag 556 def getLen(self, param): 557 result = None 558 len = param.attrib.get('len') 559 if len and len != 'null-terminated': 560 # For string arrays, 'len' can look like 'count,null-terminated', indicating that we 561 # have a null terminated array of strings. We strip the null-terminated from the 562 # 'len' field and only return the parameter specifying the string count 563 if 'null-terminated' in len: 564 result = len.split(',')[0] 565 else: 566 result = len 567 # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol 568 result = str(result).replace('::', '->') 569 return result 570 # 571 # Generate a VkStructureType based on a structure typename 572 def genVkStructureType(self, typename): 573 # Add underscore between lowercase then uppercase 574 value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename) 575 # Change to uppercase 576 value = value.upper() 577 # Add STRUCTURE_TYPE_ 578 return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value) 579 # 580 # Struct parameter check generation. 581 # This is a special case of the <type> tag where the contents are interpreted as a set of 582 # <member> tags instead of freeform C type declarations. The <member> tags are just like 583 # <param> tags - they are a declaration of a struct or union member. Only simple member 584 # declarations are supported (no nested structs etc.) 585 def genStruct(self, typeinfo, typeName, alias): 586 OutputGenerator.genStruct(self, typeinfo, typeName, alias) 587 members = typeinfo.elem.findall('.//member') 588 # Iterate over members once to get length parameters for arrays 589 lens = set() 590 for member in members: 591 len = self.getLen(member) 592 if len: 593 lens.add(len) 594 # Generate member info 595 membersInfo = [] 596 for member in members: 597 # Get the member's type and name 598 info = self.getTypeNameTuple(member) 599 type = info[0] 600 name = info[1] 601 cdecl = self.makeCParamDecl(member, 0) 602 # Process VkStructureType 603 if type == 'VkStructureType': 604 # Extract the required struct type value from the comments 605 # embedded in the original text defining the 'typeinfo' element 606 rawXml = etree.tostring(typeinfo.elem).decode('ascii') 607 result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml) 608 if result: 609 value = result.group(0) 610 else: 611 value = self.genVkStructureType(typeName) 612 # Store the required type value 613 self.structTypes[typeName] = self.StructType(name=name, value=value) 614 # Store pointer/array/string info 615 extstructs = member.attrib.get('validextensionstructs') if name == 'pNext' else None 616 membersInfo.append(self.CommandParam(type=type, 617 name=name, 618 isconst=True if 'const' in cdecl else False, 619 isoptional=self.paramIsOptional(member), 620 iscount=True if name in lens else False, 621 len=self.getLen(member), 622 extstructs=extstructs, 623 cdecl=cdecl, 624 islocal=False, 625 iscreate=False)) 626 self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo)) 627 # 628 # Insert a lock_guard line 629 def lock_guard(self, indent): 630 return '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % indent 631 # 632 # Determine if a struct has an object as a member or an embedded member 633 def struct_contains_object(self, struct_item): 634 struct_member_dict = dict(self.structMembers) 635 struct_members = struct_member_dict[struct_item] 636 637 for member in struct_members: 638 if member.type in self.handle_types: 639 return True 640 # recurse for member structs, guard against infinite recursion 641 elif member.type in struct_member_dict and member.type != struct_item: 642 if self.struct_contains_object(member.type): 643 return True 644 return False 645 # 646 # Return list of struct members which contain, or whose sub-structures contain an obj in a given list of parameters or members 647 def getParmeterStructsWithObjects(self, item_list): 648 struct_list = set() 649 for item in item_list: 650 paramtype = item.find('type') 651 typecategory = self.type_categories[paramtype.text] 652 if typecategory == 'struct': 653 if self.struct_contains_object(paramtype.text) == True: 654 struct_list.add(item) 655 return struct_list 656 # 657 # Return list of objects from a given list of parameters or members 658 def getObjectsInParameterList(self, item_list, create_func): 659 object_list = set() 660 if create_func == True: 661 member_list = item_list[0:-1] 662 else: 663 member_list = item_list 664 for item in member_list: 665 if paramtype.text in self.handle_types: 666 object_list.add(item) 667 return object_list 668 # 669 # Construct list of extension structs containing handles, or extension structs that share a <validextensionstructs> 670 # tag WITH an extension struct containing handles. 671 def GenerateCommandWrapExtensionList(self): 672 for struct in self.structMembers: 673 if (len(struct.members) > 1) and struct.members[1].extstructs is not None: 674 found = False; 675 for item in struct.members[1].extstructs.split(','): 676 if item != '' and self.struct_contains_object(item) == True: 677 found = True 678 if found == True: 679 for item in struct.members[1].extstructs.split(','): 680 if item != '' and item not in self.extension_structs: 681 self.extension_structs.append(item) 682 # 683 # Returns True if a struct may have a pNext chain containing an object 684 def StructWithExtensions(self, struct_type): 685 if struct_type in self.struct_member_dict: 686 param_info = self.struct_member_dict[struct_type] 687 if (len(param_info) > 1) and param_info[1].extstructs is not None: 688 for item in param_info[1].extstructs.split(','): 689 if item in self.extension_structs: 690 return True 691 return False 692 # 693 # Generate VulkanObjectType from object type 694 def GetVulkanObjType(self, type): 695 return 'kVulkanObjectType%s' % type[2:] 696 # 697 # Return correct dispatch table type -- instance or device 698 def GetDispType(self, type): 699 return 'instance' if type in ['VkInstance', 'VkPhysicalDevice'] else 'device' 700 # 701 # Generate source for creating a Vulkan object 702 def generate_create_object_code(self, indent, proto, params, cmd_info, allocator): 703 create_obj_code = '' 704 handle_type = params[-1].find('type') 705 is_create_pipelines = False 706 707 if handle_type.text in self.handle_types: 708 # Check for special case where multiple handles are returned 709 object_array = False 710 if cmd_info[-1].len is not None: 711 object_array = True; 712 handle_name = params[-1].find('name') 713 object_dest = '*%s' % handle_name.text 714 if object_array == True: 715 if 'CreateGraphicsPipelines' in proto.text or 'CreateComputePipelines' in proto.text or 'CreateRayTracingPipelines' in proto.text: 716 is_create_pipelines = True 717 create_obj_code += '%sif (VK_ERROR_VALIDATION_FAILED_EXT == result) return;\n' % indent 718 create_obj_code += '%sif (%s) {\n' % (indent, handle_name.text) 719 indent = self.incIndent(indent) 720 countispointer = '' 721 if 'uint32_t*' in cmd_info[-2].cdecl: 722 countispointer = '*' 723 create_obj_code += '%sfor (uint32_t index = 0; index < %s%s; index++) {\n' % (indent, countispointer, cmd_info[-1].len) 724 indent = self.incIndent(indent) 725 object_dest = '%s[index]' % cmd_info[-1].name 726 727 dispobj = params[0].find('type').text 728 if is_create_pipelines: 729 create_obj_code += '%sif (!pPipelines[index]) continue;\n' % indent 730 create_obj_code += '%sCreateObject(%s, %s, %s);\n' % (indent, object_dest, self.GetVulkanObjType(cmd_info[-1].type), allocator) 731 if object_array == True: 732 indent = self.decIndent(indent) 733 create_obj_code += '%s}\n' % indent 734 indent = self.decIndent(indent) 735 create_obj_code += '%s}\n' % indent 736 indent = self.decIndent(indent) 737 738 return create_obj_code 739 # 740 # Generate source for destroying a non-dispatchable object 741 def generate_destroy_object_code(self, indent, proto, cmd_info): 742 validate_code = '' 743 record_code = '' 744 object_array = False 745 allocator = 'pAllocator' 746 if True in [destroy_txt in proto.text for destroy_txt in ['Destroy', 'Free', 'ReleasePerformanceConfigurationINTEL']]: 747 # Check for special case where multiple handles are returned 748 if cmd_info[-1].len is not None: 749 object_array = True; 750 param = -1 751 elif 'ReleasePerformanceConfigurationINTEL' in proto.text: 752 param = -1 753 allocator = 'nullptr' 754 else: 755 param = -2 756 compatalloc_vuid_string = '%s-compatalloc' % cmd_info[param].name 757 nullalloc_vuid_string = '%s-nullalloc' % cmd_info[param].name 758 compatalloc_vuid = self.manual_vuids.get(compatalloc_vuid_string, "kVUIDUndefined") 759 nullalloc_vuid = self.manual_vuids.get(nullalloc_vuid_string, "kVUIDUndefined") 760 if cmd_info[param].type in self.handle_types: 761 if object_array == True: 762 # This API is freeing an array of handles -- add loop control 763 validate_code += 'HEY, NEED TO DESTROY AN ARRAY\n' 764 else: 765 dispobj = cmd_info[0].type 766 # Call Destroy a single time 767 validate_code += '%sskip |= ValidateDestroyObject(%s, %s, %s, %s, %s);\n' % (indent, cmd_info[param].name, self.GetVulkanObjType(cmd_info[param].type), allocator, compatalloc_vuid, nullalloc_vuid) 768 record_code += '%sRecordDestroyObject(%s, %s);\n' % (indent, cmd_info[param].name, self.GetVulkanObjType(cmd_info[param].type)) 769 return object_array, validate_code, record_code 770 # 771 # Output validation for a single object (obj_count is NULL) or a counted list of objects 772 def outputObjects(self, obj_type, obj_name, obj_count, prefix, index, indent, disp_name, parent_name, null_allowed, top_level): 773 pre_call_code = '' 774 param_suffix = '%s-parameter' % (obj_name) 775 parent_suffix = '%s-parent' % (obj_name) 776 param_vuid = self.GetVuid(parent_name, param_suffix) 777 parent_vuid = self.GetVuid(parent_name, parent_suffix) 778 779 # If no parent VUID for this member, look for a commonparent VUID 780 if parent_vuid == 'kVUIDUndefined': 781 parent_vuid = self.GetVuid(parent_name, 'commonparent') 782 if obj_count is not None: 783 784 pre_call_code += '%sif (%s%s) {\n' % (indent, prefix, obj_name) 785 indent = self.incIndent(indent) 786 pre_call_code += '%sfor (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, obj_count, index) 787 indent = self.incIndent(indent) 788 pre_call_code += '%sskip |= ValidateObject(%s%s[%s], %s, %s, %s, %s);\n' % (indent, prefix, obj_name, index, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid) 789 indent = self.decIndent(indent) 790 pre_call_code += '%s}\n' % indent 791 indent = self.decIndent(indent) 792 pre_call_code += '%s}\n' % indent 793 else: 794 bonus_indent = '' 795 if 'basePipelineHandle' in obj_name: 796 pre_call_code += '%sif ((%sflags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) && (%sbasePipelineIndex == -1))\n' % (indent, prefix, prefix) 797 bonus_indent = ' ' 798 null_allowed = 'false' 799 manual_vuid_index = parent_name + '-' + obj_name 800 param_vuid = self.manual_vuids.get(manual_vuid_index, "kVUIDUndefined") 801 pre_call_code += '%s%sskip |= ValidateObject(%s%s, %s, %s, %s, %s);\n' % (bonus_indent, indent, prefix, obj_name, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid) 802 return pre_call_code 803 # 804 # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct 805 def validate_objects(self, members, indent, prefix, array_index, disp_name, parent_name, first_level_param): 806 pre_code = '' 807 index = 'index%s' % str(array_index) 808 array_index += 1 809 # Process any objects in this structure and recurse for any sub-structs in this struct 810 for member in members: 811 # Handle objects 812 if member.iscreate and first_level_param and member == members[-1]: 813 continue 814 if member.type in self.handle_types: 815 if member.len: 816 count_name = '%s%s' % (prefix, member.len) 817 # isoptional may be a list for array types: [the array, the array elements] 818 if type(member.isoptional) == list: 819 null_allowed = member.isoptional[1] 820 else: 821 # Default to false if a value is not provided for the array elements 822 null_allowed = False 823 else: 824 count_name = None 825 null_allowed = member.isoptional 826 tmp_pre = self.outputObjects(member.type, member.name, count_name, prefix, index, indent, disp_name, parent_name, str(null_allowed).lower(), first_level_param) 827 pre_code += tmp_pre 828 # Handle Structs that contain objects at some level 829 elif member.type in self.struct_member_dict: 830 # Structs at first level will have an object 831 if self.struct_contains_object(member.type) == True: 832 struct_info = self.struct_member_dict[member.type] 833 # TODO (jbolz): Can this use paramIsPointer? 834 ispointer = '*' in member.cdecl; 835 # Struct Array 836 if member.len is not None: 837 # Update struct prefix 838 new_prefix = '%s%s' % (prefix, member.name) 839 pre_code += '%sif (%s%s) {\n' % (indent, prefix, member.name) 840 indent = self.incIndent(indent) 841 pre_code += '%sfor (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, member.len, index) 842 indent = self.incIndent(indent) 843 local_prefix = '%s[%s].' % (new_prefix, index) 844 # Process sub-structs in this struct 845 tmp_pre = self.validate_objects(struct_info, indent, local_prefix, array_index, disp_name, member.type, False) 846 pre_code += tmp_pre 847 indent = self.decIndent(indent) 848 pre_code += '%s}\n' % indent 849 indent = self.decIndent(indent) 850 pre_code += '%s}\n' % indent 851 # Single Struct Pointer 852 elif ispointer: 853 # Update struct prefix 854 new_prefix = '%s%s->' % (prefix, member.name) 855 # Declare safe_VarType for struct 856 pre_code += '%sif (%s%s) {\n' % (indent, prefix, member.name) 857 indent = self.incIndent(indent) 858 # Process sub-structs in this struct 859 tmp_pre = self.validate_objects(struct_info, indent, new_prefix, array_index, disp_name, member.type, False) 860 pre_code += tmp_pre 861 indent = self.decIndent(indent) 862 pre_code += '%s}\n' % indent 863 # Single Nested Struct 864 else: 865 # Update struct prefix 866 new_prefix = '%s%s.' % (prefix, member.name) 867 # Process sub-structs 868 tmp_pre = self.validate_objects(struct_info, indent, new_prefix, array_index, disp_name, member.type, False) 869 pre_code += tmp_pre 870 return pre_code 871 # 872 # For a particular API, generate the object handling code 873 def generate_wrapping_code(self, cmd): 874 indent = ' ' 875 pre_call_validate = '' 876 pre_call_record = '' 877 post_call_record = '' 878 879 destroy_array = False 880 validate_destroy_code = '' 881 record_destroy_code = '' 882 883 proto = cmd.find('proto/name') 884 params = cmd.findall('param') 885 if proto.text is not None: 886 cmddata = self.cmd_info_dict[proto.text] 887 cmd_info = cmddata.members 888 disp_name = cmd_info[0].name 889 # Handle object create operations if last parameter is created by this call 890 if cmddata.iscreate: 891 post_call_record += self.generate_create_object_code(indent, proto, params, cmd_info, cmddata.allocator) 892 # Handle object destroy operations 893 if cmddata.isdestroy: 894 (destroy_array, validate_destroy_code, record_destroy_code) = self.generate_destroy_object_code(indent, proto, cmd_info) 895 896 pre_call_record += record_destroy_code 897 pre_call_validate += self.validate_objects(cmd_info, indent, '', 0, disp_name, proto.text, True) 898 pre_call_validate += validate_destroy_code 899 900 return pre_call_validate, pre_call_record, post_call_record 901 # 902 # Capture command parameter info needed to create, destroy, and validate objects 903 def genCmd(self, cmdinfo, cmdname, alias): 904 # Add struct-member type information to command parameter information 905 OutputGenerator.genCmd(self, cmdinfo, cmdname, alias) 906 members = cmdinfo.elem.findall('.//param') 907 # Iterate over members once to get length parameters for arrays 908 lens = set() 909 for member in members: 910 length = self.getLen(member) 911 if length: 912 lens.add(length) 913 struct_member_dict = dict(self.structMembers) 914 915 # Set command invariant information needed at a per member level in validate... 916 is_create_command = any(filter(lambda pat: pat in cmdname, ('Create', 'Allocate', 'Enumerate', 'RegisterDeviceEvent', 'RegisterDisplayEvent', 'AcquirePerformanceConfigurationINTEL'))) 917 last_member_is_pointer = len(members) and self.paramIsPointer(members[-1]) 918 iscreate = is_create_command or ('vkGet' in cmdname and last_member_is_pointer) 919 isdestroy = any([destroy_txt in cmdname for destroy_txt in ['Destroy', 'Free', 'ReleasePerformanceConfigurationINTEL']]) 920 921 # Generate member info 922 membersInfo = [] 923 allocator = 'nullptr' 924 925 for member in members: 926 # Get type and name of member 927 info = self.getTypeNameTuple(member) 928 type = info[0] 929 name = info[1] 930 # Skip fake parameters 931 if type == '' or name == '': 932 continue 933 cdecl = self.makeCParamDecl(member, 0) 934 # Check for parameter name in lens set 935 iscount = True if name in lens else False 936 length = self.getLen(member) 937 isconst = True if 'const' in cdecl else False 938 # Mark param as local if it is an array of objects 939 islocal = False; 940 if type in self.handle_types: 941 if (length is not None) and (isconst == True): 942 islocal = True 943 # Or if it's a struct that contains an object 944 elif type in struct_member_dict: 945 if self.struct_contains_object(type) == True: 946 islocal = True 947 if type == 'VkAllocationCallbacks': 948 allocator = name 949 extstructs = member.attrib.get('validextensionstructs') if name == 'pNext' else None 950 membersInfo.append(self.CommandParam(type=type, 951 name=name, 952 isconst=isconst, 953 isoptional=self.paramIsOptional(member), 954 iscount=iscount, 955 len=length, 956 extstructs=extstructs, 957 cdecl=cdecl, 958 islocal=islocal, 959 iscreate=iscreate)) 960 961 self.cmd_list.append(cmdname) 962 self.cmd_info_dict[cmdname] =self.CmdInfoData(name=cmdname, cmdinfo=cmdinfo, members=membersInfo, iscreate=iscreate, isdestroy=isdestroy, allocator=allocator, extra_protect=self.featureExtraProtect, alias=alias) 963 # 964 # Create code Create, Destroy, and validate Vulkan objects 965 def WrapCommands(self): 966 for cmdname in self.cmd_list: 967 cmddata = self.cmd_info_dict[cmdname] 968 cmdinfo = cmddata.cmdinfo 969 if cmdname in self.interface_functions: 970 continue 971 manual = False 972 if cmdname in self.no_autogen_list: 973 manual = True 974 # Generate object handling code 975 (pre_call_validate, pre_call_record, post_call_record) = self.generate_wrapping_code(cmdinfo.elem) 976 977 feature_extra_protect = cmddata.extra_protect 978 if (feature_extra_protect is not None): 979 self.appendSection('command', '') 980 self.appendSection('command', '#ifdef '+ feature_extra_protect) 981 self.prototypes += [ '#ifdef %s' % feature_extra_protect ] 982 983 # Add intercept to procmap 984 self.prototypes += [ ' {"%s", (void*)%s},' % (cmdname,cmdname[2:]) ] 985 986 decls = self.makeCDecls(cmdinfo.elem) 987 988 # Gather the parameter items 989 params = cmdinfo.elem.findall('param/name') 990 # Pull out the text for each of the parameters, separate them by commas in a list 991 paramstext = ', '.join([str(param.text) for param in params]) 992 # Generate the API call template 993 fcn_call = cmdinfo.elem.attrib.get('name').replace('vk', 'TOKEN', 1) + '(' + paramstext + ');' 994 995 func_decl_template = decls[0][:-1].split('VKAPI_CALL ') 996 func_decl_template = func_decl_template[1] 997 998 result_type = cmdinfo.elem.find('proto/type') 999 1000 if 'object_tracker.h' in self.genOpts.filename: 1001 # Output PreCallValidateAPI prototype if necessary 1002 if pre_call_validate: 1003 pre_cv_func_decl = 'bool PreCallValidate' + func_decl_template + ' const;' 1004 self.appendSection('command', pre_cv_func_decl) 1005 1006 # Output PreCallRecordAPI prototype if necessary 1007 if pre_call_record: 1008 pre_cr_func_decl = 'void PreCallRecord' + func_decl_template + ';' 1009 self.appendSection('command', pre_cr_func_decl) 1010 1011 # Output PosCallRecordAPI prototype if necessary 1012 if post_call_record: 1013 post_cr_func_decl = 'void PostCallRecord' + func_decl_template + ';' 1014 if result_type.text == 'VkResult': 1015 post_cr_func_decl = post_cr_func_decl.replace(')', ',\n VkResult result)') 1016 elif result_type.text == 'VkDeviceAddress': 1017 post_cr_func_decl = post_cr_func_decl.replace(')', ',\n VkDeviceAddress result)') 1018 self.appendSection('command', post_cr_func_decl) 1019 1020 if 'object_tracker.cpp' in self.genOpts.filename: 1021 # Output PreCallValidateAPI function if necessary 1022 if pre_call_validate and not manual: 1023 pre_cv_func_decl = 'bool ObjectLifetimes::PreCallValidate' + func_decl_template + ' const {' 1024 self.appendSection('command', '') 1025 self.appendSection('command', pre_cv_func_decl) 1026 self.appendSection('command', ' bool skip = false;') 1027 self.appendSection('command', pre_call_validate) 1028 self.appendSection('command', ' return skip;') 1029 self.appendSection('command', '}') 1030 1031 # Output PreCallRecordAPI function if necessary 1032 if pre_call_record and not manual: 1033 pre_cr_func_decl = 'void ObjectLifetimes::PreCallRecord' + func_decl_template + ' {' 1034 self.appendSection('command', '') 1035 self.appendSection('command', pre_cr_func_decl) 1036 self.appendSection('command', pre_call_record) 1037 self.appendSection('command', '}') 1038 1039 # Output PosCallRecordAPI function if necessary 1040 if post_call_record and not manual: 1041 post_cr_func_decl = 'void ObjectLifetimes::PostCallRecord' + func_decl_template + ' {' 1042 self.appendSection('command', '') 1043 1044 if result_type.text == 'VkResult': 1045 post_cr_func_decl = post_cr_func_decl.replace(')', ',\n VkResult result)') 1046 # The two createpipelines APIs may create on failure -- skip the success result check 1047 if 'CreateGraphicsPipelines' not in cmdname and 'CreateComputePipelines' not in cmdname and 'CreateRayTracingPipelines' not in cmdname: 1048 post_cr_func_decl = post_cr_func_decl.replace('{', '{\n if (result != VK_SUCCESS) return;') 1049 elif result_type.text == 'VkDeviceAddress': 1050 post_cr_func_decl = post_cr_func_decl.replace(')', ',\n VkDeviceAddress result)') 1051 self.appendSection('command', post_cr_func_decl) 1052 1053 self.appendSection('command', post_call_record) 1054 self.appendSection('command', '}') 1055 1056 if (feature_extra_protect is not None): 1057 self.appendSection('command', '#endif // '+ feature_extra_protect) 1058 self.prototypes += [ '#endif' ] 1059