1 /* Copyright (c) 2015-2019 The Khronos Group Inc. 2 * Copyright (c) 2015-2019 Valve Corporation 3 * Copyright (c) 2015-2019 LunarG, Inc. 4 * Copyright (C) 2015-2019 Google Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Dustin Graves <dustin@lunarg.com> 19 * Author: Mark Lobodzinski <mark@lunarg.com> 20 */ 21 22 #pragma once 23 24 #include "parameter_name.h" 25 #include "vk_typemap_helper.h" 26 27 // Suppress unused warning on Linux 28 #if defined(__GNUC__) 29 #define DECORATE_UNUSED __attribute__((unused)) 30 #else 31 #define DECORATE_UNUSED 32 #endif 33 34 static const char DECORATE_UNUSED *kVUID_PVError_NONE = "UNASSIGNED-GeneralParameterError-Info"; 35 static const char DECORATE_UNUSED *kVUID_PVError_InvalidUsage = "UNASSIGNED-GeneralParameterError-InvalidUsage"; 36 static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructSType = "UNASSIGNED-GeneralParameterError-InvalidStructSType"; 37 static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructPNext = "UNASSIGNED-GeneralParameterError-InvalidStructPNext"; 38 static const char DECORATE_UNUSED *kVUID_PVError_RequiredParameter = "UNASSIGNED-GeneralParameterError-RequiredParameter"; 39 static const char DECORATE_UNUSED *kVUID_PVError_ReservedParameter = "UNASSIGNED-GeneralParameterError-ReservedParameter"; 40 static const char DECORATE_UNUSED *kVUID_PVError_UnrecognizedValue = "UNASSIGNED-GeneralParameterError-UnrecognizedValue"; 41 static const char DECORATE_UNUSED *kVUID_PVError_DeviceLimit = "UNASSIGNED-GeneralParameterError-DeviceLimit"; 42 static const char DECORATE_UNUSED *kVUID_PVError_DeviceFeature = "UNASSIGNED-GeneralParameterError-DeviceFeature"; 43 static const char DECORATE_UNUSED *kVUID_PVError_FailureCode = "UNASSIGNED-GeneralParameterError-FailureCode"; 44 static const char DECORATE_UNUSED *kVUID_PVError_ExtensionNotEnabled = "UNASSIGNED-GeneralParameterError-ExtensionNotEnabled"; 45 static const char DECORATE_UNUSED *kVUID_PVPerfWarn_SuboptimalSwapchain = "UNASSIGNED-GeneralParameterPerfWarn-SuboptimalSwapchain"; 46 47 #undef DECORATE_UNUSED 48 49 extern const uint32_t GeneratedVulkanHeaderVersion; 50 51 extern const VkQueryPipelineStatisticFlags AllVkQueryPipelineStatisticFlagBits; 52 extern const VkColorComponentFlags AllVkColorComponentFlagBits; 53 extern const VkShaderStageFlags AllVkShaderStageFlagBits; 54 extern const VkQueryControlFlags AllVkQueryControlFlagBits; 55 extern const VkImageUsageFlags AllVkImageUsageFlagBits; 56 extern const VkSampleCountFlags AllVkSampleCountFlagBits; 57 58 extern const std::vector<VkCompareOp> AllVkCompareOpEnums; 59 extern const std::vector<VkStencilOp> AllVkStencilOpEnums; 60 extern const std::vector<VkBlendFactor> AllVkBlendFactorEnums; 61 extern const std::vector<VkBlendOp> AllVkBlendOpEnums; 62 extern const std::vector<VkLogicOp> AllVkLogicOpEnums; 63 extern const std::vector<VkBorderColor> AllVkBorderColorEnums; 64 extern const std::vector<VkImageLayout> AllVkImageLayoutEnums; 65 extern const std::vector<VkFormat> AllVkFormatEnums; 66 extern const std::vector<VkVertexInputRate> AllVkVertexInputRateEnums; 67 extern const std::vector<VkPrimitiveTopology> AllVkPrimitiveTopologyEnums; 68 69 // String returned by string_VkStructureType for an unrecognized type. 70 const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType"; 71 72 // String returned by string_VkResult for an unrecognized type. 73 const std::string UnsupportedResultString = "Unhandled VkResult"; 74 75 // The base value used when computing the offset for an enumeration token value that is added by an extension. 76 // When validating enumeration tokens, any value >= to this value is considered to be provided by an extension. 77 // See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification 78 const uint32_t ExtEnumBaseValue = 1000000000; 79 80 // The value of all VK_xxx_MAX_ENUM tokens 81 const uint32_t MaxEnumValue = 0x7FFFFFFF; 82 83 // Misc parameters of log_msg that are likely constant per command (or low frequency change) 84 struct LogMiscParams { 85 VkDebugReportObjectTypeEXT objectType; 86 uint64_t srcObject; 87 const char *api_name; 88 }; 89 90 class StatelessValidation : public ValidationObject { 91 public: 92 VkPhysicalDeviceLimits device_limits = {}; 93 safe_VkPhysicalDeviceFeatures2 physical_device_features2; 94 const VkPhysicalDeviceFeatures &physical_device_features = physical_device_features2.features; 95 96 // Override chassis read/write locks for this validation object 97 // This override takes a deferred lock. i.e. it is not acquired. write_lock()98 std::unique_lock<std::mutex> write_lock() { return std::unique_lock<std::mutex>(validation_object_mutex, std::defer_lock); } 99 100 // Device extension properties -- storing properties gathered from VkPhysicalDeviceProperties2KHR::pNext chain 101 struct DeviceExtensionProperties { 102 VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props; 103 VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props; 104 VkPhysicalDeviceRayTracingPropertiesNV ray_tracing_props; 105 }; 106 DeviceExtensionProperties phys_dev_ext_props = {}; 107 108 struct SubpassesUsageStates { 109 std::unordered_set<uint32_t> subpasses_using_color_attachment; 110 std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment; 111 }; 112 113 // Though this validation object is predominantly statless, the Framebuffer checks are greatly simplified by creating and 114 // updating a map of the renderpass usage states, and these accesses need thread protection. Use a mutex separate from the 115 // parent object's to maintain that functionality. 116 std::mutex renderpass_map_mutex; 117 std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states; 118 119 // Constructor for stateles validation tracking 120 // StatelessValidation() : {} 121 /** 122 * Validate a minimum value. 123 * 124 * Verify that the specified value is greater than the specified lower bound. 125 * 126 * @param api_name Name of API call being validated. 127 * @param parameter_name Name of parameter being validated. 128 * @param value Value to validate. 129 * @param lower_bound Lower bound value to use for validation. 130 * @return Boolean value indicating that the call should be skipped. 131 */ 132 template <typename T> ValidateGreaterThan(const T value,const T lower_bound,const ParameterName & parameter_name,const std::string & vuid,const LogMiscParams & misc)133 bool ValidateGreaterThan(const T value, const T lower_bound, const ParameterName ¶meter_name, const std::string &vuid, 134 const LogMiscParams &misc) { 135 bool skip_call = false; 136 137 if (value <= lower_bound) { 138 std::ostringstream ss; 139 ss << misc.api_name << ": parameter " << parameter_name.get_name() << " (= " << value << ") is greater than " 140 << lower_bound; 141 skip_call |= 142 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, misc.objectType, misc.srcObject, vuid, "%s", ss.str().c_str()); 143 } 144 145 return skip_call; 146 } 147 148 template <typename T> ValidateGreaterThanZero(const T value,const ParameterName & parameter_name,const std::string & vuid,const LogMiscParams & misc)149 bool ValidateGreaterThanZero(const T value, const ParameterName ¶meter_name, const std::string &vuid, 150 const LogMiscParams &misc) { 151 return ValidateGreaterThan(value, T{0}, parameter_name, vuid, misc); 152 } 153 /** 154 * Validate a required pointer. 155 * 156 * Verify that a required pointer is not NULL. 157 * 158 * @param apiName Name of API call being validated. 159 * @param parameterName Name of parameter being validated. 160 * @param value Pointer to validate. 161 * @return Boolean value indicating that the call should be skipped. 162 */ validate_required_pointer(const char * apiName,const ParameterName & parameterName,const void * value,const std::string & vuid)163 bool validate_required_pointer(const char *apiName, const ParameterName ¶meterName, const void *value, 164 const std::string &vuid) { 165 bool skip_call = false; 166 167 if (value == NULL) { 168 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 169 "%s: required parameter %s specified as NULL.", apiName, parameterName.get_name().c_str()); 170 } 171 172 return skip_call; 173 } 174 175 /** 176 * Validate array count and pointer to array. 177 * 178 * Verify that required count and array parameters are not 0 or NULL. If the 179 * count parameter is not optional, verify that it is not 0. If the array 180 * parameter is NULL, and it is not optional, verify that count is 0. 181 * 182 * @param apiName Name of API call being validated. 183 * @param countName Name of count parameter. 184 * @param arrayName Name of array parameter. 185 * @param count Number of elements in the array. 186 * @param array Array to validate. 187 * @param countRequired The 'count' parameter may not be 0 when true. 188 * @param arrayRequired The 'array' parameter may not be NULL when true. 189 * @return Boolean value indicating that the call should be skipped. 190 */ 191 template <typename T1, typename T2> validate_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,T1 count,const T2 * array,bool countRequired,bool arrayRequired,const char * count_required_vuid,const char * array_required_vuid)192 bool validate_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, T1 count, 193 const T2 *array, bool countRequired, bool arrayRequired, const char *count_required_vuid, 194 const char *array_required_vuid) { 195 bool skip_call = false; 196 197 // Count parameters not tagged as optional cannot be 0 198 if (countRequired && (count == 0)) { 199 skip_call |= 200 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, count_required_vuid, 201 "%s: parameter %s must be greater than 0.", apiName, countName.get_name().c_str()); 202 } 203 204 // Array parameters not tagged as optional cannot be NULL, unless the count is 0 205 if (arrayRequired && (count != 0) && (*array == NULL)) { 206 skip_call |= 207 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, array_required_vuid, 208 "%s: required parameter %s specified as NULL.", apiName, arrayName.get_name().c_str()); 209 } 210 211 return skip_call; 212 } 213 214 /** 215 * Validate pointer to array count and pointer to array. 216 * 217 * Verify that required count and array parameters are not NULL. If count 218 * is not NULL and its value is not optional, verify that it is not 0. If the 219 * array parameter is NULL, and it is not optional, verify that count is 0. 220 * The array parameter will typically be optional for this case (where count is 221 * a pointer), allowing the caller to retrieve the available count. 222 * 223 * @param apiName Name of API call being validated. 224 * @param countName Name of count parameter. 225 * @param arrayName Name of array parameter. 226 * @param count Pointer to the number of elements in the array. 227 * @param array Array to validate. 228 * @param countPtrRequired The 'count' parameter may not be NULL when true. 229 * @param countValueRequired The '*count' value may not be 0 when true. 230 * @param arrayRequired The 'array' parameter may not be NULL when true. 231 * @return Boolean value indicating that the call should be skipped. 232 */ 233 template <typename T1, typename T2> validate_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const T1 * count,const T2 * array,bool countPtrRequired,bool countValueRequired,bool arrayRequired,const char * count_required_vuid,const char * array_required_vuid)234 bool validate_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, const T1 *count, 235 const T2 *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired, 236 const char *count_required_vuid, const char *array_required_vuid) { 237 bool skip_call = false; 238 239 if (count == NULL) { 240 if (countPtrRequired) { 241 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 242 kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName, 243 countName.get_name().c_str()); 244 } 245 } else { 246 skip_call |= validate_array(apiName, countName, arrayName, *array ? (*count) : 0, &array, countValueRequired, 247 arrayRequired, count_required_vuid, array_required_vuid); 248 } 249 250 return skip_call; 251 } 252 253 /** 254 * Validate a pointer to a Vulkan structure. 255 * 256 * Verify that a required pointer to a structure is not NULL. If the pointer is 257 * not NULL, verify that each structure's sType field is set to the correct 258 * VkStructureType value. 259 * 260 * @param apiName Name of API call being validated. 261 * @param parameterName Name of struct parameter being validated. 262 * @param sTypeName Name of expected VkStructureType value. 263 * @param value Pointer to the struct to validate. 264 * @param sType VkStructureType for structure validation. 265 * @param required The parameter may not be NULL when true. 266 * @return Boolean value indicating that the call should be skipped. 267 */ 268 template <typename T> validate_struct_type(const char * apiName,const ParameterName & parameterName,const char * sTypeName,const T * value,VkStructureType sType,bool required,const char * struct_vuid,const char * stype_vuid)269 bool validate_struct_type(const char *apiName, const ParameterName ¶meterName, const char *sTypeName, const T *value, 270 VkStructureType sType, bool required, const char *struct_vuid, const char *stype_vuid) { 271 bool skip_call = false; 272 273 if (value == NULL) { 274 if (required) { 275 skip_call |= 276 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, struct_vuid, 277 "%s: required parameter %s specified as NULL", apiName, parameterName.get_name().c_str()); 278 } 279 } else if (value->sType != sType) { 280 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid, 281 "%s: parameter %s->sType must be %s.", apiName, parameterName.get_name().c_str(), sTypeName); 282 } 283 284 return skip_call; 285 } 286 287 /** 288 * Validate an array of Vulkan structures 289 * 290 * Verify that required count and array parameters are not 0 or NULL. If 291 * the array contains 1 or more structures, verify that each structure's 292 * sType field is set to the correct VkStructureType value. 293 * 294 * @param apiName Name of API call being validated. 295 * @param countName Name of count parameter. 296 * @param arrayName Name of array parameter. 297 * @param sTypeName Name of expected VkStructureType value. 298 * @param count Number of elements in the array. 299 * @param array Array to validate. 300 * @param sType VkStructureType for structure validation. 301 * @param countRequired The 'count' parameter may not be 0 when true. 302 * @param arrayRequired The 'array' parameter may not be NULL when true. 303 * @return Boolean value indicating that the call should be skipped. 304 */ 305 template <typename T> validate_struct_type_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * sTypeName,uint32_t count,const T * array,VkStructureType sType,bool countRequired,bool arrayRequired,const char * stype_vuid,const char * param_vuid,const char * count_required_vuid)306 bool validate_struct_type_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, 307 const char *sTypeName, uint32_t count, const T *array, VkStructureType sType, 308 bool countRequired, bool arrayRequired, const char *stype_vuid, const char *param_vuid, 309 const char *count_required_vuid) { 310 bool skip_call = false; 311 312 if ((count == 0) || (array == NULL)) { 313 skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired, 314 count_required_vuid, param_vuid); 315 } else { 316 // Verify that all structs in the array have the correct type 317 for (uint32_t i = 0; i < count; ++i) { 318 if (array[i].sType != sType) { 319 skip_call |= 320 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid, 321 "%s: parameter %s[%d].sType must be %s", apiName, arrayName.get_name().c_str(), i, sTypeName); 322 } 323 } 324 } 325 326 return skip_call; 327 } 328 329 /** 330 * Validate an array of Vulkan structures. 331 * 332 * Verify that required count and array parameters are not NULL. If count 333 * is not NULL and its value is not optional, verify that it is not 0. 334 * If the array contains 1 or more structures, verify that each structure's 335 * sType field is set to the correct VkStructureType value. 336 * 337 * @param apiName Name of API call being validated. 338 * @param countName Name of count parameter. 339 * @param arrayName Name of array parameter. 340 * @param sTypeName Name of expected VkStructureType value. 341 * @param count Pointer to the number of elements in the array. 342 * @param array Array to validate. 343 * @param sType VkStructureType for structure validation. 344 * @param countPtrRequired The 'count' parameter may not be NULL when true. 345 * @param countValueRequired The '*count' value may not be 0 when true. 346 * @param arrayRequired The 'array' parameter may not be NULL when true. 347 * @return Boolean value indicating that the call should be skipped. 348 */ 349 template <typename T> validate_struct_type_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * sTypeName,uint32_t * count,const T * array,VkStructureType sType,bool countPtrRequired,bool countValueRequired,bool arrayRequired,const char * stype_vuid,const char * param_vuid,const char * count_required_vuid)350 bool validate_struct_type_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, 351 const char *sTypeName, uint32_t *count, const T *array, VkStructureType sType, 352 bool countPtrRequired, bool countValueRequired, bool arrayRequired, const char *stype_vuid, 353 const char *param_vuid, const char *count_required_vuid) { 354 bool skip_call = false; 355 356 if (count == NULL) { 357 if (countPtrRequired) { 358 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 359 kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName, 360 countName.get_name().c_str()); 361 } 362 } else { 363 skip_call |= validate_struct_type_array(apiName, countName, arrayName, sTypeName, (*count), array, sType, 364 countValueRequired, arrayRequired, stype_vuid, param_vuid, count_required_vuid); 365 } 366 367 return skip_call; 368 } 369 370 /** 371 * Validate a Vulkan handle. 372 * 373 * Verify that the specified handle is not VK_NULL_HANDLE. 374 * 375 * @param api_name Name of API call being validated. 376 * @param parameter_name Name of struct parameter being validated. 377 * @param value Handle to validate. 378 * @return Boolean value indicating that the call should be skipped. 379 */ 380 template <typename T> validate_required_handle(const char * api_name,const ParameterName & parameter_name,T value)381 bool validate_required_handle(const char *api_name, const ParameterName ¶meter_name, T value) { 382 bool skip_call = false; 383 384 if (value == VK_NULL_HANDLE) { 385 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 386 kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name, 387 parameter_name.get_name().c_str()); 388 } 389 390 return skip_call; 391 } 392 393 /** 394 * Validate an array of Vulkan handles. 395 * 396 * Verify that required count and array parameters are not NULL. If count 397 * is not NULL and its value is not optional, verify that it is not 0. 398 * If the array contains 1 or more handles, verify that no handle is set to 399 * VK_NULL_HANDLE. 400 * 401 * @note This function is only intended to validate arrays of handles when none 402 * of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles 403 * that are allowed to contain VK_NULL_HANDLE, use validate_array() instead. 404 * 405 * @param api_name Name of API call being validated. 406 * @param count_name Name of count parameter. 407 * @param array_name Name of array parameter. 408 * @param count Number of elements in the array. 409 * @param array Array to validate. 410 * @param count_required The 'count' parameter may not be 0 when true. 411 * @param array_required The 'array' parameter may not be NULL when true. 412 * @return Boolean value indicating that the call should be skipped. 413 */ 414 template <typename T> validate_handle_array(const char * api_name,const ParameterName & count_name,const ParameterName & array_name,uint32_t count,const T * array,bool count_required,bool array_required)415 bool validate_handle_array(const char *api_name, const ParameterName &count_name, const ParameterName &array_name, 416 uint32_t count, const T *array, bool count_required, bool array_required) { 417 bool skip_call = false; 418 419 if ((count == 0) || (array == NULL)) { 420 skip_call |= validate_array(api_name, count_name, array_name, count, &array, count_required, array_required, 421 kVUIDUndefined, kVUIDUndefined); 422 } else { 423 // Verify that no handles in the array are VK_NULL_HANDLE 424 for (uint32_t i = 0; i < count; ++i) { 425 if (array[i] == VK_NULL_HANDLE) { 426 skip_call |= 427 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 428 kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", 429 api_name, array_name.get_name().c_str(), i); 430 } 431 } 432 } 433 434 return skip_call; 435 } 436 437 /** 438 * Validate string array count and content. 439 * 440 * Verify that required count and array parameters are not 0 or NULL. If the 441 * count parameter is not optional, verify that it is not 0. If the array 442 * parameter is NULL, and it is not optional, verify that count is 0. If the 443 * array parameter is not NULL, verify that none of the strings are NULL. 444 * 445 * @param apiName Name of API call being validated. 446 * @param countName Name of count parameter. 447 * @param arrayName Name of array parameter. 448 * @param count Number of strings in the array. 449 * @param array Array of strings to validate. 450 * @param countRequired The 'count' parameter may not be 0 when true. 451 * @param arrayRequired The 'array' parameter may not be NULL when true. 452 * @return Boolean value indicating that the call should be skipped. 453 */ validate_string_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,uint32_t count,const char * const * array,bool countRequired,bool arrayRequired,const char * count_required_vuid,const char * array_required_vuid)454 bool validate_string_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, uint32_t count, 455 const char *const *array, bool countRequired, bool arrayRequired, const char *count_required_vuid, 456 const char *array_required_vuid) { 457 bool skip_call = false; 458 459 if ((count == 0) || (array == NULL)) { 460 skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired, 461 count_required_vuid, array_required_vuid); 462 } else { 463 // Verify that strings in the array are not NULL 464 for (uint32_t i = 0; i < count; ++i) { 465 if (array[i] == NULL) { 466 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 467 kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as NULL", 468 apiName, arrayName.get_name().c_str(), i); 469 } 470 } 471 } 472 473 return skip_call; 474 } 475 476 // Forward declaration for pNext validation 477 bool ValidatePnextStructContents(const char *api_name, const ParameterName ¶meter_name, const VkBaseOutStructure *header); 478 479 /** 480 * Validate a structure's pNext member. 481 * 482 * Verify that the specified pNext value points to the head of a list of 483 * allowed extension structures. If no extension structures are allowed, 484 * verify that pNext is null. 485 * 486 * @param api_name Name of API call being validated. 487 * @param parameter_name Name of parameter being validated. 488 * @param allowed_struct_names Names of allowed structs. 489 * @param next Pointer to validate. 490 * @param allowed_type_count Total number of allowed structure types. 491 * @param allowed_types Array of structure types allowed for pNext. 492 * @param header_version Version of header defining the pNext validation rules. 493 * @return Boolean value indicating that the call should be skipped. 494 */ validate_struct_pnext(const char * api_name,const ParameterName & parameter_name,const char * allowed_struct_names,const void * next,size_t allowed_type_count,const VkStructureType * allowed_types,uint32_t header_version,const char * vuid)495 bool validate_struct_pnext(const char *api_name, const ParameterName ¶meter_name, const char *allowed_struct_names, 496 const void *next, size_t allowed_type_count, const VkStructureType *allowed_types, 497 uint32_t header_version, const char *vuid) { 498 bool skip_call = false; 499 500 // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext. 501 // Codegen a map of vectors containing the allowable pNext types for each struct and use that here -- also simplifies parms. 502 if (next != NULL) { 503 std::unordered_set<const void *> cycle_check; 504 std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check; 505 506 const char *disclaimer = 507 "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It is possible that " 508 "you " 509 "are " 510 "using a struct from a private extension or an extension that was added to a later version of the Vulkan header, " 511 "in " 512 "which " 513 "case your use of %s is perfectly valid but is not guaranteed to work correctly with validation enabled"; 514 515 if (allowed_type_count == 0) { 516 std::string message = "%s: value of %s must be NULL. "; 517 message += disclaimer; 518 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 519 message.c_str(), api_name, parameter_name.get_name().c_str(), header_version, 520 parameter_name.get_name().c_str()); 521 } else { 522 const VkStructureType *start = allowed_types; 523 const VkStructureType *end = allowed_types + allowed_type_count; 524 const VkBaseOutStructure *current = reinterpret_cast<const VkBaseOutStructure *>(next); 525 526 cycle_check.insert(next); 527 528 while (current != NULL) { 529 if (((strncmp(api_name, "vkCreateInstance", strlen(api_name)) != 0) || 530 (current->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)) && 531 ((strncmp(api_name, "vkCreateDevice", strlen(api_name)) != 0) || 532 (current->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO))) { 533 if (cycle_check.find(current->pNext) != cycle_check.end()) { 534 std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated."; 535 skip_call |= 536 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 537 kVUID_PVError_InvalidStructPNext, message.c_str(), api_name, 538 parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next)); 539 break; 540 } else { 541 cycle_check.insert(current->pNext); 542 } 543 544 std::string type_name = string_VkStructureType(current->sType); 545 if (unique_stype_check.find(current->sType) != unique_stype_check.end()) { 546 std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times."; 547 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, 548 VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_PVError_InvalidStructPNext, 549 message.c_str(), api_name, parameter_name.get_name().c_str(), type_name.c_str()); 550 } else { 551 unique_stype_check.insert(current->sType); 552 } 553 554 if (std::find(start, end, current->sType) == end) { 555 if (type_name == UnsupportedStructureTypeString) { 556 std::string message = 557 "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are " 558 "[%s]. "; 559 message += disclaimer; 560 skip_call |= 561 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 562 0, vuid, message.c_str(), api_name, parameter_name.get_name().c_str(), current->sType, 563 allowed_struct_names, header_version, parameter_name.get_name().c_str()); 564 } else { 565 std::string message = 566 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are " 567 "[%s]. "; 568 message += disclaimer; 569 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, 570 VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, message.c_str(), api_name, 571 parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names, 572 header_version, parameter_name.get_name().c_str()); 573 } 574 } 575 skip_call |= ValidatePnextStructContents(api_name, parameter_name, current); 576 } 577 current = reinterpret_cast<const VkBaseOutStructure *>(current->pNext); 578 } 579 } 580 } 581 582 return skip_call; 583 } 584 585 /** 586 * Validate a VkBool32 value. 587 * 588 * Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE. 589 * 590 * @param apiName Name of API call being validated. 591 * @param parameterName Name of parameter being validated. 592 * @param value Boolean value to validate. 593 * @return Boolean value indicating that the call should be skipped. 594 */ validate_bool32(const char * apiName,const ParameterName & parameterName,VkBool32 value)595 bool validate_bool32(const char *apiName, const ParameterName ¶meterName, VkBool32 value) { 596 bool skip_call = false; 597 598 if ((value != VK_TRUE) && (value != VK_FALSE)) { 599 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 600 kVUID_PVError_UnrecognizedValue, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName, 601 parameterName.get_name().c_str(), value); 602 } 603 604 return skip_call; 605 } 606 607 /** 608 * Validate a Vulkan enumeration value. 609 * 610 * Generate a warning if an enumeration token value does not fall within the core enumeration 611 * begin and end token values, and was not added to the enumeration by an extension. Extension 612 * provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification, 613 * with 1,000,000,000 as the base token value. 614 * 615 * @note This function does not expect to process enumerations defining bitmask flag bits. 616 * 617 * @param apiName Name of API call being validated. 618 * @param parameterName Name of parameter being validated. 619 * @param enumName Name of the enumeration being validated. 620 * @param valid_values The list of valid values for the enumeration. 621 * @param value Enumeration value to validate. 622 * @return Boolean value indicating that the call should be skipped. 623 */ 624 template <typename T> validate_ranged_enum(const char * apiName,const ParameterName & parameterName,const char * enumName,const std::vector<T> & valid_values,T value,const char * vuid)625 bool validate_ranged_enum(const char *apiName, const ParameterName ¶meterName, const char *enumName, 626 const std::vector<T> &valid_values, T value, const char *vuid) { 627 bool skip = false; 628 629 if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) { 630 skip |= 631 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 632 "%s: value of %s (%d) does not fall within the begin..end range of the core %s enumeration tokens and is " 633 "not an extension added token.", 634 apiName, parameterName.get_name().c_str(), value, enumName); 635 } 636 637 return skip; 638 } 639 640 /** 641 * Validate an array of Vulkan enumeration value. 642 * 643 * Process all enumeration token values in the specified array and generate a warning if a value 644 * does not fall within the core enumeration begin and end token values, and was not added to 645 * the enumeration by an extension. Extension provided enumerations use the equation specified 646 * in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value. 647 * 648 * @note This function does not expect to process enumerations defining bitmask flag bits. 649 * 650 * @param apiName Name of API call being validated. 651 * @param countName Name of count parameter. 652 * @param arrayName Name of array parameter. 653 * @param enumName Name of the enumeration being validated. 654 * @param valid_values The list of valid values for the enumeration. 655 * @param count Number of enumeration values in the array. 656 * @param array Array of enumeration values to validate. 657 * @param countRequired The 'count' parameter may not be 0 when true. 658 * @param arrayRequired The 'array' parameter may not be NULL when true. 659 * @return Boolean value indicating that the call should be skipped. 660 */ 661 template <typename T> validate_ranged_enum_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * enumName,const std::vector<T> & valid_values,uint32_t count,const T * array,bool countRequired,bool arrayRequired)662 bool validate_ranged_enum_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, 663 const char *enumName, const std::vector<T> &valid_values, uint32_t count, const T *array, 664 bool countRequired, bool arrayRequired) { 665 bool skip_call = false; 666 667 if ((count == 0) || (array == NULL)) { 668 skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired, kVUIDUndefined, 669 kVUIDUndefined); 670 } else { 671 for (uint32_t i = 0; i < count; ++i) { 672 if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) { 673 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 674 kVUID_PVError_UnrecognizedValue, 675 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s " 676 "enumeration tokens and is not an extension added token", 677 apiName, arrayName.get_name().c_str(), i, array[i], enumName); 678 } 679 } 680 } 681 682 return skip_call; 683 } 684 685 /** 686 * Verify that a reserved VkFlags value is zero. 687 * 688 * Verify that the specified value is zero, to check VkFlags values that are reserved for 689 * future use. 690 * 691 * @param api_name Name of API call being validated. 692 * @param parameter_name Name of parameter being validated. 693 * @param value Value to validate. 694 * @return Boolean value indicating that the call should be skipped. 695 */ validate_reserved_flags(const char * api_name,const ParameterName & parameter_name,VkFlags value,const char * vuid)696 bool validate_reserved_flags(const char *api_name, const ParameterName ¶meter_name, VkFlags value, const char *vuid) { 697 bool skip_call = false; 698 699 if (value != 0) { 700 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 701 "%s: parameter %s must be 0.", api_name, parameter_name.get_name().c_str()); 702 } 703 704 return skip_call; 705 } 706 707 enum FlagType { kRequiredFlags, kOptionalFlags, kRequiredSingleBit, kOptionalSingleBit }; 708 709 /** 710 * Validate a Vulkan bitmask value. 711 * 712 * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits 713 * for that type. 714 * 715 * @param api_name Name of API call being validated. 716 * @param parameter_name Name of parameter being validated. 717 * @param flag_bits_name Name of the VkFlags type being validated. 718 * @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated. 719 * @param value VkFlags value to validate. 720 * @param flag_type The type of flag, like optional, or single bit. 721 * @param vuid VUID used for flag that is outside defined bits (or has more than one bit for Bits type). 722 * @param flags_zero_vuid VUID used for non-optional Flags that are zero. 723 * @return Boolean value indicating that the call should be skipped. 724 */ 725 bool validate_flags(const char *api_name, const ParameterName ¶meter_name, const char *flag_bits_name, VkFlags all_flags, 726 VkFlags value, const FlagType flag_type, const char *vuid, const char *flags_zero_vuid = nullptr) { 727 bool skip_call = false; 728 729 if ((value & ~all_flags) != 0) { 730 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 731 "%s: value of %s contains flag bits that are not recognized members of %s", api_name, 732 parameter_name.get_name().c_str(), flag_bits_name); 733 } 734 735 const bool required = flag_type == kRequiredFlags || flag_type == kRequiredSingleBit; 736 const char *zero_vuid = flag_type == kRequiredFlags ? flags_zero_vuid : vuid; 737 if (required && value == 0) { 738 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, zero_vuid, 739 "%s: value of %s must not be 0.", api_name, parameter_name.get_name().c_str()); 740 } 741 742 const auto HasMaxOneBitSet = [](const VkFlags f) { 743 // Decrement flips bits from right upto first 1. 744 // Rest stays same, and if there was any other 1s &ded together they would be non-zero. QED 745 return f == 0 || !(f & (f - 1)); 746 }; 747 748 const bool is_bits_type = flag_type == kRequiredSingleBit || flag_type == kOptionalSingleBit; 749 if (is_bits_type && !HasMaxOneBitSet(value)) { 750 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 751 "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name, 752 parameter_name.get_name().c_str(), flag_bits_name); 753 } 754 755 return skip_call; 756 } 757 758 /** 759 * Validate an array of Vulkan bitmask values. 760 * 761 * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits 762 * for that type. 763 * 764 * @param api_name Name of API call being validated. 765 * @param count_name Name of parameter being validated. 766 * @param array_name Name of parameter being validated. 767 * @param flag_bits_name Name of the VkFlags type being validated. 768 * @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated. 769 * @param count Number of VkFlags values in the array. 770 * @param array Array of VkFlags value to validate. 771 * @param count_required The 'count' parameter may not be 0 when true. 772 * @param array_required The 'array' parameter may not be NULL when true. 773 * @return Boolean value indicating that the call should be skipped. 774 */ validate_flags_array(const char * api_name,const ParameterName & count_name,const ParameterName & array_name,const char * flag_bits_name,VkFlags all_flags,uint32_t count,const VkFlags * array,bool count_required,bool array_required)775 bool validate_flags_array(const char *api_name, const ParameterName &count_name, const ParameterName &array_name, 776 const char *flag_bits_name, VkFlags all_flags, uint32_t count, const VkFlags *array, 777 bool count_required, bool array_required) { 778 bool skip_call = false; 779 780 if ((count == 0) || (array == NULL)) { 781 skip_call |= validate_array(api_name, count_name, array_name, count, &array, count_required, array_required, 782 kVUIDUndefined, kVUIDUndefined); 783 } else { 784 // Verify that all VkFlags values in the array 785 for (uint32_t i = 0; i < count; ++i) { 786 if (array[i] == 0) { 787 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if 788 // elements in the array are allowed be 0 789 if (array_required) { 790 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 791 kVUID_PVError_RequiredParameter, "%s: value of %s[%d] must not be 0", api_name, 792 array_name.get_name().c_str(), i); 793 } 794 } else if ((array[i] & (~all_flags)) != 0) { 795 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 796 kVUID_PVError_UnrecognizedValue, 797 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name, 798 array_name.get_name().c_str(), i, flag_bits_name); 799 } 800 } 801 } 802 803 return skip_call; 804 } 805 806 template <typename ExtensionState> validate_extension_reqs(const ExtensionState & extensions,const char * vuid,const char * extension_type,const char * extension_name)807 bool validate_extension_reqs(const ExtensionState &extensions, const char *vuid, const char *extension_type, 808 const char *extension_name) { 809 bool skip = false; 810 if (!extension_name) { 811 return skip; // Robust to invalid char * 812 } 813 auto info = ExtensionState::get_info(extension_name); 814 815 if (!info.state) { 816 return skip; // Unknown extensions cannot be checked so report OK 817 } 818 819 // Check against the required list in the info 820 std::vector<const char *> missing; 821 for (const auto &req : info.requires) { 822 if (!(extensions.*(req.enabled))) { 823 missing.push_back(req.name); 824 } 825 } 826 827 // Report any missing requirements 828 if (missing.size()) { 829 std::string missing_joined_list = string_join(", ", missing); 830 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 831 HandleToUint64(instance), vuid, "Missing extension%s required by the %s extension %s: %s.", 832 ((missing.size() > 1) ? "s" : ""), extension_type, extension_name, missing_joined_list.c_str()); 833 } 834 return skip; 835 } 836 837 enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 }; 838 839 template <typename RenderPassCreateInfoGeneric> ValidateSubpassGraphicsFlags(const debug_report_data * report_data,const RenderPassCreateInfoGeneric * pCreateInfo,uint32_t dependency_index,uint32_t subpass,VkPipelineStageFlags stages,const char * vuid,const char * target)840 bool ValidateSubpassGraphicsFlags(const debug_report_data *report_data, const RenderPassCreateInfoGeneric *pCreateInfo, 841 uint32_t dependency_index, uint32_t subpass, VkPipelineStageFlags stages, const char *vuid, 842 const char *target) { 843 const VkPipelineStageFlags kCommonStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 844 const VkPipelineStageFlags kFramebufferStages = 845 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | 846 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 847 const VkPipelineStageFlags kPrimitiveShadingPipelineStages = 848 kCommonStages | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | 849 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | 850 VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | 851 VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT | VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV | kFramebufferStages; 852 const VkPipelineStageFlags kMeshShadingPipelineStages = 853 kCommonStages | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV | 854 VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV | kFramebufferStages; 855 const VkPipelineStageFlags kFragmentDensityStages = VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT; 856 const VkPipelineStageFlags kConditionalRenderingStages = VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT; 857 const VkPipelineStageFlags kCommandProcessingPipelineStages = kCommonStages | VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX; 858 859 const VkPipelineStageFlags kGraphicsStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | kPrimitiveShadingPipelineStages | 860 kMeshShadingPipelineStages | kFragmentDensityStages | 861 kConditionalRenderingStages | kCommandProcessingPipelineStages; 862 863 bool skip = false; 864 865 const auto IsPipeline = [pCreateInfo](uint32_t subpass, const VkPipelineBindPoint stage) { 866 if (subpass == VK_SUBPASS_EXTERNAL) 867 return false; 868 else 869 return pCreateInfo->pSubpasses[subpass].pipelineBindPoint == stage; 870 }; 871 872 const bool is_all_graphics_stages = (stages & ~kGraphicsStages) == 0; 873 if (IsPipeline(subpass, VK_PIPELINE_BIND_POINT_GRAPHICS) && !is_all_graphics_stages) { 874 skip |= 875 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, 0, vuid, 876 "Dependency pDependencies[%" PRIu32 877 "] specifies a %sStageMask that contains stages (%s) that are not part " 878 "of the Graphics pipeline, as specified by the %sSubpass (= %" PRIu32 ") in pipelineBindPoint.", 879 dependency_index, target, string_VkPipelineStageFlags(stages & ~kGraphicsStages).c_str(), target, subpass); 880 } 881 882 return skip; 883 }; 884 885 template <typename RenderPassCreateInfoGeneric> CreateRenderPassGeneric(VkDevice device,const RenderPassCreateInfoGeneric * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass,RenderPassCreateVersion rp_version)886 bool CreateRenderPassGeneric(VkDevice device, const RenderPassCreateInfoGeneric *pCreateInfo, 887 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, 888 RenderPassCreateVersion rp_version) { 889 bool skip = false; 890 uint32_t max_color_attachments = device_limits.maxColorAttachments; 891 bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); 892 const char *vuid; 893 894 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { 895 if (pCreateInfo->pAttachments[i].format == VK_FORMAT_UNDEFINED) { 896 std::stringstream ss; 897 ss << (use_rp2 ? "vkCreateRenderPass2KHR" : "vkCreateRenderPass") << ": pCreateInfo->pAttachments[" << i 898 << "].format is VK_FORMAT_UNDEFINED. "; 899 vuid = 900 use_rp2 ? "VUID-VkAttachmentDescription2KHR-format-parameter" : "VUID-VkAttachmentDescription-format-parameter"; 901 skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 902 "%s", ss.str().c_str()); 903 } 904 if (pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_UNDEFINED || 905 pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) { 906 vuid = use_rp2 ? "VUID-VkAttachmentDescription2KHR-finalLayout-03061" 907 : "VUID-VkAttachmentDescription-finalLayout-00843"; 908 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 909 "pCreateInfo->pAttachments[%d].finalLayout must not be VK_IMAGE_LAYOUT_UNDEFINED or " 910 "VK_IMAGE_LAYOUT_PREINITIALIZED.", 911 i); 912 } 913 } 914 915 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { 916 if (pCreateInfo->pSubpasses[i].colorAttachmentCount > max_color_attachments) { 917 vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063" 918 : "VUID-VkSubpassDescription-colorAttachmentCount-00845"; 919 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, 920 "Cannot create a render pass with %d color attachments. Max is %d.", 921 pCreateInfo->pSubpasses[i].colorAttachmentCount, max_color_attachments); 922 } 923 } 924 925 for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) { 926 const auto &dependency = pCreateInfo->pDependencies[i]; 927 928 // Spec currently only supports Graphics pipeline in render pass -- so only that pipeline is currently checked 929 vuid = 930 use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03054" : "VUID-VkRenderPassCreateInfo-pDependencies-00837"; 931 skip |= ValidateSubpassGraphicsFlags(report_data, pCreateInfo, i, dependency.srcSubpass, dependency.srcStageMask, vuid, 932 "src"); 933 934 vuid = 935 use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03055" : "VUID-VkRenderPassCreateInfo-pDependencies-00838"; 936 skip |= ValidateSubpassGraphicsFlags(report_data, pCreateInfo, i, dependency.dstSubpass, dependency.dstStageMask, vuid, 937 "dst"); 938 } 939 940 return skip; 941 } 942 943 template <typename T> RecordRenderPass(VkRenderPass renderPass,const T * pCreateInfo)944 void RecordRenderPass(VkRenderPass renderPass, const T *pCreateInfo) { 945 std::unique_lock<std::mutex> lock(renderpass_map_mutex); 946 auto &renderpass_state = renderpasses_states[renderPass]; 947 lock.unlock(); 948 949 for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) { 950 bool uses_color = false; 951 for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i) 952 if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true; 953 954 bool uses_depthstencil = false; 955 if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment) 956 if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) 957 uses_depthstencil = true; 958 959 if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass); 960 if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass); 961 } 962 } 963 964 bool require_device_extension(bool flag, char const *function_name, char const *extension_name); 965 966 bool validate_instance_extensions(const VkInstanceCreateInfo *pCreateInfo); 967 968 bool validate_api_version(uint32_t api_version, uint32_t effective_api_version); 969 970 bool validate_string(const char *apiName, const ParameterName &stringName, const std::string &vuid, const char *validateString); 971 972 bool ValidateCoarseSampleOrderCustomNV(const VkCoarseSampleOrderCustomNV *order); 973 974 bool ValidateQueueFamilies(uint32_t queue_family_count, const uint32_t *queue_families, const char *cmd_name, 975 const char *array_parameter_name, const std::string &unique_error_code, 976 const std::string &valid_error_code, bool optional); 977 978 bool ValidateDeviceQueueFamily(uint32_t queue_family, const char *cmd_name, const char *parameter_name, 979 const std::string &error_code, bool optional); 980 981 bool ValidateGeometryTrianglesNV(const VkGeometryTrianglesNV &triangles, VkDebugReportObjectTypeEXT object_type, 982 uint64_t object_handle, const char *func_name) const; 983 bool ValidateGeometryAABBNV(const VkGeometryAABBNV &geometry, VkDebugReportObjectTypeEXT object_type, uint64_t object_handle, 984 const char *func_name) const; 985 bool ValidateGeometryNV(const VkGeometryNV &geometry, VkDebugReportObjectTypeEXT object_type, uint64_t object_handle, 986 const char *func_name) const; 987 bool ValidateAccelerationStructureInfoNV(const VkAccelerationStructureInfoNV &info, VkDebugReportObjectTypeEXT object_type, 988 uint64_t object_handle, const char *func_nam) const; 989 990 bool OutputExtensionError(const std::string &api_name, const std::string &extension_name); 991 992 void PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, 993 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, VkResult result); 994 void PostCallRecordCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, 995 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, VkResult result); 996 void PostCallRecordDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator); 997 void PostCallRecordCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, 998 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result); 999 1000 void PostCallRecordCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 1001 VkInstance *pInstance, VkResult result); 1002 1003 void PostCallRecordQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo, VkResult result); 1004 1005 bool manual_PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, 1006 const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool); 1007 1008 bool manual_PreCallValidateCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 1009 VkInstance *pInstance); 1010 1011 bool manual_PreCallValidateCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, 1012 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice); 1013 1014 bool manual_PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, 1015 const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer); 1016 1017 bool manual_PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, 1018 const VkAllocationCallbacks *pAllocator, VkImage *pImage); 1019 1020 bool manual_PreCallValidateViewport(const VkViewport &viewport, const char *fn_name, const ParameterName ¶meter_name, 1021 VkDebugReportObjectTypeEXT object_type, uint64_t object); 1022 1023 bool manual_PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, 1024 const VkGraphicsPipelineCreateInfo *pCreateInfos, 1025 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); 1026 bool manual_PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, 1027 const VkComputePipelineCreateInfo *pCreateInfos, 1028 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); 1029 1030 bool manual_PreCallValidateCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, 1031 const VkAllocationCallbacks *pAllocator, VkSampler *pSampler); 1032 bool manual_PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, 1033 const VkAllocationCallbacks *pAllocator, 1034 VkDescriptorSetLayout *pSetLayout); 1035 1036 bool manual_PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, 1037 const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount, 1038 const VkCopyDescriptorSet *pDescriptorCopies); 1039 1040 bool manual_PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, 1041 const VkDescriptorSet *pDescriptorSets); 1042 1043 bool manual_PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, 1044 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); 1045 1046 bool manual_PreCallValidateCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, 1047 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); 1048 1049 bool manual_PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, 1050 const VkCommandBuffer *pCommandBuffers); 1051 1052 bool manual_PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo); 1053 1054 bool manual_PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, 1055 const VkViewport *pViewports); 1056 1057 bool manual_PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, 1058 const VkRect2D *pScissors); 1059 bool manual_PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth); 1060 1061 bool manual_PreCallValidateCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, 1062 uint32_t firstVertex, uint32_t firstInstance); 1063 1064 bool manual_PreCallValidateCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, 1065 uint32_t stride); 1066 1067 bool manual_PreCallValidateCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, 1068 uint32_t count, uint32_t stride); 1069 1070 bool manual_PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, 1071 const VkClearAttachment *pAttachments, uint32_t rectCount, 1072 const VkClearRect *pRects); 1073 1074 bool manual_PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, 1075 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, 1076 const VkImageCopy *pRegions); 1077 1078 bool manual_PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, 1079 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, 1080 const VkImageBlit *pRegions, VkFilter filter); 1081 1082 bool manual_PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, 1083 VkImageLayout dstImageLayout, uint32_t regionCount, 1084 const VkBufferImageCopy *pRegions); 1085 1086 bool manual_PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, 1087 VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions); 1088 1089 bool manual_PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, 1090 VkDeviceSize dataSize, const void *pData); 1091 1092 bool manual_PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, 1093 VkDeviceSize size, uint32_t data); 1094 1095 bool manual_PreCallValidateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, 1096 const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain); 1097 bool manual_PreCallValidateQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo); 1098 1099 #ifdef VK_USE_PLATFORM_WIN32_KHR 1100 bool manual_PreCallValidateCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo, 1101 const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface); 1102 #endif // VK_USE_PLATFORM_WIN32_KHR 1103 1104 bool manual_PreCallValidateCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, 1105 const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool); 1106 bool manual_PreCallValidateCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, 1107 uint32_t groupCountZ); 1108 1109 bool manual_PreCallValidateCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); 1110 1111 bool manual_PreCallValidateCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, 1112 uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, 1113 uint32_t groupCountZ); 1114 bool manual_PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, 1115 uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors); 1116 bool manual_PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, 1117 uint32_t viewportCount, 1118 const VkShadingRatePaletteNV *pShadingRatePalettes); 1119 1120 bool manual_PreCallValidateCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, 1121 uint32_t customSampleOrderCount, 1122 const VkCoarseSampleOrderCustomNV *pCustomSampleOrders); 1123 1124 bool manual_PreCallValidateCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); 1125 bool manual_PreCallValidateCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, 1126 uint32_t drawCount, uint32_t stride); 1127 1128 bool manual_PreCallValidateCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, 1129 VkBuffer countBuffer, VkDeviceSize countBufferOffset, 1130 uint32_t maxDrawCount, uint32_t stride); 1131 1132 bool manual_PreCallValidateEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, 1133 uint32_t *pPropertyCount, VkExtensionProperties *pProperties); 1134 bool manual_PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, 1135 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory); 1136 1137 bool manual_PreCallValidateCreateAccelerationStructureNV(VkDevice device, 1138 const VkAccelerationStructureCreateInfoNV *pCreateInfo, 1139 const VkAllocationCallbacks *pAllocator, 1140 VkAccelerationStructureNV *pAccelerationStructure); 1141 bool manual_PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer, 1142 const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData, 1143 VkDeviceSize instanceOffset, VkBool32 update, 1144 VkAccelerationStructureNV dst, VkAccelerationStructureNV src, 1145 VkBuffer scratch, VkDeviceSize scratchOffset); 1146 bool manual_PreCallValidateGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, 1147 size_t dataSize, void *pData); 1148 bool manual_PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, 1149 const VkRayTracingPipelineCreateInfoNV *pCreateInfos, 1150 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); 1151 1152 #ifdef VK_USE_PLATFORM_WIN32_KHR 1153 bool PreCallValidateGetDeviceGroupSurfacePresentModes2EXT(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, 1154 VkDeviceGroupPresentModeFlagsKHR *pModes); 1155 #endif // VK_USE_PLATFORM_WIN32_KHR 1156 1157 bool manual_PreCallValidateCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, 1158 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer); 1159 1160 bool manual_PreCallValidateCmdSetLineStippleEXT(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, 1161 uint16_t lineStipplePattern); 1162 1163 bool manual_PreCallValidateCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, 1164 VkIndexType indexType); 1165 1166 #include "parameter_validation.h" 1167 }; // Class StatelessValidation 1168