From 24f5504fa89bbacf282229ef4384a67a05797d4b Mon Sep 17 00:00:00 2001 From: Dustin Graves Date: Wed, 23 Mar 2016 19:44:00 -0600 Subject: layers: Codegen VkBool32/enum parameter validation Now generating the VkBool32 and enum checks: - Warns if a VkBool32 parameter is neither VK_TRUE nor VK_FALSE - Warns if an enum token value falls outside of the enum's begin/end range and the token was not added by an extension. Only checkes enum's that have a begin/end range. Detection of tokens added by extensions is based on the base_value defined in appendic C.10 of the Vulkan specification. Change-Id: Id49ace52fea8a35972f96d54247b98aba182c09e --- layers/parameter_validation_utils.h | 166 +++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 23 deletions(-) (limited to 'layers/parameter_validation_utils.h') diff --git a/layers/parameter_validation_utils.h b/layers/parameter_validation_utils.h index 7cb80c06..ef899549 100644 --- a/layers/parameter_validation_utils.h +++ b/layers/parameter_validation_utils.h @@ -33,6 +33,7 @@ #define PARAMETER_VALIDATION_UTILS_H #include +#include #include #include "vulkan/vulkan.h" @@ -46,9 +47,29 @@ struct GenericHeader { }; } -// String returned by string_VkStructureType for an unrecognized type +// Layer name string to be logged with validation messages. +const char ParameterValidationName[] = "ParameterValidation"; + +// String returned by string_VkStructureType for an unrecognized type. const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType"; +// The base value used when computing the offset for an enumeration token value that is added by an extension. +// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension. +// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification +const uint32_t ExtEnumBaseValue = 1000000000; + +template bool is_extension_added_token(T value) { + return (std::abs(static_cast(value)) >= ExtEnumBaseValue); +} + +// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an +// extension added token. Its original value was intentionally preserved after the conversion, so it does not use +// the base value that other extension added tokens use, and it does not fall within the enum's begin/end range. +template <> bool is_extension_added_token(VkSamplerAddressMode value) { + bool result = (std::abs(static_cast(value)) >= ExtEnumBaseValue); + return (result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE)); +} + /** * Validate a required pointer. * @@ -65,8 +86,8 @@ static VkBool32 validate_required_pointer(debug_report_data *report_data, const VkBool32 skipCall = VK_FALSE; if (value == NULL) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", - "%s: required parameter %s specified as NULL", apiName, parameterName); + skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: required parameter %s specified as NULL", apiName, parameterName); } return skipCall; @@ -101,7 +122,7 @@ VkBool32 validate_array(debug_report_data *report_data, const char *apiName, con if (count == NULL) { if (countPtrRequired == VK_TRUE) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, countName); + ParameterValidationName, "%s: required parameter %s specified as NULL", apiName, countName); } } else { skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired); @@ -134,15 +155,15 @@ VkBool32 validate_array(debug_report_data *report_data, const char *apiName, con // Count parameters not tagged as optional cannot be 0 if ((count == 0) && (countRequired == VK_TRUE)) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", - "%s: value of %s must be greater than 0", apiName, countName); + skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: value of %s must be greater than 0", apiName, countName); } // Array parameters not tagged as optional cannot be NULL, // unless the count is 0 if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", - "%s: required parameter %s specified as NULL", apiName, arrayName); + skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: required parameter %s specified as NULL", apiName, arrayName); } return skipCall; @@ -168,11 +189,11 @@ VkBool32 validate_struct_type(debug_report_data *report_data, const char *apiNam if (value == NULL) { if (required == VK_TRUE) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, parameterName); + ParameterValidationName, "%s: required parameter %s specified as NULL", apiName, parameterName); } } else if (value->sType != sType) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", - "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName); + skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName); } return skipCall; @@ -209,7 +230,7 @@ VkBool32 validate_struct_type_array(debug_report_data *report_data, const char * if (count == NULL) { if (countPtrRequired == VK_TRUE) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, countName); + ParameterValidationName, "%s: required parameter %s specified as NULL", apiName, countName); } } else { skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType, @@ -248,21 +269,22 @@ VkBool32 validate_struct_type_array(debug_report_data *report_data, const char * // Count parameters not tagged as optional cannot be 0 if ((count == 0) && (countRequired == VK_TRUE)) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: parameter %s must be greater than 0", apiName, countName); + ParameterValidationName, "%s: parameter %s must be greater than 0", apiName, countName); } // Array parameters not tagged as optional cannot be NULL, // unless the count is 0 if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, arrayName); + ParameterValidationName, "%s: required parameter %s specified as NULL", apiName, arrayName); } } else { // Verify that all structs in the array have the correct type for (uint32_t i = 0; i < count; ++i) { if (array[i].sType != sType) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: parameter %s[%d].sType must be %s", apiName, arrayName, i, sTypeName); + skipCall |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: parameter %s[%d].sType must be %s", apiName, arrayName, i, sTypeName); } } } @@ -297,21 +319,22 @@ static VkBool32 validate_string_array(debug_report_data *report_data, const char // Count parameters not tagged as optional cannot be 0 if ((count == 0) && (countRequired == VK_TRUE)) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: parameter %s must be greater than 0", apiName, countName); + ParameterValidationName, "%s: parameter %s must be greater than 0", apiName, countName); } // Array parameters not tagged as optional cannot be NULL, // unless the count is 0 if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, arrayName); + ParameterValidationName, "%s: required parameter %s specified as NULL", apiName, arrayName); } } else { // Verify that strings in the array not NULL for (uint32_t i = 0; i < count; ++i) { if (array[i] == NULL) { - skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: required parameter %s[%d] specified as NULL", apiName, arrayName, i); + skipCall |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: required parameter %s[%d] specified as NULL", apiName, arrayName, i); } } } @@ -343,7 +366,7 @@ static VkBool32 validate_struct_pnext(debug_report_data *report_data, const char if (next != NULL) { if (allowedTypeCount == 0) { skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "%s: value of %s must be NULL", apiName, parameterName); + ParameterValidationName, "%s: value of %s must be NULL", apiName, parameterName); } else { const VkStructureType *start = allowedTypes; const VkStructureType *end = allowedTypes + allowedTypeCount; @@ -355,12 +378,14 @@ static VkBool32 validate_struct_pnext(debug_report_data *report_data, const char if (typeName == UnsupportedStructureTypeString) { skipCall |= log_msg( - report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", + report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed structures are [%s]", apiName, parameterName, current->sType, allowedStructNames); } else { skipCall |= log_msg( - report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", + report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]", apiName, parameterName, typeName.c_str(), allowedStructNames); } @@ -374,4 +399,99 @@ static VkBool32 validate_struct_pnext(debug_report_data *report_data, const char return skipCall; } +/** +* Validate a VkBool32 value. +* +* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE. +* +* @param report_data debug_report_data object for routing validation messages. +* @param apiName Name of API call being validated. +* @param parameterName Name of parameter being validated. +* @param value Boolean value to validate. +* @return Boolean value indicating that the call should be skipped. +*/ +static VkBool32 validate_bool32(debug_report_data *report_data, const char *apiName, const char *parameterName, VkBool32 value) { + VkBool32 skipCall = VK_FALSE; + + if ((value != VK_TRUE) && (value != VK_FALSE)) { + skipCall |= + log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName, parameterName, value); + } + + return skipCall; +} + +/** +* Validate a Vulkan enumeration value. +* +* Generate a warning if an enumeration token value does not fall within the core enumeration +* begin and end token values, and was not added to the enumeration by an extension. Extension +* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification, +* with 1,000,000,000 as the base token value. +* +* @note This function does not expect to process enumerations defining bitmask flag bits. +* +* @param report_data debug_report_data object for routing validation messages. +* @param apiName Name of API call being validated. +* @param parameterName Name of parameter being validated. +* @param enumName Name of the enumeration being validated. +* @param begin The begin range value for the enumeration. +* @param end The end range value for the enumeration. +* @param value Boolean value to validate. +* @return Boolean value indicating that the call should be skipped. +*/ +template +VkBool32 validate_ranged_enum(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *enumName, + T begin, T end, T value) { + VkBool32 skipCall = VK_FALSE; + + if (((value < begin) || (value > end)) && !is_extension_added_token(value)) { + skipCall |= + log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: value of %s (%d) does not fall within the begin..end range of the core %s " + "enumeration tokens and is not an extension added token", + apiName, parameterName, value, enumName); + } + + return skipCall; +} + +/** +* Validate an array of Vulkan enumeration value. +* +* Process all enumeration token values in the specified array and generate a warning if a value +* does not fall within the core enumeration begin and end token values, and was not added to +* the enumeration by an extension. Extension provided enumerations use the equation specified +* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value. +* +* @note This function does not expect to process enumerations defining bitmask flag bits. +* +* @param report_data debug_report_data object for routing validation messages. +* @param apiName Name of API call being validated. +* @param parameterName Name of parameter being validated. +* @param enumName Name of the enumeration being validated. +* @param begin The begin range value for the enumeration. +* @param end The end range value for the enumeration. +* @param value Boolean value to validate. +* @return Boolean value indicating that the call should be skipped. +*/ +template +static VkBool32 validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const char *parameterName, + const char *enumName, T begin, T end, uint32_t count, const T *pValues) { + VkBool32 skipCall = VK_FALSE; + + for (uint32_t i = 0; i < count; ++i) { + if (((pValues[i] < begin) || (pValues[i] > end)) && !is_extension_added_token(pValues[i])) { + skipCall |= + log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s " + "enumeration tokens and is not an extension added token", + apiName, parameterName, i, pValues[i], enumName); + } + } + + return skipCall; +} + #endif // PARAMETER_VALIDATION_UTILS_H -- cgit v1.2.3