diff options
Diffstat (limited to 'layers/buffer_validation.cpp')
-rw-r--r-- | layers/buffer_validation.cpp | 605 |
1 files changed, 374 insertions, 231 deletions
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp index 8340d037d..4e16e8e63 100644 --- a/layers/buffer_validation.cpp +++ b/layers/buffer_validation.cpp @@ -29,6 +29,7 @@ #include <string> #include "vk_enum_string_helper.h" +#include "vk_format_utils.h" #include "vk_layer_data.h" #include "vk_layer_utils.h" #include "vk_layer_logging.h" @@ -113,6 +114,8 @@ IMAGE_VIEW_STATE::IMAGE_VIEW_STATE(const IMAGE_STATE *image_state, VkImageView i // Cache a full normalization (for "full image/whole image" comparisons) normalized_subresource_range = NormalizeSubresourceRange(*image_state, ci->subresourceRange); + samples = image_state->createInfo.samples; + descriptor_format_bits = DescriptorRequirementsBitsFromFormat(create_info.format); } } @@ -174,8 +177,7 @@ void CoreChecks::SetLayout(OBJECT *pObject, ImageSubresourcePair imgpair, const } // Set the layout in supplied map -void CoreChecks::SetLayout(std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_STATE> &imageLayoutMap, - ImageSubresourcePair imgpair, VkImageLayout layout) { +void CoreChecks::SetLayout(ImageSubresPairLayoutMap &imageLayoutMap, ImageSubresourcePair imgpair, VkImageLayout layout) { auto it = imageLayoutMap.find(imgpair); if (it != imageLayoutMap.end()) { it->second.layout = layout; // Update @@ -246,8 +248,8 @@ bool CoreChecks::FindLayouts(VkImage image, std::vector<VkImageLayout> &layouts) return true; } -bool CoreChecks::FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_STATE> &imageLayoutMap, - ImageSubresourcePair imgpair, VkImageLayout &layout, const VkImageAspectFlags aspectMask) { +bool CoreChecks::FindLayout(const ImageSubresPairLayoutMap &imageLayoutMap, ImageSubresourcePair imgpair, VkImageLayout &layout, + const VkImageAspectFlags aspectMask) { if (!(imgpair.subresource.aspectMask & aspectMask)) { return false; } @@ -261,8 +263,8 @@ bool CoreChecks::FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE } // find layout in supplied map -bool CoreChecks::FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_STATE> &imageLayoutMap, - ImageSubresourcePair imgpair, VkImageLayout &layout) { +bool CoreChecks::FindLayout(const ImageSubresPairLayoutMap &imageLayoutMap, ImageSubresourcePair imgpair, + VkImageLayout &layout) const { layout = VK_IMAGE_LAYOUT_MAX_ENUM; FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT); FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT); @@ -312,6 +314,9 @@ void CoreChecks::SetImageLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_STATE &im // Set the initial image layout for all slices of an image view void CoreChecks::SetImageViewInitialLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_VIEW_STATE &view_state, VkImageLayout layout) { + if (disabled.image_layout_validation) { + return; + } IMAGE_STATE *image_state = GetImageState(view_state.create_info.image); if (image_state) { auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, *image_state); @@ -358,7 +363,7 @@ void CoreChecks::SetImageViewLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_VIEW_ bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPassCreateVersion rp_version, VkImageLayout layout, VkImage image, VkImageView image_view, VkFramebuffer framebuffer, VkRenderPass renderpass, - uint32_t attachment_index, const char *variable_name) { + uint32_t attachment_index, const char *variable_name) const { bool skip = false; auto image_state = GetImageState(image); const char *vuid; @@ -454,12 +459,13 @@ bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPass return skip; } -bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion rp_version, CMD_BUFFER_STATE *pCB, +bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion rp_version, const CMD_BUFFER_STATE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin, - const FRAMEBUFFER_STATE *framebuffer_state) { + const FRAMEBUFFER_STATE *framebuffer_state) const { bool skip = false; auto const pRenderPassInfo = GetRenderPassState(pRenderPassBegin->renderPass)->createInfo.ptr(); auto const &framebufferInfo = framebuffer_state->createInfo; + const VkImageView *attachments = framebufferInfo.pAttachments; auto render_pass = GetRenderPassState(pRenderPassBegin->renderPass)->renderPass; auto framebuffer = framebuffer_state->framebuffer; @@ -469,116 +475,124 @@ bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion r HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidRenderpass, "You cannot start a render pass using a framebuffer with a different number of attachments."); } - const auto *const_pCB = static_cast<const CMD_BUFFER_STATE *>(pCB); - for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { - const VkImageView &image_view = framebufferInfo.pAttachments[i]; - auto view_state = GetImageViewState(image_view); - if (!view_state) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, - HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter", - "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s is not a valid VkImageView handle", - report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i, - report_data->FormatHandle(image_view).c_str()); - continue; - } + const auto *attachmentInfo = lvl_find_in_chain<VkRenderPassAttachmentBeginInfoKHR>(pRenderPassBegin->pNext); + if (((framebufferInfo.flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) != 0) && attachmentInfo != nullptr) { + attachments = attachmentInfo->pAttachments; + } - const VkImage image = view_state->create_info.image; - const IMAGE_STATE *image_state = GetImageState(image); + if (attachments != nullptr) { + const auto *const_pCB = static_cast<const CMD_BUFFER_STATE *>(pCB); + for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { + auto image_view = attachments[i]; + auto view_state = GetImageViewState(image_view); + + if (!view_state) { + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, + HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter", + "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s is not a valid VkImageView handle", + report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i, + report_data->FormatHandle(image_view).c_str()); + continue; + } - if (!image_state) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, - HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter", - "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s references non-extant %s.", - report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i, - report_data->FormatHandle(image_view).c_str(), report_data->FormatHandle(image).c_str()); - continue; - } - auto attachment_initial_layout = pRenderPassInfo->pAttachments[i].initialLayout; - auto final_layout = pRenderPassInfo->pAttachments[i].finalLayout; - - // Cast pCB to const because we don't want to create entries that don't exist here (in case the key changes to something - // in common with the non-const version.) - const ImageSubresourceLayoutMap *subresource_map = - (attachment_initial_layout != VK_IMAGE_LAYOUT_UNDEFINED) ? GetImageSubresourceLayoutMap(const_pCB, image) : nullptr; - - if (subresource_map) { // If no layout information for image yet, will be checked at QueueSubmit time - LayoutUseCheckAndMessage layout_check(subresource_map); - bool subres_skip = false; - auto subresource_cb = [this, i, attachment_initial_layout, &layout_check, &subres_skip]( - const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) { - if (!layout_check.Check(subres, attachment_initial_layout, layout, initial_layout)) { - subres_skip |= - log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - kVUID_Core_DrawState_InvalidRenderpass, - "You cannot start a render pass using attachment %u where the render pass initial layout is %s " - "and the %s layout of the attachment is %s. The layouts must match, or the render " - "pass initial layout for the attachment must be VK_IMAGE_LAYOUT_UNDEFINED", - i, string_VkImageLayout(attachment_initial_layout), layout_check.message, - string_VkImageLayout(layout_check.layout)); - } - return !subres_skip; // quit checking subresources once we fail once - }; + const VkImage image = view_state->create_info.image; + const IMAGE_STATE *image_state = GetImageState(image); - subresource_map->ForRange(view_state->normalized_subresource_range, subresource_cb); - skip |= subres_skip; - } + if (!image_state) { + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, + HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter", + "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s references non-extant %s.", + report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i, + report_data->FormatHandle(image_view).c_str(), report_data->FormatHandle(image).c_str()); + continue; + } + auto attachment_initial_layout = pRenderPassInfo->pAttachments[i].initialLayout; + auto final_layout = pRenderPassInfo->pAttachments[i].finalLayout; - ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_initial_layout, image, image_view, framebuffer, - render_pass, i, "initial layout"); + // Cast pCB to const because we don't want to create entries that don't exist here (in case the key changes to something + // in common with the non-const version.) + const ImageSubresourceLayoutMap *subresource_map = + (attachment_initial_layout != VK_IMAGE_LAYOUT_UNDEFINED) ? GetImageSubresourceLayoutMap(const_pCB, image) : nullptr; - ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, final_layout, image, image_view, framebuffer, render_pass, - i, "final layout"); - } + if (subresource_map) { // If no layout information for image yet, will be checked at QueueSubmit time + LayoutUseCheckAndMessage layout_check(subresource_map); + bool subres_skip = false; + auto subresource_cb = [this, i, attachment_initial_layout, &layout_check, &subres_skip]( + const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) { + if (!layout_check.Check(subres, attachment_initial_layout, layout, initial_layout)) { + subres_skip |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + kVUID_Core_DrawState_InvalidRenderpass, + "You cannot start a render pass using attachment %u where the render pass initial layout is %s " + "and the %s layout of the attachment is %s. The layouts must match, or the render " + "pass initial layout for the attachment must be VK_IMAGE_LAYOUT_UNDEFINED", + i, string_VkImageLayout(attachment_initial_layout), layout_check.message, + string_VkImageLayout(layout_check.layout)); + } + return !subres_skip; // quit checking subresources once we fail once + }; - for (uint32_t j = 0; j < pRenderPassInfo->subpassCount; ++j) { - auto &subpass = pRenderPassInfo->pSubpasses[j]; - for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].inputAttachmentCount; ++k) { - auto &attachment_ref = subpass.pInputAttachments[k]; - if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { - auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment]; - auto view_state = GetImageViewState(image_view); + subresource_map->ForRange(view_state->normalized_subresource_range, subresource_cb); + skip |= subres_skip; + } - if (view_state) { - auto image = view_state->create_info.image; - ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view, - framebuffer, render_pass, attachment_ref.attachment, - "input attachment layout"); + ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_initial_layout, image, image_view, + framebuffer, render_pass, i, "initial layout"); + + ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, final_layout, image, image_view, framebuffer, + render_pass, i, "final layout"); + } + + for (uint32_t j = 0; j < pRenderPassInfo->subpassCount; ++j) { + auto &subpass = pRenderPassInfo->pSubpasses[j]; + for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].inputAttachmentCount; ++k) { + auto &attachment_ref = subpass.pInputAttachments[k]; + if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { + auto image_view = attachments[attachment_ref.attachment]; + auto view_state = GetImageViewState(image_view); + + if (view_state) { + auto image = view_state->create_info.image; + ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view, + framebuffer, render_pass, attachment_ref.attachment, + "input attachment layout"); + } } } - } - for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].colorAttachmentCount; ++k) { - auto &attachment_ref = subpass.pColorAttachments[k]; - if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { - auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment]; - auto view_state = GetImageViewState(image_view); + for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].colorAttachmentCount; ++k) { + auto &attachment_ref = subpass.pColorAttachments[k]; + if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { + auto image_view = attachments[attachment_ref.attachment]; + auto view_state = GetImageViewState(image_view); - if (view_state) { - auto image = view_state->create_info.image; - ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view, - framebuffer, render_pass, attachment_ref.attachment, - "color attachment layout"); - if (subpass.pResolveAttachments) { + if (view_state) { + auto image = view_state->create_info.image; ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view, framebuffer, render_pass, attachment_ref.attachment, - "resolve attachment layout"); + "color attachment layout"); + if (subpass.pResolveAttachments) { + ValidateRenderPassLayoutAgainstFramebufferImageUsage( + rp_version, attachment_ref.layout, image, image_view, framebuffer, render_pass, + attachment_ref.attachment, "resolve attachment layout"); + } } } } - } - if (pRenderPassInfo->pSubpasses[j].pDepthStencilAttachment) { - auto &attachment_ref = *subpass.pDepthStencilAttachment; - if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { - auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment]; - auto view_state = GetImageViewState(image_view); + if (pRenderPassInfo->pSubpasses[j].pDepthStencilAttachment) { + auto &attachment_ref = *subpass.pDepthStencilAttachment; + if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { + auto image_view = attachments[attachment_ref.attachment]; + auto view_state = GetImageViewState(image_view); - if (view_state) { - auto image = view_state->create_info.image; - ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view, - framebuffer, render_pass, attachment_ref.attachment, - "input attachment layout"); + if (view_state) { + auto image = view_state->create_info.image; + ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view, + framebuffer, render_pass, attachment_ref.attachment, + "input attachment layout"); + } } } } @@ -649,10 +663,11 @@ bool VerifyAspectsPresent(VkImageAspectFlags aspect_mask, VkFormat format) { } // Verify an ImageMemoryBarrier's old/new ImageLayouts are compatible with the Image's ImageUsageFlags. -bool CoreChecks::ValidateBarrierLayoutToImageUsage(const VkImageMemoryBarrier *img_barrier, bool new_not_old, - VkImageUsageFlags usage_flags, const char *func_name) { +bool CoreChecks::ValidateBarrierLayoutToImageUsage(const VkImageMemoryBarrier &img_barrier, bool new_not_old, + VkImageUsageFlags usage_flags, const char *func_name, + const char *barrier_pname) { bool skip = false; - const VkImageLayout layout = (new_not_old) ? img_barrier->newLayout : img_barrier->oldLayout; + const VkImageLayout layout = (new_not_old) ? img_barrier.newLayout : img_barrier.oldLayout; const char *msg_code = kVUIDUndefined; // sentinel value meaning "no error" switch (layout) { @@ -698,123 +713,122 @@ bool CoreChecks::ValidateBarrierLayoutToImageUsage(const VkImageMemoryBarrier *i if (msg_code != kVUIDUndefined) { skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(img_barrier->image), msg_code, - "%s: Image barrier 0x%p %s Layout=%s is not compatible with %s usage flags 0x%" PRIx32 ".", func_name, - static_cast<const void *>(img_barrier), ((new_not_old) ? "new" : "old"), string_VkImageLayout(layout), - report_data->FormatHandle(img_barrier->image).c_str(), usage_flags); + HandleToUint64(img_barrier.image), msg_code, + "%s: Image barrier %s %s Layout=%s is not compatible with %s usage flags 0x%" PRIx32 ".", func_name, + barrier_pname, ((new_not_old) ? "new" : "old"), string_VkImageLayout(layout), + report_data->FormatHandle(img_barrier.image).c_str(), usage_flags); } return skip; } -// Scoreboard for checking for duplicate and inconsistent barriers to images -struct ImageBarrierScoreboardEntry { - uint32_t index; - // This is designed for temporary storage within the scope of the API call. If retained storage of the barriers is - // required, copies should be made and smart or unique pointers used in some other stucture (or this one refactored) - const VkImageMemoryBarrier *barrier; -}; -using ImageBarrierScoreboardSubresMap = std::unordered_map<VkImageSubresourceRange, ImageBarrierScoreboardEntry>; -using ImageBarrierScoreboardImageMap = std::unordered_map<VkImage, ImageBarrierScoreboardSubresMap>; - // Verify image barriers are compatible with the images they reference. bool CoreChecks::ValidateBarriersToImages(CMD_BUFFER_STATE const *cb_state, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name) { bool skip = false; + // Scoreboard for checking for duplicate and inconsistent barriers to images + struct ImageBarrierScoreboardEntry { + uint32_t index; + // This is designed for temporary storage within the scope of the API call. If retained storage of the barriers is + // required, copies should be made and smart or unique pointers used in some other stucture (or this one refactored) + const VkImageMemoryBarrier *barrier; + }; + using ImageBarrierScoreboardSubresMap = std::unordered_map<VkImageSubresourceRange, ImageBarrierScoreboardEntry>; + using ImageBarrierScoreboardImageMap = std::unordered_map<VkImage, ImageBarrierScoreboardSubresMap>; + // Scoreboard for duplicate layout transition barriers within the list // Pointers retained in the scoreboard only have the lifetime of *this* call (i.e. within the scope of the API call) ImageBarrierScoreboardImageMap layout_transitions; for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) { - auto img_barrier = &pImageMemoryBarriers[i]; - if (!img_barrier) continue; + const auto &img_barrier = pImageMemoryBarriers[i]; + const std::string barrier_pname = "pImageMemoryBarrier[" + std::to_string(i) + "]"; // Update the scoreboard of layout transitions and check for barriers affecting the same image and subresource // TODO: a higher precision could be gained by adapting the command_buffer image_layout_map logic looking for conflicts // at a per sub-resource level - if (img_barrier->oldLayout != img_barrier->newLayout) { - ImageBarrierScoreboardEntry new_entry{i, img_barrier}; - auto image_it = layout_transitions.find(img_barrier->image); + if (img_barrier.oldLayout != img_barrier.newLayout) { + const ImageBarrierScoreboardEntry new_entry{i, &img_barrier}; + const auto image_it = layout_transitions.find(img_barrier.image); if (image_it != layout_transitions.end()) { auto &subres_map = image_it->second; - auto subres_it = subres_map.find(img_barrier->subresourceRange); + auto subres_it = subres_map.find(img_barrier.subresourceRange); if (subres_it != subres_map.end()) { auto &entry = subres_it->second; - if ((entry.barrier->newLayout != img_barrier->oldLayout) && - (img_barrier->oldLayout != VK_IMAGE_LAYOUT_UNDEFINED)) { - const VkImageSubresourceRange &range = img_barrier->subresourceRange; + if ((entry.barrier->newLayout != img_barrier.oldLayout) && + (img_barrier.oldLayout != VK_IMAGE_LAYOUT_UNDEFINED)) { + const VkImageSubresourceRange &range = img_barrier.subresourceRange; skip = log_msg( report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cb_state->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197", - "%s: pImageMemoryBarrier[%u] conflicts with earlier entry pImageMemoryBarrier[%u]. %s" + "%s: %s conflicts with earlier entry pImageMemoryBarrier[%u]. %s" " subresourceRange: aspectMask=%u baseMipLevel=%u levelCount=%u, baseArrayLayer=%u, layerCount=%u; " "conflicting barrier transitions image layout from %s when earlier barrier transitioned to layout %s.", - func_name, i, entry.index, report_data->FormatHandle(img_barrier->image).c_str(), range.aspectMask, - range.baseMipLevel, range.levelCount, range.baseArrayLayer, range.layerCount, - string_VkImageLayout(img_barrier->oldLayout), string_VkImageLayout(entry.barrier->newLayout)); + func_name, barrier_pname.c_str(), entry.index, report_data->FormatHandle(img_barrier.image).c_str(), + range.aspectMask, range.baseMipLevel, range.levelCount, range.baseArrayLayer, range.layerCount, + string_VkImageLayout(img_barrier.oldLayout), string_VkImageLayout(entry.barrier->newLayout)); } entry = new_entry; } else { - subres_map[img_barrier->subresourceRange] = new_entry; + subres_map[img_barrier.subresourceRange] = new_entry; } } else { - layout_transitions[img_barrier->image][img_barrier->subresourceRange] = new_entry; + layout_transitions[img_barrier.image][img_barrier.subresourceRange] = new_entry; } } - auto image_state = GetImageState(img_barrier->image); + auto image_state = GetImageState(img_barrier.image); if (image_state) { VkImageUsageFlags usage_flags = image_state->createInfo.usage; - skip |= ValidateBarrierLayoutToImageUsage(img_barrier, false, usage_flags, func_name); - skip |= ValidateBarrierLayoutToImageUsage(img_barrier, true, usage_flags, func_name); + skip |= ValidateBarrierLayoutToImageUsage(img_barrier, false, usage_flags, func_name, barrier_pname.c_str()); + skip |= ValidateBarrierLayoutToImageUsage(img_barrier, true, usage_flags, func_name, barrier_pname.c_str()); // Make sure layout is able to be transitioned, currently only presented shared presentable images are locked if (image_state->layout_locked) { // TODO: Add unique id for error when available skip |= log_msg( report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(img_barrier->image), 0, + HandleToUint64(img_barrier.image), 0, "Attempting to transition shared presentable %s" " from layout %s to layout %s, but image has already been presented and cannot have its layout transitioned.", - report_data->FormatHandle(img_barrier->image).c_str(), string_VkImageLayout(img_barrier->oldLayout), - string_VkImageLayout(img_barrier->newLayout)); + report_data->FormatHandle(img_barrier.image).c_str(), string_VkImageLayout(img_barrier.oldLayout), + string_VkImageLayout(img_barrier.newLayout)); } VkImageCreateInfo *image_create_info = &image_state->createInfo; // For a Depth/Stencil image both aspects MUST be set if (FormatIsDepthAndStencil(image_create_info->format)) { - auto const aspect_mask = img_barrier->subresourceRange.aspectMask; + auto const aspect_mask = img_barrier.subresourceRange.aspectMask; auto const ds_mask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; if ((aspect_mask & ds_mask) != (ds_mask)) { skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(img_barrier->image), "VUID-VkImageMemoryBarrier-image-01207", - "%s: Image barrier 0x%p references %s of format %s that must have the depth and stencil " + HandleToUint64(img_barrier.image), "VUID-VkImageMemoryBarrier-image-01207", + "%s: Image barrier %s references %s of format %s that must have the depth and stencil " "aspects set, but its aspectMask is 0x%" PRIx32 ".", - func_name, static_cast<const void *>(img_barrier), - report_data->FormatHandle(img_barrier->image).c_str(), + func_name, barrier_pname.c_str(), report_data->FormatHandle(img_barrier.image).c_str(), string_VkFormat(image_create_info->format), aspect_mask); } } - const auto *subresource_map = GetImageSubresourceLayoutMap(cb_state, img_barrier->image); - if (img_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + const auto *subresource_map = GetImageSubresourceLayoutMap(cb_state, img_barrier.image); + if (img_barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) { // TODO: Set memory invalid which is in mem_tracker currently // Not sure if this needs to be in the ForRange traversal, pulling it out as it is currently invariant with // subresource. } else if (subresource_map) { bool subres_skip = false; LayoutUseCheckAndMessage layout_check(subresource_map); - VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, img_barrier->subresourceRange); + VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, img_barrier.subresourceRange); auto subres_callback = [this, img_barrier, cb_state, &layout_check, &subres_skip]( const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) { - if (!layout_check.Check(subres, img_barrier->oldLayout, layout, initial_layout)) { + if (!layout_check.Check(subres, img_barrier.oldLayout, layout, initial_layout)) { subres_skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cb_state->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197", "For %s you cannot transition the layout of aspect=%d level=%d layer=%d from %s when the " "%s layout is %s.", - report_data->FormatHandle(img_barrier->image).c_str(), subres.aspectMask, subres.mipLevel, - subres.arrayLayer, string_VkImageLayout(img_barrier->oldLayout), layout_check.message, + report_data->FormatHandle(img_barrier.image).c_str(), subres.aspectMask, subres.mipLevel, + subres.arrayLayer, string_VkImageLayout(img_barrier.oldLayout), layout_check.message, string_VkImageLayout(layout_check.layout)); } return !subres_skip; @@ -827,11 +841,11 @@ bool CoreChecks::ValidateBarriersToImages(CMD_BUFFER_STATE const *cb_state, uint return skip; } -bool CoreChecks::IsReleaseOp(CMD_BUFFER_STATE *cb_state, VkImageMemoryBarrier const *barrier) { - if (!IsTransferOp(barrier)) return false; +bool CoreChecks::IsReleaseOp(CMD_BUFFER_STATE *cb_state, const VkImageMemoryBarrier &barrier) const { + if (!IsTransferOp(&barrier)) return false; auto pool = GetCommandPoolState(cb_state->createInfo.commandPool); - return pool && TempIsReleaseOp<VkImageMemoryBarrier, true>(pool, barrier); + return pool && TempIsReleaseOp<VkImageMemoryBarrier, true>(pool, &barrier); } template <typename Barrier> @@ -910,7 +924,7 @@ void CoreChecks::RecordBarriersQFOTransfers(CMD_BUFFER_STATE *cb_state, uint32_t template <typename BarrierRecord, typename Scoreboard> bool CoreChecks::ValidateAndUpdateQFOScoreboard(const debug_report_data *report_data, const CMD_BUFFER_STATE *cb_state, - const char *operation, const BarrierRecord &barrier, Scoreboard *scoreboard) { + const char *operation, const BarrierRecord &barrier, Scoreboard *scoreboard) const { // Record to the scoreboard or report that we have a duplication bool skip = false; auto inserted = scoreboard->insert(std::make_pair(barrier, cb_state)); @@ -928,7 +942,8 @@ bool CoreChecks::ValidateAndUpdateQFOScoreboard(const debug_report_data *report_ } template <typename Barrier> -bool CoreChecks::ValidateQueuedQFOTransferBarriers(CMD_BUFFER_STATE *cb_state, QFOTransferCBScoreboards<Barrier> *scoreboards) { +bool CoreChecks::ValidateQueuedQFOTransferBarriers(const CMD_BUFFER_STATE *cb_state, + QFOTransferCBScoreboards<Barrier> *scoreboards) const { using BarrierRecord = QFOTransferBarrier<Barrier>; using TypeTag = typename BarrierRecord::Tag; bool skip = false; @@ -976,9 +991,9 @@ bool CoreChecks::ValidateQueuedQFOTransferBarriers(CMD_BUFFER_STATE *cb_state, Q return skip; } -bool CoreChecks::ValidateQueuedQFOTransfers(CMD_BUFFER_STATE *cb_state, +bool CoreChecks::ValidateQueuedQFOTransfers(const CMD_BUFFER_STATE *cb_state, QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards, - QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) { + QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) const { bool skip = false; skip |= ValidateQueuedQFOTransferBarriers<VkImageMemoryBarrier>(cb_state, qfo_image_scoreboards); skip |= ValidateQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(cb_state, qfo_buffer_scoreboards); @@ -1024,8 +1039,7 @@ void CoreChecks::EraseQFOImageRelaseBarriers(const VkImage &image) { EraseQFORel void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t memBarrierCount, const VkImageMemoryBarrier *pImgMemBarriers) { for (uint32_t i = 0; i < memBarrierCount; ++i) { - auto mem_barrier = &pImgMemBarriers[i]; - if (!mem_barrier) continue; + const auto &mem_barrier = pImgMemBarriers[i]; // For ownership transfers, the barrier is specified twice; as a release // operation on the yielding queue family, and as an acquire operation @@ -1038,10 +1052,10 @@ void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t mem continue; } - auto *image_state = GetImageState(mem_barrier->image); + auto *image_state = GetImageState(mem_barrier.image); if (!image_state) continue; - VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, mem_barrier->subresourceRange); + VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, mem_barrier.subresourceRange); const auto &image_create_info = image_state->createInfo; // Special case for 3D images with VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR flag bit, where <extent.depth> and @@ -1052,7 +1066,7 @@ void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t mem normalized_isr.layerCount = image_create_info.extent.depth; // Treat each depth slice as a layer subresource } - SetImageLayout(cb_state, *image_state, normalized_isr, mem_barrier->newLayout, mem_barrier->oldLayout); + SetImageLayout(cb_state, *image_state, normalized_isr, mem_barrier.newLayout, mem_barrier.oldLayout); } } @@ -1060,6 +1074,7 @@ bool CoreChecks::VerifyImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_ const VkImageSubresourceRange &range, VkImageAspectFlags aspect_mask, VkImageLayout explicit_layout, VkImageLayout optimal_layout, const char *caller, const char *layout_invalid_msg_code, const char *layout_mismatch_msg_code, bool *error) const { + if (disabled.image_layout_validation) return false; assert(cb_node); assert(image_state); const auto image = image_state->image; @@ -1284,10 +1299,10 @@ bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *cre return skip; } -bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) { +bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const { bool skip = false; - IMAGE_STATE *image_state = GetImageState(image); + const IMAGE_STATE *image_state = GetImageState(image); if (image_state->imported_ahb && (0 == image_state->GetBoundMemory().size())) { skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), "VUID-vkGetImageSubresourceLayout-image-01895", @@ -1308,7 +1323,7 @@ void ValidationStateTracker::RecordCreateImageANDROID(const VkImageCreateInfo *c bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *create_info) { return false; } -bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) { return false; } +bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const { return false; } #endif // VK_USE_PLATFORM_ANDROID_KHR @@ -1360,6 +1375,36 @@ bool CoreChecks::PreCallValidateCreateImage(VkDevice device, const VkImageCreate "maxFramebufferHeight"); } + if (device_extensions.vk_ext_fragment_density_map) { + uint32_t ceiling_width = + (uint32_t)ceil((float)device_limits->maxFramebufferWidth / + std::max((float)phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width, 1.0f)); + if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.width > ceiling_width)) { + skip |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkImageCreateInfo-usage-02559", + "vkCreateImage(): Image usage flags include a fragment density map bit and image width (%u) exceeds the " + "ceiling of device " + "maxFramebufferWidth (%u) / minFragmentDensityTexelSize.width (%u). The ceiling value: %u", + pCreateInfo->extent.width, device_limits->maxFramebufferWidth, + phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width, ceiling_width); + } + + uint32_t ceiling_height = + (uint32_t)ceil((float)device_limits->maxFramebufferHeight / + std::max((float)phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height, 1.0f)); + if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.height > ceiling_height)) { + skip |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkImageCreateInfo-usage-02560", + "vkCreateImage(): Image usage flags include a fragment density map bit and image height (%u) exceeds the " + "ceiling of device " + "maxFramebufferHeight (%u) / minFragmentDensityTexelSize.height (%u). The ceiling value: %u", + pCreateInfo->extent.height, device_limits->maxFramebufferHeight, + phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height, ceiling_height); + } + } + VkImageFormatProperties format_limits = {}; VkResult res = GetPDImageFormatProperties(pCreateInfo, &format_limits); if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) { @@ -1460,15 +1505,27 @@ bool CoreChecks::PreCallValidateCreateImage(VkDevice device, const VkImageCreate void ValidationStateTracker::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage, VkResult result) { if (VK_SUCCESS != result) return; - IMAGE_STATE *is_node = new IMAGE_STATE(*pImage, pCreateInfo); + std::unique_ptr<IMAGE_STATE> is_node(new IMAGE_STATE(*pImage, pCreateInfo)); if (device_extensions.vk_android_external_memory_android_hardware_buffer) { - RecordCreateImageANDROID(pCreateInfo, is_node); + RecordCreateImageANDROID(pCreateInfo, is_node.get()); } const auto swapchain_info = lvl_find_in_chain<VkImageSwapchainCreateInfoKHR>(pCreateInfo->pNext); if (swapchain_info) { is_node->create_from_swapchain = swapchain_info->swapchain; } - imageMap.insert(std::make_pair(*pImage, std::unique_ptr<IMAGE_STATE>(is_node))); + + bool pre_fetch_memory_reqs = true; +#ifdef VK_USE_PLATFORM_ANDROID_KHR + if (is_node->external_format_android) { + // Do not fetch requirements for external memory images + pre_fetch_memory_reqs = false; + } +#endif + // Record the memory requirements in case they won't be queried + if (pre_fetch_memory_reqs) { + DispatchGetImageMemoryRequirements(device, *pImage, &is_node->requirements); + } + imageMap.insert(std::make_pair(*pImage, std::move(is_node))); } void CoreChecks::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, @@ -1483,7 +1540,6 @@ void CoreChecks::PostCallRecordCreateImage(VkDevice device, const VkImageCreateI ImageSubresourcePair subpair{*pImage, false, VkImageSubresource()}; imageSubresourceMap[*pImage].push_back(subpair); imageLayoutMap[subpair] = image_state; - imageLayoutMap[subpair] = image_state; } bool CoreChecks::PreCallValidateDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { @@ -2062,7 +2118,7 @@ bool CoreChecks::ValidateImageArrayLayerRange(const CMD_BUFFER_STATE *cb_node, c // Check valid usage Image Transfer Granularity requirements for elements of a VkBufferImageCopy structure bool CoreChecks::ValidateCopyBufferImageTransferGranularityRequirements(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img, const VkBufferImageCopy *region, const uint32_t i, - const char *function, const char *vuid) { + const char *function, const char *vuid) const { bool skip = false; VkExtent3D granularity = GetScaledItg(cb_node, img); skip |= CheckItgOffset(cb_node, ®ion->imageOffset, &granularity, i, function, "imageOffset", vuid); @@ -2768,28 +2824,26 @@ bool CoreChecks::ValidateClearAttachmentExtent(VkCommandBuffer command_buffer, u bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment *pAttachments, uint32_t rectCount, const VkClearRect *pRects) { - CMD_BUFFER_STATE *cb_node = GetCBState(commandBuffer); - bool skip = false; - if (cb_node) { - skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearAttachments()", VK_QUEUE_GRAPHICS_BIT, - "VUID-vkCmdClearAttachments-commandBuffer-cmdpool"); - skip |= ValidateCmd(cb_node, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()"); - // Warn if this is issued prior to Draw Cmd and clearing the entire attachment - if (!cb_node->hasDrawCmd && (cb_node->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) && - (cb_node->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) { - // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass) - // This warning should be made more specific. It'd be best to avoid triggering this test if it's a use that must call - // CmdClearAttachments. - skip |= - log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + const CMD_BUFFER_STATE *cb_node = GetCBState(commandBuffer); // TODO: Should be const, and never modified during validation + if (!cb_node) return skip; + + skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearAttachments()", VK_QUEUE_GRAPHICS_BIT, + "VUID-vkCmdClearAttachments-commandBuffer-cmdpool"); + skip |= ValidateCmd(cb_node, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()"); + // Warn if this is issued prior to Draw Cmd and clearing the entire attachment + if (!cb_node->hasDrawCmd && (cb_node->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) && + (cb_node->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) { + // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass) + // This warning should be made more specific. It'd be best to avoid triggering this test if it's a use that must call + // CmdClearAttachments. + skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), kVUID_Core_DrawState_ClearCmdBeforeDraw, "vkCmdClearAttachments() issued on %s prior to any Draw Cmds. It is recommended you " "use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.", report_data->FormatHandle(commandBuffer).c_str()); - } - skip |= OutsideRenderPass(cb_node, "vkCmdClearAttachments()", "VUID-vkCmdClearAttachments-renderpass"); } + skip |= OutsideRenderPass(cb_node, "vkCmdClearAttachments()", "VUID-vkCmdClearAttachments-renderpass"); // Validate that attachment is in reference list of active subpass if (cb_node->activeRenderPass) { @@ -2798,7 +2852,6 @@ bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffe const VkSubpassDescription2KHR *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass]; const auto *framebuffer = GetFramebufferState(cb_node->activeFramebuffer); const auto &render_area = cb_node->activeRenderPassBeginInfo.renderArea; - std::shared_ptr<std::vector<VkClearRect>> clear_rect_copy; for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) { auto clear_desc = &pAttachments[attachment_index]; @@ -2866,19 +2919,42 @@ bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffe if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) { skip |= ValidateClearAttachmentExtent(commandBuffer, attachment_index, framebuffer, fb_attachment, render_area, rectCount, pRects); - } else { - // if a secondary level command buffer inherits the framebuffer from the primary command buffer - // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time + } + } + } + return skip; +} + +void CoreChecks::PreCallRecordCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, + const VkClearAttachment *pAttachments, uint32_t rectCount, + const VkClearRect *pRects) { + auto *cb_node = GetCBState(commandBuffer); + if (cb_node->activeRenderPass && (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY)) { + const VkRenderPassCreateInfo2KHR *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr(); + const VkSubpassDescription2KHR *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass]; + std::shared_ptr<std::vector<VkClearRect>> clear_rect_copy; + for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) { + const auto clear_desc = &pAttachments[attachment_index]; + uint32_t fb_attachment = VK_ATTACHMENT_UNUSED; + if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) && + (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount)) { + fb_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment; + } else if ((clear_desc->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) && + subpass_desc->pDepthStencilAttachment) { + fb_attachment = subpass_desc->pDepthStencilAttachment->attachment; + } + if (fb_attachment != VK_ATTACHMENT_UNUSED) { if (!clear_rect_copy) { // We need a copy of the clear rectangles that will persist until the last lambda executes // but we want to create it as lazily as possible clear_rect_copy.reset(new std::vector<VkClearRect>(pRects, pRects + rectCount)); } - + // if a secondary level command buffer inherits the framebuffer from the primary command buffer + // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time auto val_fn = [this, commandBuffer, attachment_index, fb_attachment, rectCount, clear_rect_copy]( - CMD_BUFFER_STATE *prim_cb, VkFramebuffer fb) { + const CMD_BUFFER_STATE *prim_cb, VkFramebuffer fb) { assert(rectCount == clear_rect_copy->size()); - FRAMEBUFFER_STATE *framebuffer = GetFramebufferState(fb); + const FRAMEBUFFER_STATE *framebuffer = GetFramebufferState(fb); const auto &render_area = prim_cb->activeRenderPassBeginInfo.renderArea; bool skip = false; skip = ValidateClearAttachmentExtent(commandBuffer, attachment_index, framebuffer, fb_attachment, render_area, @@ -2889,7 +2965,6 @@ bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffe } } } - return skip; } bool CoreChecks::PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, @@ -3344,10 +3419,11 @@ void CoreChecks::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImag } // This validates that the initial layout specified in the command buffer for the IMAGE is the same as the global IMAGE layout -bool CoreChecks::ValidateCmdBufImageLayouts( - CMD_BUFFER_STATE *pCB, std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_STATE> const &globalImageLayoutMap, - std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_STATE> &overlayLayoutMap) { +bool CoreChecks::ValidateCmdBufImageLayouts(const CMD_BUFFER_STATE *pCB, const ImageSubresPairLayoutMap &globalImageLayoutMap, + ImageSubresPairLayoutMap *overlayLayoutMap_arg) const { + if (disabled.image_layout_validation) return false; bool skip = false; + ImageSubresPairLayoutMap &overlayLayoutMap = *overlayLayoutMap_arg; // Iterate over the layout maps for each referenced image for (const auto &layout_map_entry : pCB->image_layout_map) { const auto image = layout_map_entry.first; @@ -3432,7 +3508,7 @@ void CoreChecks::UpdateCmdBufImageLayouts(CMD_BUFFER_STATE *pCB) { // layout attachments don't have CLEAR as their loadOp. bool CoreChecks::ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version, const VkImageLayout first_layout, const uint32_t attachment, - const VkAttachmentDescription2KHR &attachment_description) { + const VkAttachmentDescription2KHR &attachment_description) const { bool skip = false; const char *vuid; const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); @@ -3475,7 +3551,7 @@ bool CoreChecks::ValidateLayoutVsAttachmentDescription(const debug_report_data * } bool CoreChecks::ValidateLayouts(RenderPassCreateVersion rp_version, VkDevice device, - const VkRenderPassCreateInfo2KHR *pCreateInfo) { + const VkRenderPassCreateInfo2KHR *pCreateInfo) const { bool skip = false; const char *vuid; const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); @@ -3532,7 +3608,7 @@ bool CoreChecks::ValidateLayouts(RenderPassCreateVersion rp_version, VkDevice de skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, "Layout for input attachment reference %u in subpass %u is %s but must be " "DEPTH_STENCIL_READ_ONLY, SHADER_READ_ONLY_OPTIMAL, or GENERAL.", - j, i, string_VkImageLayout(subpass.pDepthStencilAttachment->layout)); + j, i, string_VkImageLayout(subpass.pInputAttachments[j].layout)); break; case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR: @@ -3791,24 +3867,23 @@ bool CoreChecks::ValidateBufferViewRange(const BUFFER_STATE *buffer_state, const range); } // Range must be a multiple of the element size of format - const size_t format_size = FormatElementSize(pCreateInfo->format); - if (range % format_size != 0) { + const uint32_t format_size = FormatElementSize(pCreateInfo->format); + if (SafeModulo(range, format_size) != 0) { skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00929", "If VkBufferViewCreateInfo range (%" PRIuLEAST64 ") does not equal VK_WHOLE_SIZE, range must be a multiple of the element size of the format " - "(" PRINTF_SIZE_T_SPECIFIER ").", + "(%" PRIu32 ").", range, format_size); } // Range divided by the element size of format must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements - if (range / format_size > device_limits->maxTexelBufferElements) { - skip |= - log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, - HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00930", - "If VkBufferViewCreateInfo range (%" PRIuLEAST64 - ") does not equal VK_WHOLE_SIZE, range divided by the element size of the format (" PRINTF_SIZE_T_SPECIFIER - ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").", - range, format_size, device_limits->maxTexelBufferElements); + if (SafeDivision(range, format_size) > device_limits->maxTexelBufferElements) { + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, + HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00930", + "If VkBufferViewCreateInfo range (%" PRIuLEAST64 + ") does not equal VK_WHOLE_SIZE, range divided by the element size of the format (%" PRIu32 + ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").", + range, format_size, device_limits->maxTexelBufferElements); } // The sum of range and offset must be less than or equal to the size of buffer if (range + pCreateInfo->offset > buffer_state->createInfo.size) { @@ -3912,7 +3987,12 @@ void ValidationStateTracker::PostCallRecordCreateBuffer(VkDevice device, const V VkResult result) { if (result != VK_SUCCESS) return; // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid - bufferMap.insert(std::make_pair(*pBuffer, std::unique_ptr<BUFFER_STATE>(new BUFFER_STATE(*pBuffer, pCreateInfo)))); + std::unique_ptr<BUFFER_STATE> buffer_state(new BUFFER_STATE(*pBuffer, pCreateInfo)); + + // Get a set of requirements in the case the app does not + DispatchGetBufferMemoryRequirements(device, *pBuffer, &buffer_state->requirements); + + bufferMap.insert(std::make_pair(*pBuffer, std::move(buffer_state))); } bool CoreChecks::PreCallValidateCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, @@ -3939,6 +4019,68 @@ bool CoreChecks::PreCallValidateCreateBufferView(VkDevice device, const VkBuffer } const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits; + // Buffer view offset must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment + if ((pCreateInfo->offset % device_limits->minTexelBufferOffsetAlignment) != 0 && + !enabled_features.texel_buffer_alignment_features.texelBufferAlignment) { + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, + HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-offset-02749", + "VkBufferViewCreateInfo offset (%" PRIuLEAST64 + ") must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment (%" PRIuLEAST64 ").", + pCreateInfo->offset, device_limits->minTexelBufferOffsetAlignment); + } + + if (enabled_features.texel_buffer_alignment_features.texelBufferAlignment) { + VkDeviceSize elementSize = FormatElementSize(pCreateInfo->format); + if ((elementSize % 3) == 0) { + elementSize /= 3; + } + if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) { + VkDeviceSize alignmentRequirement = + phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes; + if (phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment) { + alignmentRequirement = std::min(alignmentRequirement, elementSize); + } + if (SafeModulo(pCreateInfo->offset, alignmentRequirement) != 0) { + skip |= log_msg( + report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, + HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-02750", + "If buffer was created with usage containing VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, " + "VkBufferViewCreateInfo offset (%" PRIuLEAST64 + ") must be a multiple of the lesser of " + "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64 + ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetSingleTexelAlignment " + "(%" PRId32 + ") is VK_TRUE, the size of a texel of the requested format. " + "If the size of a texel is a multiple of three bytes, then the size of a " + "single component of format is used instead", + pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes, + phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment); + } + } + if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) { + VkDeviceSize alignmentRequirement = + phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes; + if (phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment) { + alignmentRequirement = std::min(alignmentRequirement, elementSize); + } + if (SafeModulo(pCreateInfo->offset, alignmentRequirement) != 0) { + skip |= log_msg( + report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, + HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-02751", + "If buffer was created with usage containing VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, " + "VkBufferViewCreateInfo offset (%" PRIuLEAST64 + ") must be a multiple of the lesser of " + "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64 + ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetSingleTexelAlignment " + "(%" PRId32 + ") is VK_TRUE, the size of a texel of the requested format. " + "If the size of a texel is a multiple of three bytes, then the size of a " + "single component of format is used instead", + pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes, + phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment); + } + } + } skip |= ValidateBufferViewRange(buffer_state, pCreateInfo, device_limits); @@ -3956,7 +4098,7 @@ void ValidationStateTracker::PostCallRecordCreateBufferView(VkDevice device, con // For the given format verify that the aspect masks make sense bool CoreChecks::ValidateImageAspectMask(VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, const char *func_name, - const char *vuid) { + const char *vuid) const { bool skip = false; VkDebugReportObjectTypeEXT objectType = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; if (image != VK_NULL_HANDLE) { @@ -4151,13 +4293,14 @@ bool CoreChecks::PreCallValidateCreateImageView(VkDevice device, const VkImageVi bool skip = false; IMAGE_STATE *image_state = GetImageState(pCreateInfo->image); if (image_state) { - skip |= ValidateImageUsageFlags( - image_state, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, - false, kVUIDUndefined, "vkCreateImageView()", - "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|INPUT_ATTACHMENT|SHADING_RATE_IMAGE]_BIT"); + skip |= + ValidateImageUsageFlags(image_state, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV | VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, + false, kVUIDUndefined, "vkCreateImageView()", + "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|INPUT_ATTACHMENT|" + "SHADING_RATE_IMAGE|FRAGMENT_DENSITY_MAP]_BIT"); // If this isn't a sparse image, it needs to have memory backing it at CreateImageView time skip |= ValidateMemoryIsBoundToImage(image_state, "vkCreateImageView()", "VUID-VkImageViewCreateInfo-image-01020"); // Checks imported from image layer @@ -4364,9 +4507,9 @@ void ValidationStateTracker::PostCallRecordCreateImageView(VkDevice device, cons bool CoreChecks::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy *pRegions) { - auto cb_node = GetCBState(commandBuffer); - auto src_buffer_state = GetBufferState(srcBuffer); - auto dst_buffer_state = GetBufferState(dstBuffer); + const auto cb_node = GetCBState(commandBuffer); + const auto src_buffer_state = GetBufferState(srcBuffer); + const auto dst_buffer_state = GetBufferState(dstBuffer); bool skip = false; skip |= ValidateMemoryIsBoundToBuffer(src_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-srcBuffer-00119"); @@ -4821,9 +4964,9 @@ static inline bool ValidateBufferBounds(const debug_report_data *report_data, IM bool CoreChecks::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) { - auto cb_node = GetCBState(commandBuffer); - auto src_image_state = GetImageState(srcImage); - auto dst_buffer_state = GetBufferState(dstBuffer); + const auto cb_node = GetCBState(commandBuffer); + const auto src_image_state = GetImageState(srcImage); + const auto dst_buffer_state = GetBufferState(dstBuffer); bool skip = ValidateBufferImageCopyData(regionCount, pRegions, src_image_state, "vkCmdCopyImageToBuffer"); @@ -4831,7 +4974,7 @@ bool CoreChecks::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuff skip |= ValidateCmd(cb_node, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()"); // Command pool must support graphics, compute, or transfer operations - auto pPool = GetCommandPoolState(cb_node->createInfo.commandPool); + const auto pPool = GetCommandPoolState(cb_node->createInfo.commandPool); VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags; @@ -4913,9 +5056,9 @@ void CoreChecks::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer bool CoreChecks::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy *pRegions) { - auto cb_node = GetCBState(commandBuffer); - auto src_buffer_state = GetBufferState(srcBuffer); - auto dst_image_state = GetImageState(dstImage); + const auto cb_node = GetCBState(commandBuffer); + const auto src_buffer_state = GetBufferState(srcBuffer); + const auto dst_image_state = GetImageState(dstImage); bool skip = ValidateBufferImageCopyData(regionCount, pRegions, dst_image_state, "vkCmdCopyBufferToImage"); @@ -4923,7 +5066,7 @@ bool CoreChecks::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuff skip |= ValidateCmd(cb_node, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()"); // Command pool must support graphics, compute, or transfer operations - auto pPool = GetCommandPoolState(cb_node->createInfo.commandPool); + const auto pPool = GetCommandPoolState(cb_node->createInfo.commandPool); VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags; if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) { skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, @@ -5012,7 +5155,7 @@ bool CoreChecks::PreCallValidateGetImageSubresourceLayout(VkDevice device, VkIma "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must have exactly 1 bit set."); } - IMAGE_STATE *image_entry = GetImageState(image); + const IMAGE_STATE *image_entry = GetImageState(image); if (!image_entry) { return skip; } |