| 402 | } |
| 403 | |
| 404 | std::string FormatErrorMessage(const HazardResult& hazard, const CommandExecutionContext& context, vvl::Func command, |
| 405 | const std::string& resouce_description, const AdditionalMessageInfo& additional_info) { |
| 406 | const SyncHazard hazard_type = hazard.Hazard(); |
| 407 | const SyncHazardInfo hazard_info = GetSyncHazardInfo(hazard_type); |
| 408 | |
| 409 | const SyncAccessInfo& access = GetAccessInfo(hazard.State().access_index); |
| 410 | const SyncAccessInfo& prior_access = GetAccessInfo(hazard.State().prior_access_index); |
| 411 | |
| 412 | const SyncAccessFlags write_barriers = hazard.State().access_state->GetWriteBarriers(); |
| 413 | VkPipelineStageFlags2 read_barriers = hazard.State().access_state->GetReadBarriers(hazard.State().prior_access_index); |
| 414 | |
| 415 | // TODO: BOTTOM_OF_PIPE part will go away when syncval switches internally to use NONE/ALL for everything. |
| 416 | // Remove this block then. |
| 417 | if (read_barriers & VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT) { |
| 418 | read_barriers &= ~VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT; |
| 419 | } |
| 420 | |
| 421 | const bool missing_synchronization = (hazard_info.IsPriorWrite() && write_barriers.none()) || |
| 422 | (hazard_info.IsPriorRead() && read_barriers == VK_PIPELINE_STAGE_2_NONE); |
| 423 | |
| 424 | std::ostringstream ss; |
| 425 | |
| 426 | // Brief description of what happened |
| 427 | ss << string_SyncHazard(hazard_type) << " hazard detected"; |
| 428 | if (!additional_info.hazard_overview.empty()) { |
| 429 | ss << ": " << additional_info.hazard_overview; |
| 430 | } |
| 431 | ss << ". "; |
| 432 | ss << (additional_info.access_initiator.empty() ? vvl::String(command) : additional_info.access_initiator); |
| 433 | ss << " "; |
| 434 | if (!additional_info.access_action.empty()) { |
| 435 | ss << additional_info.access_action; |
| 436 | } else { |
| 437 | ss << (hazard_info.IsWrite() ? "writes to" : "reads"); |
| 438 | } |
| 439 | ss << " " << resouce_description << ", which was previously "; |
| 440 | if (prior_access.access_index == SYNC_PRESENT_ENGINE_SYNCVAL_PRESENT_ACQUIRE_READ_SYNCVAL) { |
| 441 | ss << "accessed "; |
| 442 | } else if (hazard_info.IsPriorWrite()) { |
| 443 | if (prior_access.access_index == SYNC_IMAGE_LAYOUT_TRANSITION) { |
| 444 | ss << "written during an image layout transition initiated "; |
| 445 | } else { |
| 446 | ss << "written "; |
| 447 | } |
| 448 | } else { |
| 449 | ss << "read "; |
| 450 | } |
| 451 | if (hazard.Tag() == kInvalidTag) { |
| 452 | // Invalid tag for prior access means the same command performed ILT before loadOp, |
| 453 | // resolve before ILT or ILT after storeOp. |
| 454 | ss << "by the same command"; |
| 455 | } else { |
| 456 | const ResourceUsageInfo prior_usage_info = context.GetResourceUsageInfo(hazard.TagEx()); |
| 457 | const vvl::Func prior_command = prior_usage_info.command; |
| 458 | if (prior_usage_info.sub_command_type == SubCommandType::kLoadOp) { |
| 459 | if (prior_usage_info.subpass != vvl::kNoIndex32) { |
| 460 | ss << "at the beginning of subpass " << prior_usage_info.subpass << " "; |
| 461 | } else { |
no test coverage detected