| 232 | } |
| 233 | |
| 234 | bool Context::ValidateStructPnext(const Location& loc, const void* next, size_t allowed_type_count, |
| 235 | const VkStructureType* allowed_types, uint32_t header_version, const char* pnext_vuid, |
| 236 | const char* stype_vuid, const bool is_const_param) const { |
| 237 | bool skip = false; |
| 238 | |
| 239 | if (HasCustomStypeInfo()) { |
| 240 | return skip; |
| 241 | } |
| 242 | |
| 243 | if (next != nullptr) { |
| 244 | vvl::unordered_set<const void*> cycle_check; |
| 245 | vvl::unordered_set<VkStructureType, vvl::hash<int>> unique_stype_check; |
| 246 | const char* disclaimer = |
| 247 | "This error is based on the Valid Usage documentation for version %" PRIu32 |
| 248 | " of the Vulkan header. It is possible that " |
| 249 | "you are using a struct from a private extension or an extension that was added to a later version of the Vulkan " |
| 250 | "header, in which case the use of %s is undefined and may not work correctly with validation enabled"; |
| 251 | |
| 252 | const Location pNext_loc = loc.dot(Field::pNext); |
| 253 | if (allowed_type_count == 0) { |
| 254 | std::string message = "must be NULL.\n"; |
| 255 | message += disclaimer; |
| 256 | skip |= |
| 257 | log.LogError(pnext_vuid, error_obj.handle, pNext_loc, message.c_str(), header_version, pNext_loc.Fields().c_str()); |
| 258 | } else { |
| 259 | const VkStructureType* start = allowed_types; |
| 260 | const VkStructureType* end = allowed_types + allowed_type_count; |
| 261 | const VkBaseOutStructure* current = reinterpret_cast<const VkBaseOutStructure*>(next); |
| 262 | |
| 263 | while (current != nullptr) { |
| 264 | if ((loc.function != Func::vkCreateInstance || (current->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)) && |
| 265 | (loc.function != Func::vkCreateDevice || (current->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO))) { |
| 266 | if (unique_stype_check.find(current->sType) != unique_stype_check.end() && !IsDuplicatePnext(current->sType)) { |
| 267 | // stype_vuid will only be null if there are no listed pNext and will hit disclaimer check |
| 268 | skip |= log.LogError(stype_vuid, error_obj.handle, pNext_loc, |
| 269 | "chain contains duplicate structure types: %s appears multiple times.\n%s", |
| 270 | string_VkStructureName(current->sType), PrintPNextChain(loc.structure, next).c_str()); |
| 271 | } else { |
| 272 | unique_stype_check.insert(current->sType); |
| 273 | } |
| 274 | |
| 275 | if (std::find(start, end, current->sType) == end) { |
| 276 | const std::string type_name = string_VkStructureType(current->sType); |
| 277 | if (type_name.compare("Unhandled VkStructureType") == 0) { |
| 278 | std::string message = "chain includes a structure with unknown VkStructureType (%" PRIu32 ").\n%s\n"; |
| 279 | message += disclaimer; |
| 280 | skip |= log.LogError(pnext_vuid, error_obj.handle, pNext_loc, message.c_str(), current->sType, |
| 281 | PrintPNextChain(Struct::Empty, next).c_str(), header_version, |
| 282 | pNext_loc.Fields().c_str()); |
| 283 | } else { |
| 284 | std::string message = "chain includes a structure with unexpected VkStructureType %s.\n%s\n"; |
| 285 | message += disclaimer; |
| 286 | skip |= log.LogError(pnext_vuid, error_obj.handle, pNext_loc, message.c_str(), type_name.c_str(), |
| 287 | PrintPNextChain(Struct::Empty, next).c_str(), header_version, |
| 288 | pNext_loc.Fields().c_str()); |
| 289 | } |
| 290 | } |
| 291 | // Send Location without pNext field so the pNext() connector can be used |
no test coverage detected