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