layers: Move parameter validation to layer chassis
Change-Id: I22724f632ca80354ce59fe535979250f65e1c9b6
diff --git a/scripts/layer_chassis_generator.py b/scripts/layer_chassis_generator.py
index d1744dc..8f31fe3 100644
--- a/scripts/layer_chassis_generator.py
+++ b/scripts/layer_chassis_generator.py
@@ -391,6 +391,7 @@
#include "thread_safety.h"
#define OBJECT_LAYER_NAME "VK_LAYER_GOOGLE_threading"
#elif BUILD_PARAMETER_VALIDATION
+#include "stateless_validation.h"
#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_parameter_validation"
#elif BUILD_CORE_VALIDATION
#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_core_validation"
@@ -518,6 +519,10 @@
auto thread_checker = new ThreadSafety;
local_object_dispatch.emplace_back(thread_checker);
thread_checker->container_type = LayerObjectTypeThreading;
+#elif BUILD_PARAMETER_VALIDATION
+ auto parameter_validation = new StatelessValidation;
+ local_object_dispatch.emplace_back(parameter_validation);
+ parameter_validation->container_type = LayerObjectTypeParameterValidation;
#endif
@@ -544,8 +549,16 @@
(pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0), pCreateInfo);
#if BUILD_OBJECT_TRACKER
layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_object_tracker");
+ object_tracker->report_data = framework->report_data;
+ object_tracker->api_version = framework->api_version;
#elif BUILD_THREAD_SAFETY
layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "google_thread_checker");
+ thread_checker->report_data = framework->report_data;
+ thread_checker->api_version = framework->api_version;
+#elif BUILD_PARAMETER_VALIDATION
+ layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_parameter_validation");
+ parameter_validation->report_data = framework->report_data;
+ parameter_validation->api_version = framework->api_version;
#else
layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_unique_objects");
#endif
@@ -659,7 +672,6 @@
device_interceptor->physical_device = gpu;
device_interceptor->instance = instance_interceptor->instance;
device_interceptor->report_data = layer_debug_utils_create_device(instance_interceptor->report_data, *pDevice);
- device_interceptor->api_version = instance_interceptor->api_version;
#if BUILD_OBJECT_TRACKER
// Create child layer objects for this key and add to dispatch vector
@@ -670,6 +682,7 @@
object_tracker->instance = instance_interceptor->instance;
object_tracker->report_data = device_interceptor->report_data;
object_tracker->device_dispatch_table = device_interceptor->device_dispatch_table;
+ object_tracker->api_version = device_interceptor->api_version;
device_interceptor->object_dispatch.emplace_back(object_tracker);
#elif BUILD_THREAD_SAFETY
auto thread_safety = new ThreadSafety;
@@ -679,7 +692,18 @@
thread_safety->instance = instance_interceptor->instance;
thread_safety->report_data = device_interceptor->report_data;
thread_safety->device_dispatch_table = device_interceptor->device_dispatch_table;
+ thread_safety->api_version = device_interceptor->api_version;
device_interceptor->object_dispatch.emplace_back(thread_safety);
+#elif BUILD_PARAMETER_VALIDATION
+ auto stateless_validation = new StatelessValidation;
+ // TODO: Initialize child objects with parent info thru constuctor taking a parent object
+ stateless_validation->container_type = LayerObjectTypeParameterValidation;
+ stateless_validation->physical_device = gpu;
+ stateless_validation->instance = instance_interceptor->instance;
+ stateless_validation->report_data = device_interceptor->report_data;
+ stateless_validation->device_dispatch_table = device_interceptor->device_dispatch_table;
+ stateless_validation->api_version = device_interceptor->api_version;
+ device_interceptor->object_dispatch.emplace_back(stateless_validation);
#endif
for (auto intercept : instance_interceptor->object_dispatch) {
diff --git a/scripts/lvl_genvk.py b/scripts/lvl_genvk.py
index e5f4ecf..bd1d3cf 100644
--- a/scripts/lvl_genvk.py
+++ b/scripts/lvl_genvk.py
@@ -157,7 +157,7 @@
expandEnumerants = False)
]
- # Options for parameter validation layer
+ # Options for stateless validation source file
genOpts['parameter_validation.cpp'] = [
ParameterValidationOutputGenerator,
ParameterValidationGeneratorOptions(
@@ -180,6 +180,29 @@
valid_usage_path = args.scripts)
]
+ # Options for stateless validation source file
+ genOpts['parameter_validation.h'] = [
+ ParameterValidationOutputGenerator,
+ ParameterValidationGeneratorOptions(
+ filename = 'parameter_validation.h',
+ directory = directory,
+ apiname = 'vulkan',
+ profile = None,
+ versions = featuresPat,
+ emitversions = featuresPat,
+ defaultExtensions = 'vulkan',
+ addExtensions = addExtensionsPat,
+ removeExtensions = removeExtensionsPat,
+ emitExtensions = emitExtensionsPat,
+ prefixText = prefixStrings + vkPrefixStrings,
+ apicall = 'VKAPI_ATTR ',
+ apientry = 'VKAPI_CALL ',
+ apientryp = 'VKAPI_PTR *',
+ alignFuncParam = 48,
+ expandEnumerants = False,
+ valid_usage_path = args.scripts)
+ ]
+
# Options for object_tracker code-generated validation routines
genOpts['object_tracker.cpp'] = [
ObjectTrackerOutputGenerator,
diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py
index 114cec3..5237f8d 100644
--- a/scripts/parameter_validation_generator.py
+++ b/scripts/parameter_validation_generator.py
@@ -123,8 +123,60 @@
diagFile = sys.stdout):
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
self.INDENT_SPACES = 4
- self.intercepts = []
self.declarations = []
+
+ inline_custom_source_preamble = """
+"""
+
+ # These functions have additional, custome-written checks in the utils cpp file. CodeGen will automatically add a call
+ # to those functions of the form 'bool manual_PreCallValidateAPIName', where the 'vk' is dropped.
+ # see 'manual_PreCallValidateCreateGraphicsPipelines' as an example.
+ self.functions_with_manual_checks = [
+ 'vkCreateInstance',
+ 'vkCreateDevice',
+ 'vkCreateQueryPool'
+ 'vkCreateCommandPool',
+ 'vkCreateRenderPass',
+ 'vkCreateRenderPass2KHR',
+ 'vkGetDeviceQueue',
+ 'vkCreateBuffer',
+ 'vkCreateImage',
+ 'vkCreateImageView',
+ 'vkCreateGraphicsPipelines',
+ 'vkCreateComputePipelines',
+ 'vkCreateSampler',
+ 'vkCreateDescriptorSetLayout',
+ 'vkFreeDescriptorSets',
+ 'vkUpdateDescriptorSets',
+ 'vkCreateRenderPass',
+ 'vkCreateRenderPass2KHR',
+ 'vkBeginCommandBuffer',
+ 'vkCmdSetViewport',
+ 'vkCmdSetScissor',
+ 'vkCmdSetLineWidth',
+ 'vkCmdDraw',
+ 'vkCmdDrawIndirect',
+ 'vkCmdDrawIndexedIndirect',
+ 'vkCmdCopyImage',
+ 'vkCmdBlitImage',
+ 'vkCmdCopyBufferToImage',
+ 'vkCmdCopyImageToBuffer',
+ 'vkCmdUpdateBuffer',
+ 'vkCmdFillBuffer',
+ 'vkCreateSwapchainKHR',
+ 'vkQueuePresentKHR',
+ 'vkCreateDescriptorPool',
+ 'vkCmdDispatch',
+ 'vkCmdDispatchIndirect',
+ 'vkCmdDispatchBaseKHR',
+ 'vkCmdSetExclusiveScissorNV',
+ 'vkCmdSetViewportShadingRatePaletteNV',
+ 'vkCmdSetCoarseSampleOrderNV',
+ 'vkCmdDrawMeshTasksNV',
+ 'vkCmdDrawMeshTasksIndirectNV',
+ 'vkCmdDrawMeshTasksIndirectCountNV',
+ ]
+
# Commands to ignore
self.blacklist = [
'vkGetInstanceProcAddr',
@@ -134,23 +186,8 @@
'vkEnumerateInstanceExtensionProperties',
'vkEnumerateDeviceLayerProperties',
'vkEnumerateDeviceExtensionProperties',
- 'vkCmdDebugMarkerEndEXT',
]
- self.validate_only = [
- 'vkCreateInstance',
- 'vkDestroyInstance',
- 'vkCreateDevice',
- 'vkDestroyDevice',
- 'vkCreateQueryPool',
- 'vkCreateDebugReportCallbackEXT',
- 'vkDestroyDebugReportCallbackEXT',
- 'vkCreateCommandPool',
- 'vkCreateRenderPass',
- 'vkCreateRenderPass2KHR',
- 'vkDestroyRenderPass',
- 'vkCreateDebugUtilsMessengerEXT',
- 'vkDestroyDebugUtilsMessengerEXT',
- ]
+
# Structure fields to ignore
self.structMemberBlacklist = { 'VkWriteDescriptorSet' : ['dstSet'] }
# Validation conditions for some special case struct members that are conditionally validated
@@ -167,8 +204,6 @@
self.validatedStructs = dict() # Map of structs type names to generated validation code for that struct type
self.enumRanges = dict() # Map of enum name to BEGIN/END range values
self.enumValueLists = '' # String containing enumerated type map definitions
- self.func_pointers = '' # String containing function pointers for manual PV functions
- self.typedefs = '' # String containing function pointer typedefs
self.flags = set() # Map of flags typenames
self.flagBits = dict() # Map of flag bits typename to list of values
self.newFlags = set() # Map of flags typenames /defined in the current feature/
@@ -180,6 +215,8 @@
self.valid_vuids = set() # Set of all valid VUIDs
self.vuid_dict = dict() # VUID dictionary (from JSON)
self.alias_dict = dict() # Dict of cmd|struct aliases
+ self.header_file = False # Header file generation flag
+ self.source_file = False # Source file generation flag
self.returnedonly_structs = []
# Named tuples to store struct and command data
self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isbool', 'israngedenum',
@@ -246,6 +283,20 @@
# Called at file creation time
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
+ self.header_file = (genOpts.filename == 'parameter_validation.h')
+ self.source_file = (genOpts.filename == 'parameter_validation.cpp')
+
+ if not self.header_file and not self.source_file:
+ print("Error: Output Filenames have changed, update generator source.\n")
+ sys.exit(1)
+
+ if self.source_file or self.header_file:
+ # Output Copyright text
+ s = self.GenerateCopyright()
+ write(s, file=self.outFile)
+
+ if self.header_file:
+ return
# Build map of structure type names to VkStructureType enum values
# Find all types of category "struct"
@@ -265,115 +316,77 @@
if len(self.vuid_dict) == 0:
print("Error: Could not find, or error loading %s/validusage.json\n", vu_json_filename)
sys.exit(1)
-
- # C-specific
#
# Build a set of all vuid text strings found in validusage.json
for json_vuid_string in self.ExtractVUIDs(self.vuid_dict):
self.valid_vuids.add(json_vuid_string)
#
- # User-supplied prefix text, if any (list of strings)
- s = self.GenerateCopyright()
- write(s, file=self.outFile)
- #
# Headers
- write('#include <string>', file=self.outFile)
+ write('#include "chassis.h"', file=self.outFile)
self.newline()
- write('#include "vk_loader_platform.h"', file=self.outFile)
- write('#include "vulkan/vulkan.h"', file=self.outFile)
- write('#include "vk_layer_extension_utils.h"', file=self.outFile)
- write('#include "parameter_validation.h"', file=self.outFile)
- #
- # Macros
+ write('#include "stateless_validation.h"', file=self.outFile)
self.newline()
- write('#ifndef UNUSED_PARAMETER', file=self.outFile)
- write('#define UNUSED_PARAMETER(x) (void)(x)', file=self.outFile)
- write('#endif // UNUSED_PARAMETER', file=self.outFile)
- #
- # Namespace
- self.newline()
- write('namespace parameter_validation {', file = self.outFile)
- self.newline()
- write('extern std::mutex global_lock;', file = self.outFile)
- write('extern std::unordered_map<void *, layer_data *> layer_data_map;', file = self.outFile)
- write('extern std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;', file = self.outFile)
- self.newline()
- #
- # FuncPtrMap
- self.func_pointers += 'std::unordered_map<std::string, void *> custom_functions = {\n'
#
# Called at end-time for final content output
def endFile(self):
- # C-specific
- self.newline()
- write(self.enumValueLists, file=self.outFile)
- self.newline()
- write(self.typedefs, file=self.outFile)
- self.newline()
- self.func_pointers += '};\n'
- write(self.func_pointers, file=self.outFile)
- self.newline()
+ if self.source_file:
+ # C-specific
+ self.newline()
+ write(self.enumValueLists, file=self.outFile)
+ self.newline()
- pnext_handler = 'bool ValidatePnextStructContents(debug_report_data *report_data, const char *api_name, const ParameterName ¶meter_name, const GenericHeader* header) {\n'
- pnext_handler += ' bool skip = false;\n'
- pnext_handler += ' switch(header->sType) {\n'
+ pnext_handler = 'bool StatelessValidation::ValidatePnextStructContents(const char *api_name, const ParameterName ¶meter_name, const GenericHeader* header) {\n'
+ pnext_handler += ' bool skip = false;\n'
+ pnext_handler += ' switch(header->sType) {\n'
- # Do some processing here to extract data from validatedstructs...
- for item in self.structextends_list:
- postProcSpec = {}
- postProcSpec['ppp'] = '' if not item else '{postProcPrefix}'
- postProcSpec['pps'] = '' if not item else '{postProcSuffix}'
- postProcSpec['ppi'] = '' if not item else '{postProcInsert}'
+ # Do some processing here to extract data from validatedstructs...
+ for item in self.structextends_list:
+ postProcSpec = {}
+ postProcSpec['ppp'] = '' if not item else '{postProcPrefix}'
+ postProcSpec['pps'] = '' if not item else '{postProcSuffix}'
+ postProcSpec['ppi'] = '' if not item else '{postProcInsert}'
- pnext_case = '\n'
- protect = ''
- # Guard struct cases with feature ifdefs, if necessary
- if item in self.struct_feature_protect.keys():
- protect = self.struct_feature_protect[item]
- pnext_case += '#ifdef %s\n' % protect
- pnext_case += ' // Validation code for %s structure members\n' % item
- pnext_case += ' case %s: {\n' % self.structTypes[item]
- pnext_case += ' %s *structure = (%s *) header;\n' % (item, item)
- expr = self.expandStructCode(item, item, 'structure->', '', ' ', [], postProcSpec)
- struct_validation_source = self.ScrubStructCode(expr)
- pnext_case += '%s' % struct_validation_source
- pnext_case += ' } break;\n'
- if protect is not '':
- pnext_case += '#endif // %s\n' % protect
- # Skip functions containing no validation
- if struct_validation_source != '':
- pnext_handler += pnext_case;
- pnext_handler += ' default:\n'
- pnext_handler += ' skip = false;\n'
- pnext_handler += ' }\n'
- pnext_handler += ' return skip;\n'
- pnext_handler += '}\n'
- write(pnext_handler, file=self.outFile)
- self.newline()
+ pnext_case = '\n'
+ protect = ''
+ # Guard struct cases with feature ifdefs, if necessary
+ if item in self.struct_feature_protect.keys():
+ protect = self.struct_feature_protect[item]
+ pnext_case += '#ifdef %s\n' % protect
+ pnext_case += ' // Validation code for %s structure members\n' % item
+ pnext_case += ' case %s: {\n' % self.structTypes[item]
+ pnext_case += ' %s *structure = (%s *) header;\n' % (item, item)
+ expr = self.expandStructCode(item, item, 'structure->', '', ' ', [], postProcSpec)
+ struct_validation_source = self.ScrubStructCode(expr)
+ pnext_case += '%s' % struct_validation_source
+ pnext_case += ' } break;\n'
+ if protect is not '':
+ pnext_case += '#endif // %s\n' % protect
+ # Skip functions containing no validation
+ if struct_validation_source != '':
+ pnext_handler += pnext_case;
+ pnext_handler += ' default:\n'
+ pnext_handler += ' skip = false;\n'
+ pnext_handler += ' }\n'
+ pnext_handler += ' return skip;\n'
+ pnext_handler += '}\n'
+ write(pnext_handler, file=self.outFile)
+ self.newline()
- ext_template = 'template <typename T>\n'
- ext_template += 'bool OutputExtensionError(const T *layer_data, const std::string &api_name, const std::string &extension_name) {\n'
- ext_template += ' return log_msg(layer_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,\n'
- ext_template += ' kVUID_PVError_ExtensionNotEnabled, "Attemped to call %s() but its required extension %s has not been enabled\\n",\n'
- ext_template += ' api_name.c_str(), extension_name.c_str());\n'
- ext_template += '}\n'
- write(ext_template, file=self.outFile)
- self.newline()
- commands_text = '\n'.join(self.validation)
- write(commands_text, file=self.outFile)
- self.newline()
- # Output declarations and record intercepted procedures
- write('// Declarations', file=self.outFile)
- write('\n'.join(self.declarations), file=self.outFile)
- write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
- write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
- write('\n'.join(self.intercepts), file=self.outFile)
- write('};\n', file=self.outFile)
- self.newline()
- # Namespace
- write('} // namespace parameter_validation', file = self.outFile)
- # Finish processing in superclass
- OutputGenerator.endFile(self)
+ ext_template = 'bool StatelessValidation::OutputExtensionError(const std::string &api_name, const std::string &extension_name) {\n'
+ ext_template += ' return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,\n'
+ ext_template += ' kVUID_PVError_ExtensionNotEnabled, "Attemped to call %s() but its required extension %s has not been enabled\\n",\n'
+ ext_template += ' api_name.c_str(), extension_name.c_str());\n'
+ ext_template += '}\n'
+ write(ext_template, file=self.outFile)
+ self.newline()
+ commands_text = '\n'.join(self.validation)
+ write(commands_text, file=self.outFile)
+ self.newline()
+ if self.header_file:
+ # Output declarations and record intercepted procedures
+ write('\n'.join(self.declarations), file=self.outFile)
+ # Finish processing in superclass
+ OutputGenerator.endFile(self)
#
# Processing at beginning of each feature or extension
def beginFeature(self, interface, emit):
@@ -419,6 +432,8 @@
#
# Called at the end of each extension (feature)
def endFeature(self):
+ if self.header_file:
+ return
# C-specific
# Actually write the interface to the output file.
if (self.emit):
@@ -434,7 +449,7 @@
self.processCmdData()
# Write the declaration for the HeaderVersion
if self.headerVersion:
- write('const uint32_t GeneratedHeaderVersion = {};'.format(self.headerVersion), file=self.outFile)
+ write('const uint32_t GeneratedVulkanHeaderVersion = {};'.format(self.headerVersion), file=self.outFile)
self.newline()
# Write the declarations for the VkFlags values combining all flag bits
for flag in sorted(self.newFlags):
@@ -479,6 +494,8 @@
# type declarations. The <member> tags are just like <param> tags - they are a declaration of a struct or union member.
# Only simple member declarations are supported (no nested structs etc.)
def genStruct(self, typeinfo, typeName, alias):
+ if not self.source_file:
+ return
# alias has already been recorded in genType, above
OutputGenerator.genStruct(self, typeinfo, typeName, alias)
conditions = self.structMemberValidationConditions[typeName] if typeName in self.structMemberValidationConditions else None
@@ -544,6 +561,8 @@
# Capture group (e.g. C "enum" type) info to be used for param check code generation.
# These are concatenated together with other types.
def genGroup(self, groupinfo, groupName, alias):
+ if not self.source_file:
+ return
# record the name/alias pair
if alias is not None:
self.alias_dict[groupName]=alias
@@ -591,61 +610,51 @@
decls = self.makeCDecls(cmdinfo.elem)
typedef = decls[1]
typedef = typedef.split(')',1)[1]
- if name not in self.blacklist:
- if (self.featureExtraProtect is not None):
- self.declarations += [ '#ifdef %s' % self.featureExtraProtect ]
- self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
- if (name not in self.validate_only):
- self.func_pointers += '#ifdef %s\n' % self.featureExtraProtect
- self.typedefs += '#ifdef %s\n' % self.featureExtraProtect
- if (name not in self.validate_only):
- self.typedefs += 'typedef bool (*PFN_manual_%s)%s\n' % (name, typedef)
- self.func_pointers += ' {"%s", nullptr},\n' % name
- self.intercepts += [ ' {"%s", (void*)%s},' % (name,name) ]
- # Strip off 'vk' from API name
- self.declarations += [ '%s' % decls[0].replace("VKAPI_CALL vk", "VKAPI_CALL ") ]
- if (self.featureExtraProtect is not None):
- self.intercepts += [ '#endif' ]
- self.declarations += [ '#endif' ]
- if (name not in self.validate_only):
- self.func_pointers += '#endif\n'
- self.typedefs += '#endif\n'
- if name not in self.blacklist:
- params = cmdinfo.elem.findall('param')
- # Get list of array lengths
- lens = set()
- for param in params:
- len = self.getLen(param)
- if len:
- lens.add(len)
- # Get param info
- paramsInfo = []
- for param in params:
- paramInfo = self.getTypeNameTuple(param)
- cdecl = self.makeCParamDecl(param, 0)
- # Check for parameter name in lens set
- iscount = False
- if paramInfo[1] in lens:
- iscount = True
- paramsInfo.append(self.CommandParam(type=paramInfo[0], name=paramInfo[1],
- ispointer=self.paramIsPointer(param),
- isstaticarray=self.paramIsStaticArray(param),
- isbool=True if paramInfo[0] == 'VkBool32' else False,
- israngedenum=True if paramInfo[0] in self.enumRanges else False,
- isconst=True if 'const' in cdecl else False,
- isoptional=self.paramIsOptional(param),
- iscount=iscount,
- noautovalidity=True if param.attrib.get('noautovalidity') is not None else False,
- len=self.getLen(param),
- extstructs=None,
- condition=None,
- cdecl=cdecl))
- # Save return value information, if any
- result_type = ''
- resultinfo = cmdinfo.elem.find('proto/type')
- if (resultinfo is not None and resultinfo.text != 'void'):
- result_type = resultinfo.text
- self.commands.append(self.CommandData(name=name, params=paramsInfo, cdecl=self.makeCDecls(cmdinfo.elem)[0], extension_type=self.extension_type, result=result_type))
+ if self.header_file:
+ if name not in self.blacklist:
+ if (self.featureExtraProtect is not None):
+ self.declarations += [ '#ifdef %s' % self.featureExtraProtect ]
+ # Strip off 'vk' from API name
+ self.declarations += [ '%s%s' % ('bool PreCallValidate', decls[0].split("VKAPI_CALL vk")[1])]
+ if (self.featureExtraProtect is not None):
+ self.declarations += [ '#endif' ]
+ if self.source_file:
+ if name not in self.blacklist:
+ params = cmdinfo.elem.findall('param')
+ # Get list of array lengths
+ lens = set()
+ for param in params:
+ len = self.getLen(param)
+ if len:
+ lens.add(len)
+ # Get param info
+ paramsInfo = []
+ for param in params:
+ paramInfo = self.getTypeNameTuple(param)
+ cdecl = self.makeCParamDecl(param, 0)
+ # Check for parameter name in lens set
+ iscount = False
+ if paramInfo[1] in lens:
+ iscount = True
+ paramsInfo.append(self.CommandParam(type=paramInfo[0], name=paramInfo[1],
+ ispointer=self.paramIsPointer(param),
+ isstaticarray=self.paramIsStaticArray(param),
+ isbool=True if paramInfo[0] == 'VkBool32' else False,
+ israngedenum=True if paramInfo[0] in self.enumRanges else False,
+ isconst=True if 'const' in cdecl else False,
+ isoptional=self.paramIsOptional(param),
+ iscount=iscount,
+ noautovalidity=True if param.attrib.get('noautovalidity') is not None else False,
+ len=self.getLen(param),
+ extstructs=None,
+ condition=None,
+ cdecl=cdecl))
+ # Save return value information, if any
+ result_type = ''
+ resultinfo = cmdinfo.elem.find('proto/type')
+ if (resultinfo is not None and resultinfo.text != 'void'):
+ result_type = resultinfo.text
+ self.commands.append(self.CommandData(name=name, params=paramsInfo, cdecl=self.makeCDecls(cmdinfo.elem)[0], extension_type=self.extension_type, result=result_type))
#
# Check if the parameter passed in is a pointer
def paramIsPointer(self, param):
@@ -841,15 +850,15 @@
# This is an array with a pointer to a count value
if lenValue.ispointer:
# When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
- 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(
+ checkExpr.append('skip |= validate_struct_type_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {}, {});\n'.format(
funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, stype_vuid, param_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype, pf=prefix, **postProcSpec))
# This is an array with an integer count value
else:
- 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(
+ checkExpr.append('skip |= validate_struct_type_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {});\n'.format(
funcPrintName, lenValueRequired, valueRequired, stype_vuid, param_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype, pf=prefix, **postProcSpec))
# This is an individual struct
else:
- checkExpr.append('skip |= validate_struct_type(local_data->report_data, "{}", {ppp}"{}"{pps}, "{sv}", {}{vn}, {sv}, {}, {}, {});\n'.format(
+ checkExpr.append('skip |= validate_struct_type("{}", {ppp}"{}"{pps}, "{sv}", {}{vn}, {sv}, {}, {}, {});\n'.format(
funcPrintName, valuePrintName, prefix, valueRequired, param_vuid, stype_vuid, vn=value.name, sv=stype, vt=value.type, **postProcSpec))
return checkExpr
#
@@ -862,7 +871,7 @@
raise('Unsupported parameter validation case: Output handle array elements are not NULL checked')
else:
# This is an array with an integer count value
- checkExpr.append('skip |= validate_handle_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
+ checkExpr.append('skip |= validate_handle_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
else:
# This is assumed to be an output handle pointer
@@ -877,7 +886,7 @@
raise('Unsupported parameter validation case: array of reserved VkFlags')
else:
allFlags = 'All' + flagBitsName
- 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))
+ checkExpr.append('skip |= validate_flags_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcPrintName, lenPrintName, valuePrintName, flagBitsName, allFlags, lenValue.name, value.name, lenValueRequired, valueRequired, pf=prefix, **postProcSpec))
return checkExpr
#
# Generate pNext check string
@@ -893,7 +902,7 @@
extStructCount = 'ARRAY_SIZE({})'.format(extStructVar)
extStructNames = '"' + ', '.join(value.extstructs) + '"'
checkExpr.append('const VkStructureType {}[] = {{ {} }};\n'.format(extStructVar, ', '.join([self.structTypes[s] for s in value.extstructs])))
- checkExpr.append('skip |= validate_struct_pnext(local_data->report_data, "{}", {ppp}"{}"{pps}, {}, {}{}, {}, {}, GeneratedHeaderVersion, {});\n'.format(
+ checkExpr.append('skip |= validate_struct_pnext("{}", {ppp}"{}"{pps}, {}, {}{}, {}, {}, GeneratedVulkanHeaderVersion, {});\n'.format(
funcPrintName, valuePrintName, extStructNames, prefix, value.name, extStructCount, extStructVar, vuid, **postProcSpec))
return checkExpr
#
@@ -909,18 +918,18 @@
# If count and array parameters are optional, there will be no validation
if valueRequired == 'true' or lenPtrRequired == 'true' or lenValueRequired == 'true':
# When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
- checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {}, {});\n'.format(
+ checkExpr.append('skip |= validate_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {}, {});\n'.format(
funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
# This is an array with an integer count value
else:
# If count and array parameters are optional, there will be no validation
if valueRequired == 'true' or lenValueRequired == 'true':
if value.type != 'char':
- checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {});\n'.format(
+ checkExpr.append('skip |= validate_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {});\n'.format(
funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
else:
# Arrays of strings receive special processing
- checkExpr.append('skip |= validate_string_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format(
+ checkExpr.append('skip |= validate_string_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format(
funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
if checkExpr:
if lenValue and ('->' in lenValue.name):
@@ -939,9 +948,9 @@
vuid = allocator_dict.get(value.name)
if vuid is not None:
ptr_required_vuid = vuid
- 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))
+ checkExpr.append('skip |= validate_required_pointer("{}", {ppp}"{}"{pps}, reinterpret_cast<const void*>({}{}), {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
else:
- checkExpr.append('skip |= validate_required_pointer(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{}, {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
+ checkExpr.append('skip |= validate_required_pointer("{}", {ppp}"{}"{pps}, {}{}, {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
return checkExpr
#
# Process struct member validation code, performing name substitution if required
@@ -1119,10 +1128,10 @@
elif value.type in self.flags and value.isconst:
usedLines += self.makeFlagsArrayCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
elif value.isbool and value.isconst:
- 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))
+ usedLines.append('skip |= validate_bool32_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
elif value.israngedenum and value.isconst:
enum_value_list = 'All%sEnums' % value.type
- 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))
+ usedLines.append('skip |= validate_ranged_enum_array("{}", {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))
elif value.name == 'pNext' and value.isconst:
usedLines += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName, postProcSpec, structTypeName)
else:
@@ -1147,16 +1156,16 @@
stype = self.structTypes[value.type]
vuid = self.GetVuid(value.type, "sType-sType")
undefined_vuid = '"kVUIDUndefined"'
- usedLines.append('skip |= validate_struct_type(local_data->report_data, "{}", {ppp}"{}"{pps}, "{sv}", &({}{vn}), {sv}, false, kVUIDUndefined, {});\n'.format(
+ usedLines.append('skip |= validate_struct_type("{}", {ppp}"{}"{pps}, "{sv}", &({}{vn}), {sv}, false, kVUIDUndefined, {});\n'.format(
funcName, valueDisplayName, valuePrefix, vuid, vn=value.name, sv=stype, vt=value.type, **postProcSpec))
elif value.type in self.handleTypes:
if not self.isHandleOptional(value, None):
- usedLines.append('skip |= validate_required_handle(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
+ usedLines.append('skip |= validate_required_handle("{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
elif value.type in self.flags:
flagBitsName = value.type.replace('Flags', 'FlagBits')
if not flagBitsName in self.flagBits:
vuid = self.GetVuid(vuid_name_tag, "%s-zerobitmask" % (value.name))
- usedLines.append('skip |= validate_reserved_flags(local_data->report_data, "{}", {ppp}"{}"{pps}, {pf}{}, {});\n'.format(funcName, valueDisplayName, value.name, vuid, pf=valuePrefix, **postProcSpec))
+ usedLines.append('skip |= validate_reserved_flags("{}", {ppp}"{}"{pps}, {pf}{}, {});\n'.format(funcName, valueDisplayName, value.name, vuid, pf=valuePrefix, **postProcSpec))
else:
if value.isoptional:
flagsRequired = 'false'
@@ -1165,18 +1174,18 @@
flagsRequired = 'true'
vuid = self.GetVuid(vuid_name_tag, "%s-requiredbitmask" % (value.name))
allFlagsName = 'All' + flagBitsName
- 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))
+ usedLines.append('skip |= validate_flags("{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, false, {});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
elif value.type in self.flagBits:
flagsRequired = 'false' if value.isoptional else 'true'
allFlagsName = 'All' + value.type
vuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name))
- 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))
+ usedLines.append('skip |= validate_flags("{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, true, {});\n'.format(funcName, valueDisplayName, value.type, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
elif value.isbool:
- usedLines.append('skip |= validate_bool32(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
+ usedLines.append('skip |= validate_bool32("{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
elif value.israngedenum:
vuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name))
enum_value_list = 'All%sEnums' % value.type
- 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))
+ usedLines.append('skip |= validate_ranged_enum("{}", {ppp}"{}"{pps}, "{}", {}, {}{}, {});\n'.format(funcName, valueDisplayName, value.type, enum_value_list, valuePrefix, value.name, vuid, **postProcSpec))
# If this is a struct, see if it contains members that need to be checked
if value.type in self.validatedStructs:
memberNamePrefix = '{}{}.'.format(valuePrefix, value.name)
@@ -1210,15 +1219,16 @@
def processCmdData(self):
indent = self.incIndent(None)
for command in self.commands:
- just_validate = False
- if command.name in self.validate_only:
- just_validate = True
# Skip first parameter if it is a dispatch handle (everything except vkCreateInstance)
startIndex = 0 if command.name == 'vkCreateInstance' else 1
lines, unused = self.genFuncBody(command.name, command.params[startIndex:], '', '', None)
# Cannot validate extension dependencies for device extension APIs having a physical device as their dispatchable object
if (command.name in self.required_extensions) and (self.extension_type != 'device' or command.params[0].type != 'VkPhysicalDevice'):
ext_test = ''
+ if command.params[0].type in ["VkInstance", "VkPhysicalDevice"] or command.name == 'vkCreateInstance':
+ ext_table_type = 'instance'
+ else:
+ ext_table_type = 'device'
for ext in self.required_extensions[command.name]:
ext_name_define = ''
ext_enable_name = ''
@@ -1228,77 +1238,27 @@
ext_enable_name = ext_name_define.lower()
ext_enable_name = re.sub('_extension_name', '', ext_enable_name)
break
- ext_test = 'if (!local_data->extensions.%s) skip |= OutputExtensionError(local_data, "%s", %s);\n' % (ext_enable_name, command.name, ext_name_define)
+ ext_test = 'if (!%s_extensions.%s) skip |= OutputExtensionError("%s", %s);\n' % (ext_table_type, ext_enable_name, command.name, ext_name_define)
lines.insert(0, ext_test)
if lines:
- cmdDef = self.getCmdDef(command) + '\n'
- # For a validation-only routine, change the function declaration
- if just_validate:
- jv_def = '// Generated function handles validation only -- API definition is in non-generated source\n'
- jv_def += 'extern %s\n\n' % command.cdecl
- cmdDef = 'bool parameter_validation_' + cmdDef.split('VKAPI_CALL ',1)[1]
- if command.name == 'vkCreateInstance':
- cmdDef = cmdDef.replace('(\n', '(\n VkInstance instance,\n')
- cmdDef = jv_def + cmdDef
- cmdDef += '{\n'
-
- # Add list of commands to skip -- just generate the routine signature and put the manual source in parameter_validation_utils.cpp
- if command.params[0].type in ["VkInstance", "VkPhysicalDevice"] or command.name == 'vkCreateInstance':
- map_name = 'instance_layer_data_map'
- map_type = 'instance_layer_data'
- else:
- map_name = 'layer_data_map'
- map_type = 'layer_data'
- instance_param = command.params[0].name
- if command.name == 'vkCreateInstance':
- instance_param = 'instance'
- layer_data = ' %s *local_data = GetLayerDataPtr(get_dispatch_key(%s), %s);\n' % (map_type, instance_param, map_name)
- cmdDef += layer_data
+ func_sig = self.getCmdDef(command) + ' {\n'
+ func_sig = func_sig.split('VKAPI_CALL vk')[1]
+ cmdDef = 'bool StatelessValidation::PreCallValidate' + func_sig
cmdDef += '%sbool skip = false;\n' % indent
- if not just_validate:
- if command.result != '':
- if command.result == "VkResult":
- cmdDef += indent + '%s result = VK_ERROR_VALIDATION_FAILED_EXT;\n' % command.result
- elif command.result == "VkBool32":
- cmdDef += indent + '%s result = VK_FALSE;\n' % command.result
- else:
- raise Exception("Unknown result type: " + command.result)
-
- cmdDef += '%sstd::unique_lock<std::mutex> lock(global_lock);\n' % indent
+ # Insert call to custom-written function if present
+ if command.name in self.functions_with_manual_checks:
+ # Generate parameter list for manual fcn and down-chain calls
+ params_text = ''
+ for param in command.params:
+ params_text += '%s, ' % param.name
+ params_text = params_text[:-2] + ');\n'
+ cmdDef += ' skip |= manual_PreCallValidate'+ command.name[2:] + '(' + params_text
for line in lines:
- cmdDef += '\n'
if type(line) is list:
for sub in line:
cmdDef += indent + sub
else:
cmdDef += indent + line
- cmdDef += '\n'
- if not just_validate:
- # Generate parameter list for manual fcn and down-chain calls
- params_text = ''
- for param in command.params:
- params_text += '%s, ' % param.name
- params_text = params_text[:-2]
- # Generate call to manual function if its function pointer is non-null
- cmdDef += '%sPFN_manual_%s custom_func = (PFN_manual_%s)custom_functions["%s"];\n' % (indent, command.name, command.name, command.name)
- cmdDef += '%sif (custom_func != nullptr) {\n' % indent
- cmdDef += ' %sskip |= custom_func(%s);\n' % (indent, params_text)
- cmdDef += '%s}\n\n' % indent
- # Release the validation lock
- cmdDef += '%slock.unlock();\n' % indent
- # Generate skip check and down-chain call
- cmdDef += '%sif (!skip) {\n' % indent
- down_chain_call = ' %s' % indent
- if command.result != '':
- down_chain_call += ' result = '
- # Generate down-chain API call
- api_call = '%s(%s);' % (command.name, params_text)
- down_chain_call += 'local_data->dispatch_table.%s\n' % api_call[2:]
- cmdDef += down_chain_call
- cmdDef += '%s}\n' % indent
- if command.result != '':
- cmdDef += '%sreturn result;\n' % indent
- else:
- cmdDef += '%sreturn skip;\n' % indent
+ cmdDef += '%sreturn skip;\n' % indent
cmdDef += '}\n'
self.validation.append(cmdDef)