blob: 4d4ad6c0948669c23e64351c4a3d2b4a38d292f6 [file] [log] [blame]
Mark Lobodzinski85672672016-10-13 08:36:42 -06001#!/usr/bin/python3 -i
2#
3# Copyright (c) 2015-2016 The Khronos Group Inc.
4# Copyright (c) 2015-2016 Valve Corporation
5# Copyright (c) 2015-2016 LunarG, Inc.
6# Copyright (c) 2015-2016 Google Inc.
7#
8# Licensed under the Apache License, Version 2.0 (the "License");
9# you may not use this file except in compliance with the License.
10# You may obtain a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS,
16# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17# See the License for the specific language governing permissions and
18# limitations under the License.
19#
20# Author: Dustin Graves <dustin@lunarg.com>
Mark Lobodzinski26112592017-05-30 12:02:17 -060021# Author: Mark Lobodzinski <mark@lunarg.com>
Mark Lobodzinski85672672016-10-13 08:36:42 -060022
Mark Lobodzinski06954ea2017-06-21 12:21:45 -060023import os,re,sys,string
Mark Lobodzinski85672672016-10-13 08:36:42 -060024import xml.etree.ElementTree as etree
25from generator import *
26from collections import namedtuple
Mark Lobodzinski06954ea2017-06-21 12:21:45 -060027from vuid_mapping import *
28
Mark Lobodzinski85672672016-10-13 08:36:42 -060029
Mark Lobodzinskid4950072017-08-01 13:02:20 -060030# ParameterValidationGeneratorOptions - subclass of GeneratorOptions.
Mark Lobodzinski85672672016-10-13 08:36:42 -060031#
Mark Lobodzinskid4950072017-08-01 13:02:20 -060032# Adds options used by ParameterValidationOutputGenerator object during Parameter validation layer generation.
Mark Lobodzinski85672672016-10-13 08:36:42 -060033#
34# Additional members
35# prefixText - list of strings to prefix generated header with
36# (usually a copyright statement + calling convention macros).
37# protectFile - True if multiple inclusion protection should be
38# generated (based on the filename) around the entire header.
39# protectFeature - True if #ifndef..#endif protection should be
40# generated around a feature interface in the header file.
41# genFuncPointers - True if function pointer typedefs should be
42# generated
43# protectProto - If conditional protection should be generated
44# around prototype declarations, set to either '#ifdef'
45# to require opt-in (#ifdef protectProtoStr) or '#ifndef'
46# to require opt-out (#ifndef protectProtoStr). Otherwise
47# set to None.
48# protectProtoStr - #ifdef/#ifndef symbol to use around prototype
49# declarations, if protectProto is set
50# apicall - string to use for the function declaration prefix,
51# such as APICALL on Windows.
52# apientry - string to use for the calling convention macro,
53# in typedefs, such as APIENTRY.
54# apientryp - string to use for the calling convention macro
55# in function pointer typedefs, such as APIENTRYP.
56# indentFuncProto - True if prototype declarations should put each
57# parameter on a separate line
58# indentFuncPointer - True if typedefed function pointers should put each
59# parameter on a separate line
60# alignFuncParam - if nonzero and parameters are being put on a
61# separate line, align parameter names at the specified column
Mark Lobodzinskid4950072017-08-01 13:02:20 -060062class ParameterValidationGeneratorOptions(GeneratorOptions):
Mark Lobodzinski85672672016-10-13 08:36:42 -060063 def __init__(self,
64 filename = None,
65 directory = '.',
66 apiname = None,
67 profile = None,
68 versions = '.*',
69 emitversions = '.*',
70 defaultExtensions = None,
71 addExtensions = None,
72 removeExtensions = None,
73 sortProcedure = regSortFeatures,
74 prefixText = "",
75 genFuncPointers = True,
76 protectFile = True,
77 protectFeature = True,
78 protectProto = None,
79 protectProtoStr = None,
80 apicall = '',
81 apientry = '',
82 apientryp = '',
83 indentFuncProto = True,
84 indentFuncPointer = False,
85 alignFuncParam = 0):
86 GeneratorOptions.__init__(self, filename, directory, apiname, profile,
87 versions, emitversions, defaultExtensions,
88 addExtensions, removeExtensions, sortProcedure)
89 self.prefixText = prefixText
90 self.genFuncPointers = genFuncPointers
91 self.protectFile = protectFile
92 self.protectFeature = protectFeature
93 self.protectProto = protectProto
94 self.protectProtoStr = protectProtoStr
95 self.apicall = apicall
96 self.apientry = apientry
97 self.apientryp = apientryp
98 self.indentFuncProto = indentFuncProto
99 self.indentFuncPointer = indentFuncPointer
100 self.alignFuncParam = alignFuncParam
101
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600102# ParameterValidationOutputGenerator - subclass of OutputGenerator.
Mark Lobodzinski85672672016-10-13 08:36:42 -0600103# Generates param checker layer code.
104#
105# ---- methods ----
106# ParamCheckerOutputGenerator(errFile, warnFile, diagFile) - args as for
107# OutputGenerator. Defines additional internal state.
108# ---- methods overriding base class ----
109# beginFile(genOpts)
110# endFile()
111# beginFeature(interface, emit)
112# endFeature()
113# genType(typeinfo,name)
114# genStruct(typeinfo,name)
115# genGroup(groupinfo,name)
116# genEnum(enuminfo, name)
117# genCmd(cmdinfo)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600118class ParameterValidationOutputGenerator(OutputGenerator):
119 """Generate Parameter Validation code based on XML element attributes"""
Mark Lobodzinski85672672016-10-13 08:36:42 -0600120 # This is an ordered list of sections in the header file.
121 ALL_SECTIONS = ['command']
122 def __init__(self,
123 errFile = sys.stderr,
124 warnFile = sys.stderr,
125 diagFile = sys.stdout):
126 OutputGenerator.__init__(self, errFile, warnFile, diagFile)
127 self.INDENT_SPACES = 4
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700128 self.intercepts = []
129 self.declarations = []
Mark Lobodzinski85672672016-10-13 08:36:42 -0600130 # Commands to ignore
131 self.blacklist = [
132 'vkGetInstanceProcAddr',
133 'vkGetDeviceProcAddr',
134 'vkEnumerateInstanceLayerProperties',
135 'vkEnumerateInstanceExtensionsProperties',
136 'vkEnumerateDeviceLayerProperties',
137 'vkEnumerateDeviceExtensionsProperties',
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600138 'vkCreateDebugReportCallbackKHR',
139 'vkDestroyDebugReportCallbackKHR',
140 'vkEnumerateInstanceLayerProperties',
141 'vkEnumerateInstanceExtensionProperties',
142 'vkEnumerateDeviceLayerProperties',
143 'vkCmdDebugMarkerEndEXT',
144 'vkEnumerateDeviceExtensionProperties',
145 ]
146 self.validate_only = [
147 'vkCreateInstance',
148 'vkDestroyInstance',
149 'vkCreateDevice',
150 'vkDestroyDevice',
151 'vkCreateQueryPool',
Mark Lobodzinski85672672016-10-13 08:36:42 -0600152 'vkCreateDebugReportCallbackEXT',
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600153 'vkDestroyDebugReportCallbackEXT',
154 'vkCreateCommandPool',
155 ]
Dustin Gravesce68f082017-03-30 15:42:16 -0600156 # Structure fields to ignore
157 self.structMemberBlacklist = { 'VkWriteDescriptorSet' : ['dstSet'] }
Mark Lobodzinski85672672016-10-13 08:36:42 -0600158 # Validation conditions for some special case struct members that are conditionally validated
159 self.structMemberValidationConditions = { 'VkPipelineColorBlendStateCreateInfo' : { 'logicOp' : '{}logicOpEnable == VK_TRUE' } }
160 # Header version
161 self.headerVersion = None
162 # Internal state - accumulators for different inner block text
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600163 self.validation = [] # Text comprising the main per-api parameter validation routines
Mark Lobodzinski85672672016-10-13 08:36:42 -0600164 self.structNames = [] # List of Vulkan struct typenames
165 self.stypes = [] # Values from the VkStructureType enumeration
166 self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType
167 self.handleTypes = set() # Set of handle type names
168 self.commands = [] # List of CommandData records for all Vulkan commands
169 self.structMembers = [] # List of StructMemberData records for all Vulkan structs
170 self.validatedStructs = dict() # Map of structs type names to generated validation code for that struct type
171 self.enumRanges = dict() # Map of enum name to BEGIN/END range values
Mark Lobodzinskif31e0422017-07-25 14:29:42 -0600172 self.enumValueLists = '' # String containing enumerated type map definitions
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600173 self.func_pointers = '' # String containing function pointers for manual PV functions
174 self.typedefs = '' # String containing function pointer typedefs
Mark Lobodzinski85672672016-10-13 08:36:42 -0600175 self.flags = set() # Map of flags typenames
176 self.flagBits = dict() # Map of flag bits typename to list of values
Chris Forbes78ea32d2016-11-28 11:14:17 +1300177 self.newFlags = set() # Map of flags typenames /defined in the current feature/
Mark Lobodzinski26112592017-05-30 12:02:17 -0600178 self.required_extensions = [] # List of required extensions for the current extension
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600179 self.extension_type = '' # Type of active feature (extension), device or instance
180 self.extension_names = dict() # Dictionary of extension names to extension name defines
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600181 self.valid_vuids = set() # Set of all valid VUIDs
Mark Lobodzinski85672672016-10-13 08:36:42 -0600182 # Named tuples to store struct and command data
183 self.StructType = namedtuple('StructType', ['name', 'value'])
184 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isbool', 'israngedenum',
185 'isconst', 'isoptional', 'iscount', 'noautovalidity', 'len', 'extstructs',
186 'condition', 'cdecl'])
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600187 self.CommandData = namedtuple('CommandData', ['name', 'params', 'cdecl', 'extension_type', 'result'])
Mark Lobodzinski85672672016-10-13 08:36:42 -0600188 self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600189
190 self.vuid_file = None
191 # Cover cases where file is built from scripts directory, Lin/Win, or Android build structure
192 vuid_filename_locations = [
Mark Lobodzinskifc20c4d2017-07-03 15:50:39 -0600193 './vk_validation_error_messages.h',
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600194 '../layers/vk_validation_error_messages.h',
195 '../../layers/vk_validation_error_messages.h',
196 '../../../layers/vk_validation_error_messages.h',
197 ]
198 for vuid_filename in vuid_filename_locations:
199 if os.path.isfile(vuid_filename):
200 self.vuid_file = open(vuid_filename, "r")
201 break
202 if self.vuid_file == None:
203 print("Error: Could not find vk_validation_error_messages.h")
204 quit()
Mark Lobodzinski85672672016-10-13 08:36:42 -0600205 #
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600206 # Generate Copyright comment block for file
207 def GenerateCopyright(self):
208 copyright = '/* *** THIS FILE IS GENERATED - DO NOT EDIT! ***\n'
209 copyright += ' * See parameter_validation_generator.py for modifications\n'
210 copyright += ' *\n'
211 copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n'
212 copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n'
213 copyright += ' * Copyright (C) 2015-2017 Google Inc.\n'
214 copyright += ' *\n'
215 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
216 copyright += ' * you may not use this file except in compliance with the License.\n'
217 copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n'
218 copyright += ' * You may obtain a copy of the License at\n'
219 copyright += ' *\n'
220 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n'
221 copyright += ' *\n'
222 copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
223 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
224 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
225 copyright += ' * See the License for the specific language governing permissions and\n'
226 copyright += ' * limitations under the License.\n'
227 copyright += ' *\n'
228 copyright += ' * Author: Mark Lobodzinski <mark@LunarG.com>\n'
229 copyright += ' */\n\n'
230 return copyright
231 #
232 # Increases the global indent variable
Mark Lobodzinski85672672016-10-13 08:36:42 -0600233 def incIndent(self, indent):
234 inc = ' ' * self.INDENT_SPACES
235 if indent:
236 return indent + inc
237 return inc
238 #
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600239 # Decreases the global indent variable
Mark Lobodzinski85672672016-10-13 08:36:42 -0600240 def decIndent(self, indent):
241 if indent and (len(indent) > self.INDENT_SPACES):
242 return indent[:-self.INDENT_SPACES]
243 return ''
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600244 #
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600245 # Convert decimal number to 8 digit hexadecimal lower-case representation
246 def IdToHex(self, dec_num):
247 if dec_num > 4294967295:
248 print ("ERROR: Decimal # %d can't be represented in 8 hex digits" % (dec_num))
249 sys.exit()
250 hex_num = hex(dec_num)
251 return hex_num[2:].zfill(8)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600252 #
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600253 # Called at file creation time
Mark Lobodzinski85672672016-10-13 08:36:42 -0600254 def beginFile(self, genOpts):
255 OutputGenerator.beginFile(self, genOpts)
256 # C-specific
257 #
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600258 # Open vk_validation_error_messages.h file to verify computed VUIDs
259 for line in self.vuid_file:
260 # Grab hex number from enum definition
261 vuid_list = line.split('0x')
262 # If this is a valid enumeration line, remove trailing comma and CR
263 if len(vuid_list) == 2:
264 vuid_num = vuid_list[1][:-2]
265 # Make sure this is a good hex number before adding to set
266 if len(vuid_num) == 8 and all(c in string.hexdigits for c in vuid_num):
267 self.valid_vuids.add(vuid_num)
268 #
Mark Lobodzinski85672672016-10-13 08:36:42 -0600269 # User-supplied prefix text, if any (list of strings)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600270 s = self.GenerateCopyright()
271 write(s, file=self.outFile)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600272 #
273 # Headers
274 write('#include <string>', file=self.outFile)
275 self.newline()
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600276 write('#include "vk_loader_platform.h"', file=self.outFile)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600277 write('#include "vulkan/vulkan.h"', file=self.outFile)
278 write('#include "vk_layer_extension_utils.h"', file=self.outFile)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600279 write('#include "parameter_validation.h"', file=self.outFile)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600280 #
281 # Macros
282 self.newline()
283 write('#ifndef UNUSED_PARAMETER', file=self.outFile)
284 write('#define UNUSED_PARAMETER(x) (void)(x)', file=self.outFile)
285 write('#endif // UNUSED_PARAMETER', file=self.outFile)
286 #
287 # Namespace
288 self.newline()
289 write('namespace parameter_validation {', file = self.outFile)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600290 self.newline()
291 write('extern std::mutex global_lock;', file = self.outFile)
292 write('extern std::unordered_map<void *, layer_data *> layer_data_map;', file = self.outFile)
293 write('extern std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;', file = self.outFile)
294 self.newline()
Mark Lobodzinski78a12a92017-08-08 14:16:51 -0600295 #
296 # FuncPtrMap
297 self.func_pointers += 'std::unordered_map<std::string, void *> custom_functions = {\n'
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600298 #
299 # Called at end-time for final content output
Mark Lobodzinski85672672016-10-13 08:36:42 -0600300 def endFile(self):
301 # C-specific
302 self.newline()
Mark Lobodzinskif31e0422017-07-25 14:29:42 -0600303 write(self.enumValueLists, file=self.outFile)
304 self.newline()
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600305 write(self.typedefs, file=self.outFile)
306 self.newline()
Mark Lobodzinski78a12a92017-08-08 14:16:51 -0600307 self.func_pointers += '};\n'
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600308 write(self.func_pointers, file=self.outFile)
309 self.newline()
310 ext_template = 'template <typename T>\n'
311 ext_template += 'bool OutputExtensionError(const T *layer_data, const std::string &api_name, const std::string &extension_name) {\n'
312 ext_template += ' return log_msg(layer_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,\n'
313 ext_template += ' EXTENSION_NOT_ENABLED, LayerName, "Attemped to call %s() but its required extension %s has not been enabled\\n",\n'
314 ext_template += ' api_name.c_str(), extension_name.c_str());\n'
315 ext_template += '}\n'
316 write(ext_template, file=self.outFile)
317 self.newline()
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600318 commands_text = '\n'.join(self.validation)
319 write(commands_text, file=self.outFile)
320 self.newline()
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700321 # Output declarations and record intercepted procedures
322 write('// Declarations', file=self.outFile)
323 write('\n'.join(self.declarations), file=self.outFile)
Mark Lobodzinskide43e642017-06-07 14:00:31 -0600324 write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600325 write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700326 write('\n'.join(self.intercepts), file=self.outFile)
327 write('};\n', file=self.outFile)
328 self.newline()
Mark Lobodzinski85672672016-10-13 08:36:42 -0600329 # Namespace
330 write('} // namespace parameter_validation', file = self.outFile)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600331 # Finish processing in superclass
332 OutputGenerator.endFile(self)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600333 #
334 # Processing at beginning of each feature or extension
Mark Lobodzinski85672672016-10-13 08:36:42 -0600335 def beginFeature(self, interface, emit):
336 # Start processing in superclass
337 OutputGenerator.beginFeature(self, interface, emit)
338 # C-specific
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600339 # Accumulate includes, defines, types, enums, function pointer typedefs, end function prototypes separately for this
340 # feature. They're only printed in endFeature().
Mark Lobodzinski85672672016-10-13 08:36:42 -0600341 self.headerVersion = None
Mark Lobodzinski85672672016-10-13 08:36:42 -0600342 self.structNames = []
343 self.stypes = []
344 self.structTypes = dict()
Mark Lobodzinski85672672016-10-13 08:36:42 -0600345 self.commands = []
346 self.structMembers = []
Chris Forbes78ea32d2016-11-28 11:14:17 +1300347 self.newFlags = set()
Mark Lobodzinski26112592017-05-30 12:02:17 -0600348 # Save list of required extensions for this extension
349 self.required_extensions = []
350 if self.featureName != "VK_VERSION_1_0":
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600351 # Save Name Define to get correct enable name later
352 nameElem = interface[0][1]
353 name = nameElem.get('name')
354 self.extension_names[self.featureName] = name
355 # This extension is the first dependency for this command
Mark Lobodzinski26112592017-05-30 12:02:17 -0600356 self.required_extensions.append(self.featureName)
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600357 # Add any defined extension dependencies to the dependency list for this command
Mark Lobodzinski26112592017-05-30 12:02:17 -0600358 required_extensions = interface.get('requires')
359 if required_extensions is not None:
360 self.required_extensions.extend(required_extensions.split(','))
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600361 # And note if this is an Instance or Device extension
362 self.extension_type = interface.get('type')
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600363 #
364 # Called at the end of each extension (feature)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600365 def endFeature(self):
366 # C-specific
367 # Actually write the interface to the output file.
368 if (self.emit):
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600369 # If type declarations are needed by other features based on this one, it may be necessary to suppress the ExtraProtect,
Mark Lobodzinski85672672016-10-13 08:36:42 -0600370 # or move it below the 'for section...' loop.
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600371 ifdef = ''
Mark Lobodzinski85672672016-10-13 08:36:42 -0600372 if (self.featureExtraProtect != None):
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600373 ifdef = '#ifdef %s\n' % self.featureExtraProtect
374 self.validation.append(ifdef)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600375 # Generate the struct member checking code from the captured data
376 self.processStructMemberData()
377 # Generate the command parameter checking code from the captured data
378 self.processCmdData()
379 # Write the declaration for the HeaderVersion
380 if self.headerVersion:
381 write('const uint32_t GeneratedHeaderVersion = {};'.format(self.headerVersion), file=self.outFile)
382 self.newline()
383 # Write the declarations for the VkFlags values combining all flag bits
Chris Forbes78ea32d2016-11-28 11:14:17 +1300384 for flag in sorted(self.newFlags):
Mark Lobodzinski85672672016-10-13 08:36:42 -0600385 flagBits = flag.replace('Flags', 'FlagBits')
386 if flagBits in self.flagBits:
387 bits = self.flagBits[flagBits]
388 decl = 'const {} All{} = {}'.format(flag, flagBits, bits[0])
389 for bit in bits[1:]:
390 decl += '|' + bit
391 decl += ';'
392 write(decl, file=self.outFile)
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600393 endif = '\n'
Mark Lobodzinski85672672016-10-13 08:36:42 -0600394 if (self.featureExtraProtect != None):
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600395 endif = '#endif // %s\n' % self.featureExtraProtect
396 self.validation.append(endif)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600397 # Finish processing in superclass
398 OutputGenerator.endFeature(self)
399 #
Mark Lobodzinski85672672016-10-13 08:36:42 -0600400 # Type generation
401 def genType(self, typeinfo, name):
402 OutputGenerator.genType(self, typeinfo, name)
403 typeElem = typeinfo.elem
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600404 # If the type is a struct type, traverse the imbedded <member> tags generating a structure. Otherwise, emit the tag text.
Mark Lobodzinski85672672016-10-13 08:36:42 -0600405 category = typeElem.get('category')
406 if (category == 'struct' or category == 'union'):
407 self.structNames.append(name)
408 self.genStruct(typeinfo, name)
409 elif (category == 'handle'):
410 self.handleTypes.add(name)
411 elif (category == 'bitmask'):
412 self.flags.add(name)
Chris Forbes78ea32d2016-11-28 11:14:17 +1300413 self.newFlags.add(name)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600414 elif (category == 'define'):
415 if name == 'VK_HEADER_VERSION':
416 nameElem = typeElem.find('name')
417 self.headerVersion = noneStr(nameElem.tail).strip()
418 #
419 # Struct parameter check generation.
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600420 # This is a special case of the <type> tag where the contents are interpreted as a set of <member> tags instead of freeform C
421 # type declarations. The <member> tags are just like <param> tags - they are a declaration of a struct or union member.
422 # Only simple member declarations are supported (no nested structs etc.)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600423 def genStruct(self, typeinfo, typeName):
424 OutputGenerator.genStruct(self, typeinfo, typeName)
425 conditions = self.structMemberValidationConditions[typeName] if typeName in self.structMemberValidationConditions else None
426 members = typeinfo.elem.findall('.//member')
427 #
428 # Iterate over members once to get length parameters for arrays
429 lens = set()
430 for member in members:
431 len = self.getLen(member)
432 if len:
433 lens.add(len)
434 #
435 # Generate member info
436 membersInfo = []
437 for member in members:
438 # Get the member's type and name
439 info = self.getTypeNameTuple(member)
440 type = info[0]
441 name = info[1]
442 stypeValue = ''
443 cdecl = self.makeCParamDecl(member, 0)
444 # Process VkStructureType
445 if type == 'VkStructureType':
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600446 # Extract the required struct type value from the comments embedded in the original text defining the
447 # 'typeinfo' element
Mark Lobodzinski85672672016-10-13 08:36:42 -0600448 rawXml = etree.tostring(typeinfo.elem).decode('ascii')
449 result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml)
450 if result:
451 value = result.group(0)
452 else:
453 value = self.genVkStructureType(typeName)
454 # Store the required type value
455 self.structTypes[typeName] = self.StructType(name=name, value=value)
456 #
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600457 # Store pointer/array/string info -- Check for parameter name in lens set
Mark Lobodzinski85672672016-10-13 08:36:42 -0600458 iscount = False
459 if name in lens:
460 iscount = True
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600461 # The pNext members are not tagged as optional, but are treated as optional for parameter NULL checks. Static array
462 # members are also treated as optional to skip NULL pointer validation, as they won't be NULL.
Mark Lobodzinski85672672016-10-13 08:36:42 -0600463 isstaticarray = self.paramIsStaticArray(member)
464 isoptional = False
465 if self.paramIsOptional(member) or (name == 'pNext') or (isstaticarray):
466 isoptional = True
Dustin Gravesce68f082017-03-30 15:42:16 -0600467 # Determine if value should be ignored by code generation.
468 noautovalidity = False
469 if (member.attrib.get('noautovalidity') is not None) or ((typeName in self.structMemberBlacklist) and (name in self.structMemberBlacklist[typeName])):
470 noautovalidity = True
Mark Lobodzinski85672672016-10-13 08:36:42 -0600471 membersInfo.append(self.CommandParam(type=type, name=name,
472 ispointer=self.paramIsPointer(member),
473 isstaticarray=isstaticarray,
474 isbool=True if type == 'VkBool32' else False,
475 israngedenum=True if type in self.enumRanges else False,
476 isconst=True if 'const' in cdecl else False,
477 isoptional=isoptional,
478 iscount=iscount,
Dustin Gravesce68f082017-03-30 15:42:16 -0600479 noautovalidity=noautovalidity,
Mark Lobodzinski85672672016-10-13 08:36:42 -0600480 len=self.getLen(member),
Mike Schuchardta40d0b02017-07-23 12:47:47 -0600481 extstructs=self.registry.validextensionstructs[typeName] if name == 'pNext' else None,
Mark Lobodzinski85672672016-10-13 08:36:42 -0600482 condition=conditions[name] if conditions and name in conditions else None,
483 cdecl=cdecl))
484 self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo))
485 #
Mark Lobodzinskif31e0422017-07-25 14:29:42 -0600486 # Capture group (e.g. C "enum" type) info to be used for param check code generation.
Mark Lobodzinski85672672016-10-13 08:36:42 -0600487 # These are concatenated together with other types.
488 def genGroup(self, groupinfo, groupName):
489 OutputGenerator.genGroup(self, groupinfo, groupName)
490 groupElem = groupinfo.elem
Mark Lobodzinski85672672016-10-13 08:36:42 -0600491 # Store the sType values
492 if groupName == 'VkStructureType':
493 for elem in groupElem.findall('enum'):
494 self.stypes.append(elem.get('name'))
495 elif 'FlagBits' in groupName:
496 bits = []
497 for elem in groupElem.findall('enum'):
498 bits.append(elem.get('name'))
499 if bits:
500 self.flagBits[groupName] = bits
501 else:
502 # Determine if begin/end ranges are needed (we don't do this for VkStructureType, which has a more finely grained check)
503 expandName = re.sub(r'([0-9a-z_])([A-Z0-9][^A-Z0-9]?)',r'\1_\2',groupName).upper()
504 expandPrefix = expandName
505 expandSuffix = ''
506 expandSuffixMatch = re.search(r'[A-Z][A-Z]+$',groupName)
507 if expandSuffixMatch:
508 expandSuffix = '_' + expandSuffixMatch.group()
509 # Strip off the suffix from the prefix
510 expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
511 isEnum = ('FLAG_BITS' not in expandPrefix)
512 if isEnum:
513 self.enumRanges[groupName] = (expandPrefix + '_BEGIN_RANGE' + expandSuffix, expandPrefix + '_END_RANGE' + expandSuffix)
Mark Lobodzinskif31e0422017-07-25 14:29:42 -0600514 # Create definition for a list containing valid enum values for this enumerated type
515 enum_entry = 'const std::vector<%s> All%sEnums = {' % (groupName, groupName)
516 for enum in groupElem:
517 name = enum.get('name')
Mark Lobodzinski117d88f2017-07-27 12:09:08 -0600518 if name is not None and enum.get('supported') != 'disabled':
519 enum_entry += '%s, ' % name
Mark Lobodzinskif31e0422017-07-25 14:29:42 -0600520 enum_entry += '};\n'
521 self.enumValueLists += enum_entry
Mark Lobodzinski85672672016-10-13 08:36:42 -0600522 #
Mark Lobodzinskif31e0422017-07-25 14:29:42 -0600523 # Capture command parameter info to be used for param check code generation.
Mark Lobodzinski85672672016-10-13 08:36:42 -0600524 def genCmd(self, cmdinfo, name):
525 OutputGenerator.genCmd(self, cmdinfo, name)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600526 decls = self.makeCDecls(cmdinfo.elem)
527 typedef = decls[1]
528 typedef = typedef.split(')',1)[1]
529 if name not in self.blacklist:
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700530 if (self.featureExtraProtect != None):
531 self.declarations += [ '#ifdef %s' % self.featureExtraProtect ]
532 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600533 if (name not in self.validate_only):
534 self.func_pointers += '#ifdef %s\n' % self.featureExtraProtect
535 self.typedefs += '#ifdef %s\n' % self.featureExtraProtect
536 if (name not in self.validate_only):
537 self.typedefs += 'typedef bool (*PFN_manual_%s)%s\n' % (name, typedef)
Mark Lobodzinski78a12a92017-08-08 14:16:51 -0600538 self.func_pointers += ' {"%s", nullptr},\n' % name
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600539 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name) ]
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700540 # Strip off 'vk' from API name
541 self.declarations += [ '%s' % decls[0].replace("VKAPI_CALL vk", "VKAPI_CALL ") ]
542 if (self.featureExtraProtect != None):
543 self.intercepts += [ '#endif' ]
544 self.declarations += [ '#endif' ]
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600545 if (name not in self.validate_only):
546 self.func_pointers += '#endif\n'
547 self.typedefs += '#endif\n'
Mark Lobodzinski85672672016-10-13 08:36:42 -0600548 if name not in self.blacklist:
549 params = cmdinfo.elem.findall('param')
550 # Get list of array lengths
551 lens = set()
552 for param in params:
553 len = self.getLen(param)
554 if len:
555 lens.add(len)
556 # Get param info
557 paramsInfo = []
558 for param in params:
559 paramInfo = self.getTypeNameTuple(param)
560 cdecl = self.makeCParamDecl(param, 0)
561 # Check for parameter name in lens set
562 iscount = False
563 if paramInfo[1] in lens:
564 iscount = True
565 paramsInfo.append(self.CommandParam(type=paramInfo[0], name=paramInfo[1],
566 ispointer=self.paramIsPointer(param),
567 isstaticarray=self.paramIsStaticArray(param),
568 isbool=True if paramInfo[0] == 'VkBool32' else False,
569 israngedenum=True if paramInfo[0] in self.enumRanges else False,
570 isconst=True if 'const' in cdecl else False,
571 isoptional=self.paramIsOptional(param),
572 iscount=iscount,
573 noautovalidity=True if param.attrib.get('noautovalidity') is not None else False,
574 len=self.getLen(param),
575 extstructs=None,
576 condition=None,
577 cdecl=cdecl))
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600578 # Save return value information, if any
579 result_type = ''
580 resultinfo = cmdinfo.elem.find('proto/type')
581 if (resultinfo != None and resultinfo.text != 'void'):
582 result_type = resultinfo.text
583 self.commands.append(self.CommandData(name=name, params=paramsInfo, cdecl=self.makeCDecls(cmdinfo.elem)[0], extension_type=self.extension_type, result=result_type))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600584 #
585 # Check if the parameter passed in is a pointer
586 def paramIsPointer(self, param):
587 ispointer = 0
588 paramtype = param.find('type')
589 if (paramtype.tail is not None) and ('*' in paramtype.tail):
590 ispointer = paramtype.tail.count('*')
591 elif paramtype.text[:4] == 'PFN_':
592 # Treat function pointer typedefs as a pointer to a single value
593 ispointer = 1
594 return ispointer
595 #
596 # Check if the parameter passed in is a static array
597 def paramIsStaticArray(self, param):
598 isstaticarray = 0
599 paramname = param.find('name')
600 if (paramname.tail is not None) and ('[' in paramname.tail):
601 isstaticarray = paramname.tail.count('[')
602 return isstaticarray
603 #
604 # Check if the parameter passed in is optional
605 # Returns a list of Boolean values for comma separated len attributes (len='false,true')
606 def paramIsOptional(self, param):
607 # See if the handle is optional
608 isoptional = False
609 # Simple, if it's optional, return true
610 optString = param.attrib.get('optional')
611 if optString:
612 if optString == 'true':
613 isoptional = True
614 elif ',' in optString:
615 opts = []
616 for opt in optString.split(','):
617 val = opt.strip()
618 if val == 'true':
619 opts.append(True)
620 elif val == 'false':
621 opts.append(False)
622 else:
623 print('Unrecognized len attribute value',val)
624 isoptional = opts
625 return isoptional
626 #
627 # Check if the handle passed in is optional
628 # Uses the same logic as ValidityOutputGenerator.isHandleOptional
629 def isHandleOptional(self, param, lenParam):
630 # Simple, if it's optional, return true
631 if param.isoptional:
632 return True
633 # If no validity is being generated, it usually means that validity is complex and not absolute, so let's say yes.
634 if param.noautovalidity:
635 return True
636 # If the parameter is an array and we haven't already returned, find out if any of the len parameters are optional
637 if lenParam and lenParam.isoptional:
638 return True
639 return False
640 #
641 # Generate a VkStructureType based on a structure typename
642 def genVkStructureType(self, typename):
643 # Add underscore between lowercase then uppercase
644 value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
Mark Young39389872017-01-19 21:10:49 -0700645 value = value.replace('D3_D12', 'D3D12')
646 value = value.replace('Device_IDProp', 'Device_ID_Prop')
Mark Lobodzinski85672672016-10-13 08:36:42 -0600647 # Change to uppercase
648 value = value.upper()
649 # Add STRUCTURE_TYPE_
650 return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value)
651 #
652 # Get the cached VkStructureType value for the specified struct typename, or generate a VkStructureType
653 # value assuming the struct is defined by a different feature
654 def getStructType(self, typename):
655 value = None
656 if typename in self.structTypes:
657 value = self.structTypes[typename].value
658 else:
659 value = self.genVkStructureType(typename)
660 self.logMsg('diag', 'ParameterValidation: Generating {} for {} structure type that was not defined by the current feature'.format(value, typename))
661 return value
662 #
663 # Retrieve the value of the len tag
664 def getLen(self, param):
665 result = None
666 len = param.attrib.get('len')
667 if len and len != 'null-terminated':
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600668 # For string arrays, 'len' can look like 'count,null-terminated', indicating that we have a null terminated array of
669 # strings. We strip the null-terminated from the 'len' field and only return the parameter specifying the string count
Mark Lobodzinski85672672016-10-13 08:36:42 -0600670 if 'null-terminated' in len:
671 result = len.split(',')[0]
672 else:
673 result = len
674 result = str(result).replace('::', '->')
675 return result
676 #
677 # Retrieve the type and name for a parameter
678 def getTypeNameTuple(self, param):
679 type = ''
680 name = ''
681 for elem in param:
682 if elem.tag == 'type':
683 type = noneStr(elem.text)
684 elif elem.tag == 'name':
685 name = noneStr(elem.text)
686 return (type, name)
687 #
688 # Find a named parameter in a parameter list
689 def getParamByName(self, params, name):
690 for param in params:
691 if param.name == name:
692 return param
693 return None
694 #
695 # Extract length values from latexmath. Currently an inflexible solution that looks for specific
696 # patterns that are found in vk.xml. Will need to be updated when new patterns are introduced.
697 def parseLateXMath(self, source):
698 name = 'ERROR'
699 decoratedName = 'ERROR'
700 if 'mathit' in source:
Mark Lobodzinski36c33862017-02-13 10:15:53 -0700701 # Matches expressions similar to 'latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]'
702 match = re.match(r'latexmath\s*\:\s*\[\s*\\l(\w+)\s*\{\s*\\mathit\s*\{\s*(\w+)\s*\}\s*\\over\s*(\d+)\s*\}\s*\\r(\w+)\s*\]', source)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600703 if not match or match.group(1) != match.group(4):
704 raise 'Unrecognized latexmath expression'
705 name = match.group(2)
706 decoratedName = '{}({}/{})'.format(*match.group(1, 2, 3))
707 else:
Mark Lobodzinski36c33862017-02-13 10:15:53 -0700708 # Matches expressions similar to 'latexmath : [dataSize \over 4]'
Mark Young0f183a82017-02-28 09:58:04 -0700709 match = re.match(r'latexmath\s*\:\s*\[\s*(\w+)\s*\\over\s*(\d+)\s*\]', source)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600710 name = match.group(1)
711 decoratedName = '{}/{}'.format(*match.group(1, 2))
712 return name, decoratedName
713 #
714 # Get the length paramater record for the specified parameter name
715 def getLenParam(self, params, name):
716 lenParam = None
717 if name:
718 if '->' in name:
719 # The count is obtained by dereferencing a member of a struct parameter
720 lenParam = self.CommandParam(name=name, iscount=True, ispointer=False, isbool=False, israngedenum=False, isconst=False,
721 isstaticarray=None, isoptional=False, type=None, noautovalidity=False, len=None, extstructs=None,
722 condition=None, cdecl=None)
723 elif 'latexmath' in name:
724 lenName, decoratedName = self.parseLateXMath(name)
725 lenParam = self.getParamByName(params, lenName)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600726 else:
727 lenParam = self.getParamByName(params, name)
728 return lenParam
729 #
730 # Convert a vulkan.h command declaration into a parameter_validation.h definition
731 def getCmdDef(self, cmd):
Mark Lobodzinski85672672016-10-13 08:36:42 -0600732 # Strip the trailing ';' and split into individual lines
733 lines = cmd.cdecl[:-1].split('\n')
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600734 cmd_hdr = '\n'.join(lines)
735 return cmd_hdr
Mark Lobodzinski85672672016-10-13 08:36:42 -0600736 #
737 # Generate the code to check for a NULL dereference before calling the
738 # validation function
739 def genCheckedLengthCall(self, name, exprs):
740 count = name.count('->')
741 if count:
742 checkedExpr = []
743 localIndent = ''
744 elements = name.split('->')
745 # Open the if expression blocks
746 for i in range(0, count):
747 checkedExpr.append(localIndent + 'if ({} != NULL) {{\n'.format('->'.join(elements[0:i+1])))
748 localIndent = self.incIndent(localIndent)
749 # Add the validation expression
750 for expr in exprs:
751 checkedExpr.append(localIndent + expr)
752 # Close the if blocks
753 for i in range(0, count):
754 localIndent = self.decIndent(localIndent)
755 checkedExpr.append(localIndent + '}\n')
756 return [checkedExpr]
757 # No if statements were required
758 return exprs
759 #
760 # Generate code to check for a specific condition before executing validation code
761 def genConditionalCall(self, prefix, condition, exprs):
762 checkedExpr = []
763 localIndent = ''
764 formattedCondition = condition.format(prefix)
765 checkedExpr.append(localIndent + 'if ({})\n'.format(formattedCondition))
766 checkedExpr.append(localIndent + '{\n')
767 localIndent = self.incIndent(localIndent)
768 for expr in exprs:
769 checkedExpr.append(localIndent + expr)
770 localIndent = self.decIndent(localIndent)
771 checkedExpr.append(localIndent + '}\n')
772 return [checkedExpr]
773 #
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600774 # Get VUID identifier from implicit VUID tag
775 def GetVuid(self, vuid_string):
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600776 if '->' in vuid_string:
777 return "VALIDATION_ERROR_UNDEFINED"
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600778 vuid_num = self.IdToHex(convertVUID(vuid_string))
779 if vuid_num in self.valid_vuids:
780 vuid = "VALIDATION_ERROR_%s" % vuid_num
781 else:
782 vuid = "VALIDATION_ERROR_UNDEFINED"
783 return vuid
784 #
Mark Lobodzinski85672672016-10-13 08:36:42 -0600785 # Generate the sType check string
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600786 def makeStructTypeCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec, struct_type_name):
Mark Lobodzinski85672672016-10-13 08:36:42 -0600787 checkExpr = []
788 stype = self.structTypes[value.type]
789 if lenValue:
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600790 vuid_name = struct_type_name if struct_type_name is not None else funcPrintName
791 vuid = self.GetVuid("VUID-%s-%s-parameter" % (vuid_name, value.name))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600792 # This is an array with a pointer to a count value
793 if lenValue.ispointer:
794 # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600795 checkExpr.append('skip |= validate_struct_type_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {});\n'.format(
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600796 funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600797 # This is an array with an integer count value
798 else:
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600799 checkExpr.append('skip |= validate_struct_type_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {});\n'.format(
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600800 funcPrintName, lenValueRequired, valueRequired, vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600801 # This is an individual struct
802 else:
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600803 vuid = self.GetVuid("VUID-%s-sType-sType" % value.type)
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600804 checkExpr.append('skip |= validate_struct_type(local_data->report_data, "{}", {ppp}"{}"{pps}, "{sv}", {}{vn}, {sv}, {}, {});\n'.format(
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600805 funcPrintName, valuePrintName, prefix, valueRequired, vuid, vn=value.name, sv=stype.value, vt=value.type, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600806 return checkExpr
807 #
808 # Generate the handle check string
809 def makeHandleCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec):
810 checkExpr = []
811 if lenValue:
812 if lenValue.ispointer:
813 # This is assumed to be an output array with a pointer to a count value
814 raise('Unsupported parameter validation case: Output handle array elements are not NULL checked')
815 else:
816 # This is an array with an integer count value
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600817 checkExpr.append('skip |= validate_handle_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
Mark Lobodzinski85672672016-10-13 08:36:42 -0600818 funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
819 else:
820 # This is assumed to be an output handle pointer
821 raise('Unsupported parameter validation case: Output handles are not NULL checked')
822 return checkExpr
823 #
824 # Generate check string for an array of VkFlags values
825 def makeFlagsArrayCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec):
826 checkExpr = []
827 flagBitsName = value.type.replace('Flags', 'FlagBits')
828 if not flagBitsName in self.flagBits:
829 raise('Unsupported parameter validation case: array of reserved VkFlags')
830 else:
831 allFlags = 'All' + flagBitsName
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600832 checkExpr.append('skip |= validate_flags_array(local_data->report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcPrintName, lenPrintName, valuePrintName, flagBitsName, allFlags, lenValue.name, value.name, lenValueRequired, valueRequired, pf=prefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600833 return checkExpr
834 #
835 # Generate pNext check string
Mark Lobodzinski3c828522017-06-26 13:05:57 -0600836 def makeStructNextCheck(self, prefix, value, funcPrintName, valuePrintName, postProcSpec, struct_type_name):
Mark Lobodzinski85672672016-10-13 08:36:42 -0600837 checkExpr = []
838 # Generate an array of acceptable VkStructureType values for pNext
839 extStructCount = 0
840 extStructVar = 'NULL'
841 extStructNames = 'NULL'
Mark Lobodzinski3c828522017-06-26 13:05:57 -0600842 vuid = self.GetVuid("VUID-%s-pNext-pNext" % struct_type_name)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600843 if value.extstructs:
Mike Schuchardtc73d07e2017-07-12 10:10:01 -0600844 extStructVar = 'allowed_structs_{}'.format(struct_type_name)
845 extStructCount = 'ARRAY_SIZE({})'.format(extStructVar)
Mike Schuchardta40d0b02017-07-23 12:47:47 -0600846 extStructNames = '"' + ', '.join(value.extstructs) + '"'
847 checkExpr.append('const VkStructureType {}[] = {{ {} }};\n'.format(extStructVar, ', '.join([self.getStructType(s) for s in value.extstructs])))
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600848 checkExpr.append('skip |= validate_struct_pnext(local_data->report_data, "{}", {ppp}"{}"{pps}, {}, {}{}, {}, {}, GeneratedHeaderVersion, {});\n'.format(
Mark Lobodzinski3c828522017-06-26 13:05:57 -0600849 funcPrintName, valuePrintName, extStructNames, prefix, value.name, extStructCount, extStructVar, vuid, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600850 return checkExpr
851 #
852 # Generate the pointer check string
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600853 def makePointerCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec, struct_type_name):
Mark Lobodzinski85672672016-10-13 08:36:42 -0600854 checkExpr = []
Mark Lobodzinskidead0b62017-06-28 13:22:03 -0600855 vuid_tag_name = struct_type_name if struct_type_name is not None else funcPrintName
Mark Lobodzinski85672672016-10-13 08:36:42 -0600856 if lenValue:
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600857 count_required_vuid = self.GetVuid("VUID-%s-%s-arraylength" % (vuid_tag_name, lenValue.name))
858 array_required_vuid = self.GetVuid("VUID-%s-%s-parameter" % (vuid_tag_name, value.name))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600859 # This is an array with a pointer to a count value
860 if lenValue.ispointer:
861 # If count and array parameters are optional, there will be no validation
862 if valueRequired == 'true' or lenPtrRequired == 'true' or lenValueRequired == 'true':
863 # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600864 checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {}, {});\n'.format(
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600865 funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600866 # This is an array with an integer count value
867 else:
868 # If count and array parameters are optional, there will be no validation
869 if valueRequired == 'true' or lenValueRequired == 'true':
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600870 if value.type != 'char':
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600871 checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format(
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600872 funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
873 else:
874 # Arrays of strings receive special processing
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600875 checkExpr.append('skip |= validate_string_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format(
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600876 funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600877 if checkExpr:
878 if lenValue and ('->' in lenValue.name):
879 # Add checks to ensure the validation call does not dereference a NULL pointer to obtain the count
880 checkExpr = self.genCheckedLengthCall(lenValue.name, checkExpr)
881 # This is an individual struct that is not allowed to be NULL
882 elif not value.isoptional:
883 # Function pointers need a reinterpret_cast to void*
Mark Lobodzinskidead0b62017-06-28 13:22:03 -0600884 ptr_required_vuid = self.GetVuid("VUID-%s-%s-parameter" % (vuid_tag_name, value.name))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600885 if value.type[:4] == 'PFN_':
Mark Lobodzinski02fa1972017-06-28 14:46:14 -0600886 allocator_dict = {'pfnAllocation': '002004f0',
887 'pfnReallocation': '002004f2',
888 'pfnFree': '002004f4',
889 'pfnInternalAllocation': '002004f6'
890 }
891 vuid = allocator_dict.get(value.name)
892 if vuid is not None:
893 ptr_required_vuid = 'VALIDATION_ERROR_%s' % vuid
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600894 checkExpr.append('skip |= validate_required_pointer(local_data->report_data, "{}", {ppp}"{}"{pps}, reinterpret_cast<const void*>({}{}), {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600895 else:
Mark Lobodzinskid4950072017-08-01 13:02:20 -0600896 checkExpr.append('skip |= validate_required_pointer(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{}, {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600897 return checkExpr
898 #
899 # Process struct member validation code, performing name suibstitution if required
900 def processStructMemberCode(self, line, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec):
901 # Build format specifier list
902 kwargs = {}
903 if '{postProcPrefix}' in line:
904 # If we have a tuple that includes a format string and format parameters, need to use ParameterName class
905 if type(memberDisplayNamePrefix) is tuple:
906 kwargs['postProcPrefix'] = 'ParameterName('
907 else:
908 kwargs['postProcPrefix'] = postProcSpec['ppp']
909 if '{postProcSuffix}' in line:
910 # If we have a tuple that includes a format string and format parameters, need to use ParameterName class
911 if type(memberDisplayNamePrefix) is tuple:
912 kwargs['postProcSuffix'] = ', ParameterName::IndexVector{{ {}{} }})'.format(postProcSpec['ppi'], memberDisplayNamePrefix[1])
913 else:
914 kwargs['postProcSuffix'] = postProcSpec['pps']
915 if '{postProcInsert}' in line:
916 # If we have a tuple that includes a format string and format parameters, need to use ParameterName class
917 if type(memberDisplayNamePrefix) is tuple:
918 kwargs['postProcInsert'] = '{}{}, '.format(postProcSpec['ppi'], memberDisplayNamePrefix[1])
919 else:
920 kwargs['postProcInsert'] = postProcSpec['ppi']
921 if '{funcName}' in line:
922 kwargs['funcName'] = funcName
923 if '{valuePrefix}' in line:
924 kwargs['valuePrefix'] = memberNamePrefix
925 if '{displayNamePrefix}' in line:
926 # Check for a tuple that includes a format string and format parameters to be used with the ParameterName class
927 if type(memberDisplayNamePrefix) is tuple:
928 kwargs['displayNamePrefix'] = memberDisplayNamePrefix[0]
929 else:
930 kwargs['displayNamePrefix'] = memberDisplayNamePrefix
931
932 if kwargs:
933 # Need to escape the C++ curly braces
934 if 'IndexVector' in line:
935 line = line.replace('IndexVector{ ', 'IndexVector{{ ')
936 line = line.replace(' }),', ' }}),')
937 return line.format(**kwargs)
938 return line
939 #
940 # Process struct validation code for inclusion in function or parent struct validation code
941 def expandStructCode(self, lines, funcName, memberNamePrefix, memberDisplayNamePrefix, indent, output, postProcSpec):
942 for line in lines:
943 if output:
944 output[-1] += '\n'
945 if type(line) is list:
946 for sub in line:
947 output.append(self.processStructMemberCode(indent + sub, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec))
948 else:
949 output.append(self.processStructMemberCode(indent + line, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec))
950 return output
951 #
952 # Process struct pointer/array validation code, perfoeming name substitution if required
953 def expandStructPointerCode(self, prefix, value, lenValue, funcName, valueDisplayName, postProcSpec):
954 expr = []
955 expr.append('if ({}{} != NULL)\n'.format(prefix, value.name))
956 expr.append('{')
957 indent = self.incIndent(None)
958 if lenValue:
959 # Need to process all elements in the array
960 indexName = lenValue.name.replace('Count', 'Index')
961 expr[-1] += '\n'
Mark Young39389872017-01-19 21:10:49 -0700962 if lenValue.ispointer:
963 # If the length value is a pointer, de-reference it for the count.
964 expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < *{}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName))
965 else:
966 expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < {}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600967 expr.append(indent + '{')
968 indent = self.incIndent(indent)
969 # Prefix for value name to display in error message
Mark Lobodzinski6f82eb52016-12-05 07:38:41 -0700970 if value.ispointer == 2:
971 memberNamePrefix = '{}{}[{}]->'.format(prefix, value.name, indexName)
972 memberDisplayNamePrefix = ('{}[%i]->'.format(valueDisplayName), indexName)
973 else:
974 memberNamePrefix = '{}{}[{}].'.format(prefix, value.name, indexName)
975 memberDisplayNamePrefix = ('{}[%i].'.format(valueDisplayName), indexName)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600976 else:
977 memberNamePrefix = '{}{}->'.format(prefix, value.name)
978 memberDisplayNamePrefix = '{}->'.format(valueDisplayName)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600979 # Expand the struct validation lines
980 expr = self.expandStructCode(self.validatedStructs[value.type], funcName, memberNamePrefix, memberDisplayNamePrefix, indent, expr, postProcSpec)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600981 if lenValue:
982 # Close if and for scopes
983 indent = self.decIndent(indent)
984 expr.append(indent + '}\n')
985 expr.append('}\n')
986 return expr
987 #
988 # Generate the parameter checking code
989 def genFuncBody(self, funcName, values, valuePrefix, displayNamePrefix, structTypeName):
990 lines = [] # Generated lines of code
991 unused = [] # Unused variable names
992 for value in values:
993 usedLines = []
994 lenParam = None
995 #
996 # Prefix and suffix for post processing of parameter names for struct members. Arrays of structures need special processing to include the array index in the full parameter name.
997 postProcSpec = {}
998 postProcSpec['ppp'] = '' if not structTypeName else '{postProcPrefix}'
999 postProcSpec['pps'] = '' if not structTypeName else '{postProcSuffix}'
1000 postProcSpec['ppi'] = '' if not structTypeName else '{postProcInsert}'
1001 #
1002 # Generate the full name of the value, which will be printed in the error message, by adding the variable prefix to the value name
1003 valueDisplayName = '{}{}'.format(displayNamePrefix, value.name)
1004 #
1005 # Check for NULL pointers, ignore the inout count parameters that
1006 # will be validated with their associated array
1007 if (value.ispointer or value.isstaticarray) and not value.iscount:
Mark Lobodzinski85672672016-10-13 08:36:42 -06001008 # Parameters for function argument generation
1009 req = 'true' # Paramerter cannot be NULL
1010 cpReq = 'true' # Count pointer cannot be NULL
1011 cvReq = 'true' # Count value cannot be 0
1012 lenDisplayName = None # Name of length parameter to print with validation messages; parameter name with prefix applied
Mark Lobodzinski85672672016-10-13 08:36:42 -06001013 # Generate required/optional parameter strings for the pointer and count values
1014 if value.isoptional:
1015 req = 'false'
1016 if value.len:
1017 # The parameter is an array with an explicit count parameter
1018 lenParam = self.getLenParam(values, value.len)
1019 lenDisplayName = '{}{}'.format(displayNamePrefix, lenParam.name)
1020 if lenParam.ispointer:
1021 # Count parameters that are pointers are inout
1022 if type(lenParam.isoptional) is list:
1023 if lenParam.isoptional[0]:
1024 cpReq = 'false'
1025 if lenParam.isoptional[1]:
1026 cvReq = 'false'
1027 else:
1028 if lenParam.isoptional:
1029 cpReq = 'false'
1030 else:
1031 if lenParam.isoptional:
1032 cvReq = 'false'
1033 #
1034 # The parameter will not be processes when tagged as 'noautovalidity'
1035 # For the pointer to struct case, the struct pointer will not be validated, but any
1036 # members not tagged as 'noatuvalidity' will be validated
1037 if value.noautovalidity:
1038 # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually
1039 self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name))
1040 else:
Mark Lobodzinski85672672016-10-13 08:36:42 -06001041 # If this is a pointer to a struct with an sType field, verify the type
1042 if value.type in self.structTypes:
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -06001043 usedLines += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName, postProcSpec, structTypeName)
Mark Lobodzinski85672672016-10-13 08:36:42 -06001044 # If this is an input handle array that is not allowed to contain NULL handles, verify that none of the handles are VK_NULL_HANDLE
1045 elif value.type in self.handleTypes and value.isconst and not self.isHandleOptional(value, lenParam):
1046 usedLines += self.makeHandleCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
1047 elif value.type in self.flags and value.isconst:
1048 usedLines += self.makeFlagsArrayCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
1049 elif value.isbool and value.isconst:
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001050 usedLines.append('skip |= validate_bool32_array(local_data->report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001051 elif value.israngedenum and value.isconst:
Mark Lobodzinskiaff801e2017-07-25 15:29:57 -06001052 enum_value_list = 'All%sEnums' % value.type
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001053 usedLines.append('skip |= validate_ranged_enum_array(local_data->report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, value.type, enum_value_list, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001054 elif value.name == 'pNext':
1055 # We need to ignore VkDeviceCreateInfo and VkInstanceCreateInfo, as the loader manipulates them in a way that is not documented in vk.xml
1056 if not structTypeName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']:
Mark Lobodzinski3c828522017-06-26 13:05:57 -06001057 usedLines += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName, postProcSpec, structTypeName)
Mark Lobodzinski85672672016-10-13 08:36:42 -06001058 else:
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -06001059 usedLines += self.makePointerCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName, postProcSpec, structTypeName)
Mark Lobodzinski85672672016-10-13 08:36:42 -06001060 # If this is a pointer to a struct (input), see if it contains members that need to be checked
1061 if value.type in self.validatedStructs and value.isconst:
1062 usedLines.append(self.expandStructPointerCode(valuePrefix, value, lenParam, funcName, valueDisplayName, postProcSpec))
1063 # Non-pointer types
1064 else:
Mark Lobodzinski85672672016-10-13 08:36:42 -06001065 # The parameter will not be processes when tagged as 'noautovalidity'
1066 # For the struct case, the struct type will not be validated, but any
1067 # members not tagged as 'noatuvalidity' will be validated
1068 if value.noautovalidity:
1069 # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually
1070 self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name))
1071 else:
Mark Lobodzinski024b2822017-06-27 13:22:05 -06001072 vuid_name_tag = structTypeName if structTypeName is not None else funcName
Mark Lobodzinski85672672016-10-13 08:36:42 -06001073 if value.type in self.structTypes:
1074 stype = self.structTypes[value.type]
Mark Lobodzinski06954ea2017-06-21 12:21:45 -06001075 vuid = self.GetVuid("VUID-%s-sType-sType" % value.type)
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001076 usedLines.append('skip |= validate_struct_type(local_data->report_data, "{}", {ppp}"{}"{pps}, "{sv}", &({}{vn}), {sv}, false, {});\n'.format(
Mark Lobodzinski06954ea2017-06-21 12:21:45 -06001077 funcName, valueDisplayName, valuePrefix, vuid, vn=value.name, sv=stype.value, vt=value.type, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001078 elif value.type in self.handleTypes:
1079 if not self.isHandleOptional(value, None):
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001080 usedLines.append('skip |= validate_required_handle(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001081 elif value.type in self.flags:
1082 flagBitsName = value.type.replace('Flags', 'FlagBits')
1083 if not flagBitsName in self.flagBits:
Mark Lobodzinskid0b0c512017-06-28 12:06:41 -06001084 vuid = self.GetVuid("VUID-%s-%s-zerobitmask" % (vuid_name_tag, value.name))
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001085 usedLines.append('skip |= validate_reserved_flags(local_data->report_data, "{}", {ppp}"{}"{pps}, {pf}{}, {});\n'.format(funcName, valueDisplayName, value.name, vuid, pf=valuePrefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001086 else:
Mark Lobodzinskie643fcc2017-06-26 16:27:15 -06001087 if value.isoptional:
1088 flagsRequired = 'false'
Mark Lobodzinski024b2822017-06-27 13:22:05 -06001089 vuid = self.GetVuid("VUID-%s-%s-parameter" % (vuid_name_tag, value.name))
Mark Lobodzinskie643fcc2017-06-26 16:27:15 -06001090 else:
1091 flagsRequired = 'true'
Mark Lobodzinskie643fcc2017-06-26 16:27:15 -06001092 vuid = self.GetVuid("VUID-%s-%s-requiredbitmask" % (vuid_name_tag, value.name))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001093 allFlagsName = 'All' + flagBitsName
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001094 usedLines.append('skip |= validate_flags(local_data->report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, false, {});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
Mike Schuchardt47619c82017-05-31 09:14:22 -06001095 elif value.type in self.flagBits:
1096 flagsRequired = 'false' if value.isoptional else 'true'
1097 allFlagsName = 'All' + value.type
Mark Lobodzinski024b2822017-06-27 13:22:05 -06001098 vuid = self.GetVuid("VUID-%s-%s-parameter" % (vuid_name_tag, value.name))
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001099 usedLines.append('skip |= validate_flags(local_data->report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, true, {});\n'.format(funcName, valueDisplayName, value.type, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001100 elif value.isbool:
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001101 usedLines.append('skip |= validate_bool32(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001102 elif value.israngedenum:
Mark Lobodzinski42eb3c32017-06-28 11:47:22 -06001103 vuid = self.GetVuid("VUID-%s-%s-parameter" % (vuid_name_tag, value.name))
Mark Lobodzinski74cb45f2017-07-25 15:10:29 -06001104 enum_value_list = 'All%sEnums' % value.type
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001105 usedLines.append('skip |= validate_ranged_enum(local_data->report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {}{}, {});\n'.format(funcName, valueDisplayName, value.type, enum_value_list, valuePrefix, value.name, vuid, **postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001106 # If this is a struct, see if it contains members that need to be checked
1107 if value.type in self.validatedStructs:
1108 memberNamePrefix = '{}{}.'.format(valuePrefix, value.name)
1109 memberDisplayNamePrefix = '{}.'.format(valueDisplayName)
1110 usedLines.append(self.expandStructCode(self.validatedStructs[value.type], funcName, memberNamePrefix, memberDisplayNamePrefix, '', [], postProcSpec))
Mark Lobodzinski85672672016-10-13 08:36:42 -06001111 # Append the parameter check to the function body for the current command
1112 if usedLines:
1113 # Apply special conditional checks
1114 if value.condition:
1115 usedLines = self.genConditionalCall(valuePrefix, value.condition, usedLines)
1116 lines += usedLines
1117 elif not value.iscount:
1118 # If no expression was generated for this value, it is unreferenced by the validation function, unless
1119 # it is an array count, which is indirectly referenced for array valiadation.
1120 unused.append(value.name)
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001121 if not lines:
1122 lines.append('// No xml-driven validation\n')
Mark Lobodzinski85672672016-10-13 08:36:42 -06001123 return lines, unused
1124 #
1125 # Generate the struct member check code from the captured data
1126 def processStructMemberData(self):
1127 indent = self.incIndent(None)
1128 for struct in self.structMembers:
1129 #
1130 # The string returned by genFuncBody will be nested in an if check for a NULL pointer, so needs its indent incremented
1131 lines, unused = self.genFuncBody('{funcName}', struct.members, '{valuePrefix}', '{displayNamePrefix}', struct.name)
1132 if lines:
1133 self.validatedStructs[struct.name] = lines
1134 #
1135 # Generate the command param check code from the captured data
1136 def processCmdData(self):
1137 indent = self.incIndent(None)
1138 for command in self.commands:
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001139 just_validate = False
1140 if command.name in self.validate_only:
1141 just_validate = True
Mark Lobodzinski85672672016-10-13 08:36:42 -06001142 # Skip first parameter if it is a dispatch handle (everything except vkCreateInstance)
1143 startIndex = 0 if command.name == 'vkCreateInstance' else 1
1144 lines, unused = self.genFuncBody(command.name, command.params[startIndex:], '', '', None)
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -06001145 # Cannot validate extension dependencies for device extension APIs a physical device as their dispatchable object
1146 if self.required_extensions and self.extension_type == 'device' and command.params[0].type != 'VkPhysicalDevice':
1147 # The actual extension names are not all available yet, so we'll tag these now and replace them just before
1148 # writing the validation routines out to a file
1149 ext_test = ''
Mark Lobodzinski26112592017-05-30 12:02:17 -06001150 for ext in self.required_extensions:
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -06001151 ext_name_define = ''
1152 ext_enable_name = ''
1153 for extension in self.registry.extensions:
1154 if extension.attrib['name'] == ext:
1155 ext_name_define = extension[0][1].get('name')
1156 ext_enable_name = ext_name_define.lower()
1157 ext_enable_name = re.sub('_extension_name', '', ext_enable_name)
1158 break
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001159 ext_test = 'if (!local_data->extensions.%s) skip |= OutputExtensionError(local_data, "%s", %s);\n' % (ext_enable_name, command.name, ext_name_define)
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -06001160 lines.insert(0, ext_test)
Mark Lobodzinski85672672016-10-13 08:36:42 -06001161 if lines:
1162 cmdDef = self.getCmdDef(command) + '\n'
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001163 # For a validation-only routine, change the function declaration
1164 if just_validate:
1165 jv_def = '// Generated function handles validation only -- API definition is in non-generated source\n'
1166 jv_def += 'extern %s\n\n' % command.cdecl
1167 cmdDef = 'bool parameter_validation_' + cmdDef.split('VKAPI_CALL ',1)[1]
1168 if command.name == 'vkCreateInstance':
1169 cmdDef = cmdDef.replace('(\n', '(\n VkInstance instance,\n')
1170 cmdDef = jv_def + cmdDef
Mark Lobodzinski85672672016-10-13 08:36:42 -06001171 cmdDef += '{\n'
Mark Lobodzinski26112592017-05-30 12:02:17 -06001172
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001173 # Add list of commands to skip -- just generate the routine signature and put the manual source in PV_utils.cpp
1174 if command.params[0].type in ["VkInstance", "VkPhysicalDevice"] or command.name == 'VkCreateInstance':
1175 map_name = 'instance_layer_data_map'
1176 map_type = 'instance_layer_data'
1177 else:
1178 map_name = 'layer_data_map'
1179 map_type = 'layer_data'
1180 instance_param = command.params[0].name
1181 if command.name == 'vkCreateInstance':
1182 instance_param = 'instance'
1183 layer_data = ' %s *local_data = GetLayerDataPtr(get_dispatch_key(%s), %s);\n' % (map_type, instance_param, map_name)
1184 cmdDef += layer_data
1185 cmdDef += '%sbool skip = false;\n' % indent
1186 if not just_validate:
1187 if command.result != '':
1188 cmdDef += indent + '%s result = VK_ERROR_VALIDATION_FAILED_EXT;\n' % command.result
1189 cmdDef += '%sstd::unique_lock<std::mutex> lock(global_lock);\n' % indent
Mark Lobodzinski85672672016-10-13 08:36:42 -06001190 for line in lines:
1191 cmdDef += '\n'
1192 if type(line) is list:
1193 for sub in line:
1194 cmdDef += indent + sub
1195 else:
1196 cmdDef += indent + line
1197 cmdDef += '\n'
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001198 if not just_validate:
1199 # Generate parameter list for manual fcn and down-chain calls
1200 params_text = ''
1201 for param in command.params:
1202 params_text += '%s, ' % param.name
1203 params_text = params_text[:-2]
1204 # Generate call to manual function if its function pointer is non-null
Mark Lobodzinski78a12a92017-08-08 14:16:51 -06001205 cmdDef += '%sPFN_manual_%s custom_func = (PFN_manual_%s)custom_functions["%s"];\n' % (indent, command.name, command.name, command.name)
1206 cmdDef += '%sif (custom_func != nullptr) {\n' % indent
1207 cmdDef += ' %sskip |= custom_func(%s);\n' % (indent, params_text)
Mark Lobodzinskid4950072017-08-01 13:02:20 -06001208 cmdDef += '%s}\n\n' % indent
1209 # Release the validation lock
1210 cmdDef += '%slock.unlock();\n' % indent
1211 # Generate skip check and down-chain call
1212 cmdDef += '%sif (!skip) {\n' % indent
1213 down_chain_call = ' %s' % indent
1214 if command.result != '':
1215 down_chain_call += ' result = '
1216 # Generate down-chain API call
1217 api_call = '%s(%s);' % (command.name, params_text)
1218 down_chain_call += 'local_data->dispatch_table.%s\n' % api_call[2:]
1219 cmdDef += down_chain_call
1220 cmdDef += '%s}\n' % indent
1221 if command.result != '':
1222 cmdDef += '%sreturn result;\n' % indent
1223 else:
1224 cmdDef += '%sreturn skip;\n' % indent
Mark Lobodzinski85672672016-10-13 08:36:42 -06001225 cmdDef += '}\n'
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -06001226 self.validation.append(cmdDef)