blob: 35d9ecff52f9d14a1ddf08970e04b2cf99d7f31f [file] [log] [blame]
Mark Lobodzinskid1461482017-07-18 13:56:09 -06001#!/usr/bin/python3 -i
2#
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -07003# Copyright (c) 2015-2019 The Khronos Group Inc.
4# Copyright (c) 2015-2019 Valve Corporation
5# Copyright (c) 2015-2019 LunarG, Inc.
6# Copyright (c) 2015-2019 Google Inc.
Mark Lobodzinskid1461482017-07-18 13:56:09 -06007#
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>
Dave Houlton57ae22f2018-05-18 16:20:52 -060021# Author: Dave Houlton <daveh@lunarg.com>
Mark Lobodzinskid1461482017-07-18 13:56:09 -060022
Dave Houlton57ae22f2018-05-18 16:20:52 -060023import os,re,sys,string,json
Mark Lobodzinskid1461482017-07-18 13:56:09 -060024import xml.etree.ElementTree as etree
25from generator import *
26from collections import namedtuple
Mark Lobodzinski62f71562017-10-24 13:41:18 -060027from common_codegen import *
Mark Lobodzinskid1461482017-07-18 13:56:09 -060028
Jamie Madill8d4cda22017-11-08 13:40:09 -050029# This is a workaround to use a Python 2.7 and 3.x compatible syntax.
30from io import open
31
Mark Lobodzinskid1461482017-07-18 13:56:09 -060032# 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 filename = None,
68 directory = '.',
69 apiname = None,
70 profile = None,
71 versions = '.*',
72 emitversions = '.*',
73 defaultExtensions = None,
74 addExtensions = None,
75 removeExtensions = None,
Mark Lobodzinski62f71562017-10-24 13:41:18 -060076 emitExtensions = None,
Mark Lobodzinskid1461482017-07-18 13:56:09 -060077 sortProcedure = regSortFeatures,
78 prefixText = "",
79 genFuncPointers = True,
80 protectFile = True,
81 protectFeature = True,
Mark Lobodzinskid1461482017-07-18 13:56:09 -060082 apicall = '',
83 apientry = '',
84 apientryp = '',
85 indentFuncProto = True,
86 indentFuncPointer = False,
Mark Lobodzinski62f71562017-10-24 13:41:18 -060087 alignFuncParam = 0,
Mark Lobodzinski27a9e7c2018-05-31 16:01:57 -060088 expandEnumerants = True,
89 valid_usage_path = ''):
Mark Lobodzinskid1461482017-07-18 13:56:09 -060090 GeneratorOptions.__init__(self, filename, directory, apiname, profile,
91 versions, emitversions, defaultExtensions,
Mark Lobodzinski62f71562017-10-24 13:41:18 -060092 addExtensions, removeExtensions, emitExtensions, sortProcedure)
Mark Lobodzinskid1461482017-07-18 13:56:09 -060093 self.prefixText = prefixText
94 self.genFuncPointers = genFuncPointers
95 self.protectFile = protectFile
96 self.protectFeature = protectFeature
Mark Lobodzinskid1461482017-07-18 13:56:09 -060097 self.apicall = apicall
98 self.apientry = apientry
99 self.apientryp = apientryp
100 self.indentFuncProto = indentFuncProto
101 self.indentFuncPointer = indentFuncPointer
102 self.alignFuncParam = alignFuncParam
Mark Lobodzinski62f71562017-10-24 13:41:18 -0600103 self.expandEnumerants = expandEnumerants
Mark Lobodzinski27a9e7c2018-05-31 16:01:57 -0600104 self.valid_usage_path = valid_usage_path
Mark Lobodzinski62f71562017-10-24 13:41:18 -0600105
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600106
107# ObjectTrackerOutputGenerator - subclass of OutputGenerator.
108# Generates object_tracker layer object validation code
109#
110# ---- methods ----
111# ObjectTrackerOutputGenerator(errFile, warnFile, diagFile) - args as for OutputGenerator. Defines additional internal state.
112# ---- methods overriding base class ----
113# beginFile(genOpts)
114# endFile()
115# beginFeature(interface, emit)
116# endFeature()
117# genCmd(cmdinfo)
118# genStruct()
119# genType()
120class ObjectTrackerOutputGenerator(OutputGenerator):
121 """Generate ObjectTracker code based on XML element attributes"""
122 # This is an ordered list of sections in the header file.
123 ALL_SECTIONS = ['command']
124 def __init__(self,
125 errFile = sys.stderr,
126 warnFile = sys.stderr,
127 diagFile = sys.stdout):
128 OutputGenerator.__init__(self, errFile, warnFile, diagFile)
129 self.INDENT_SPACES = 4
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600130 self.prototypes = []
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600131 self.instance_extensions = []
132 self.device_extensions = []
133 # Commands which are not autogenerated but still intercepted
134 self.no_autogen_list = [
135 'vkDestroyInstance',
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600136 'vkCreateInstance',
137 'vkEnumeratePhysicalDevices',
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600138 'vkGetPhysicalDeviceQueueFamilyProperties',
139 'vkGetPhysicalDeviceQueueFamilyProperties2',
140 'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
141 'vkGetDeviceQueue',
142 'vkGetDeviceQueue2',
143 'vkCreateDescriptorSetLayout',
144 'vkDestroyDescriptorPool',
145 'vkDestroyCommandPool',
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600146 'vkAllocateCommandBuffers',
147 'vkAllocateDescriptorSets',
148 'vkFreeDescriptorSets',
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600149 'vkFreeCommandBuffers',
150 'vkUpdateDescriptorSets',
151 'vkBeginCommandBuffer',
Mark Lobodzinski5a1c8d22018-07-02 10:28:12 -0600152 'vkGetDescriptorSetLayoutSupport',
153 'vkGetDescriptorSetLayoutSupportKHR',
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600154 'vkDestroySwapchainKHR',
155 'vkGetSwapchainImagesKHR',
156 'vkCmdPushDescriptorSetKHR',
157 'vkDestroyDevice',
158 'vkResetDescriptorPool',
Shannon McPherson9d5167f2018-05-02 15:24:37 -0600159 'vkGetPhysicalDeviceDisplayPropertiesKHR',
Piers Daniell16c253f2018-05-30 14:34:05 -0600160 'vkGetPhysicalDeviceDisplayProperties2KHR',
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600161 'vkGetDisplayModePropertiesKHR',
Piers Daniell16c253f2018-05-30 14:34:05 -0600162 'vkGetDisplayModeProperties2KHR',
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600163 ]
164 # These VUIDS are not implicit, but are best handled in this layer. Codegen for vkDestroy calls will generate a key
165 # which is translated here into a good VU. Saves ~40 checks.
166 self.manual_vuids = dict()
167 self.manual_vuids = {
Dave Houlton57ae22f2018-05-18 16:20:52 -0600168 "fence-compatalloc": "\"VUID-vkDestroyFence-fence-01121\"",
169 "fence-nullalloc": "\"VUID-vkDestroyFence-fence-01122\"",
170 "event-compatalloc": "\"VUID-vkDestroyEvent-event-01146\"",
171 "event-nullalloc": "\"VUID-vkDestroyEvent-event-01147\"",
172 "buffer-compatalloc": "\"VUID-vkDestroyBuffer-buffer-00923\"",
173 "buffer-nullalloc": "\"VUID-vkDestroyBuffer-buffer-00924\"",
174 "image-compatalloc": "\"VUID-vkDestroyImage-image-01001\"",
175 "image-nullalloc": "\"VUID-vkDestroyImage-image-01002\"",
176 "shaderModule-compatalloc": "\"VUID-vkDestroyShaderModule-shaderModule-01092\"",
177 "shaderModule-nullalloc": "\"VUID-vkDestroyShaderModule-shaderModule-01093\"",
178 "pipeline-compatalloc": "\"VUID-vkDestroyPipeline-pipeline-00766\"",
179 "pipeline-nullalloc": "\"VUID-vkDestroyPipeline-pipeline-00767\"",
180 "sampler-compatalloc": "\"VUID-vkDestroySampler-sampler-01083\"",
181 "sampler-nullalloc": "\"VUID-vkDestroySampler-sampler-01084\"",
182 "renderPass-compatalloc": "\"VUID-vkDestroyRenderPass-renderPass-00874\"",
183 "renderPass-nullalloc": "\"VUID-vkDestroyRenderPass-renderPass-00875\"",
184 "descriptorUpdateTemplate-compatalloc": "\"VUID-vkDestroyDescriptorUpdateTemplate-descriptorSetLayout-00356\"",
185 "descriptorUpdateTemplate-nullalloc": "\"VUID-vkDestroyDescriptorUpdateTemplate-descriptorSetLayout-00357\"",
186 "imageView-compatalloc": "\"VUID-vkDestroyImageView-imageView-01027\"",
187 "imageView-nullalloc": "\"VUID-vkDestroyImageView-imageView-01028\"",
188 "pipelineCache-compatalloc": "\"VUID-vkDestroyPipelineCache-pipelineCache-00771\"",
189 "pipelineCache-nullalloc": "\"VUID-vkDestroyPipelineCache-pipelineCache-00772\"",
190 "pipelineLayout-compatalloc": "\"VUID-vkDestroyPipelineLayout-pipelineLayout-00299\"",
191 "pipelineLayout-nullalloc": "\"VUID-vkDestroyPipelineLayout-pipelineLayout-00300\"",
192 "descriptorSetLayout-compatalloc": "\"VUID-vkDestroyDescriptorSetLayout-descriptorSetLayout-00284\"",
193 "descriptorSetLayout-nullalloc": "\"VUID-vkDestroyDescriptorSetLayout-descriptorSetLayout-00285\"",
194 "semaphore-compatalloc": "\"VUID-vkDestroySemaphore-semaphore-01138\"",
195 "semaphore-nullalloc": "\"VUID-vkDestroySemaphore-semaphore-01139\"",
196 "queryPool-compatalloc": "\"VUID-vkDestroyQueryPool-queryPool-00794\"",
197 "queryPool-nullalloc": "\"VUID-vkDestroyQueryPool-queryPool-00795\"",
198 "bufferView-compatalloc": "\"VUID-vkDestroyBufferView-bufferView-00937\"",
199 "bufferView-nullalloc": "\"VUID-vkDestroyBufferView-bufferView-00938\"",
200 "surface-compatalloc": "\"VUID-vkDestroySurfaceKHR-surface-01267\"",
201 "surface-nullalloc": "\"VUID-vkDestroySurfaceKHR-surface-01268\"",
202 "framebuffer-compatalloc": "\"VUID-vkDestroyFramebuffer-framebuffer-00893\"",
203 "framebuffer-nullalloc": "\"VUID-vkDestroyFramebuffer-framebuffer-00894\"",
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600204 }
205
206 # Commands shadowed by interface functions and are not implemented
207 self.interface_functions = [
208 ]
209 self.headerVersion = None
210 # Internal state - accumulators for different inner block text
211 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
John Zulaufbb6e5e42018-08-06 16:00:07 -0600212 self.cmd_list = [] # list of commands processed to maintain ordering
213 self.cmd_info_dict = {} # Per entry-point data for code generation and validation
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600214 self.structMembers = [] # List of StructMemberData records for all Vulkan structs
215 self.extension_structs = [] # List of all structs or sister-structs containing handles
216 # A sister-struct may contain no handles but shares <validextensionstructs> with one that does
217 self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType
218 self.struct_member_dict = dict()
219 # Named tuples to store struct and command data
220 self.StructType = namedtuple('StructType', ['name', 'value'])
John Zulaufbb6e5e42018-08-06 16:00:07 -0600221 self.CmdInfoData = namedtuple('CmdInfoData', ['name', 'cmdinfo', 'members', 'extra_protect', 'alias', 'iscreate', 'isdestroy', 'allocator'])
222 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'isconst', 'isoptional', 'iscount', 'iscreate', 'len', 'extstructs', 'cdecl', 'islocal'])
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600223 self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
224 self.object_types = [] # List of all handle types
225 self.valid_vuids = set() # Set of all valid VUIDs
Dave Houlton57ae22f2018-05-18 16:20:52 -0600226 self.vuid_dict = dict() # VUID dictionary (from JSON)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600227 #
228 # Check if the parameter passed in is optional
229 def paramIsOptional(self, param):
230 # See if the handle is optional
231 isoptional = False
232 # Simple, if it's optional, return true
233 optString = param.attrib.get('optional')
234 if optString:
235 if optString == 'true':
236 isoptional = True
237 elif ',' in optString:
238 opts = []
239 for opt in optString.split(','):
240 val = opt.strip()
241 if val == 'true':
242 opts.append(True)
243 elif val == 'false':
244 opts.append(False)
245 else:
246 print('Unrecognized len attribute value',val)
247 isoptional = opts
John Zulauf9f6788c2018-04-04 14:54:11 -0600248 if not isoptional:
249 # Matching logic in parameter validation and ValidityOutputGenerator.isHandleOptional
250 optString = param.attrib.get('noautovalidity')
251 if optString and optString == 'true':
252 isoptional = True;
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600253 return isoptional
254 #
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600255 # Get VUID identifier from implicit VUID tag
Dave Houlton57ae22f2018-05-18 16:20:52 -0600256 def GetVuid(self, parent, suffix):
257 vuid_string = 'VUID-%s-%s' % (parent, suffix)
258 vuid = "kVUIDUndefined"
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600259 if '->' in vuid_string:
Dave Houlton57ae22f2018-05-18 16:20:52 -0600260 return vuid
261 if vuid_string in self.valid_vuids:
262 vuid = "\"%s\"" % vuid_string
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600263 else:
John Zulaufbb6e5e42018-08-06 16:00:07 -0600264 alias = self.cmd_info_dict[parent].alias if parent in self.cmd_info_dict else None
265 if alias:
266 alias_string = 'VUID-%s-%s' % (alias, suffix)
Dave Houlton57ae22f2018-05-18 16:20:52 -0600267 if alias_string in self.valid_vuids:
268 vuid = "\"%s\"" % vuid_string
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600269 return vuid
270 #
271 # Increases indent by 4 spaces and tracks it globally
272 def incIndent(self, indent):
273 inc = ' ' * self.INDENT_SPACES
274 if indent:
275 return indent + inc
276 return inc
277 #
278 # Decreases indent by 4 spaces and tracks it globally
279 def decIndent(self, indent):
280 if indent and (len(indent) > self.INDENT_SPACES):
281 return indent[:-self.INDENT_SPACES]
282 return ''
283 #
284 # Override makeProtoName to drop the "vk" prefix
285 def makeProtoName(self, name, tail):
286 return self.genOpts.apientry + name[2:] + tail
287 #
288 # Check if the parameter passed in is a pointer to an array
289 def paramIsArray(self, param):
290 return param.attrib.get('len') is not None
Gabríel Arthúr Péturssonfdcb5402018-03-20 21:52:06 +0000291
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600292 #
293 # Generate the object tracker undestroyed object validation function
294 def GenReportFunc(self):
295 output_func = ''
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600296 output_func += 'bool ObjectLifetimes::ReportUndestroyedObjects(VkDevice device, const std::string& error_code) {\n'
Mark Lobodzinski5183a032018-09-13 14:44:28 -0600297 output_func += ' bool skip = false;\n'
298 output_func += ' skip |= DeviceReportUndestroyedObjects(device, kVulkanObjectTypeCommandBuffer, error_code);\n'
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600299 for handle in self.object_types:
300 if self.isHandleTypeNonDispatchable(handle):
Mark Lobodzinski5183a032018-09-13 14:44:28 -0600301 output_func += ' skip |= DeviceReportUndestroyedObjects(device, %s, error_code);\n' % (self.GetVulkanObjType(handle))
302 output_func += ' return skip;\n'
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600303 output_func += '}\n'
304 return output_func
Gabríel Arthúr Péturssonfdcb5402018-03-20 21:52:06 +0000305
306 #
307 # Generate the object tracker undestroyed object destruction function
308 def GenDestroyFunc(self):
309 output_func = ''
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600310 output_func += 'void ObjectLifetimes::DestroyUndestroyedObjects(VkDevice device) {\n'
Gabríel Arthúr Péturssonfdcb5402018-03-20 21:52:06 +0000311 output_func += ' DeviceDestroyUndestroyedObjects(device, kVulkanObjectTypeCommandBuffer);\n'
312 for handle in self.object_types:
313 if self.isHandleTypeNonDispatchable(handle):
314 output_func += ' DeviceDestroyUndestroyedObjects(device, %s);\n' % (self.GetVulkanObjType(handle))
315 output_func += '}\n'
316 return output_func
317
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600318 #
Dave Houlton57ae22f2018-05-18 16:20:52 -0600319 # Walk the JSON-derived dict and find all "vuid" key values
320 def ExtractVUIDs(self, d):
321 if hasattr(d, 'items'):
322 for k, v in d.items():
323 if k == "vuid":
324 yield v
325 elif isinstance(v, dict):
326 for s in self.ExtractVUIDs(v):
327 yield s
328 elif isinstance (v, list):
329 for l in v:
330 for s in self.ExtractVUIDs(l):
331 yield s
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600332 #
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600333 # Separate content for validation source and header files
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600334 def otwrite(self, dest, formatstring):
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600335 if 'object_tracker.h' in self.genOpts.filename and (dest == 'hdr' or dest == 'both'):
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600336 write(formatstring, file=self.outFile)
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600337 elif 'object_tracker.cpp' in self.genOpts.filename and (dest == 'cpp' or dest == 'both'):
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600338 write(formatstring, file=self.outFile)
Dave Houlton57ae22f2018-05-18 16:20:52 -0600339
340 #
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600341 # Called at beginning of processing as file is opened
342 def beginFile(self, genOpts):
343 OutputGenerator.beginFile(self, genOpts)
Mark Lobodzinski27a9e7c2018-05-31 16:01:57 -0600344
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600345 header_file = (genOpts.filename == 'object_tracker.h')
346 source_file = (genOpts.filename == 'object_tracker.cpp')
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600347
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600348 if not header_file and not source_file:
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600349 print("Error: Output Filenames have changed, update generator source.\n")
350 sys.exit(1)
351
Mark Lobodzinski27a9e7c2018-05-31 16:01:57 -0600352 self.valid_usage_path = genOpts.valid_usage_path
353 vu_json_filename = os.path.join(self.valid_usage_path + os.sep, 'validusage.json')
354 if os.path.isfile(vu_json_filename):
355 json_file = open(vu_json_filename, 'r')
356 self.vuid_dict = json.load(json_file)
357 json_file.close()
358 if len(self.vuid_dict) == 0:
359 print("Error: Could not find, or error loading %s/validusage.json\n", vu_json_filename)
360 sys.exit(1)
361
Dave Houlton57ae22f2018-05-18 16:20:52 -0600362 # Build a set of all vuid text strings found in validusage.json
363 for json_vuid_string in self.ExtractVUIDs(self.vuid_dict):
364 self.valid_vuids.add(json_vuid_string)
365
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600366 # File Comment
367 file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
368 file_comment += '// See object_tracker_generator.py for modifications\n'
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600369 self.otwrite('both', file_comment)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600370 # Copyright Statement
371 copyright = ''
372 copyright += '\n'
373 copyright += '/***************************************************************************\n'
374 copyright += ' *\n'
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700375 copyright += ' * Copyright (c) 2015-2019 The Khronos Group Inc.\n'
376 copyright += ' * Copyright (c) 2015-2019 Valve Corporation\n'
377 copyright += ' * Copyright (c) 2015-2019 LunarG, Inc.\n'
378 copyright += ' * Copyright (c) 2015-2019 Google Inc.\n'
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600379 copyright += ' *\n'
380 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
381 copyright += ' * you may not use this file except in compliance with the License.\n'
382 copyright += ' * You may obtain a copy of the License at\n'
383 copyright += ' *\n'
384 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n'
385 copyright += ' *\n'
386 copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
387 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
388 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
389 copyright += ' * See the License for the specific language governing permissions and\n'
390 copyright += ' * limitations under the License.\n'
391 copyright += ' *\n'
392 copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
Dave Houlton57ae22f2018-05-18 16:20:52 -0600393 copyright += ' * Author: Dave Houlton <daveh@lunarg.com>\n'
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600394 copyright += ' *\n'
395 copyright += ' ****************************************************************************/\n'
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600396 self.otwrite('both', copyright)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600397 self.newline()
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600398 self.otwrite('cpp', '#include "chassis.h"')
399 self.otwrite('cpp', '#include "object_lifetime_validation.h"')
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600400
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600401 #
402 # Now that the data is all collected and complete, generate and output the object validation routines
403 def endFile(self):
404 self.struct_member_dict = dict(self.structMembers)
405 # Generate the list of APIs that might need to handle wrapped extension structs
406 # self.GenerateCommandWrapExtensionList()
407 self.WrapCommands()
408 # Build undestroyed objects reporting function
409 report_func = self.GenReportFunc()
410 self.newline()
Gabríel Arthúr Péturssonfdcb5402018-03-20 21:52:06 +0000411 # Build undestroyed objects destruction function
412 destroy_func = self.GenDestroyFunc()
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600413 self.otwrite('cpp', '\n')
414 self.otwrite('cpp', '// ObjectTracker undestroyed objects validation function')
415 self.otwrite('cpp', '%s' % report_func)
416 self.otwrite('cpp', '%s' % destroy_func)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600417 # Actually write the interface to the output file.
418 if (self.emit):
419 self.newline()
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600420 if self.featureExtraProtect is not None:
421 prot = '#ifdef %s' % self.featureExtraProtect
422 self.otwrite('both', '%s' % prot)
423 # Write the object_tracker code to the file
424 if self.sections['command']:
425 source = ('\n'.join(self.sections['command']))
426 self.otwrite('both', '%s' % source)
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100427 if (self.featureExtraProtect is not None):
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600428 prot = '\n#endif // %s', self.featureExtraProtect
429 self.otwrite('both', prot)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600430 else:
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600431 self.otwrite('both', '\n')
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600432
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600433
434 self.otwrite('hdr', 'void PostCallRecordDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator);')
435 self.otwrite('hdr', 'void PreCallRecordResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);')
436 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties);')
437 self.otwrite('hdr', 'void PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers);')
438 self.otwrite('hdr', 'void PreCallRecordFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets);')
439 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties);')
440 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties);')
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700441 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkDisplayPropertiesKHR *pProperties, VkResult result);')
442 self.otwrite('hdr', 'void PostCallRecordGetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties, VkResult result);')
443 self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkDisplayProperties2KHR *pProperties, VkResult result);')
444 self.otwrite('hdr', 'void PostCallRecordGetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties, VkResult result);')
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600445 OutputGenerator.endFile(self)
446 #
447 # Processing point at beginning of each extension definition
448 def beginFeature(self, interface, emit):
449 # Start processing in superclass
450 OutputGenerator.beginFeature(self, interface, emit)
451 self.headerVersion = None
Mark Lobodzinski62f71562017-10-24 13:41:18 -0600452 self.featureExtraProtect = GetFeatureProtect(interface)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600453
Mark Lobodzinski31964ca2017-09-18 14:15:09 -0600454 if self.featureName != 'VK_VERSION_1_0' and self.featureName != 'VK_VERSION_1_1':
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600455 white_list_entry = []
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100456 if (self.featureExtraProtect is not None):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600457 white_list_entry += [ '#ifdef %s' % self.featureExtraProtect ]
458 white_list_entry += [ '"%s"' % self.featureName ]
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100459 if (self.featureExtraProtect is not None):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600460 white_list_entry += [ '#endif' ]
461 featureType = interface.get('type')
462 if featureType == 'instance':
463 self.instance_extensions += white_list_entry
464 elif featureType == 'device':
465 self.device_extensions += white_list_entry
466 #
467 # Processing point at end of each extension definition
468 def endFeature(self):
469 # Finish processing in superclass
470 OutputGenerator.endFeature(self)
471 #
472 # Process enums, structs, etc.
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700473 def genType(self, typeinfo, name, alias):
474 OutputGenerator.genType(self, typeinfo, name, alias)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600475 typeElem = typeinfo.elem
476 # If the type is a struct type, traverse the imbedded <member> tags generating a structure.
477 # Otherwise, emit the tag text.
478 category = typeElem.get('category')
479 if (category == 'struct' or category == 'union'):
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700480 self.genStruct(typeinfo, name, alias)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600481 if category == 'handle':
482 self.object_types.append(name)
483 #
484 # Append a definition to the specified section
485 def appendSection(self, section, text):
486 # self.sections[section].append('SECTION: ' + section + '\n')
487 self.sections[section].append(text)
488 #
489 # Check if the parameter passed in is a pointer
490 def paramIsPointer(self, param):
491 ispointer = False
492 for elem in param:
493 if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
494 ispointer = True
495 return ispointer
496 #
497 # Get the category of a type
498 def getTypeCategory(self, typename):
499 types = self.registry.tree.findall("types/type")
500 for elem in types:
501 if (elem.find("name") is not None and elem.find('name').text == typename) or elem.attrib.get('name') == typename:
502 return elem.attrib.get('category')
503 #
504 # Check if a parent object is dispatchable or not
505 def isHandleTypeObject(self, handletype):
506 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
507 if handle is not None:
508 return True
509 else:
510 return False
511 #
512 # Check if a parent object is dispatchable or not
513 def isHandleTypeNonDispatchable(self, handletype):
514 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
515 if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
516 return True
517 else:
518 return False
519 #
520 # Retrieve the type and name for a parameter
521 def getTypeNameTuple(self, param):
522 type = ''
523 name = ''
524 for elem in param:
525 if elem.tag == 'type':
526 type = noneStr(elem.text)
527 elif elem.tag == 'name':
528 name = noneStr(elem.text)
529 return (type, name)
530 #
531 # Retrieve the value of the len tag
532 def getLen(self, param):
533 result = None
534 len = param.attrib.get('len')
535 if len and len != 'null-terminated':
536 # For string arrays, 'len' can look like 'count,null-terminated', indicating that we
537 # have a null terminated array of strings. We strip the null-terminated from the
538 # 'len' field and only return the parameter specifying the string count
539 if 'null-terminated' in len:
540 result = len.split(',')[0]
541 else:
542 result = len
543 # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol
544 result = str(result).replace('::', '->')
545 return result
546 #
547 # Generate a VkStructureType based on a structure typename
548 def genVkStructureType(self, typename):
549 # Add underscore between lowercase then uppercase
550 value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
551 # Change to uppercase
552 value = value.upper()
553 # Add STRUCTURE_TYPE_
554 return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value)
555 #
556 # Struct parameter check generation.
557 # This is a special case of the <type> tag where the contents are interpreted as a set of
558 # <member> tags instead of freeform C type declarations. The <member> tags are just like
559 # <param> tags - they are a declaration of a struct or union member. Only simple member
560 # declarations are supported (no nested structs etc.)
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700561 def genStruct(self, typeinfo, typeName, alias):
562 OutputGenerator.genStruct(self, typeinfo, typeName, alias)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600563 members = typeinfo.elem.findall('.//member')
564 # Iterate over members once to get length parameters for arrays
565 lens = set()
566 for member in members:
567 len = self.getLen(member)
568 if len:
569 lens.add(len)
570 # Generate member info
571 membersInfo = []
572 for member in members:
573 # Get the member's type and name
574 info = self.getTypeNameTuple(member)
575 type = info[0]
576 name = info[1]
577 cdecl = self.makeCParamDecl(member, 0)
578 # Process VkStructureType
579 if type == 'VkStructureType':
580 # Extract the required struct type value from the comments
581 # embedded in the original text defining the 'typeinfo' element
582 rawXml = etree.tostring(typeinfo.elem).decode('ascii')
583 result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml)
584 if result:
585 value = result.group(0)
586 else:
587 value = self.genVkStructureType(typeName)
588 # Store the required type value
589 self.structTypes[typeName] = self.StructType(name=name, value=value)
590 # Store pointer/array/string info
591 extstructs = member.attrib.get('validextensionstructs') if name == 'pNext' else None
592 membersInfo.append(self.CommandParam(type=type,
593 name=name,
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600594 isconst=True if 'const' in cdecl else False,
595 isoptional=self.paramIsOptional(member),
596 iscount=True if name in lens else False,
597 len=self.getLen(member),
598 extstructs=extstructs,
599 cdecl=cdecl,
600 islocal=False,
John Zulaufbb6e5e42018-08-06 16:00:07 -0600601 iscreate=False))
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600602 self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo))
603 #
604 # Insert a lock_guard line
605 def lock_guard(self, indent):
606 return '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % indent
607 #
608 # Determine if a struct has an object as a member or an embedded member
609 def struct_contains_object(self, struct_item):
610 struct_member_dict = dict(self.structMembers)
611 struct_members = struct_member_dict[struct_item]
612
613 for member in struct_members:
614 if self.isHandleTypeObject(member.type):
615 return True
Mike Schuchardtcf2eda02018-08-11 20:34:07 -0700616 # recurse for member structs, guard against infinite recursion
617 elif member.type in struct_member_dict and member.type != struct_item:
618 if self.struct_contains_object(member.type):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600619 return True
620 return False
621 #
622 # Return list of struct members which contain, or whose sub-structures contain an obj in a given list of parameters or members
623 def getParmeterStructsWithObjects(self, item_list):
624 struct_list = set()
625 for item in item_list:
626 paramtype = item.find('type')
627 typecategory = self.getTypeCategory(paramtype.text)
628 if typecategory == 'struct':
629 if self.struct_contains_object(paramtype.text) == True:
630 struct_list.add(item)
631 return struct_list
632 #
633 # Return list of objects from a given list of parameters or members
634 def getObjectsInParameterList(self, item_list, create_func):
635 object_list = set()
636 if create_func == True:
637 member_list = item_list[0:-1]
638 else:
639 member_list = item_list
640 for item in member_list:
641 if self.isHandleTypeObject(paramtype.text):
642 object_list.add(item)
643 return object_list
644 #
645 # Construct list of extension structs containing handles, or extension structs that share a <validextensionstructs>
Shannon McPherson9d5167f2018-05-02 15:24:37 -0600646 # tag WITH an extension struct containing handles.
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600647 def GenerateCommandWrapExtensionList(self):
648 for struct in self.structMembers:
649 if (len(struct.members) > 1) and struct.members[1].extstructs is not None:
650 found = False;
651 for item in struct.members[1].extstructs.split(','):
652 if item != '' and self.struct_contains_object(item) == True:
653 found = True
654 if found == True:
655 for item in struct.members[1].extstructs.split(','):
656 if item != '' and item not in self.extension_structs:
657 self.extension_structs.append(item)
658 #
659 # Returns True if a struct may have a pNext chain containing an object
660 def StructWithExtensions(self, struct_type):
661 if struct_type in self.struct_member_dict:
662 param_info = self.struct_member_dict[struct_type]
663 if (len(param_info) > 1) and param_info[1].extstructs is not None:
664 for item in param_info[1].extstructs.split(','):
665 if item in self.extension_structs:
666 return True
667 return False
668 #
669 # Generate VulkanObjectType from object type
670 def GetVulkanObjType(self, type):
671 return 'kVulkanObjectType%s' % type[2:]
672 #
673 # Return correct dispatch table type -- instance or device
674 def GetDispType(self, type):
675 return 'instance' if type in ['VkInstance', 'VkPhysicalDevice'] else 'device'
676 #
677 # Generate source for creating a Vulkan object
John Zulaufbb6e5e42018-08-06 16:00:07 -0600678 def generate_create_object_code(self, indent, proto, params, cmd_info, allocator):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600679 create_obj_code = ''
680 handle_type = params[-1].find('type')
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600681
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600682 if self.isHandleTypeObject(handle_type.text):
683 # Check for special case where multiple handles are returned
684 object_array = False
685 if cmd_info[-1].len is not None:
686 object_array = True;
687 handle_name = params[-1].find('name')
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600688 object_dest = '*%s' % handle_name.text
689 if object_array == True:
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600690 countispointer = ''
691 if 'uint32_t*' in cmd_info[-2].cdecl:
692 countispointer = '*'
693 create_obj_code += '%sfor (uint32_t index = 0; index < %s%s; index++) {\n' % (indent, countispointer, cmd_info[-1].len)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600694 indent = self.incIndent(indent)
695 object_dest = '%s[index]' % cmd_info[-1].name
Mark Lobodzinskic3ff7a92018-09-20 11:05:57 -0600696
697 dispobj = params[0].find('type').text
Mark Lobodzinskifd2d0a42019-02-20 16:34:56 -0700698 if 'CreateGraphicsPipelines' in proto.text or 'CreateComputePipelines' in proto.text or 'CreateRayTracingPipelines' in proto.text:
699 create_obj_code += '%sif (!pPipelines[index]) continue;\n' % indent
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600700 create_obj_code += '%sCreateObject(%s, %s, %s, %s);\n' % (indent, params[0].find('name').text, object_dest, self.GetVulkanObjType(cmd_info[-1].type), allocator)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600701 if object_array == True:
702 indent = self.decIndent(indent)
703 create_obj_code += '%s}\n' % indent
704 indent = self.decIndent(indent)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600705 return create_obj_code
706 #
707 # Generate source for destroying a non-dispatchable object
708 def generate_destroy_object_code(self, indent, proto, cmd_info):
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600709 validate_code = ''
710 record_code = ''
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600711 object_array = False
712 if True in [destroy_txt in proto.text for destroy_txt in ['Destroy', 'Free']]:
713 # Check for special case where multiple handles are returned
714 if cmd_info[-1].len is not None:
715 object_array = True;
716 param = -1
717 else:
718 param = -2
719 compatalloc_vuid_string = '%s-compatalloc' % cmd_info[param].name
720 nullalloc_vuid_string = '%s-nullalloc' % cmd_info[param].name
Dave Houlton57ae22f2018-05-18 16:20:52 -0600721 compatalloc_vuid = self.manual_vuids.get(compatalloc_vuid_string, "kVUIDUndefined")
722 nullalloc_vuid = self.manual_vuids.get(nullalloc_vuid_string, "kVUIDUndefined")
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600723 if self.isHandleTypeObject(cmd_info[param].type) == True:
724 if object_array == True:
725 # This API is freeing an array of handles -- add loop control
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600726 validate_code += 'HEY, NEED TO DESTROY AN ARRAY\n'
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600727 else:
Mark Lobodzinskic3ff7a92018-09-20 11:05:57 -0600728 dispobj = cmd_info[0].type
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600729 # Call Destroy a single time
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600730 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)
731 record_code += '%sRecordDestroyObject(%s, %s, %s);\n' % (indent, cmd_info[0].name, cmd_info[param].name, self.GetVulkanObjType(cmd_info[param].type))
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600732 return object_array, validate_code, record_code
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600733 #
734 # Output validation for a single object (obj_count is NULL) or a counted list of objects
Mark Lobodzinski8c0d3f92018-09-13 10:45:20 -0600735 def outputObjects(self, obj_type, obj_name, obj_count, prefix, index, indent, disp_name, parent_name, null_allowed, top_level):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600736 pre_call_code = ''
Dave Houlton57ae22f2018-05-18 16:20:52 -0600737 param_suffix = '%s-parameter' % (obj_name)
738 parent_suffix = '%s-parent' % (obj_name)
739 param_vuid = self.GetVuid(parent_name, param_suffix)
740 parent_vuid = self.GetVuid(parent_name, parent_suffix)
741
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600742 # If no parent VUID for this member, look for a commonparent VUID
Dave Houlton57ae22f2018-05-18 16:20:52 -0600743 if parent_vuid == 'kVUIDUndefined':
744 parent_vuid = self.GetVuid(parent_name, 'commonparent')
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600745 if obj_count is not None:
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600746 pre_call_code += '%sfor (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, obj_count, index)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600747 indent = self.incIndent(indent)
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600748 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)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600749 indent = self.decIndent(indent)
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600750 pre_call_code += '%s}\n' % indent
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600751 else:
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600752 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)
Mark Lobodzinski8c0d3f92018-09-13 10:45:20 -0600753 return pre_call_code
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600754 #
755 # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct
Mark Lobodzinski8c0d3f92018-09-13 10:45:20 -0600756 def validate_objects(self, members, indent, prefix, array_index, disp_name, parent_name, first_level_param):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600757 pre_code = ''
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600758 index = 'index%s' % str(array_index)
759 array_index += 1
760 # Process any objects in this structure and recurse for any sub-structs in this struct
761 for member in members:
762 # Handle objects
763 if member.iscreate and first_level_param and member == members[-1]:
764 continue
765 if self.isHandleTypeObject(member.type) == True:
766 count_name = member.len
767 if (count_name is not None):
768 count_name = '%s%s' % (prefix, member.len)
769 null_allowed = member.isoptional
Mark Lobodzinski8c0d3f92018-09-13 10:45:20 -0600770 tmp_pre = self.outputObjects(member.type, member.name, count_name, prefix, index, indent, disp_name, parent_name, str(null_allowed).lower(), first_level_param)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600771 pre_code += tmp_pre
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600772 # Handle Structs that contain objects at some level
773 elif member.type in self.struct_member_dict:
774 # Structs at first level will have an object
775 if self.struct_contains_object(member.type) == True:
776 struct_info = self.struct_member_dict[member.type]
Jeff Bolz38b3ce72018-09-19 12:53:38 -0500777 # TODO (jbolz): Can this use paramIsPointer?
Jeff Bolzba74d972018-09-12 15:54:57 -0500778 ispointer = '*' in member.cdecl;
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600779 # Struct Array
780 if member.len is not None:
781 # Update struct prefix
782 new_prefix = '%s%s' % (prefix, member.name)
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600783 pre_code += '%sif (%s%s) {\n' % (indent, prefix, member.name)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600784 indent = self.incIndent(indent)
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600785 pre_code += '%sfor (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, member.len, index)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600786 indent = self.incIndent(indent)
787 local_prefix = '%s[%s].' % (new_prefix, index)
788 # Process sub-structs in this struct
Mark Lobodzinski8c0d3f92018-09-13 10:45:20 -0600789 tmp_pre = self.validate_objects(struct_info, indent, local_prefix, array_index, disp_name, member.type, False)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600790 pre_code += tmp_pre
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600791 indent = self.decIndent(indent)
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600792 pre_code += '%s}\n' % indent
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600793 indent = self.decIndent(indent)
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600794 pre_code += '%s}\n' % indent
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600795 # Single Struct
Jeff Bolzba74d972018-09-12 15:54:57 -0500796 elif ispointer:
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600797 # Update struct prefix
798 new_prefix = '%s%s->' % (prefix, member.name)
799 # Declare safe_VarType for struct
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600800 pre_code += '%sif (%s%s) {\n' % (indent, prefix, member.name)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600801 indent = self.incIndent(indent)
802 # Process sub-structs in this struct
Mark Lobodzinski8c0d3f92018-09-13 10:45:20 -0600803 tmp_pre = self.validate_objects(struct_info, indent, new_prefix, array_index, disp_name, member.type, False)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600804 pre_code += tmp_pre
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600805 indent = self.decIndent(indent)
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600806 pre_code += '%s}\n' % indent
Mark Lobodzinski8c0d3f92018-09-13 10:45:20 -0600807 return pre_code
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600808 #
809 # For a particular API, generate the object handling code
810 def generate_wrapping_code(self, cmd):
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600811 indent = ' '
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600812 pre_call_validate = ''
813 pre_call_record = ''
814 post_call_record = ''
815
816 destroy_array = False
817 validate_destroy_code = ''
818 record_destroy_code = ''
819
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600820 proto = cmd.find('proto/name')
821 params = cmd.findall('param')
822 if proto.text is not None:
John Zulaufbb6e5e42018-08-06 16:00:07 -0600823 cmddata = self.cmd_info_dict[proto.text]
824 cmd_info = cmddata.members
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600825 disp_name = cmd_info[0].name
John Zulaufbb6e5e42018-08-06 16:00:07 -0600826 # Handle object create operations if last parameter is created by this call
827 if cmddata.iscreate:
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600828 post_call_record += self.generate_create_object_code(indent, proto, params, cmd_info, cmddata.allocator)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600829 # Handle object destroy operations
John Zulaufbb6e5e42018-08-06 16:00:07 -0600830 if cmddata.isdestroy:
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600831 (destroy_array, validate_destroy_code, record_destroy_code) = self.generate_destroy_object_code(indent, proto, cmd_info)
Mark Lobodzinski2a51e802018-09-12 16:07:01 -0600832
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600833 pre_call_record += record_destroy_code
834 pre_call_validate += self.validate_objects(cmd_info, indent, '', 0, disp_name, proto.text, True)
835 pre_call_validate += validate_destroy_code
836
837 return pre_call_validate, pre_call_record, post_call_record
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600838 #
839 # Capture command parameter info needed to create, destroy, and validate objects
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700840 def genCmd(self, cmdinfo, cmdname, alias):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600841
842 # Add struct-member type information to command parameter information
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700843 OutputGenerator.genCmd(self, cmdinfo, cmdname, alias)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600844 members = cmdinfo.elem.findall('.//param')
845 # Iterate over members once to get length parameters for arrays
846 lens = set()
847 for member in members:
John Zulaufbb6e5e42018-08-06 16:00:07 -0600848 length = self.getLen(member)
849 if length:
850 lens.add(length)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600851 struct_member_dict = dict(self.structMembers)
John Zulaufbb6e5e42018-08-06 16:00:07 -0600852
853 # Set command invariant information needed at a per member level in validate...
854 is_create_command = any(filter(lambda pat: pat in cmdname, ('Create', 'Allocate', 'Enumerate', 'RegisterDeviceEvent', 'RegisterDisplayEvent')))
855 last_member_is_pointer = len(members) and self.paramIsPointer(members[-1])
856 iscreate = is_create_command or ('vkGet' in cmdname and last_member_is_pointer)
857 isdestroy = any([destroy_txt in cmdname for destroy_txt in ['Destroy', 'Free']])
858
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600859 # Generate member info
860 membersInfo = []
861 constains_extension_structs = False
John Zulaufbb6e5e42018-08-06 16:00:07 -0600862 allocator = 'nullptr'
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600863 for member in members:
864 # Get type and name of member
865 info = self.getTypeNameTuple(member)
866 type = info[0]
867 name = info[1]
868 cdecl = self.makeCParamDecl(member, 0)
869 # Check for parameter name in lens set
870 iscount = True if name in lens else False
John Zulaufbb6e5e42018-08-06 16:00:07 -0600871 length = self.getLen(member)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600872 isconst = True if 'const' in cdecl else False
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600873 # Mark param as local if it is an array of objects
874 islocal = False;
875 if self.isHandleTypeObject(type) == True:
John Zulaufbb6e5e42018-08-06 16:00:07 -0600876 if (length is not None) and (isconst == True):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600877 islocal = True
878 # Or if it's a struct that contains an object
879 elif type in struct_member_dict:
880 if self.struct_contains_object(type) == True:
881 islocal = True
John Zulaufbb6e5e42018-08-06 16:00:07 -0600882 if type == 'VkAllocationCallbacks':
883 allocator = name
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600884 extstructs = member.attrib.get('validextensionstructs') if name == 'pNext' else None
885 membersInfo.append(self.CommandParam(type=type,
886 name=name,
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600887 isconst=isconst,
888 isoptional=self.paramIsOptional(member),
889 iscount=iscount,
John Zulaufbb6e5e42018-08-06 16:00:07 -0600890 len=length,
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600891 extstructs=extstructs,
892 cdecl=cdecl,
893 islocal=islocal,
John Zulaufbb6e5e42018-08-06 16:00:07 -0600894 iscreate=iscreate))
895
896 self.cmd_list.append(cmdname)
897 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)
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600898 #
899 # Create code Create, Destroy, and validate Vulkan objects
900 def WrapCommands(self):
John Zulaufbb6e5e42018-08-06 16:00:07 -0600901 for cmdname in self.cmd_list:
902 cmddata = self.cmd_info_dict[cmdname]
903 cmdinfo = cmddata.cmdinfo
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600904 if cmdname in self.interface_functions:
905 continue
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600906 manual = False
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600907 if cmdname in self.no_autogen_list:
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600908 manual = True
909
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600910 # Generate object handling code
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600911 (pre_call_validate, pre_call_record, post_call_record) = self.generate_wrapping_code(cmdinfo.elem)
912
John Zulaufbb6e5e42018-08-06 16:00:07 -0600913 feature_extra_protect = cmddata.extra_protect
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100914 if (feature_extra_protect is not None):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600915 self.appendSection('command', '')
916 self.appendSection('command', '#ifdef '+ feature_extra_protect)
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600917 self.prototypes += [ '#ifdef %s' % feature_extra_protect ]
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600918
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600919 # Add intercept to procmap
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600920 self.prototypes += [ ' {"%s", (void*)%s},' % (cmdname,cmdname[2:]) ]
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600921
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600922 decls = self.makeCDecls(cmdinfo.elem)
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600923
924 # Gather the parameter items
925 params = cmdinfo.elem.findall('param/name')
926 # Pull out the text for each of the parameters, separate them by commas in a list
927 paramstext = ', '.join([str(param.text) for param in params])
928 # Generate the API call template
929 fcn_call = cmdinfo.elem.attrib.get('name').replace('vk', 'TOKEN', 1) + '(' + paramstext + ');'
930
931 func_decl_template = decls[0][:-1].split('VKAPI_CALL ')
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600932 func_decl_template = func_decl_template[1]
Mark Lobodzinskia9e7e9c2018-09-13 13:29:49 -0600933
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700934 result_type = cmdinfo.elem.find('proto/type')
935
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600936 if 'object_tracker.h' in self.genOpts.filename:
937 # Output PreCallValidateAPI prototype if necessary
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600938 if pre_call_validate:
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600939 pre_cv_func_decl = 'bool PreCallValidate' + func_decl_template + ';'
940 self.appendSection('command', pre_cv_func_decl)
941
942 # Output PreCallRecordAPI prototype if necessary
943 if pre_call_record:
944 pre_cr_func_decl = 'void PreCallRecord' + func_decl_template + ';'
945 self.appendSection('command', pre_cr_func_decl)
946
947 # Output PosCallRecordAPI prototype if necessary
948 if post_call_record:
949 post_cr_func_decl = 'void PostCallRecord' + func_decl_template + ';'
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700950 if result_type.text == 'VkResult':
951 post_cr_func_decl = post_cr_func_decl.replace(')', ',\n VkResult result)')
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600952 self.appendSection('command', post_cr_func_decl)
953
954 if 'object_tracker.cpp' in self.genOpts.filename:
955 # Output PreCallValidateAPI function if necessary
956 if pre_call_validate and not manual:
957 pre_cv_func_decl = 'bool ObjectLifetimes::PreCallValidate' + func_decl_template + ' {'
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600958 self.appendSection('command', '')
959 self.appendSection('command', pre_cv_func_decl)
960 self.appendSection('command', ' bool skip = false;')
961 self.appendSection('command', pre_call_validate)
962 self.appendSection('command', ' return skip;')
963 self.appendSection('command', '}')
964
965 # Output PreCallRecordAPI function if necessary
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600966 if pre_call_record and not manual:
967 pre_cr_func_decl = 'void ObjectLifetimes::PreCallRecord' + func_decl_template + ' {'
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600968 self.appendSection('command', '')
969 self.appendSection('command', pre_cr_func_decl)
970 self.appendSection('command', pre_call_record)
971 self.appendSection('command', '}')
972
973 # Output PosCallRecordAPI function if necessary
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600974 if post_call_record and not manual:
975 post_cr_func_decl = 'void ObjectLifetimes::PostCallRecord' + func_decl_template + ' {'
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600976 self.appendSection('command', '')
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700977
978 if result_type.text == 'VkResult':
979 post_cr_func_decl = post_cr_func_decl.replace(')', ',\n VkResult result)')
Mark Lobodzinskifd2d0a42019-02-20 16:34:56 -0700980 # The two createpipelines APIs may create on failure -- skip the success result check
981 if 'CreateGraphicsPipelines' not in cmdname and 'CreateComputePipelines' not in cmdname and 'CreateRayTracingPipelines' not in cmdname:
982 post_cr_func_decl = post_cr_func_decl.replace('{', '{\n if (result != VK_SUCCESS) return;')
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600983 self.appendSection('command', post_cr_func_decl)
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700984
985
Mark Lobodzinski63902f02018-09-21 10:36:44 -0600986 self.appendSection('command', post_call_record)
987 self.appendSection('command', '}')
988
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100989 if (feature_extra_protect is not None):
Mark Lobodzinskid1461482017-07-18 13:56:09 -0600990 self.appendSection('command', '#endif // '+ feature_extra_protect)
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600991 self.prototypes += [ '#endif' ]