1 /* Copyright (c) 2015-2016 The Khronos Group Inc. 2 * Copyright (c) 2015-2016 Valve Corporation 3 * Copyright (c) 2015-2016 LunarG, Inc. 4 * Copyright (C) 2015-2016 Google Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and/or associated documentation files (the "Materials"), to 8 * deal in the Materials without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Materials, and to permit persons to whom the Materials 11 * are furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice(s) and this permission notice shall be included 14 * in all copies or substantial portions of the Materials. 15 * 16 * The Materials are Confidential Information as defined by the Khronos 17 * Membership Agreement until designated non-confidential by Khronos, at which 18 * point this condition clause shall be removed. 19 * 20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 * 24 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 26 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 27 * USE OR OTHER DEALINGS IN THE MATERIALS 28 * 29 * Author: Dustin Graves <dustin (at) lunarg.com> 30 */ 31 32 #ifndef PARAMETER_VALIDATION_UTILS_H 33 #define PARAMETER_VALIDATION_UTILS_H 34 35 #include <algorithm> 36 #include <string> 37 38 #include "vulkan/vulkan.h" 39 #include "vk_enum_string_helper.h" 40 #include "vk_layer_logging.h" 41 42 namespace { 43 struct GenericHeader { 44 VkStructureType sType; 45 const void *pNext; 46 }; 47 } 48 49 // String returned by string_VkStructureType for an unrecognized type 50 const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType"; 51 52 /** 53 * Validate a required pointer. 54 * 55 * Verify that a required pointer is not NULL. 56 * 57 * @param report_data debug_report_data object for routing validation messages. 58 * @param apiName Name of API call being validated. 59 * @param parameterName Name of parameter being validated. 60 * @param value Pointer to validate. 61 * @return Boolean value indicating that the call should be skipped. 62 */ 63 static VkBool32 validate_required_pointer(debug_report_data *report_data, const char *apiName, const char *parameterName, 64 const void *value) { 65 VkBool32 skipCall = VK_FALSE; 66 67 if (value == NULL) { 68 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", 69 "%s: required parameter %s specified as NULL", apiName, parameterName); 70 } 71 72 return skipCall; 73 } 74 75 /** 76 * Validate pointer to array count and pointer to array. 77 * 78 * Verify that required count and array parameters are not NULL. If count 79 * is not NULL and its value is not optional, verify that it is not 0. If the 80 * array parameter is NULL, and it is not optional, verify that count is 0. 81 * The array parameter will typically be optional for this case (where count is 82 * a pointer), allowing the caller to retrieve the available count. 83 * 84 * @param report_data debug_report_data object for routing validation messages. 85 * @param apiName Name of API call being validated. 86 * @param countName Name of count parameter. 87 * @param arrayName Name of array parameter. 88 * @param count Pointer to the number of elements in the array. 89 * @param array Array to validate. 90 * @param countPtrRequired The 'count' parameter may not be NULL when true. 91 * @param countValueRequired The '*count' value may not be 0 when true. 92 * @param arrayRequired The 'array' parameter may not be NULL when true. 93 * @return Boolean value indicating that the call should be skipped. 94 */ 95 template <typename T> 96 VkBool32 validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, 97 const T *count, const void *array, VkBool32 countPtrRequired, VkBool32 countValueRequired, 98 VkBool32 arrayRequired) { 99 VkBool32 skipCall = VK_FALSE; 100 101 if (count == NULL) { 102 if (countPtrRequired == VK_TRUE) { 103 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 104 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, countName); 105 } 106 } else { 107 skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired); 108 } 109 110 return skipCall; 111 } 112 113 /** 114 * Validate array count and pointer to array. 115 * 116 * Verify that required count and array parameters are not 0 or NULL. If the 117 * count parameter is not optional, verify that it is not 0. If the array 118 * parameter is NULL, and it is not optional, verify that count is 0. 119 * 120 * @param report_data debug_report_data object for routing validation messages. 121 * @param apiName Name of API call being validated. 122 * @param countName Name of count parameter. 123 * @param arrayName Name of array parameter. 124 * @param count Number of elements in the array. 125 * @param array Array to validate. 126 * @param countRequired The 'count' parameter may not be 0 when true. 127 * @param arrayRequired The 'array' parameter may not be NULL when true. 128 * @return Boolean value indicating that the call should be skipped. 129 */ 130 template <typename T> 131 VkBool32 validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, T count, 132 const void *array, VkBool32 countRequired, VkBool32 arrayRequired) { 133 VkBool32 skipCall = VK_FALSE; 134 135 // Count parameters not tagged as optional cannot be 0 136 if ((count == 0) && (countRequired == VK_TRUE)) { 137 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", 138 "%s: value of %s must be greater than 0", apiName, countName); 139 } 140 141 // Array parameters not tagged as optional cannot be NULL, 142 // unless the count is 0 143 if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) { 144 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", 145 "%s: required parameter %s specified as NULL", apiName, arrayName); 146 } 147 148 return skipCall; 149 } 150 151 /** 152 * Validate an Vulkan structure type. 153 * 154 * @param report_data debug_report_data object for routing validation messages. 155 * @param apiName Name of API call being validated. 156 * @param parameterName Name of struct parameter being validated. 157 * @param sTypeName Name of expected VkStructureType value. 158 * @param value Pointer to the struct to validate. 159 * @param sType VkStructureType for structure validation. 160 * @param required The parameter may not be NULL when true. 161 * @return Boolean value indicating that the call should be skipped. 162 */ 163 template <typename T> 164 VkBool32 validate_struct_type(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *sTypeName, 165 const T *value, VkStructureType sType, VkBool32 required) { 166 VkBool32 skipCall = VK_FALSE; 167 168 if (value == NULL) { 169 if (required == VK_TRUE) { 170 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 171 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, parameterName); 172 } 173 } else if (value->sType != sType) { 174 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", 175 "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName); 176 } 177 178 return skipCall; 179 } 180 181 /** 182 * Validate an array of Vulkan structures. 183 * 184 * Verify that required count and array parameters are not NULL. If count 185 * is not NULL and its value is not optional, verify that it is not 0. 186 * If the array contains 1 or more structures, verify that each structure's 187 * sType field is set to the correct VkStructureType value. 188 * 189 * @param report_data debug_report_data object for routing validation messages. 190 * @param apiName Name of API call being validated. 191 * @param countName Name of count parameter. 192 * @param arrayName Name of array parameter. 193 * @param sTypeName Name of expected VkStructureType value. 194 * @param count Pointer to the number of elements in the array. 195 * @param array Array to validate. 196 * @param sType VkStructureType for structure validation. 197 * @param countPtrRequired The 'count' parameter may not be NULL when true. 198 * @param countValueRequired The '*count' value may not be 0 when true. 199 * @param arrayRequired The 'array' parameter may not be NULL when true. 200 * @return Boolean value indicating that the call should be skipped. 201 */ 202 template <typename T> 203 VkBool32 validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, 204 const char *arrayName, const char *sTypeName, const uint32_t *count, const T *array, 205 VkStructureType sType, VkBool32 countPtrRequired, VkBool32 countValueRequired, 206 VkBool32 arrayRequired) { 207 VkBool32 skipCall = VK_FALSE; 208 209 if (count == NULL) { 210 if (countPtrRequired == VK_TRUE) { 211 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 212 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, countName); 213 } 214 } else { 215 skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType, 216 countValueRequired, arrayRequired); 217 } 218 219 return skipCall; 220 } 221 222 /** 223 * Validate an array of Vulkan structures 224 * 225 * Verify that required count and array parameters are not 0 or NULL. If 226 * the array contains 1 or more structures, verify that each structure's 227 * sType field is set to the correct VkStructureType value. 228 * 229 * @param report_data debug_report_data object for routing validation messages. 230 * @param apiName Name of API call being validated. 231 * @param countName Name of count parameter. 232 * @param arrayName Name of array parameter. 233 * @param sTypeName Name of expected VkStructureType value. 234 * @param count Number of elements in the array. 235 * @param array Array to validate. 236 * @param sType VkStructureType for structure validation. 237 * @param countRequired The 'count' parameter may not be 0 when true. 238 * @param arrayRequired The 'array' parameter may not be NULL when true. 239 * @return Boolean value indicating that the call should be skipped. 240 */ 241 template <typename T> 242 VkBool32 validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, 243 const char *arrayName, const char *sTypeName, uint32_t count, const T *array, 244 VkStructureType sType, VkBool32 countRequired, VkBool32 arrayRequired) { 245 VkBool32 skipCall = VK_FALSE; 246 247 if ((count == 0) || (array == NULL)) { 248 // Count parameters not tagged as optional cannot be 0 249 if ((count == 0) && (countRequired == VK_TRUE)) { 250 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 251 "PARAMCHECK", "%s: parameter %s must be greater than 0", apiName, countName); 252 } 253 254 // Array parameters not tagged as optional cannot be NULL, 255 // unless the count is 0 256 if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) { 257 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 258 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, arrayName); 259 } 260 } else { 261 // Verify that all structs in the array have the correct type 262 for (uint32_t i = 0; i < count; ++i) { 263 if (array[i].sType != sType) { 264 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 265 "PARAMCHECK", "%s: parameter %s[%d].sType must be %s", apiName, arrayName, i, sTypeName); 266 } 267 } 268 } 269 270 return skipCall; 271 } 272 273 /** 274 * Validate string array count and content. 275 * 276 * Verify that required count and array parameters are not 0 or NULL. If the 277 * count parameter is not optional, verify that it is not 0. If the array 278 * parameter is NULL, and it is not optional, verify that count is 0. If the 279 * array parameter is not NULL, verify that none of the strings are NULL. 280 * 281 * @param report_data debug_report_data object for routing validation messages. 282 * @param apiName Name of API call being validated. 283 * @param countName Name of count parameter. 284 * @param arrayName Name of array parameter. 285 * @param count Number of strings in the array. 286 * @param array Array of strings to validate. 287 * @param countRequired The 'count' parameter may not be 0 when true. 288 * @param arrayRequired The 'array' parameter may not be NULL when true. 289 * @return Boolean value indicating that the call should be skipped. 290 */ 291 static VkBool32 validate_string_array(debug_report_data *report_data, const char *apiName, const char *countName, 292 const char *arrayName, uint32_t count, const char *const *array, VkBool32 countRequired, 293 VkBool32 arrayRequired) { 294 VkBool32 skipCall = VK_FALSE; 295 296 if ((count == 0) || (array == NULL)) { 297 // Count parameters not tagged as optional cannot be 0 298 if ((count == 0) && (countRequired == VK_TRUE)) { 299 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 300 "PARAMCHECK", "%s: parameter %s must be greater than 0", apiName, countName); 301 } 302 303 // Array parameters not tagged as optional cannot be NULL, 304 // unless the count is 0 305 if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) { 306 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 307 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, arrayName); 308 } 309 } else { 310 // Verify that strings in the array not NULL 311 for (uint32_t i = 0; i < count; ++i) { 312 if (array[i] == NULL) { 313 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 314 "PARAMCHECK", "%s: required parameter %s[%d] specified as NULL", apiName, arrayName, i); 315 } 316 } 317 } 318 319 return skipCall; 320 } 321 322 /** 323 * Validate a structure's pNext member. 324 * 325 * Verify that the specified pNext value points to the head of a list of 326 * allowed extension structures. If no extension structures are allowed, 327 * verify that pNext is null. 328 * 329 * @param report_data debug_report_data object for routing validation messages. 330 * @param apiName Name of API call being validated. 331 * @param parameterName Name of parameter being validated. 332 * @param allowedStructNames Names of allowed structs. 333 * @param next Pointer to validate. 334 * @param allowedTypeCount total number of allowed structure types. 335 * @param allowedTypes array of strcuture types allowed for pNext. 336 * @return Boolean value indicating that the call should be skipped. 337 */ 338 static VkBool32 validate_struct_pnext(debug_report_data *report_data, const char *apiName, const char *parameterName, 339 const char *allowedStructNames, const void *next, size_t allowedTypeCount, 340 const VkStructureType *allowedTypes) { 341 VkBool32 skipCall = VK_FALSE; 342 343 if (next != NULL) { 344 if (allowedTypeCount == 0) { 345 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, 346 "PARAMCHECK", "%s: value of %s must be NULL", apiName, parameterName); 347 } else { 348 const VkStructureType *start = allowedTypes; 349 const VkStructureType *end = allowedTypes + allowedTypeCount; 350 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next); 351 352 while (current != NULL) { 353 if (std::find(start, end, current->sType) == end) { 354 std::string typeName = string_VkStructureType(current->sType); 355 356 if (typeName == UnsupportedStructureTypeString) { 357 skipCall |= log_msg( 358 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", 359 "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed structures are [%s]", 360 apiName, parameterName, current->sType, allowedStructNames); 361 } else { 362 skipCall |= log_msg( 363 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", 364 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]", 365 apiName, parameterName, typeName.c_str(), allowedStructNames); 366 } 367 } 368 369 current = reinterpret_cast<const GenericHeader *>(current->pNext); 370 } 371 } 372 } 373 374 return skipCall; 375 } 376 377 #endif // PARAMETER_VALIDATION_UTILS_H 378