blob: 1d0dec8141de51363d57a94c99260bda8cf53f9f [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>
21
22import os,re,sys
23import xml.etree.ElementTree as etree
24from generator import *
25from collections import namedtuple
26
27
28# ParamCheckerGeneratorOptions - subclass of GeneratorOptions.
29#
30# Adds options used by ParamCheckerOutputGenerator object during Parameter
31# validation layer generation.
32#
33# Additional members
34# prefixText - list of strings to prefix generated header with
35# (usually a copyright statement + calling convention macros).
36# protectFile - True if multiple inclusion protection should be
37# generated (based on the filename) around the entire header.
38# protectFeature - True if #ifndef..#endif protection should be
39# generated around a feature interface in the header file.
40# genFuncPointers - True if function pointer typedefs should be
41# generated
42# protectProto - If conditional protection should be generated
43# around prototype declarations, set to either '#ifdef'
44# to require opt-in (#ifdef protectProtoStr) or '#ifndef'
45# to require opt-out (#ifndef protectProtoStr). Otherwise
46# set to None.
47# protectProtoStr - #ifdef/#ifndef symbol to use around prototype
48# declarations, if protectProto is set
49# apicall - string to use for the function declaration prefix,
50# such as APICALL on Windows.
51# apientry - string to use for the calling convention macro,
52# in typedefs, such as APIENTRY.
53# apientryp - string to use for the calling convention macro
54# in function pointer typedefs, such as APIENTRYP.
55# indentFuncProto - True if prototype declarations should put each
56# parameter on a separate line
57# indentFuncPointer - True if typedefed function pointers should put each
58# parameter on a separate line
59# alignFuncParam - if nonzero and parameters are being put on a
60# separate line, align parameter names at the specified column
61class ParamCheckerGeneratorOptions(GeneratorOptions):
62 def __init__(self,
63 filename = None,
64 directory = '.',
65 apiname = None,
66 profile = None,
67 versions = '.*',
68 emitversions = '.*',
69 defaultExtensions = None,
70 addExtensions = None,
71 removeExtensions = None,
72 sortProcedure = regSortFeatures,
73 prefixText = "",
74 genFuncPointers = True,
75 protectFile = True,
76 protectFeature = True,
77 protectProto = None,
78 protectProtoStr = None,
79 apicall = '',
80 apientry = '',
81 apientryp = '',
82 indentFuncProto = True,
83 indentFuncPointer = False,
84 alignFuncParam = 0):
85 GeneratorOptions.__init__(self, filename, directory, apiname, profile,
86 versions, emitversions, defaultExtensions,
87 addExtensions, removeExtensions, sortProcedure)
88 self.prefixText = prefixText
89 self.genFuncPointers = genFuncPointers
90 self.protectFile = protectFile
91 self.protectFeature = protectFeature
92 self.protectProto = protectProto
93 self.protectProtoStr = protectProtoStr
94 self.apicall = apicall
95 self.apientry = apientry
96 self.apientryp = apientryp
97 self.indentFuncProto = indentFuncProto
98 self.indentFuncPointer = indentFuncPointer
99 self.alignFuncParam = alignFuncParam
100
101# ParamCheckerOutputGenerator - subclass of OutputGenerator.
102# Generates param checker layer code.
103#
104# ---- methods ----
105# ParamCheckerOutputGenerator(errFile, warnFile, diagFile) - args as for
106# OutputGenerator. Defines additional internal state.
107# ---- methods overriding base class ----
108# beginFile(genOpts)
109# endFile()
110# beginFeature(interface, emit)
111# endFeature()
112# genType(typeinfo,name)
113# genStruct(typeinfo,name)
114# genGroup(groupinfo,name)
115# genEnum(enuminfo, name)
116# genCmd(cmdinfo)
117class ParamCheckerOutputGenerator(OutputGenerator):
118 """Generate ParamChecker code based on XML element attributes"""
119 # This is an ordered list of sections in the header file.
120 ALL_SECTIONS = ['command']
121 def __init__(self,
122 errFile = sys.stderr,
123 warnFile = sys.stderr,
124 diagFile = sys.stdout):
125 OutputGenerator.__init__(self, errFile, warnFile, diagFile)
126 self.INDENT_SPACES = 4
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700127 self.intercepts = []
128 self.declarations = []
Mark Lobodzinski85672672016-10-13 08:36:42 -0600129 # Commands to ignore
130 self.blacklist = [
131 'vkGetInstanceProcAddr',
132 'vkGetDeviceProcAddr',
133 'vkEnumerateInstanceLayerProperties',
134 'vkEnumerateInstanceExtensionsProperties',
135 'vkEnumerateDeviceLayerProperties',
136 'vkEnumerateDeviceExtensionsProperties',
137 'vkCreateDebugReportCallbackEXT',
138 'vkDebugReportMessageEXT']
139 # Validation conditions for some special case struct members that are conditionally validated
140 self.structMemberValidationConditions = { 'VkPipelineColorBlendStateCreateInfo' : { 'logicOp' : '{}logicOpEnable == VK_TRUE' } }
141 # Header version
142 self.headerVersion = None
143 # Internal state - accumulators for different inner block text
144 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
145 self.structNames = [] # List of Vulkan struct typenames
146 self.stypes = [] # Values from the VkStructureType enumeration
147 self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType
148 self.handleTypes = set() # Set of handle type names
149 self.commands = [] # List of CommandData records for all Vulkan commands
150 self.structMembers = [] # List of StructMemberData records for all Vulkan structs
151 self.validatedStructs = dict() # Map of structs type names to generated validation code for that struct type
152 self.enumRanges = dict() # Map of enum name to BEGIN/END range values
153 self.flags = set() # Map of flags typenames
154 self.flagBits = dict() # Map of flag bits typename to list of values
Chris Forbes78ea32d2016-11-28 11:14:17 +1300155 self.newFlags = set() # Map of flags typenames /defined in the current feature/
Mark Lobodzinski85672672016-10-13 08:36:42 -0600156 # Named tuples to store struct and command data
157 self.StructType = namedtuple('StructType', ['name', 'value'])
158 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isbool', 'israngedenum',
159 'isconst', 'isoptional', 'iscount', 'noautovalidity', 'len', 'extstructs',
160 'condition', 'cdecl'])
161 self.CommandData = namedtuple('CommandData', ['name', 'params', 'cdecl'])
162 self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
163 #
164 def incIndent(self, indent):
165 inc = ' ' * self.INDENT_SPACES
166 if indent:
167 return indent + inc
168 return inc
169 #
170 def decIndent(self, indent):
171 if indent and (len(indent) > self.INDENT_SPACES):
172 return indent[:-self.INDENT_SPACES]
173 return ''
174 #
175 def beginFile(self, genOpts):
176 OutputGenerator.beginFile(self, genOpts)
177 # C-specific
178 #
179 # User-supplied prefix text, if any (list of strings)
180 if (genOpts.prefixText):
181 for s in genOpts.prefixText:
182 write(s, file=self.outFile)
183 #
184 # Multiple inclusion protection & C++ wrappers.
185 if (genOpts.protectFile and self.genOpts.filename):
186 headerSym = re.sub('\.h', '_H', os.path.basename(self.genOpts.filename)).upper()
187 write('#ifndef', headerSym, file=self.outFile)
188 write('#define', headerSym, '1', file=self.outFile)
189 self.newline()
190 #
191 # Headers
192 write('#include <string>', file=self.outFile)
193 self.newline()
194 write('#include "vulkan/vulkan.h"', file=self.outFile)
195 write('#include "vk_layer_extension_utils.h"', file=self.outFile)
196 write('#include "parameter_validation_utils.h"', file=self.outFile)
197 #
198 # Macros
199 self.newline()
200 write('#ifndef UNUSED_PARAMETER', file=self.outFile)
201 write('#define UNUSED_PARAMETER(x) (void)(x)', file=self.outFile)
202 write('#endif // UNUSED_PARAMETER', file=self.outFile)
203 #
204 # Namespace
205 self.newline()
206 write('namespace parameter_validation {', file = self.outFile)
207 def endFile(self):
208 # C-specific
209 self.newline()
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700210
211 # Output declarations and record intercepted procedures
212 write('// Declarations', file=self.outFile)
213 write('\n'.join(self.declarations), file=self.outFile)
214 write('// Intercepts', file=self.outFile)
215 write('struct { const char* name; PFN_vkVoidFunction pFunc;} procmap[] = {', file=self.outFile)
216 write('\n'.join(self.intercepts), file=self.outFile)
217 write('};\n', file=self.outFile)
218 self.newline()
Mark Lobodzinski85672672016-10-13 08:36:42 -0600219 # Namespace
220 write('} // namespace parameter_validation', file = self.outFile)
221 # Finish C++ wrapper and multiple inclusion protection
222 if (self.genOpts.protectFile and self.genOpts.filename):
223 self.newline()
224 write('#endif', file=self.outFile)
225 # Finish processing in superclass
226 OutputGenerator.endFile(self)
227 def beginFeature(self, interface, emit):
228 # Start processing in superclass
229 OutputGenerator.beginFeature(self, interface, emit)
230 # C-specific
231 # Accumulate includes, defines, types, enums, function pointer typedefs,
232 # end function prototypes separately for this feature. They're only
233 # printed in endFeature().
234 self.headerVersion = None
235 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
236 self.structNames = []
237 self.stypes = []
238 self.structTypes = dict()
Mark Lobodzinski85672672016-10-13 08:36:42 -0600239 self.commands = []
240 self.structMembers = []
Chris Forbes78ea32d2016-11-28 11:14:17 +1300241 self.newFlags = set()
Mark Lobodzinski85672672016-10-13 08:36:42 -0600242 def endFeature(self):
243 # C-specific
244 # Actually write the interface to the output file.
245 if (self.emit):
246 self.newline()
247 # If type declarations are needed by other features based on
248 # this one, it may be necessary to suppress the ExtraProtect,
249 # or move it below the 'for section...' loop.
250 if (self.featureExtraProtect != None):
251 write('#ifdef', self.featureExtraProtect, file=self.outFile)
252 # Generate the struct member checking code from the captured data
253 self.processStructMemberData()
254 # Generate the command parameter checking code from the captured data
255 self.processCmdData()
256 # Write the declaration for the HeaderVersion
257 if self.headerVersion:
258 write('const uint32_t GeneratedHeaderVersion = {};'.format(self.headerVersion), file=self.outFile)
259 self.newline()
260 # Write the declarations for the VkFlags values combining all flag bits
Chris Forbes78ea32d2016-11-28 11:14:17 +1300261 for flag in sorted(self.newFlags):
Mark Lobodzinski85672672016-10-13 08:36:42 -0600262 flagBits = flag.replace('Flags', 'FlagBits')
263 if flagBits in self.flagBits:
264 bits = self.flagBits[flagBits]
265 decl = 'const {} All{} = {}'.format(flag, flagBits, bits[0])
266 for bit in bits[1:]:
267 decl += '|' + bit
268 decl += ';'
269 write(decl, file=self.outFile)
270 self.newline()
271 # Write the parameter validation code to the file
272 if (self.sections['command']):
273 if (self.genOpts.protectProto):
274 write(self.genOpts.protectProto,
275 self.genOpts.protectProtoStr, file=self.outFile)
Jamie Madill24aa9742016-12-13 17:02:57 -0500276 write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600277 if (self.featureExtraProtect != None):
278 write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile)
279 else:
280 self.newline()
281 # Finish processing in superclass
282 OutputGenerator.endFeature(self)
283 #
284 # Append a definition to the specified section
285 def appendSection(self, section, text):
286 # self.sections[section].append('SECTION: ' + section + '\n')
287 self.sections[section].append(text)
288 #
289 # Type generation
290 def genType(self, typeinfo, name):
291 OutputGenerator.genType(self, typeinfo, name)
292 typeElem = typeinfo.elem
293 # If the type is a struct type, traverse the imbedded <member> tags
294 # generating a structure. Otherwise, emit the tag text.
295 category = typeElem.get('category')
296 if (category == 'struct' or category == 'union'):
297 self.structNames.append(name)
298 self.genStruct(typeinfo, name)
299 elif (category == 'handle'):
300 self.handleTypes.add(name)
301 elif (category == 'bitmask'):
302 self.flags.add(name)
Chris Forbes78ea32d2016-11-28 11:14:17 +1300303 self.newFlags.add(name)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600304 elif (category == 'define'):
305 if name == 'VK_HEADER_VERSION':
306 nameElem = typeElem.find('name')
307 self.headerVersion = noneStr(nameElem.tail).strip()
308 #
309 # Struct parameter check generation.
310 # This is a special case of the <type> tag where the contents are
311 # interpreted as a set of <member> tags instead of freeform C
312 # C type declarations. The <member> tags are just like <param>
313 # tags - they are a declaration of a struct or union member.
314 # Only simple member declarations are supported (no nested
315 # structs etc.)
316 def genStruct(self, typeinfo, typeName):
317 OutputGenerator.genStruct(self, typeinfo, typeName)
318 conditions = self.structMemberValidationConditions[typeName] if typeName in self.structMemberValidationConditions else None
319 members = typeinfo.elem.findall('.//member')
320 #
321 # Iterate over members once to get length parameters for arrays
322 lens = set()
323 for member in members:
324 len = self.getLen(member)
325 if len:
326 lens.add(len)
327 #
328 # Generate member info
329 membersInfo = []
330 for member in members:
331 # Get the member's type and name
332 info = self.getTypeNameTuple(member)
333 type = info[0]
334 name = info[1]
335 stypeValue = ''
336 cdecl = self.makeCParamDecl(member, 0)
337 # Process VkStructureType
338 if type == 'VkStructureType':
339 # Extract the required struct type value from the comments
340 # embedded in the original text defining the 'typeinfo' element
341 rawXml = etree.tostring(typeinfo.elem).decode('ascii')
342 result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml)
343 if result:
344 value = result.group(0)
345 else:
346 value = self.genVkStructureType(typeName)
347 # Store the required type value
348 self.structTypes[typeName] = self.StructType(name=name, value=value)
349 #
350 # Store pointer/array/string info
351 # Check for parameter name in lens set
352 iscount = False
353 if name in lens:
354 iscount = True
355 # The pNext members are not tagged as optional, but are treated as
356 # optional for parameter NULL checks. Static array members
357 # are also treated as optional to skip NULL pointer validation, as
358 # they won't be NULL.
359 isstaticarray = self.paramIsStaticArray(member)
360 isoptional = False
361 if self.paramIsOptional(member) or (name == 'pNext') or (isstaticarray):
362 isoptional = True
363 membersInfo.append(self.CommandParam(type=type, name=name,
364 ispointer=self.paramIsPointer(member),
365 isstaticarray=isstaticarray,
366 isbool=True if type == 'VkBool32' else False,
367 israngedenum=True if type in self.enumRanges else False,
368 isconst=True if 'const' in cdecl else False,
369 isoptional=isoptional,
370 iscount=iscount,
371 noautovalidity=True if member.attrib.get('noautovalidity') is not None else False,
372 len=self.getLen(member),
373 extstructs=member.attrib.get('validextensionstructs') if name == 'pNext' else None,
374 condition=conditions[name] if conditions and name in conditions else None,
375 cdecl=cdecl))
376 self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo))
377 #
378 # Capture group (e.g. C "enum" type) info to be used for
379 # param check code generation.
380 # These are concatenated together with other types.
381 def genGroup(self, groupinfo, groupName):
382 OutputGenerator.genGroup(self, groupinfo, groupName)
383 groupElem = groupinfo.elem
384 #
385 # Store the sType values
386 if groupName == 'VkStructureType':
387 for elem in groupElem.findall('enum'):
388 self.stypes.append(elem.get('name'))
389 elif 'FlagBits' in groupName:
390 bits = []
391 for elem in groupElem.findall('enum'):
392 bits.append(elem.get('name'))
393 if bits:
394 self.flagBits[groupName] = bits
395 else:
396 # Determine if begin/end ranges are needed (we don't do this for VkStructureType, which has a more finely grained check)
397 expandName = re.sub(r'([0-9a-z_])([A-Z0-9][^A-Z0-9]?)',r'\1_\2',groupName).upper()
398 expandPrefix = expandName
399 expandSuffix = ''
400 expandSuffixMatch = re.search(r'[A-Z][A-Z]+$',groupName)
401 if expandSuffixMatch:
402 expandSuffix = '_' + expandSuffixMatch.group()
403 # Strip off the suffix from the prefix
404 expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
405 isEnum = ('FLAG_BITS' not in expandPrefix)
406 if isEnum:
407 self.enumRanges[groupName] = (expandPrefix + '_BEGIN_RANGE' + expandSuffix, expandPrefix + '_END_RANGE' + expandSuffix)
408 #
409 # Capture command parameter info to be used for param
410 # check code generation.
411 def genCmd(self, cmdinfo, name):
412 OutputGenerator.genCmd(self, cmdinfo, name)
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700413 interface_functions = [
414 'vkEnumerateInstanceLayerProperties',
415 'vkEnumerateInstanceExtensionProperties',
416 'vkEnumerateDeviceLayerProperties',
Mark Lobodzinski099b3b62017-02-08 16:04:35 -0700417 'vkCmdDebugMarkerEndEXT', # No validation!
Mark Lobodzinskib6b8bbd2017-02-08 14:37:15 -0700418 ]
419 # Record that the function will be intercepted
420 if name not in interface_functions:
421 if (self.featureExtraProtect != None):
422 self.declarations += [ '#ifdef %s' % self.featureExtraProtect ]
423 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
424 self.intercepts += [ ' {"%s", reinterpret_cast<PFN_vkVoidFunction>(%s)},' % (name,name[2:]) ]
425 decls = self.makeCDecls(cmdinfo.elem)
426 # Strip off 'vk' from API name
427 self.declarations += [ '%s' % decls[0].replace("VKAPI_CALL vk", "VKAPI_CALL ") ]
428 if (self.featureExtraProtect != None):
429 self.intercepts += [ '#endif' ]
430 self.declarations += [ '#endif' ]
Mark Lobodzinski85672672016-10-13 08:36:42 -0600431 if name not in self.blacklist:
432 params = cmdinfo.elem.findall('param')
433 # Get list of array lengths
434 lens = set()
435 for param in params:
436 len = self.getLen(param)
437 if len:
438 lens.add(len)
439 # Get param info
440 paramsInfo = []
441 for param in params:
442 paramInfo = self.getTypeNameTuple(param)
443 cdecl = self.makeCParamDecl(param, 0)
444 # Check for parameter name in lens set
445 iscount = False
446 if paramInfo[1] in lens:
447 iscount = True
448 paramsInfo.append(self.CommandParam(type=paramInfo[0], name=paramInfo[1],
449 ispointer=self.paramIsPointer(param),
450 isstaticarray=self.paramIsStaticArray(param),
451 isbool=True if paramInfo[0] == 'VkBool32' else False,
452 israngedenum=True if paramInfo[0] in self.enumRanges else False,
453 isconst=True if 'const' in cdecl else False,
454 isoptional=self.paramIsOptional(param),
455 iscount=iscount,
456 noautovalidity=True if param.attrib.get('noautovalidity') is not None else False,
457 len=self.getLen(param),
458 extstructs=None,
459 condition=None,
460 cdecl=cdecl))
461 self.commands.append(self.CommandData(name=name, params=paramsInfo, cdecl=self.makeCDecls(cmdinfo.elem)[0]))
462 #
463 # Check if the parameter passed in is a pointer
464 def paramIsPointer(self, param):
465 ispointer = 0
466 paramtype = param.find('type')
467 if (paramtype.tail is not None) and ('*' in paramtype.tail):
468 ispointer = paramtype.tail.count('*')
469 elif paramtype.text[:4] == 'PFN_':
470 # Treat function pointer typedefs as a pointer to a single value
471 ispointer = 1
472 return ispointer
473 #
474 # Check if the parameter passed in is a static array
475 def paramIsStaticArray(self, param):
476 isstaticarray = 0
477 paramname = param.find('name')
478 if (paramname.tail is not None) and ('[' in paramname.tail):
479 isstaticarray = paramname.tail.count('[')
480 return isstaticarray
481 #
482 # Check if the parameter passed in is optional
483 # Returns a list of Boolean values for comma separated len attributes (len='false,true')
484 def paramIsOptional(self, param):
485 # See if the handle is optional
486 isoptional = False
487 # Simple, if it's optional, return true
488 optString = param.attrib.get('optional')
489 if optString:
490 if optString == 'true':
491 isoptional = True
492 elif ',' in optString:
493 opts = []
494 for opt in optString.split(','):
495 val = opt.strip()
496 if val == 'true':
497 opts.append(True)
498 elif val == 'false':
499 opts.append(False)
500 else:
501 print('Unrecognized len attribute value',val)
502 isoptional = opts
503 return isoptional
504 #
505 # Check if the handle passed in is optional
506 # Uses the same logic as ValidityOutputGenerator.isHandleOptional
507 def isHandleOptional(self, param, lenParam):
508 # Simple, if it's optional, return true
509 if param.isoptional:
510 return True
511 # If no validity is being generated, it usually means that validity is complex and not absolute, so let's say yes.
512 if param.noautovalidity:
513 return True
514 # If the parameter is an array and we haven't already returned, find out if any of the len parameters are optional
515 if lenParam and lenParam.isoptional:
516 return True
517 return False
518 #
519 # Generate a VkStructureType based on a structure typename
520 def genVkStructureType(self, typename):
521 # Add underscore between lowercase then uppercase
522 value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
Mark Young39389872017-01-19 21:10:49 -0700523 value = value.replace('D3_D12', 'D3D12')
524 value = value.replace('Device_IDProp', 'Device_ID_Prop')
Mark Lobodzinski85672672016-10-13 08:36:42 -0600525 # Change to uppercase
526 value = value.upper()
527 # Add STRUCTURE_TYPE_
528 return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value)
529 #
530 # Get the cached VkStructureType value for the specified struct typename, or generate a VkStructureType
531 # value assuming the struct is defined by a different feature
532 def getStructType(self, typename):
533 value = None
534 if typename in self.structTypes:
535 value = self.structTypes[typename].value
536 else:
537 value = self.genVkStructureType(typename)
538 self.logMsg('diag', 'ParameterValidation: Generating {} for {} structure type that was not defined by the current feature'.format(value, typename))
539 return value
540 #
541 # Retrieve the value of the len tag
542 def getLen(self, param):
543 result = None
544 len = param.attrib.get('len')
545 if len and len != 'null-terminated':
546 # For string arrays, 'len' can look like 'count,null-terminated',
547 # indicating that we have a null terminated array of strings. We
548 # strip the null-terminated from the 'len' field and only return
549 # the parameter specifying the string count
550 if 'null-terminated' in len:
551 result = len.split(',')[0]
552 else:
553 result = len
554 result = str(result).replace('::', '->')
555 return result
556 #
557 # Retrieve the type and name for a parameter
558 def getTypeNameTuple(self, param):
559 type = ''
560 name = ''
561 for elem in param:
562 if elem.tag == 'type':
563 type = noneStr(elem.text)
564 elif elem.tag == 'name':
565 name = noneStr(elem.text)
566 return (type, name)
567 #
568 # Find a named parameter in a parameter list
569 def getParamByName(self, params, name):
570 for param in params:
571 if param.name == name:
572 return param
573 return None
574 #
575 # Extract length values from latexmath. Currently an inflexible solution that looks for specific
576 # patterns that are found in vk.xml. Will need to be updated when new patterns are introduced.
577 def parseLateXMath(self, source):
578 name = 'ERROR'
579 decoratedName = 'ERROR'
580 if 'mathit' in source:
Mark Lobodzinski36c33862017-02-13 10:15:53 -0700581 # Matches expressions similar to 'latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]'
582 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 -0600583 if not match or match.group(1) != match.group(4):
584 raise 'Unrecognized latexmath expression'
585 name = match.group(2)
586 decoratedName = '{}({}/{})'.format(*match.group(1, 2, 3))
587 else:
Mark Lobodzinski36c33862017-02-13 10:15:53 -0700588 # Matches expressions similar to 'latexmath : [dataSize \over 4]'
Mark Young0f183a82017-02-28 09:58:04 -0700589 match = re.match(r'latexmath\s*\:\s*\[\s*(\w+)\s*\\over\s*(\d+)\s*\]', source)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600590 name = match.group(1)
591 decoratedName = '{}/{}'.format(*match.group(1, 2))
592 return name, decoratedName
593 #
594 # Get the length paramater record for the specified parameter name
595 def getLenParam(self, params, name):
596 lenParam = None
597 if name:
598 if '->' in name:
599 # The count is obtained by dereferencing a member of a struct parameter
600 lenParam = self.CommandParam(name=name, iscount=True, ispointer=False, isbool=False, israngedenum=False, isconst=False,
601 isstaticarray=None, isoptional=False, type=None, noautovalidity=False, len=None, extstructs=None,
602 condition=None, cdecl=None)
603 elif 'latexmath' in name:
604 lenName, decoratedName = self.parseLateXMath(name)
605 lenParam = self.getParamByName(params, lenName)
606 # TODO: Zero-check the result produced by the equation?
607 # Copy the stored len parameter entry and overwrite the name with the processed latexmath equation
608 #param = self.getParamByName(params, lenName)
609 #lenParam = self.CommandParam(name=decoratedName, iscount=param.iscount, ispointer=param.ispointer,
610 # isoptional=param.isoptional, type=param.type, len=param.len,
611 # isstaticarray=param.isstaticarray, extstructs=param.extstructs,
612 # noautovalidity=True, condition=None, cdecl=param.cdecl)
613 else:
614 lenParam = self.getParamByName(params, name)
615 return lenParam
616 #
617 # Convert a vulkan.h command declaration into a parameter_validation.h definition
618 def getCmdDef(self, cmd):
619 #
620 # Strip the trailing ';' and split into individual lines
621 lines = cmd.cdecl[:-1].split('\n')
622 # Replace Vulkan prototype
623 lines[0] = 'static bool parameter_validation_' + cmd.name + '('
624 # Replace the first argument with debug_report_data, when the first
625 # argument is a handle (not vkCreateInstance)
626 reportData = ' debug_report_data*'.ljust(self.genOpts.alignFuncParam) + 'report_data,'
627 if cmd.name != 'vkCreateInstance':
628 lines[1] = reportData
629 else:
630 lines.insert(1, reportData)
631 return '\n'.join(lines)
632 #
633 # Generate the code to check for a NULL dereference before calling the
634 # validation function
635 def genCheckedLengthCall(self, name, exprs):
636 count = name.count('->')
637 if count:
638 checkedExpr = []
639 localIndent = ''
640 elements = name.split('->')
641 # Open the if expression blocks
642 for i in range(0, count):
643 checkedExpr.append(localIndent + 'if ({} != NULL) {{\n'.format('->'.join(elements[0:i+1])))
644 localIndent = self.incIndent(localIndent)
645 # Add the validation expression
646 for expr in exprs:
647 checkedExpr.append(localIndent + expr)
648 # Close the if blocks
649 for i in range(0, count):
650 localIndent = self.decIndent(localIndent)
651 checkedExpr.append(localIndent + '}\n')
652 return [checkedExpr]
653 # No if statements were required
654 return exprs
655 #
656 # Generate code to check for a specific condition before executing validation code
657 def genConditionalCall(self, prefix, condition, exprs):
658 checkedExpr = []
659 localIndent = ''
660 formattedCondition = condition.format(prefix)
661 checkedExpr.append(localIndent + 'if ({})\n'.format(formattedCondition))
662 checkedExpr.append(localIndent + '{\n')
663 localIndent = self.incIndent(localIndent)
664 for expr in exprs:
665 checkedExpr.append(localIndent + expr)
666 localIndent = self.decIndent(localIndent)
667 checkedExpr.append(localIndent + '}\n')
668 return [checkedExpr]
669 #
670 # Generate the sType check string
671 def makeStructTypeCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec):
672 checkExpr = []
673 stype = self.structTypes[value.type]
674 if lenValue:
675 # This is an array with a pointer to a count value
676 if lenValue.ispointer:
677 # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
678 checkExpr.append('skipCall |= validate_struct_type_array(report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {});\n'.format(
679 funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix, **postProcSpec))
680 # This is an array with an integer count value
681 else:
682 checkExpr.append('skipCall |= validate_struct_type_array(report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {});\n'.format(
683 funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix, **postProcSpec))
684 # This is an individual struct
685 else:
686 checkExpr.append('skipCall |= validate_struct_type(report_data, "{}", {ppp}"{}"{pps}, "{sv}", {}{vn}, {sv}, {});\n'.format(
687 funcPrintName, valuePrintName, prefix, valueRequired, vn=value.name, sv=stype.value, **postProcSpec))
688 return checkExpr
689 #
690 # Generate the handle check string
691 def makeHandleCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec):
692 checkExpr = []
693 if lenValue:
694 if lenValue.ispointer:
695 # This is assumed to be an output array with a pointer to a count value
696 raise('Unsupported parameter validation case: Output handle array elements are not NULL checked')
697 else:
698 # This is an array with an integer count value
699 checkExpr.append('skipCall |= validate_handle_array(report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
700 funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
701 else:
702 # This is assumed to be an output handle pointer
703 raise('Unsupported parameter validation case: Output handles are not NULL checked')
704 return checkExpr
705 #
706 # Generate check string for an array of VkFlags values
707 def makeFlagsArrayCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec):
708 checkExpr = []
709 flagBitsName = value.type.replace('Flags', 'FlagBits')
710 if not flagBitsName in self.flagBits:
711 raise('Unsupported parameter validation case: array of reserved VkFlags')
712 else:
713 allFlags = 'All' + flagBitsName
714 checkExpr.append('skipCall |= validate_flags_array(report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcPrintName, lenPrintName, valuePrintName, flagBitsName, allFlags, lenValue.name, value.name, lenValueRequired, valueRequired, pf=prefix, **postProcSpec))
715 return checkExpr
716 #
717 # Generate pNext check string
718 def makeStructNextCheck(self, prefix, value, funcPrintName, valuePrintName, postProcSpec):
719 checkExpr = []
720 # Generate an array of acceptable VkStructureType values for pNext
721 extStructCount = 0
722 extStructVar = 'NULL'
723 extStructNames = 'NULL'
724 if value.extstructs:
725 structs = value.extstructs.split(',')
726 checkExpr.append('const VkStructureType allowedStructs[] = {' + ', '.join([self.getStructType(s) for s in structs]) + '};\n')
727 extStructCount = 'ARRAY_SIZE(allowedStructs)'
728 extStructVar = 'allowedStructs'
729 extStructNames = '"' + ', '.join(structs) + '"'
730 checkExpr.append('skipCall |= validate_struct_pnext(report_data, "{}", {ppp}"{}"{pps}, {}, {}{}, {}, {}, GeneratedHeaderVersion);\n'.format(
731 funcPrintName, valuePrintName, extStructNames, prefix, value.name, extStructCount, extStructVar, **postProcSpec))
732 return checkExpr
733 #
734 # Generate the pointer check string
735 def makePointerCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec):
736 checkExpr = []
737 if lenValue:
738 # This is an array with a pointer to a count value
739 if lenValue.ispointer:
740 # If count and array parameters are optional, there will be no validation
741 if valueRequired == 'true' or lenPtrRequired == 'true' or lenValueRequired == 'true':
742 # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
743 checkExpr.append('skipCall |= validate_array(report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {});\n'.format(
744 funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
745 # This is an array with an integer count value
746 else:
747 # If count and array parameters are optional, there will be no validation
748 if valueRequired == 'true' or lenValueRequired == 'true':
749 # Arrays of strings receive special processing
750 validationFuncName = 'validate_array' if value.type != 'char' else 'validate_string_array'
751 checkExpr.append('skipCall |= {}(report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
752 validationFuncName, funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
753 if checkExpr:
754 if lenValue and ('->' in lenValue.name):
755 # Add checks to ensure the validation call does not dereference a NULL pointer to obtain the count
756 checkExpr = self.genCheckedLengthCall(lenValue.name, checkExpr)
757 # This is an individual struct that is not allowed to be NULL
758 elif not value.isoptional:
759 # Function pointers need a reinterpret_cast to void*
760 if value.type[:4] == 'PFN_':
761 checkExpr.append('skipCall |= validate_required_pointer(report_data, "{}", {ppp}"{}"{pps}, reinterpret_cast<const void*>({}{}));\n'.format(funcPrintName, valuePrintName, prefix, value.name, **postProcSpec))
762 else:
763 checkExpr.append('skipCall |= validate_required_pointer(report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcPrintName, valuePrintName, prefix, value.name, **postProcSpec))
764 return checkExpr
765 #
766 # Process struct member validation code, performing name suibstitution if required
767 def processStructMemberCode(self, line, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec):
768 # Build format specifier list
769 kwargs = {}
770 if '{postProcPrefix}' in line:
771 # If we have a tuple that includes a format string and format parameters, need to use ParameterName class
772 if type(memberDisplayNamePrefix) is tuple:
773 kwargs['postProcPrefix'] = 'ParameterName('
774 else:
775 kwargs['postProcPrefix'] = postProcSpec['ppp']
776 if '{postProcSuffix}' in line:
777 # If we have a tuple that includes a format string and format parameters, need to use ParameterName class
778 if type(memberDisplayNamePrefix) is tuple:
779 kwargs['postProcSuffix'] = ', ParameterName::IndexVector{{ {}{} }})'.format(postProcSpec['ppi'], memberDisplayNamePrefix[1])
780 else:
781 kwargs['postProcSuffix'] = postProcSpec['pps']
782 if '{postProcInsert}' in line:
783 # If we have a tuple that includes a format string and format parameters, need to use ParameterName class
784 if type(memberDisplayNamePrefix) is tuple:
785 kwargs['postProcInsert'] = '{}{}, '.format(postProcSpec['ppi'], memberDisplayNamePrefix[1])
786 else:
787 kwargs['postProcInsert'] = postProcSpec['ppi']
788 if '{funcName}' in line:
789 kwargs['funcName'] = funcName
790 if '{valuePrefix}' in line:
791 kwargs['valuePrefix'] = memberNamePrefix
792 if '{displayNamePrefix}' in line:
793 # Check for a tuple that includes a format string and format parameters to be used with the ParameterName class
794 if type(memberDisplayNamePrefix) is tuple:
795 kwargs['displayNamePrefix'] = memberDisplayNamePrefix[0]
796 else:
797 kwargs['displayNamePrefix'] = memberDisplayNamePrefix
798
799 if kwargs:
800 # Need to escape the C++ curly braces
801 if 'IndexVector' in line:
802 line = line.replace('IndexVector{ ', 'IndexVector{{ ')
803 line = line.replace(' }),', ' }}),')
804 return line.format(**kwargs)
805 return line
806 #
807 # Process struct validation code for inclusion in function or parent struct validation code
808 def expandStructCode(self, lines, funcName, memberNamePrefix, memberDisplayNamePrefix, indent, output, postProcSpec):
809 for line in lines:
810 if output:
811 output[-1] += '\n'
812 if type(line) is list:
813 for sub in line:
814 output.append(self.processStructMemberCode(indent + sub, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec))
815 else:
816 output.append(self.processStructMemberCode(indent + line, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec))
817 return output
818 #
819 # Process struct pointer/array validation code, perfoeming name substitution if required
820 def expandStructPointerCode(self, prefix, value, lenValue, funcName, valueDisplayName, postProcSpec):
821 expr = []
822 expr.append('if ({}{} != NULL)\n'.format(prefix, value.name))
823 expr.append('{')
824 indent = self.incIndent(None)
825 if lenValue:
826 # Need to process all elements in the array
827 indexName = lenValue.name.replace('Count', 'Index')
828 expr[-1] += '\n'
Mark Young39389872017-01-19 21:10:49 -0700829 if lenValue.ispointer:
830 # If the length value is a pointer, de-reference it for the count.
831 expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < *{}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName))
832 else:
833 expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < {}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName))
Mark Lobodzinski85672672016-10-13 08:36:42 -0600834 expr.append(indent + '{')
835 indent = self.incIndent(indent)
836 # Prefix for value name to display in error message
Mark Lobodzinski6f82eb52016-12-05 07:38:41 -0700837 if value.ispointer == 2:
838 memberNamePrefix = '{}{}[{}]->'.format(prefix, value.name, indexName)
839 memberDisplayNamePrefix = ('{}[%i]->'.format(valueDisplayName), indexName)
840 else:
841 memberNamePrefix = '{}{}[{}].'.format(prefix, value.name, indexName)
842 memberDisplayNamePrefix = ('{}[%i].'.format(valueDisplayName), indexName)
Mark Lobodzinski85672672016-10-13 08:36:42 -0600843 else:
844 memberNamePrefix = '{}{}->'.format(prefix, value.name)
845 memberDisplayNamePrefix = '{}->'.format(valueDisplayName)
846 #
847 # Expand the struct validation lines
848 expr = self.expandStructCode(self.validatedStructs[value.type], funcName, memberNamePrefix, memberDisplayNamePrefix, indent, expr, postProcSpec)
849 #
850 if lenValue:
851 # Close if and for scopes
852 indent = self.decIndent(indent)
853 expr.append(indent + '}\n')
854 expr.append('}\n')
855 return expr
856 #
857 # Generate the parameter checking code
858 def genFuncBody(self, funcName, values, valuePrefix, displayNamePrefix, structTypeName):
859 lines = [] # Generated lines of code
860 unused = [] # Unused variable names
861 for value in values:
862 usedLines = []
863 lenParam = None
864 #
865 # 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.
866 postProcSpec = {}
867 postProcSpec['ppp'] = '' if not structTypeName else '{postProcPrefix}'
868 postProcSpec['pps'] = '' if not structTypeName else '{postProcSuffix}'
869 postProcSpec['ppi'] = '' if not structTypeName else '{postProcInsert}'
870 #
871 # Generate the full name of the value, which will be printed in the error message, by adding the variable prefix to the value name
872 valueDisplayName = '{}{}'.format(displayNamePrefix, value.name)
873 #
874 # Check for NULL pointers, ignore the inout count parameters that
875 # will be validated with their associated array
876 if (value.ispointer or value.isstaticarray) and not value.iscount:
877 #
878 # Parameters for function argument generation
879 req = 'true' # Paramerter cannot be NULL
880 cpReq = 'true' # Count pointer cannot be NULL
881 cvReq = 'true' # Count value cannot be 0
882 lenDisplayName = None # Name of length parameter to print with validation messages; parameter name with prefix applied
883 #
884 # Generate required/optional parameter strings for the pointer and count values
885 if value.isoptional:
886 req = 'false'
887 if value.len:
888 # The parameter is an array with an explicit count parameter
889 lenParam = self.getLenParam(values, value.len)
890 lenDisplayName = '{}{}'.format(displayNamePrefix, lenParam.name)
891 if lenParam.ispointer:
892 # Count parameters that are pointers are inout
893 if type(lenParam.isoptional) is list:
894 if lenParam.isoptional[0]:
895 cpReq = 'false'
896 if lenParam.isoptional[1]:
897 cvReq = 'false'
898 else:
899 if lenParam.isoptional:
900 cpReq = 'false'
901 else:
902 if lenParam.isoptional:
903 cvReq = 'false'
904 #
905 # The parameter will not be processes when tagged as 'noautovalidity'
906 # For the pointer to struct case, the struct pointer will not be validated, but any
907 # members not tagged as 'noatuvalidity' will be validated
908 if value.noautovalidity:
909 # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually
910 self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name))
911 else:
912 #
913 # If this is a pointer to a struct with an sType field, verify the type
914 if value.type in self.structTypes:
915 usedLines += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
916 # 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
917 elif value.type in self.handleTypes and value.isconst and not self.isHandleOptional(value, lenParam):
918 usedLines += self.makeHandleCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
919 elif value.type in self.flags and value.isconst:
920 usedLines += self.makeFlagsArrayCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
921 elif value.isbool and value.isconst:
922 usedLines.append('skipCall |= validate_bool32_array(report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
923 elif value.israngedenum and value.isconst:
924 enumRange = self.enumRanges[value.type]
925 usedLines.append('skipCall |= validate_ranged_enum_array(report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, value.type, enumRange[0], enumRange[1], lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
926 elif value.name == 'pNext':
927 # We need to ignore VkDeviceCreateInfo and VkInstanceCreateInfo, as the loader manipulates them in a way that is not documented in vk.xml
928 if not structTypeName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']:
929 usedLines += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName, postProcSpec)
930 else:
931 usedLines += self.makePointerCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
932 #
933 # If this is a pointer to a struct (input), see if it contains members that need to be checked
934 if value.type in self.validatedStructs and value.isconst:
935 usedLines.append(self.expandStructPointerCode(valuePrefix, value, lenParam, funcName, valueDisplayName, postProcSpec))
936 # Non-pointer types
937 else:
938 #
939 # The parameter will not be processes when tagged as 'noautovalidity'
940 # For the struct case, the struct type will not be validated, but any
941 # members not tagged as 'noatuvalidity' will be validated
942 if value.noautovalidity:
943 # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually
944 self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name))
945 else:
946 if value.type in self.structTypes:
947 stype = self.structTypes[value.type]
948 usedLines.append('skipCall |= validate_struct_type(report_data, "{}", {ppp}"{}"{pps}, "{sv}", &({}{vn}), {sv}, false);\n'.format(
949 funcName, valueDisplayName, valuePrefix, vn=value.name, sv=stype.value, **postProcSpec))
950 elif value.type in self.handleTypes:
951 if not self.isHandleOptional(value, None):
952 usedLines.append('skipCall |= validate_required_handle(report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
953 elif value.type in self.flags:
954 flagBitsName = value.type.replace('Flags', 'FlagBits')
955 if not flagBitsName in self.flagBits:
956 usedLines.append('skipCall |= validate_reserved_flags(report_data, "{}", {ppp}"{}"{pps}, {pf}{});\n'.format(funcName, valueDisplayName, value.name, pf=valuePrefix, **postProcSpec))
957 else:
958 flagsRequired = 'false' if value.isoptional else 'true'
959 allFlagsName = 'All' + flagBitsName
960 usedLines.append('skipCall |= validate_flags(report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsRequired, pf=valuePrefix, **postProcSpec))
961 elif value.isbool:
962 usedLines.append('skipCall |= validate_bool32(report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
963 elif value.israngedenum:
964 enumRange = self.enumRanges[value.type]
Mark Lobodzinski6f82eb52016-12-05 07:38:41 -0700965 if value.type == "VkObjectEntryTypeNVX":
966 garbage = 2
Mark Lobodzinski85672672016-10-13 08:36:42 -0600967 usedLines.append('skipCall |= validate_ranged_enum(report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {}, {}{});\n'.format(funcName, valueDisplayName, value.type, enumRange[0], enumRange[1], valuePrefix, value.name, **postProcSpec))
968 #
969 # If this is a struct, see if it contains members that need to be checked
970 if value.type in self.validatedStructs:
971 memberNamePrefix = '{}{}.'.format(valuePrefix, value.name)
972 memberDisplayNamePrefix = '{}.'.format(valueDisplayName)
973 usedLines.append(self.expandStructCode(self.validatedStructs[value.type], funcName, memberNamePrefix, memberDisplayNamePrefix, '', [], postProcSpec))
974 #
975 # Append the parameter check to the function body for the current command
976 if usedLines:
977 # Apply special conditional checks
978 if value.condition:
979 usedLines = self.genConditionalCall(valuePrefix, value.condition, usedLines)
980 lines += usedLines
981 elif not value.iscount:
982 # If no expression was generated for this value, it is unreferenced by the validation function, unless
983 # it is an array count, which is indirectly referenced for array valiadation.
984 unused.append(value.name)
985 return lines, unused
986 #
987 # Generate the struct member check code from the captured data
988 def processStructMemberData(self):
989 indent = self.incIndent(None)
990 for struct in self.structMembers:
991 #
992 # The string returned by genFuncBody will be nested in an if check for a NULL pointer, so needs its indent incremented
993 lines, unused = self.genFuncBody('{funcName}', struct.members, '{valuePrefix}', '{displayNamePrefix}', struct.name)
994 if lines:
995 self.validatedStructs[struct.name] = lines
996 #
997 # Generate the command param check code from the captured data
998 def processCmdData(self):
999 indent = self.incIndent(None)
1000 for command in self.commands:
1001 # Skip first parameter if it is a dispatch handle (everything except vkCreateInstance)
1002 startIndex = 0 if command.name == 'vkCreateInstance' else 1
1003 lines, unused = self.genFuncBody(command.name, command.params[startIndex:], '', '', None)
1004 if lines:
1005 cmdDef = self.getCmdDef(command) + '\n'
1006 cmdDef += '{\n'
1007 # Process unused parameters, Ignoring the first dispatch handle parameter, which is not
1008 # processed by parameter_validation (except for vkCreateInstance, which does not have a
1009 # handle as its first parameter)
1010 if unused:
1011 for name in unused:
1012 cmdDef += indent + 'UNUSED_PARAMETER({});\n'.format(name)
1013 if len(unused) > 0:
1014 cmdDef += '\n'
1015 cmdDef += indent + 'bool skipCall = false;\n'
1016 for line in lines:
1017 cmdDef += '\n'
1018 if type(line) is list:
1019 for sub in line:
1020 cmdDef += indent + sub
1021 else:
1022 cmdDef += indent + line
1023 cmdDef += '\n'
1024 cmdDef += indent + 'return skipCall;\n'
1025 cmdDef += '}\n'
1026 self.appendSection('command', cmdDef)