From 4f7fe373328c9406410df11098593f27f0ed6f5e Mon Sep 17 00:00:00 2001 From: Dustin Graves Date: Mon, 16 May 2016 11:07:59 -0600 Subject: layers: Ignore 'noautovalidity' params w/codgen Add special handling to the parameter_validation layer's code generator for vk.xml parameters with the 'noautovalidty' attribute: - Ignore vk.xml parameters with the 'noautovalidity' attribute when generating code for the parameter_validation layer. - Implement custom validation routines for parameters with 'noautovalidity' tags. Issues-Addressed: GitHub 515 Change-Id: I1bd28cc79233fb8b040d6e107ed5e2176a84edb5 --- generator.py | 110 +++++---- layers/parameter_validation.cpp | 523 ++++++++++++++++++++++++++++++++++------ 2 files changed, 513 insertions(+), 120 deletions(-) diff --git a/generator.py b/generator.py index d9301dfa..eead2119 100644 --- a/generator.py +++ b/generator.py @@ -2863,7 +2863,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): self.structMembers = [] # List of StructMemberData records for all Vulkan structs 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.flags = dict() # Map of flags typenames to a Boolean value indicating that validation code is generated for a value of this type + self.flags = set() # Map of flags typenames self.flagBits = dict() # Map of flag bits typename to list of values # Named tuples to store struct and command data self.StructType = namedtuple('StructType', ['name', 'value']) @@ -2943,7 +2943,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): self.structMembers = [] self.validatedStructs = dict() self.enumRanges = dict() - self.flags = dict() + self.flags = set() self.flagBits = dict() def endFeature(self): # C-specific @@ -2961,8 +2961,8 @@ class ParamCheckerOutputGenerator(OutputGenerator): self.processCmdData() # Write the declarations for the VkFlags values combining all flag bits for flag in sorted(self.flags): - if self.flags[flag]: - flagBits = flag.replace('Flags', 'FlagBits') + flagBits = flag.replace('Flags', 'FlagBits') + if flagBits in self.flagBits: bits = self.flagBits[flagBits] decl = 'const {} All{} = {}'.format(flag, flagBits, bits[0]) for bit in bits[1:]: @@ -3001,7 +3001,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): elif (category == 'handle'): self.handleTypes.add(name) elif (category == 'bitmask'): - self.flags[name] = False + self.flags.add(name) # # Struct parameter check generation. # This is a special case of the tag where the contents are @@ -3212,7 +3212,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): value = self.structTypes[typename].value else: value = self.genVkStructureType(typename) - #print('Generating {} for {} structure type that was not defined by the current feature'.format(value, typename)) + self.logMsg('diag', 'ParameterValidation: Generating {} for {} structure type that was not defined by the current feature'.format(value, typename)) return value # # Retrieve the value of the len tag @@ -3388,7 +3388,6 @@ class ParamCheckerOutputGenerator(OutputGenerator): else: allFlags = 'All' + flagBitsName checkExpr.append('skipCall |= validate_flags_array(report_data, "{}", "{}", "{}", "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcPrintName, lenPrintName, valuePrintName, flagBitsName, allFlags, lenValue.name, value.name, lenValueRequired, valueRequired, pf=prefix)) - self.flags[value.type] = True return checkExpr # # Generate pNext check string @@ -3530,56 +3529,73 @@ class ParamCheckerOutputGenerator(OutputGenerator): if lenParam.isoptional: cvReq = 'false' # - # If this is a pointer to a struct with an sType field, verify the type - if value.type in self.structTypes: - usedLines += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName) - # 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 - elif value.type in self.handleTypes and value.isconst and not self.isHandleOptional(value, lenParam): - usedLines += self.makeHandleCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName) - elif value.type in self.flags and value.isconst: - usedLines += self.makeFlagsArrayCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName) - elif value.isbool and value.isconst: - usedLines.append('skipCall |= validate_bool32_array(report_data, "{}", "{}", "{}", {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix)) - elif value.israngedenum and value.isconst: - enumRange = self.enumRanges[value.type] - usedLines.append('skipCall |= validate_ranged_enum_array(report_data, "{}", "{}", "{}", "{}", {}, {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, value.type, enumRange[0], enumRange[1], lenParam.name, value.name, cvReq, req, pf=valuePrefix)) - elif value.name == 'pNext': - # We need to ignore VkDeviceCreateInfo and VkInstanceCreateInfo, as the loader manipulates them in a way that is not documented in vk.xml - if not structTypeName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']: - usedLines += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName) + # The parameter will not be processes when tagged as 'noautovalidity' + # For the pointer to struct case, the struct pointer will not be validated, but any + # members not tagged as 'noatuvalidity' will be validated + if value.noautovalidity: + # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually + self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name)) else: - usedLines += self.makePointerCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName) + # + # If this is a pointer to a struct with an sType field, verify the type + if value.type in self.structTypes: + usedLines += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName) + # 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 + elif value.type in self.handleTypes and value.isconst and not self.isHandleOptional(value, lenParam): + usedLines += self.makeHandleCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName) + elif value.type in self.flags and value.isconst: + usedLines += self.makeFlagsArrayCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName) + elif value.isbool and value.isconst: + usedLines.append('skipCall |= validate_bool32_array(report_data, "{}", "{}", "{}", {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix)) + elif value.israngedenum and value.isconst: + enumRange = self.enumRanges[value.type] + usedLines.append('skipCall |= validate_ranged_enum_array(report_data, "{}", "{}", "{}", "{}", {}, {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, value.type, enumRange[0], enumRange[1], lenParam.name, value.name, cvReq, req, pf=valuePrefix)) + elif value.name == 'pNext': + # We need to ignore VkDeviceCreateInfo and VkInstanceCreateInfo, as the loader manipulates them in a way that is not documented in vk.xml + if not structTypeName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']: + usedLines += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName) + else: + usedLines += self.makePointerCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName) # # If this is a pointer to a struct (input), see if it contains members that need to be checked if value.type in self.validatedStructs and value.isconst: usedLines.append(self.expandStructPointerCode(valuePrefix, value, lenParam, funcName, valueDisplayName)) # Non-pointer types - elif (value.type in self.structTypes) or (value.type in self.validatedStructs): - if value.type in self.structTypes: - stype = self.structTypes[value.type] - usedLines.append('skipCall |= validate_struct_type(report_data, "{}", "{}", "{sv}", &({}{vn}), {sv}, false);\n'.format( - funcName, valueDisplayName, valuePrefix, vn=value.name, sv=stype.value)) + else: + # + # The parameter will not be processes when tagged as 'noautovalidity' + # For the struct case, the struct type will not be validated, but any + # members not tagged as 'noatuvalidity' will be validated + if value.noautovalidity: + # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually + self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name)) + else: + if value.type in self.structTypes: + stype = self.structTypes[value.type] + usedLines.append('skipCall |= validate_struct_type(report_data, "{}", "{}", "{sv}", &({}{vn}), {sv}, false);\n'.format( + funcName, valueDisplayName, valuePrefix, vn=value.name, sv=stype.value)) + elif value.type in self.handleTypes: + if not self.isHandleOptional(value, None): + usedLines.append('skipCall |= validate_required_handle(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name)) + elif value.type in self.flags: + flagBitsName = value.type.replace('Flags', 'FlagBits') + if not flagBitsName in self.flagBits: + usedLines.append('skipCall |= validate_reserved_flags(report_data, "{}", "{}", {pf}{});\n'.format(funcName, valueDisplayName, value.name, pf=valuePrefix)) + else: + flagsRequired = 'false' if value.isoptional else 'true' + allFlagsName = 'All' + flagBitsName + usedLines.append('skipCall |= validate_flags(report_data, "{}", "{}", "{}", {}, {pf}{}, {});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsRequired, pf=valuePrefix)) + elif value.isbool: + usedLines.append('skipCall |= validate_bool32(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name)) + elif value.israngedenum: + enumRange = self.enumRanges[value.type] + usedLines.append('skipCall |= validate_ranged_enum(report_data, "{}", "{}", "{}", {}, {}, {}{});\n'.format(funcName, valueDisplayName, value.type, enumRange[0], enumRange[1], valuePrefix, value.name)) + # + # If this is a pointer to a struct (input), see if it contains members that need to be checked if value.type in self.validatedStructs: memberNamePrefix = '{}{}.'.format(valuePrefix, value.name) memberDisplayNamePrefix = '{}.'.format(valueDisplayName) usedLines.append(self.expandStructCode(self.validatedStructs[value.type], funcName, memberNamePrefix, memberDisplayNamePrefix, '', [])) - elif value.type in self.handleTypes: - if not self.isHandleOptional(value, None): - usedLines.append('skipCall |= validate_required_handle(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name)) - elif value.type in self.flags: - flagBitsName = value.type.replace('Flags', 'FlagBits') - if not flagBitsName in self.flagBits: - usedLines.append('skipCall |= validate_reserved_flags(report_data, "{}", "{}", {pf}{});\n'.format(funcName, valueDisplayName, value.name, pf=valuePrefix)) - else: - flagsRequired = 'false' if value.isoptional else 'true' - allFlagsName = 'All' + flagBitsName - usedLines.append('skipCall |= validate_flags(report_data, "{}", "{}", "{}", {}, {pf}{}, {});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsRequired, pf=valuePrefix)) - self.flags[value.type] = True - elif value.isbool: - usedLines.append('skipCall |= validate_bool32(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name)) - elif value.israngedenum: - enumRange = self.enumRanges[value.type] - usedLines.append('skipCall |= validate_ranged_enum(report_data, "{}", "{}", "{}", {}, {}, {}{});\n'.format(funcName, valueDisplayName, value.type, enumRange[0], enumRange[1], valuePrefix, value.name)) # # Append the parameter check to the function body for the current command if usedLines: diff --git a/layers/parameter_validation.cpp b/layers/parameter_validation.cpp index 20676b4a..035b9290 100644 --- a/layers/parameter_validation.cpp +++ b/layers/parameter_validation.cpp @@ -2237,16 +2237,31 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent(VkDevice device, VkE VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != nullptr); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkCreateQueryPool(my_data->report_data, pCreateInfo, pAllocator, pQueryPool); + skip_call |= parameter_validation_vkCreateQueryPool(device_data->report_data, pCreateInfo, pAllocator, pQueryPool); - if (!skipCall) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + if (pCreateInfo != nullptr) { + // If queryType is VK_QUERY_TYPE_PIPELINE_STATISTICS, pipelineStatistics must be a valid combination of + // VkQueryPipelineStatisticFlagBits values + if ((pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) && (pCreateInfo->pipelineStatistics != 0) && + ((pCreateInfo->pipelineStatistics & (~AllVkQueryPipelineStatisticFlagBits)) != 0)) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, + UNRECOGNIZED_VALUE, LayerName, "vkCreateQueryPool: if pCreateInfo->queryType is " + "VK_QUERY_TYPE_PIPELINE_STATISTICS, pCreateInfo->pipelineStatistics must be " + "a valid combination of VkQueryPipelineStatisticFlagBits values"); + } + } + + if (!skip_call) { result = get_dispatch_table(pc_device_table_map, device)->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool); - validate_result(my_data->report_data, "vkCreateQueryPool", result); + validate_result(report_data, "vkCreateQueryPool", result); } return result; @@ -2286,32 +2301,47 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(VkDevice de return result; } -bool PreCreateBuffer(layer_data *device_data, const VkBufferCreateInfo *pCreateInfo) { - if (pCreateInfo != nullptr) { - if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) { - validate_queue_family_indices(device_data, "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices", - pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices); - } - } - - return true; -} - VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != nullptr); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkCreateBuffer(my_data->report_data, pCreateInfo, pAllocator, pBuffer); + skip_call |= parameter_validation_vkCreateBuffer(report_data, pCreateInfo, pAllocator, pBuffer); - if (!skipCall) { - PreCreateBuffer(my_data, pCreateInfo); + if (pCreateInfo != nullptr) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) { + // If sharingMode is VK_SHARING_MODE_CONCURRENT, queueFamilyIndexCount must be greater than 1 + if (pCreateInfo->queueFamilyIndexCount <= 1) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, + INVALID_USAGE, LayerName, "vkCreateBuffer: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, " + "pCreateInfo->queueFamilyIndexCount must be greater than 1"); + } + // If sharingMode is VK_SHARING_MODE_CONCURRENT, pQueueFamilyIndices must be a pointer to an array of + // queueFamilyIndexCount uint32_t values + if (pCreateInfo->pQueueFamilyIndices == nullptr) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkCreateBuffer: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, " + "pCreateInfo->pQueueFamilyIndices must be a pointer to an array of " + "pCreateInfo->queueFamilyIndexCount uint32_t values"); + } + + // Ensure that the queue family indices were specified at device creation + skip_call |= validate_queue_family_indices(device_data, "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices", + pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices); + } + } + + if (!skip_call) { result = get_dispatch_table(pc_device_table_map, device)->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer); - validate_result(my_data->report_data, "vkCreateBuffer", result); + validate_result(report_data, "vkCreateBuffer", result); } return result; @@ -2366,20 +2396,31 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, co VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; bool skip_call = false; layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(device_data != NULL); + assert(device_data != nullptr); debug_report_data *report_data = device_data->report_data; skip_call |= parameter_validation_vkCreateImage(report_data, pCreateInfo, pAllocator, pImage); if (pCreateInfo != nullptr) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) { - // pQueueFamilyIndices must not be NULL - skip_call |= validate_required_pointer(report_data, "vkCreateImage", "pCreateInfo->pQueueFamilyIndices", - pCreateInfo->pQueueFamilyIndices); + // If sharingMode is VK_SHARING_MODE_CONCURRENT, queueFamilyIndexCount must be greater than 1 + if (pCreateInfo->queueFamilyIndexCount <= 1) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, + INVALID_USAGE, LayerName, "vkCreateImage: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, " + "pCreateInfo->queueFamilyIndexCount must be greater than 1"); + } - // queueFamilyIndexCount must be greater than 1 - skip_call |= ValidateGreaterThan(report_data, "vkCreateImage", "pCreateInfo->pQueueFamilyIndices", - pCreateInfo->queueFamilyIndexCount, 1u); + // If sharingMode is VK_SHARING_MODE_CONCURRENT, pQueueFamilyIndices must be a pointer to an array of + // queueFamilyIndexCount uint32_t values + if (pCreateInfo->pQueueFamilyIndices == nullptr) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkCreateImage: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, " + "pCreateInfo->pQueueFamilyIndices must be a pointer to an array of " + "pCreateInfo->queueFamilyIndexCount uint32_t values"); + } skip_call |= validate_queue_family_indices(device_data, "vkCreateImage", "pCreateInfo->pQueueFamilyIndices", pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices); @@ -2730,20 +2771,185 @@ vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32 const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != nullptr); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkCreateGraphicsPipelines(my_data->report_data, pipelineCache, createInfoCount, pCreateInfos, - pAllocator, pPipelines); + skip_call |= parameter_validation_vkCreateGraphicsPipelines(report_data, pipelineCache, createInfoCount, pCreateInfos, + pAllocator, pPipelines); - if (!skipCall) { + if (pCreateInfos != nullptr) { + for (uint32_t i = 0; i < createInfoCount; ++i) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + if (pCreateInfos[i].pTessellationState == nullptr) { + if (pCreateInfos[i].pStages != nullptr) { + // If pStages includes a tessellation control shader stage and a tessellation evaluation shader stage, + // pTessellationState must not be NULL + bool has_control = false; + bool has_eval = false; + + for (uint32_t stage_index = 0; stage_index < pCreateInfos[i].stageCount; ++stage_index) { + if (pCreateInfos[i].pStages[stage_index].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) { + has_control = true; + } else if (pCreateInfos[i].pStages[stage_index].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { + has_eval = true; + } + } + + if (has_control && has_eval) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkCreateGraphicsPipelines: if pCreateInfos[%d].pStages includes a tessellation " + "control shader stage and a tessellation evaluation shader stage, " + "pCreateInfos[%d].pTessellationState must not be NULL", + i, i); + } + } + } else if (pCreateInfos[i].pTessellationState->sType != VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, INVALID_STRUCT_STYPE, LayerName, + "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pTessellationState->sType must be " + "VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO", + i); + } + + if (pCreateInfos[i].pViewportState == nullptr) { + // If the rasterizerDiscardEnable member of pRasterizationState is VK_FALSE, pViewportState must be a pointer to a + // valid VkPipelineViewportStateCreateInfo structure + if ((pCreateInfos[i].pRasterizationState != nullptr) && + (pCreateInfos[i].pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) { + skip_call |= log_msg( + report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, + REQUIRED_PARAMETER, LayerName, + "vkCreateGraphicsPipelines: if pCreateInfos[%d].pRasterizationState->rasterizerDiscardEnable is VK_FALSE, " + "pCreateInfos[%d].pViewportState must be a pointer to a valid VkPipelineViewportStateCreateInfo structure", + i, i); + } + } else { + if (pCreateInfos[i].pViewportState->sType != VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, INVALID_STRUCT_STYPE, LayerName, + "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pViewportState->sType must be " + "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO", + i); + } + + if (pCreateInfos[i].pDynamicState != nullptr) { + bool has_dynamic_viewport = false; + bool has_dynamic_scissor = false; + + for (uint32_t state_index = 0; state_index < pCreateInfos[i].pDynamicState->dynamicStateCount; ++state_index) { + if (pCreateInfos[i].pDynamicState->pDynamicStates[state_index] == VK_DYNAMIC_STATE_VIEWPORT) { + has_dynamic_viewport = true; + } else if (pCreateInfos[i].pDynamicState->pDynamicStates[state_index] == VK_DYNAMIC_STATE_SCISSOR) { + has_dynamic_scissor = true; + } + } + + // viewportCount must be greater than 0 + // TODO: viewportCount must be 1 when multiple_viewport feature is not enabled + if (pCreateInfos[i].pViewportState->viewportCount == 0) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates " + "contains VK_DYNAMIC_STATE_VIEWPORT, pCreateInfos[%d].pViewportState->viewportCount " + "must be greater than 0", + i, i); + } + + // If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_VIEWPORT, the pViewports + // member of pViewportState must be a pointer to an array of pViewportState->viewportCount VkViewport structures + if (!has_dynamic_viewport && (pCreateInfos[i].pViewportState->pViewports == nullptr)) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates contains " + "VK_DYNAMIC_STATE_VIEWPORT, pCreateInfos[%d].pViewportState->pViewports must not be NULL", + i, i); + } + + // scissorCount must be greater than 0 + // TODO: scissorCount must be 1 when multiple_viewport feature is not enabled + if (pCreateInfos[i].pViewportState->scissorCount == 0) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates " + "contains VK_DYNAMIC_STATE_SCISSOR, pCreateInfos[%d].pViewportState->scissorCount " + "must be greater than 0", + i, i); + } + + // If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_SCISSOR, the pScissors member + // of pViewportState must be a pointer to an array of pViewportState->scissorCount VkRect2D structures + if (!has_dynamic_scissor && (pCreateInfos[i].pViewportState->pScissors == nullptr)) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates contains " + "VK_DYNAMIC_STATE_SCISSOR, pCreateInfos[%d].pViewportState->pScissors must not be NULL", + i, i); + } + } + } + + if (pCreateInfos[i].pMultisampleState == nullptr) { + // If the rasterizerDiscardEnable member of pRasterizationState is VK_FALSE, pMultisampleState must be a pointer to + // a valid VkPipelineMultisampleStateCreateInfo structure + if ((pCreateInfos[i].pRasterizationState != nullptr) && + pCreateInfos[i].pRasterizationState->rasterizerDiscardEnable == VK_FALSE) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, + REQUIRED_PARAMETER, LayerName, "vkCreateGraphicsPipelines: if " + "pCreateInfos[%d].pRasterizationState->rasterizerDiscardEnable is " + "VK_FALSE, pCreateInfos[%d].pMultisampleState must not be NULL", + i, i); + } + } else if (pCreateInfos[i].pMultisampleState->sType != VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, INVALID_STRUCT_STYPE, LayerName, + "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pMultisampleState->sType must be " + "VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO", + i); + } + + // TODO: Conditional NULL check based on rasterizerDiscardEnable and subpass + if ((pCreateInfos[i].pDepthStencilState != nullptr) && + (pCreateInfos[i].pDepthStencilState->sType != VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO)) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, INVALID_STRUCT_STYPE, LayerName, + "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pDepthStencilState->sType must be " + "VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO", + i); + } + + // TODO: Conditional NULL check based on rasterizerDiscardEnable and subpass + if (pCreateInfos[i].pColorBlendState != nullptr) { + if (pCreateInfos[i].pColorBlendState->sType != VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, INVALID_STRUCT_STYPE, LayerName, + "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pColorBlendState->sType must be " + "VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO", + i); + } + + // If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value + if (pCreateInfos[i].pColorBlendState->logicOpEnable == VK_TRUE) { + skip_call |= validate_ranged_enum( + report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pColorBlendState->logicOp", "VkLogicOp", + VK_LOGIC_OP_BEGIN_RANGE, VK_LOGIC_OP_END_RANGE, pCreateInfos[i].pColorBlendState->logicOp); + } + } + } + } + + if (!skip_call) { PreCreateGraphicsPipelines(device, pCreateInfos); result = get_dispatch_table(pc_device_table_map, device) ->CreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); - validate_result(my_data->report_data, "vkCreateGraphicsPipelines", result); + validate_result(report_data, "vkCreateGraphicsPipelines", result); } return result; @@ -2834,16 +3040,35 @@ vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != NULL); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkCreateSampler(my_data->report_data, pCreateInfo, pAllocator, pSampler); + skip_call |= parameter_validation_vkCreateSampler(report_data, pCreateInfo, pAllocator, pSampler); - if (!skipCall) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + if (pCreateInfo != nullptr) { + // If compareEnable is VK_TRUE, compareOp must be a valid VkCompareOp value + if (pCreateInfo->compareEnable == VK_TRUE) { + skip_call |= validate_ranged_enum(report_data, "vkCreateSampler", "pCreateInfo->compareOp", "VkCompareOp", + VK_COMPARE_OP_BEGIN_RANGE, VK_COMPARE_OP_END_RANGE, pCreateInfo->compareOp); + } + + // If any of addressModeU, addressModeV or addressModeW are VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, borderColor must be a + // valid VkBorderColor value + if ((pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) || + (pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) || + (pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)) { + skip_call |= validate_ranged_enum(report_data, "vkCreateSampler", "pCreateInfo->borderColor", "VkBorderColor", + VK_BORDER_COLOR_BEGIN_RANGE, VK_BORDER_COLOR_END_RANGE, pCreateInfo->borderColor); + } + } + + if (!skip_call) { result = get_dispatch_table(pc_device_table_map, device)->CreateSampler(device, pCreateInfo, pAllocator, pSampler); - validate_result(my_data->report_data, "vkCreateSampler", result); + validate_result(report_data, "vkCreateSampler", result); } return result; @@ -2866,17 +3091,55 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != nullptr); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkCreateDescriptorSetLayout(my_data->report_data, pCreateInfo, pAllocator, pSetLayout); + skip_call |= parameter_validation_vkCreateDescriptorSetLayout(report_data, pCreateInfo, pAllocator, pSetLayout); + + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + if ((pCreateInfo != nullptr) && (pCreateInfo->pBindings != nullptr)) { + for (uint32_t i = 0; i < pCreateInfo->bindingCount; ++i) { + if (pCreateInfo->pBindings[i].descriptorCount != 0) { + // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and descriptorCount + // is not 0 and pImmutableSamplers is not NULL, pImmutableSamplers must be a pointer to an array of descriptorCount + // valid VkSampler handles + if (((pCreateInfo->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) || + (pCreateInfo->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) && + (pCreateInfo->pBindings[i].pImmutableSamplers != nullptr)) { + for (uint32_t descriptor_index = 0; descriptor_index < pCreateInfo->pBindings[i].descriptorCount; + ++descriptor_index) { + if (pCreateInfo->pBindings[i].pImmutableSamplers[descriptor_index] == VK_NULL_HANDLE) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, "vkCreateDescriptorSetLayout: required parameter " + "pCreateInfo->pBindings[%d].pImmutableSamplers[%d]" + " specified as VK_NULL_HANDLE", + i, descriptor_index); + } + } + } - if (!skipCall) { + // If descriptorCount is not 0, stageFlags must be a valid combination of VkShaderStageFlagBits values + if ((pCreateInfo->pBindings[i].stageFlags != 0) && + ((pCreateInfo->pBindings[i].stageFlags & (~AllVkShaderStageFlagBits)) != 0)) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, + UNRECOGNIZED_VALUE, LayerName, + "vkCreateDescriptorSetLayout: if pCreateInfo->pBindings[%d].descriptorCount is not 0, " + "pCreateInfo->pBindings[%d].stageFlags must be a valid combination of VkShaderStageFlagBits values", + i, i); + } + } + } + } + + if (!skip_call) { result = get_dispatch_table(pc_device_table_map, device)->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout); - validate_result(my_data->report_data, "vkCreateDescriptorSetLayout", result); + validate_result(report_data, "vkCreateDescriptorSetLayout", result); } return result; @@ -2970,17 +3233,24 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets(VkDevice dev uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != nullptr); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkFreeDescriptorSets(my_data->report_data, descriptorPool, descriptorSetCount, pDescriptorSets); + skip_call |= parameter_validation_vkFreeDescriptorSets(report_data, descriptorPool, descriptorSetCount, pDescriptorSets); - if (!skipCall) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + // This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond + // validate_array() + skip_call |= validate_array(report_data, "vkFreeDescriptorSets", "descriptorSetCount", "pDescriptorSets", descriptorSetCount, + pDescriptorSets, true, true); + + if (!skip_call) { result = get_dispatch_table(pc_device_table_map, device) ->FreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets); - validate_result(my_data->report_data, "vkFreeDescriptorSets", result); + validate_result(report_data, "vkFreeDescriptorSets", result); } return result; @@ -2989,14 +3259,96 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets(VkDevice dev VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) { - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != NULL); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkUpdateDescriptorSets(my_data->report_data, descriptorWriteCount, pDescriptorWrites, - descriptorCopyCount, pDescriptorCopies); + skip_call |= parameter_validation_vkUpdateDescriptorSets(report_data, descriptorWriteCount, pDescriptorWrites, + descriptorCopyCount, pDescriptorCopies); - if (!skipCall) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + if (pDescriptorWrites != NULL) { + for (uint32_t i = 0; i < descriptorWriteCount; ++i) { + // descriptorCount must be greater than 0 + if (pDescriptorWrites[i].descriptorCount == 0) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, + REQUIRED_PARAMETER, LayerName, + "vkUpdateDescriptorSets: parameter pDescriptorWrites[%d].descriptorCount must be greater than 0", i); + } + + if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) { + // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + // VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE or VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + // pImageInfo must be a pointer to an array of descriptorCount valid VkDescriptorImageInfo structures + if (pDescriptorWrites[i].pImageInfo == nullptr) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkUpdateDescriptorSets: if pDescriptorWrites[%d].descriptorType is " + "VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, " + "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE or " + "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, pDescriptorWrites[%d].pImageInfo must not be NULL", + i, i); + } else if (pDescriptorWrites[i].descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) { + // If descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + // VK_DESCRIPTOR_TYPE_STORAGE_IMAGE or VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, the imageView and imageLayout + // members of any given element of pImageInfo must be a valid VkImageView and VkImageLayout, respectively + for (uint32_t descriptor_index = 0; descriptor_index < pDescriptorWrites[i].descriptorCount; + ++descriptor_index) { + skip_call |= validate_required_handle(report_data, "vkUpdateDescriptorSets", + "pDescriptorWrites[i].pImageInfo[i].imageView", + pDescriptorWrites[i].pImageInfo[descriptor_index].imageView); + skip_call |= validate_ranged_enum(report_data, "vkUpdateDescriptorSets", + "pDescriptorWrites[i].pImageInfo[i].imageLayout", "VkImageLayout", + VK_IMAGE_LAYOUT_BEGIN_RANGE, VK_IMAGE_LAYOUT_END_RANGE, + pDescriptorWrites[i].pImageInfo[descriptor_index].imageLayout); + } + } + } else if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) { + // If descriptorType is VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, pBufferInfo must be a + // pointer to an array of descriptorCount valid VkDescriptorBufferInfo structures + if (pDescriptorWrites[i].pBufferInfo == nullptr) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkUpdateDescriptorSets: if pDescriptorWrites[%d].descriptorType is " + "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, " + "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, " + "pDescriptorWrites[%d].pBufferInfo must not be NULL", + i, i); + } + } else if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) || + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)) { + // If descriptorType is VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, + // pTexelBufferView must be a pointer to an array of descriptorCount valid VkBufferView handles + if (pDescriptorWrites[i].pTexelBufferView == nullptr) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + __LINE__, REQUIRED_PARAMETER, LayerName, + "vkUpdateDescriptorSets: if pDescriptorWrites[%d].descriptorType is " + "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, " + "pDescriptorWrites[%d].pTexelBufferView must not be NULL", + i, i); + } else { + for (uint32_t descriptor_index = 0; descriptor_index < pDescriptorWrites[i].descriptorCount; + ++descriptor_index) { + skip_call |= validate_required_handle(report_data, "vkUpdateDescriptorSets", + "pDescriptorWrites[i].pTexelBufferView[i]", + pDescriptorWrites[i].pTexelBufferView[descriptor_index]); + } + } + } + } + } + + if (!skip_call) { get_dispatch_table(pc_device_table_map, device) ->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); } @@ -3153,13 +3505,20 @@ vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAl VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) { - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(device_data != nullptr); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkFreeCommandBuffers(my_data->report_data, commandPool, commandBufferCount, pCommandBuffers); + skip_call |= parameter_validation_vkFreeCommandBuffers(report_data, commandPool, commandBufferCount, pCommandBuffers); - if (!skipCall) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + // This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond + // validate_array() + skip_call |= validate_array(report_data, "vkFreeCommandBuffers", "commandBufferCount", "pCommandBuffers", commandBufferCount, + pCommandBuffers, true, true); + + if (!skip_call) { get_dispatch_table(pc_device_table_map, device) ->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers); } @@ -3168,16 +3527,34 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool skipCall = false; - layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - assert(my_data != NULL); + bool skip_call = false; + layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(device_data != nullptr); + debug_report_data *report_data = device_data->report_data; - skipCall |= parameter_validation_vkBeginCommandBuffer(my_data->report_data, pBeginInfo); + skip_call |= parameter_validation_vkBeginCommandBuffer(report_data, pBeginInfo); - if (!skipCall) { + // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml + // TODO: pBeginInfo->pInheritanceInfo must not be NULL if commandBuffer is a secondary command buffer + skip_call |= validate_struct_type(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo", + "VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO", pBeginInfo->pInheritanceInfo, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, false); + + if (pBeginInfo->pInheritanceInfo != NULL) { + // TODO: This only needs to be validated when the inherited queries feature is enabled + // skip_call |= validate_flags(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->queryFlags", + // "VkQueryControlFlagBits", AllVkQueryControlFlagBits, pBeginInfo->pInheritanceInfo->queryFlags, false); + + // TODO: This must be 0 if the pipeline statistics queries feature is not enabled + skip_call |= validate_flags(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->pipelineStatistics", + "VkQueryPipelineStatisticFlagBits", AllVkQueryPipelineStatisticFlagBits, + pBeginInfo->pInheritanceInfo->pipelineStatistics, false); + } + + if (!skip_call) { result = get_dispatch_table(pc_device_table_map, commandBuffer)->BeginCommandBuffer(commandBuffer, pBeginInfo); - validate_result(my_data->report_data, "vkBeginCommandBuffer", result); + validate_result(report_data, "vkBeginCommandBuffer", result); } return result; -- cgit v1.2.3