layers: Refactor cmd buffer Image Layout tracking
Based on profiling, the map used for tracking image layout state within
command buffers was a hot spot. A new two level (image, then
subresource) map is construct where the second level is a specialized,
adpative sparse_vector that can function as a map for sparse usage, and
as a vector for dense usage. In testing, this yeilded performance
improvment.
Layout tracking was also changed semantically, such that only operations
that *change* layout alter the current layout state. This may cause
additional layout incompatibility messages, as subsequent incorrect uses
will not be (incorrectly) masked by a previous incorrect use.
Based on user feedback, record time reporting of layout incompatibility
is preserved.
Change-Id: Ia975fe5d2a9f257bdf39e60791155645c078aa25
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp
index 98c3ee2..0095d34 100644
--- a/layers/buffer_validation.cpp
+++ b/layers/buffer_validation.cpp
@@ -40,6 +40,69 @@
#include "descriptor_sets.h"
#include "buffer_validation.h"
+// Transfer VkImageSubresourceLayers into VkImageSubresourceRange struct
+static VkImageSubresourceRange RangeFromLayers(const VkImageSubresourceLayers &subresource_layers) {
+ VkImageSubresourceRange subresource_range;
+ subresource_range.aspectMask = subresource_layers.aspectMask;
+ subresource_range.baseArrayLayer = subresource_layers.baseArrayLayer;
+ subresource_range.layerCount = subresource_layers.layerCount;
+ subresource_range.baseMipLevel = subresource_layers.mipLevel;
+ subresource_range.levelCount = 1;
+ return subresource_range;
+}
+
+IMAGE_STATE::IMAGE_STATE(VkImage img, const VkImageCreateInfo *pCreateInfo)
+ : image(img),
+ createInfo(*pCreateInfo),
+ valid(false),
+ acquired(false),
+ shared_presentable(false),
+ layout_locked(false),
+ get_sparse_reqs_called(false),
+ sparse_metadata_required(false),
+ sparse_metadata_bound(false),
+ imported_ahb(false),
+ has_ahb_format(false),
+ ahb_format(0),
+ full_range{},
+ sparse_requirements{} {
+ if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
+ uint32_t *pQueueFamilyIndices = new uint32_t[createInfo.queueFamilyIndexCount];
+ for (uint32_t i = 0; i < createInfo.queueFamilyIndexCount; i++) {
+ pQueueFamilyIndices[i] = pCreateInfo->pQueueFamilyIndices[i];
+ }
+ createInfo.pQueueFamilyIndices = pQueueFamilyIndices;
+ }
+
+ if (createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) {
+ sparse = true;
+ }
+ const auto format = createInfo.format;
+ VkImageSubresourceRange init_range{0, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS};
+ if (FormatIsColor(format) || FormatIsMultiplane(format)) {
+ init_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // Normalization will expand this for multiplane
+ } else {
+ init_range.aspectMask =
+ (FormatHasDepth(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (FormatHasStencil(format) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
+ }
+ full_range = NormalizeSubresourceRange(*this, init_range);
+}
+
+IMAGE_VIEW_STATE::IMAGE_VIEW_STATE(const IMAGE_STATE *image_state, VkImageView iv, const VkImageViewCreateInfo *ci)
+ : image_view(iv), create_info(*ci), normalized_subresource_range(ci->subresourceRange), samplerConversion(VK_NULL_HANDLE) {
+ auto *conversionInfo = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(create_info.pNext);
+ if (conversionInfo) samplerConversion = conversionInfo->conversion;
+ if (image_state) {
+ // A light normalization of the createInfo range
+ auto &sub_res_range = create_info.subresourceRange;
+ sub_res_range.levelCount = ResolveRemainingLevels(&sub_res_range, image_state->createInfo.mipLevels);
+ sub_res_range.layerCount = ResolveRemainingLayers(&sub_res_range, image_state->createInfo.arrayLayers);
+
+ // Cache a full normalization (for "full image/whole image" comparisons)
+ normalized_subresource_range = NormalizeSubresourceRange(*image_state, ci->subresourceRange);
+ }
+}
+
uint32_t FullMipChainLevels(uint32_t height, uint32_t width, uint32_t depth) {
// uint cast applies floor()
return 1u + (uint32_t)log2(std::max({height, width, depth}));
@@ -49,18 +112,30 @@
uint32_t FullMipChainLevels(VkExtent2D extent) { return FullMipChainLevels(extent.height, extent.width); }
-void CoreChecks::SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
- auto it = pCB->imageLayoutMap.find(imgpair);
- if (it != pCB->imageLayoutMap.end()) {
- it->second.layout = layout;
- } else {
- assert(imgpair.hasSubresource);
- IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (!FindCmdBufLayout(pCB, imgpair.image, imgpair.subresource, node)) {
- node.initialLayout = layout;
+VkImageSubresourceRange NormalizeSubresourceRange(const IMAGE_STATE &image_state, const VkImageSubresourceRange &range) {
+ const VkImageCreateInfo &image_create_info = image_state.createInfo;
+ VkImageSubresourceRange norm = range;
+ norm.levelCount = ResolveRemainingLevels(&range, image_create_info.mipLevels);
+
+ // Special case for 3D images with VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR flag bit, where <extent.depth> and
+ // <arrayLayers> can potentially alias.
+ uint32_t layer_limit = (0 != (image_create_info.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR))
+ ? image_create_info.extent.depth
+ : image_create_info.arrayLayers;
+ norm.layerCount = ResolveRemainingLayers(&range, layer_limit);
+
+ // For multiplanar formats, IMAGE_ASPECT_COLOR is equivalent to adding the aspect of the individual planes
+ VkImageAspectFlags &aspect_mask = norm.aspectMask;
+ if (FormatIsMultiplane(image_create_info.format)) {
+ if (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) {
+ aspect_mask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
+ aspect_mask |= (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
+ if (FormatPlaneCount(image_create_info.format) > 2) {
+ aspect_mask |= VK_IMAGE_ASPECT_PLANE_2_BIT;
+ }
}
- SetLayout(pCB, imgpair, {node.initialLayout, layout});
}
+ return norm;
}
template <class OBJECT, class LAYOUT>
@@ -96,36 +171,6 @@
}
}
-bool CoreChecks::FindLayoutVerifyNode(GLOBAL_CB_NODE const *pCB, ImageSubresourcePair imgpair, IMAGE_CMD_BUF_LAYOUT_NODE &node,
- const VkImageAspectFlags aspectMask) {
- if (!(imgpair.subresource.aspectMask & aspectMask)) {
- return false;
- }
- VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
- imgpair.subresource.aspectMask = aspectMask;
- auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
- if (imgsubIt == pCB->imageLayoutMap.end()) {
- return false;
- }
- if (node.layout != VK_IMAGE_LAYOUT_MAX_ENUM && node.layout != imgsubIt->second.layout) {
- log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
- kVUID_Core_DrawState_InvalidLayout,
- "Cannot query for VkImage %s layout when combined aspect mask %d has multiple layout types: %s and %s",
- report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(node.layout),
- string_VkImageLayout(imgsubIt->second.layout));
- }
- if (node.initialLayout != VK_IMAGE_LAYOUT_MAX_ENUM && node.initialLayout != imgsubIt->second.initialLayout) {
- log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
- kVUID_Core_DrawState_InvalidLayout,
- "Cannot query for VkImage %s"
- " layout when combined aspect mask %d has multiple initial layout types: %s and %s",
- report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(node.initialLayout),
- string_VkImageLayout(imgsubIt->second.initialLayout));
- }
- node = imgsubIt->second;
- return true;
-}
-
bool CoreChecks::FindLayoutVerifyLayout(ImageSubresourcePair imgpair, VkImageLayout &layout, const VkImageAspectFlags aspectMask) {
if (!(imgpair.subresource.aspectMask & aspectMask)) {
return false;
@@ -147,30 +192,6 @@
return true;
}
-// Find layout(s) on the command buffer level
-bool CoreChecks::FindCmdBufLayout(GLOBAL_CB_NODE const *pCB, VkImage image, VkImageSubresource range,
- IMAGE_CMD_BUF_LAYOUT_NODE &node) {
- ImageSubresourcePair imgpair = {image, true, range};
- node = IMAGE_CMD_BUF_LAYOUT_NODE(VK_IMAGE_LAYOUT_MAX_ENUM, VK_IMAGE_LAYOUT_MAX_ENUM);
- FindLayoutVerifyNode(pCB, imgpair, node, VK_IMAGE_ASPECT_COLOR_BIT);
- FindLayoutVerifyNode(pCB, imgpair, node, VK_IMAGE_ASPECT_DEPTH_BIT);
- FindLayoutVerifyNode(pCB, imgpair, node, VK_IMAGE_ASPECT_STENCIL_BIT);
- FindLayoutVerifyNode(pCB, imgpair, node, VK_IMAGE_ASPECT_METADATA_BIT);
- if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
- FindLayoutVerifyNode(pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
- FindLayoutVerifyNode(pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
- FindLayoutVerifyNode(pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
- }
- if (node.layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
- imgpair = {image, false, VkImageSubresource()};
- auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
- if (imgsubIt == pCB->imageLayoutMap.end()) return false;
- // TODO: This is ostensibly a find function but it changes state here
- node = imgsubIt->second;
- }
- return true;
-}
-
// Find layout(s) on the global level
bool CoreChecks::FindGlobalLayout(ImageSubresourcePair imgpair, VkImageLayout &layout) {
layout = VK_IMAGE_LAYOUT_MAX_ENUM;
@@ -266,81 +287,60 @@
}
}
-// Set the layout on the cmdbuf level
-void CoreChecks::SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
- auto it = pCB->imageLayoutMap.find(imgpair);
- if (it != pCB->imageLayoutMap.end()) {
- it->second = node; // Update
- } else {
- pCB->imageLayoutMap[imgpair] = node; // Insert
- }
-}
// Set image layout for given VkImageSubresourceRange struct
-void CoreChecks::SetImageLayout(GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
- VkImageSubresourceRange image_subresource_range, const VkImageLayout &layout) {
- assert(image_state);
- cb_node->image_layout_change_count++; // Change the version of this data to force revalidation
- for (uint32_t level_index = 0; level_index < image_subresource_range.levelCount; ++level_index) {
- uint32_t level = image_subresource_range.baseMipLevel + level_index;
- for (uint32_t layer_index = 0; layer_index < image_subresource_range.layerCount; layer_index++) {
- uint32_t layer = image_subresource_range.baseArrayLayer + layer_index;
- VkImageSubresource sub = {image_subresource_range.aspectMask, level, layer};
- // TODO: If ImageView was created with depth or stencil, transition both layouts as the aspectMask is ignored and both
- // are used. Verify that the extra implicit layout is OK for descriptor set layout validation
- if (image_subresource_range.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
- if (FormatIsDepthAndStencil(image_state->createInfo.format)) {
- sub.aspectMask |= (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
- }
- }
- // For multiplane images, IMAGE_ASPECT_COLOR is an alias for all of the plane bits
- if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
- if (FormatIsMultiplane(image_state->createInfo.format)) {
- if (sub.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
- sub.aspectMask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
- sub.aspectMask |= VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR;
- if (FormatPlaneCount(image_state->createInfo.format) > 2) {
- sub.aspectMask |= VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
- }
- }
- }
- }
- SetLayout(cb_node, image_state->image, sub, layout);
- }
+void CoreChecks::SetImageLayout(GLOBAL_CB_NODE *cb_node, const IMAGE_STATE &image_state,
+ const VkImageSubresourceRange &image_subresource_range, VkImageLayout layout,
+ VkImageLayout expected_layout) {
+ auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state);
+ assert(subresource_map); // the non-const getter must return a valid pointer
+ if (subresource_map->SetSubresourceRangeLayout(image_subresource_range, layout, expected_layout)) {
+ cb_node->image_layout_change_count++; // Change the version of this data to force revalidation
}
}
-// Set image layout for given VkImageSubresourceLayers struct
-void CoreChecks::SetImageLayout(GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
- VkImageSubresourceLayers image_subresource_layers, const VkImageLayout &layout) {
- // Transfer VkImageSubresourceLayers into VkImageSubresourceRange struct
- VkImageSubresourceRange image_subresource_range;
- image_subresource_range.aspectMask = image_subresource_layers.aspectMask;
- image_subresource_range.baseArrayLayer = image_subresource_layers.baseArrayLayer;
- image_subresource_range.layerCount = image_subresource_layers.layerCount;
- image_subresource_range.baseMipLevel = image_subresource_layers.mipLevel;
- image_subresource_range.levelCount = 1;
- SetImageLayout(cb_node, image_state, image_subresource_range, layout);
+
+// Set the initial image layout for all slices of an image view
+void CoreChecks::SetImageViewInitialLayout(GLOBAL_CB_NODE *cb_node, const IMAGE_VIEW_STATE &view_state, VkImageLayout layout) {
+ IMAGE_STATE *image_state = GetImageState(view_state.create_info.image);
+ if (image_state) {
+ auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, *image_state);
+ subresource_map->SetSubresourceRangeInitialLayout(view_state.normalized_subresource_range, layout);
+ }
+}
+
+// Set the initial image layout for a passed non-normalized subresource range
+void CoreChecks::SetImageInitialLayout(GLOBAL_CB_NODE *cb_node, const IMAGE_STATE &image_state,
+ const VkImageSubresourceRange &range, VkImageLayout layout) {
+ auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state);
+ assert(subresource_map);
+ subresource_map->SetSubresourceRangeInitialLayout(NormalizeSubresourceRange(image_state, range), layout);
+}
+
+void CoreChecks::SetImageInitialLayout(GLOBAL_CB_NODE *cb_node, VkImage image, const VkImageSubresourceRange &range,
+ VkImageLayout layout) {
+ const IMAGE_STATE *image_state = GetImageState(image);
+ if (!image_state) return;
+ SetImageInitialLayout(cb_node, *image_state, range, layout);
+};
+
+void CoreChecks::SetImageInitialLayout(GLOBAL_CB_NODE *cb_node, const IMAGE_STATE &image_state,
+ const VkImageSubresourceLayers &layers, VkImageLayout layout) {
+ SetImageInitialLayout(cb_node, image_state, RangeFromLayers(layers), layout);
}
// Set image layout for all slices of an image view
-void CoreChecks::SetImageViewLayout(GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state, const VkImageLayout &layout) {
- assert(view_state);
+void CoreChecks::SetImageViewLayout(GLOBAL_CB_NODE *cb_node, const IMAGE_VIEW_STATE &view_state, VkImageLayout layout) {
+ IMAGE_STATE *image_state = GetImageState(view_state.create_info.image);
+ if (!image_state) return; // TODO: track/report stale image references
- IMAGE_STATE *image_state = GetImageState(view_state->create_info.image);
- VkImageSubresourceRange sub_range = view_state->create_info.subresourceRange;
-
+ VkImageSubresourceRange sub_range = view_state.normalized_subresource_range;
// When changing the layout of a 3D image subresource via a 2D or 2D_ARRRAY image view, all depth slices of
// the subresource mip level(s) are transitioned, ignoring any layers restriction in the subresource info.
- if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) && (view_state->create_info.viewType != VK_IMAGE_VIEW_TYPE_3D)) {
+ if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) && (view_state.create_info.viewType != VK_IMAGE_VIEW_TYPE_3D)) {
sub_range.baseArrayLayer = 0;
sub_range.layerCount = image_state->createInfo.extent.depth;
}
- SetImageLayout(cb_node, image_state, sub_range, layout);
-}
-
-void CoreChecks::SetImageViewLayout(GLOBAL_CB_NODE *cb_node, VkImageView imageView, const VkImageLayout &layout) {
- auto view_state = GetImageViewState(imageView);
- SetImageViewLayout(cb_node, view_state, layout);
+ SetImageLayout(cb_node, *image_state, sub_range, layout);
}
bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPassCreateVersion rp_version, VkImageLayout layout,
@@ -458,6 +458,7 @@
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 GLOBAL_CB_NODE *>(pCB);
for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
const VkImageView &image_view = framebufferInfo.pAttachments[i];
auto view_state = GetImageViewState(image_view);
@@ -472,34 +473,49 @@
continue;
}
- const VkImage &image = view_state->create_info.image;
- const VkImageSubresourceRange &subRange = view_state->create_info.subresourceRange;
- auto initial_layout = pRenderPassInfo->pAttachments[i].initialLayout;
+ const VkImage image = view_state->create_info.image;
+ const IMAGE_STATE *image_state = GetImageState(image);
+
+ 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(): framebuffer %s pAttachments[%" PRIu32
+ "] = VkImageView %s references non-extant VkImage %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;
- // TODO: Do not iterate over every possibility - consolidate where possible
- for (uint32_t j = 0; j < subRange.levelCount; j++) {
- uint32_t level = subRange.baseMipLevel + j;
- for (uint32_t k = 0; k < subRange.layerCount; k++) {
- uint32_t layer = subRange.baseArrayLayer + k;
- VkImageSubresource sub = {subRange.aspectMask, level, layer};
- IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (!FindCmdBufLayout(pCB, image, sub, node)) {
- // Missing layouts will be added during state update
- continue;
+ // 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
+ bool subres_skip = false;
+ auto subresource_cb = [this, i, attachment_initial_layout, &subres_skip](
+ const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
+ LayoutUseCheckAndMessage layout_check(attachment_initial_layout, layout, initial_layout);
+ if (layout_check.CheckFailed()) {
+ 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));
}
- if (initial_layout != VK_IMAGE_LAYOUT_UNDEFINED && initial_layout != node.layout) {
- 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 previous known 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(initial_layout), string_VkImageLayout(node.layout));
- }
- }
+ return !subres_skip; // quit checking subresources once we fail once
+ };
+
+ subresource_map->ForRange(view_state->normalized_subresource_range, subresource_cb);
+ skip |= subres_skip;
}
- ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, initial_layout, image, image_view, framebuffer,
+ 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,
@@ -566,7 +582,7 @@
if (ref.attachment != VK_ATTACHMENT_UNUSED) {
auto image_view = GetAttachmentImageViewState(pFramebuffer, ref.attachment);
if (image_view) {
- SetImageViewLayout(pCB, image_view, ref.layout);
+ SetImageViewLayout(pCB, *image_view, ref.layout);
}
}
}
@@ -589,30 +605,6 @@
}
}
-bool CoreChecks::ValidateImageAspectLayout(GLOBAL_CB_NODE const *pCB, const VkImageMemoryBarrier *mem_barrier, uint32_t level,
- uint32_t layer, VkImageAspectFlags aspect) {
- if (!(mem_barrier->subresourceRange.aspectMask & aspect)) {
- return false;
- }
- VkImageSubresource sub = {aspect, level, layer};
- IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (!FindCmdBufLayout(pCB, mem_barrier->image, sub, node)) {
- return false;
- }
- bool skip = false;
- if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
- // TODO: Set memory invalid which is in mem_tracker currently
- } else if (node.layout != mem_barrier->oldLayout) {
- skip = log_msg(
- report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
- HandleToUint64(pCB->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197",
- "For image %s you cannot transition the layout of aspect=%d level=%d layer=%d from %s when current layout is %s.",
- report_data->FormatHandle(mem_barrier->image).c_str(), aspect, level, layer,
- string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
- }
- return skip;
-}
-
// Transition the layout state for renderpass attachments based on the BeginRenderPass() call. This includes:
// 1. Transition into initialLayout state
// 2. Transition from initialLayout to layout used in subpass 0
@@ -623,31 +615,13 @@
for (uint32_t i = 0; i < rpci->attachmentCount; ++i) {
auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
if (view_state) {
- SetImageViewLayout(cb_state, view_state, rpci->pAttachments[i].initialLayout);
+ SetImageViewLayout(cb_state, *view_state, rpci->pAttachments[i].initialLayout);
}
}
// Now transition for first subpass (index 0)
TransitionSubpassLayouts(cb_state, render_pass_state, 0, framebuffer_state);
}
-void CoreChecks::TransitionImageAspectLayout(GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier, uint32_t level,
- uint32_t layer, VkImageAspectFlags aspect_mask, VkImageAspectFlags aspect) {
- if (!(aspect_mask & aspect)) {
- return;
- }
- VkImageSubresource sub = {aspect, level, layer};
- IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (!FindCmdBufLayout(pCB, mem_barrier->image, sub, node)) {
- pCB->image_layout_change_count++; // Change the version of this data to force revalidation
- SetLayout(pCB, mem_barrier->image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(mem_barrier->oldLayout, mem_barrier->newLayout));
- return;
- }
- if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
- // TODO: Set memory invalid
- }
- SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout);
-}
-
bool VerifyAspectsPresent(VkImageAspectFlags aspect_mask, VkFormat format) {
if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
if (!(FormatIsColor(format) || FormatIsMultiplane(format))) return false;
@@ -716,7 +690,7 @@
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 %sLayout=%s is not compatible with image %s usage flags 0x%" PRIx32 ".", func_name,
+ "%s: Image barrier 0x%p %s Layout=%s is not compatible with image %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);
}
@@ -796,40 +770,49 @@
report_data->FormatHandle(img_barrier->image).c_str(), string_VkImageLayout(img_barrier->oldLayout),
string_VkImageLayout(img_barrier->newLayout));
}
- }
- VkImageCreateInfo *image_create_info = &(GetImageState(img_barrier->image)->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 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 image %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(), string_VkFormat(image_create_info->format),
- aspect_mask);
- }
- }
- uint32_t level_count = ResolveRemainingLevels(&img_barrier->subresourceRange, image_create_info->mipLevels);
- uint32_t layer_count = ResolveRemainingLayers(&img_barrier->subresourceRange, image_create_info->arrayLayers);
-
- for (uint32_t j = 0; j < level_count; j++) {
- uint32_t level = img_barrier->subresourceRange.baseMipLevel + j;
- for (uint32_t k = 0; k < layer_count; k++) {
- uint32_t layer = img_barrier->subresourceRange.baseArrayLayer + k;
- skip |= ValidateImageAspectLayout(cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_COLOR_BIT);
- skip |= ValidateImageAspectLayout(cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_DEPTH_BIT);
- skip |= ValidateImageAspectLayout(cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_STENCIL_BIT);
- skip |= ValidateImageAspectLayout(cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_METADATA_BIT);
- if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
- skip |= ValidateImageAspectLayout(cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
- skip |= ValidateImageAspectLayout(cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
- skip |= ValidateImageAspectLayout(cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
+ 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 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 image %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(),
+ 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) {
+ // 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;
+ VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, img_barrier->subresourceRange);
+ auto subres_callback = [this, img_barrier, cb_state, &subres_skip](
+ const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
+ LayoutUseCheckAndMessage layout_check(img_barrier->oldLayout, layout, initial_layout);
+ if (layout_check.CheckFailed()) {
+ 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 image %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,
+ string_VkImageLayout(layout_check.layout));
+ }
+ return !subres_skip;
+ };
+ subresource_map->ForRange(normalized_isr, subres_callback);
+ skip |= subres_skip;
+ }
}
}
return skip;
@@ -1046,72 +1029,54 @@
continue;
}
- VkImageCreateInfo *image_create_info = &(GetImageState(mem_barrier->image)->createInfo);
- uint32_t level_count = ResolveRemainingLevels(&mem_barrier->subresourceRange, image_create_info->mipLevels);
- uint32_t layer_count = ResolveRemainingLayers(&mem_barrier->subresourceRange, image_create_info->arrayLayers);
+ auto *image_state = GetImageState(mem_barrier->image);
+ if (!image_state) continue;
+
+ 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
// <arrayLayers> can potentially alias. When recording layout for the entire image, pre-emptively record layouts
// for all (potential) layer sub_resources.
- if ((0 != (image_create_info->flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR)) &&
- (mem_barrier->subresourceRange.baseArrayLayer == 0) && (layer_count == 1)) {
- layer_count = image_create_info->extent.depth; // Treat each depth slice as a layer subresource
+ if (0 != (image_create_info.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR)) {
+ normalized_isr.baseArrayLayer = 0;
+ normalized_isr.layerCount = image_create_info.extent.depth; // Treat each depth slice as a layer subresource
}
- // For multiplanar formats, IMAGE_ASPECT_COLOR is equivalent to adding the aspect of the individual planes
- VkImageAspectFlags aspect_mask = mem_barrier->subresourceRange.aspectMask;
- if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
- if (FormatIsMultiplane(image_create_info->format)) {
- if (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) {
- aspect_mask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
- aspect_mask |= (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
- if (FormatPlaneCount(image_create_info->format) > 2) {
- aspect_mask |= VK_IMAGE_ASPECT_PLANE_2_BIT;
- }
- }
- }
- }
-
- for (uint32_t j = 0; j < level_count; j++) {
- uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j;
- for (uint32_t k = 0; k < layer_count; k++) {
- uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k;
- TransitionImageAspectLayout(cb_state, mem_barrier, level, layer, aspect_mask, VK_IMAGE_ASPECT_COLOR_BIT);
- TransitionImageAspectLayout(cb_state, mem_barrier, level, layer, aspect_mask, VK_IMAGE_ASPECT_DEPTH_BIT);
- TransitionImageAspectLayout(cb_state, mem_barrier, level, layer, aspect_mask, VK_IMAGE_ASPECT_STENCIL_BIT);
- TransitionImageAspectLayout(cb_state, mem_barrier, level, layer, aspect_mask, VK_IMAGE_ASPECT_METADATA_BIT);
- if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
- TransitionImageAspectLayout(cb_state, mem_barrier, level, layer, aspect_mask, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
- TransitionImageAspectLayout(cb_state, mem_barrier, level, layer, aspect_mask, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
- TransitionImageAspectLayout(cb_state, mem_barrier, level, layer, aspect_mask, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
- }
- }
- }
+ SetImageLayout(cb_state, *image_state, normalized_isr, mem_barrier->newLayout, mem_barrier->oldLayout);
}
}
-bool CoreChecks::VerifyImageLayout(GLOBAL_CB_NODE const *cb_node, IMAGE_STATE *image_state, VkImageSubresourceLayers subLayers,
+bool CoreChecks::VerifyImageLayout(GLOBAL_CB_NODE const *cb_node, IMAGE_STATE *image_state, const VkImageSubresourceRange &range,
VkImageLayout explicit_layout, VkImageLayout optimal_layout, const char *caller,
const char *layout_invalid_msg_code, const char *layout_mismatch_msg_code, bool *error) {
+ assert(cb_node);
+ assert(image_state);
const auto image = image_state->image;
bool skip = false;
- for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
- uint32_t layer = i + subLayers.baseArrayLayer;
- VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
- IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (FindCmdBufLayout(cb_node, image, sub, node)) {
- if (node.layout != explicit_layout) {
+ const auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image);
+ if (subresource_map) {
+ bool subres_skip = false;
+ auto subresource_cb = [this, explicit_layout, cb_node, layout_mismatch_msg_code, caller, image, &error, &subres_skip](
+ const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
+ LayoutUseCheckAndMessage layout_check(explicit_layout, layout, initial_layout);
+ if (layout_check.CheckFailed()) {
*error = true;
- skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
- HandleToUint64(cb_node->commandBuffer), layout_mismatch_msg_code,
- "%s: Cannot use image %s (layer=%u mip=%u) with specific layout %s that doesn't match the actual "
- "current layout %s.",
- caller, report_data->FormatHandle(image).c_str(), layer, subLayers.mipLevel,
- string_VkImageLayout(explicit_layout), string_VkImageLayout(node.layout));
+ subres_skip |=
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(cb_node->commandBuffer), layout_mismatch_msg_code,
+ "%s: Cannot use image %s (layer=%u mip=%u) with specific layout %s that doesn't match the "
+ "%s layout %s.",
+ caller, report_data->FormatHandle(image).c_str(), subres.arrayLayer, subres.mipLevel,
+ string_VkImageLayout(explicit_layout), layout_check.message, string_VkImageLayout(layout_check.layout));
}
- }
+ return !subres_skip;
+ };
+ subresource_map->ForRange(range, subresource_cb);
+ skip |= subres_skip;
}
+
// If optimal_layout is not UNDEFINED, check that layout matches optimal for this case
if ((VK_IMAGE_LAYOUT_UNDEFINED != optimal_layout) && (explicit_layout != optimal_layout)) {
if (VK_IMAGE_LAYOUT_GENERAL == explicit_layout) {
@@ -1143,6 +1108,13 @@
}
return skip;
}
+bool CoreChecks::VerifyImageLayout(GLOBAL_CB_NODE const *cb_node, IMAGE_STATE *image_state,
+ const VkImageSubresourceLayers &subLayers, VkImageLayout explicit_layout,
+ VkImageLayout optimal_layout, const char *caller, const char *layout_invalid_msg_code,
+ const char *layout_mismatch_msg_code, bool *error) {
+ return VerifyImageLayout(cb_node, image_state, RangeFromLayers(subLayers), explicit_layout, optimal_layout, caller,
+ layout_invalid_msg_code, layout_mismatch_msg_code, error);
+}
void CoreChecks::TransitionFinalSubpassLayouts(GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
FRAMEBUFFER_STATE *framebuffer_state) {
@@ -1154,7 +1126,7 @@
for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
if (view_state) {
- SetImageViewLayout(pCB, view_state, pRenderPassInfo->pAttachments[i].finalLayout);
+ SetImageViewLayout(pCB, *view_state, pRenderPassInfo->pAttachments[i].finalLayout);
}
}
}
@@ -1567,9 +1539,6 @@
VkImageLayout dest_image_layout, const char *func_name) {
bool skip = false;
- uint32_t level_count = ResolveRemainingLevels(&range, image_state->createInfo.mipLevels);
- uint32_t layer_count = ResolveRemainingLayers(&range, image_state->createInfo.arrayLayers);
-
if (dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
if (dest_image_layout == VK_IMAGE_LAYOUT_GENERAL) {
if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
@@ -1609,51 +1578,36 @@
}
}
- for (uint32_t level_index = 0; level_index < level_count; ++level_index) {
- uint32_t level = level_index + range.baseMipLevel;
- for (uint32_t layer_index = 0; layer_index < layer_count; ++layer_index) {
- uint32_t layer = layer_index + range.baseArrayLayer;
- VkImageSubresource sub = {range.aspectMask, level, layer};
- IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (FindCmdBufLayout(cb_node, image_state->image, sub, node)) {
- if (node.layout != dest_image_layout) {
- const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
- if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
- error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00011";
- } else {
- assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
- }
- skip |=
- log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
- error_code, "%s: Cannot clear an image whose layout is %s and doesn't match the current layout %s.",
- func_name, string_VkImageLayout(dest_image_layout), string_VkImageLayout(node.layout));
+ // Cast to const to prevent creation at validate time.
+ const auto *subresource_map = GetImageSubresourceLayoutMap(static_cast<const GLOBAL_CB_NODE *>(cb_node), image_state->image);
+ if (subresource_map) {
+ bool subres_skip = false;
+ VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, range);
+ auto subres_callback = [this, cb_node, dest_image_layout, func_name, &subres_skip](
+ const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
+ LayoutUseCheckAndMessage layout_check(dest_image_layout, layout, initial_layout);
+ if (layout_check.CheckFailed()) {
+ const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
+ if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
+ error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00011";
+ } else {
+ assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
}
+ subres_skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(cb_node->commandBuffer), error_code,
+ "%s: Cannot clear an image whose layout is %s and doesn't match the %s layout %s.",
+ func_name, string_VkImageLayout(dest_image_layout), layout_check.message,
+ string_VkImageLayout(layout_check.layout));
}
- }
+ return !subres_skip;
+ };
+ subresource_map->ForRange(normalized_isr, subres_callback);
+ skip |= subres_skip;
}
return skip;
}
-void CoreChecks::RecordClearImageLayout(GLOBAL_CB_NODE *cb_node, VkImage image, VkImageSubresourceRange range,
- VkImageLayout dest_image_layout) {
- VkImageCreateInfo *image_create_info = &(GetImageState(image)->createInfo);
- uint32_t level_count = ResolveRemainingLevels(&range, image_create_info->mipLevels);
- uint32_t layer_count = ResolveRemainingLayers(&range, image_create_info->arrayLayers);
-
- for (uint32_t level_index = 0; level_index < level_count; ++level_index) {
- uint32_t level = level_index + range.baseMipLevel;
- for (uint32_t layer_index = 0; layer_index < layer_count; ++layer_index) {
- uint32_t layer = layer_index + range.baseArrayLayer;
- VkImageSubresource sub = {range.aspectMask, level, layer};
- IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (!FindCmdBufLayout(cb_node, image, sub, node)) {
- SetLayout(cb_node, image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(dest_image_layout, dest_image_layout));
- }
- }
- }
-}
-
bool CoreChecks::PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
const VkClearColorValue *pColor, uint32_t rangeCount,
const VkImageSubresourceRange *pRanges) {
@@ -1690,7 +1644,7 @@
if (cb_node && image_state) {
AddCommandBufferBindingImage(cb_node, image_state);
for (uint32_t i = 0; i < rangeCount; ++i) {
- RecordClearImageLayout(cb_node, image, pRanges[i], imageLayout);
+ SetImageInitialLayout(cb_node, image, pRanges[i], imageLayout);
}
}
}
@@ -1753,7 +1707,7 @@
if (cb_node && image_state) {
AddCommandBufferBindingImage(cb_node, image_state);
for (uint32_t i = 0; i < rangeCount; ++i) {
- RecordClearImageLayout(cb_node, image, pRanges[i], imageLayout);
+ SetImageInitialLayout(cb_node, image, pRanges[i], imageLayout);
}
}
}
@@ -2688,8 +2642,8 @@
// Make sure that all image slices are updated to correct layout
for (uint32_t i = 0; i < regionCount; ++i) {
- SetImageLayout(cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout);
- SetImageLayout(cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
+ SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].srcSubresource, srcImageLayout);
+ SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
}
// Update bindings between images and cmd buffer
AddCommandBufferBindingImage(cb_node, src_image_state);
@@ -3297,8 +3251,8 @@
// Make sure that all image slices are updated to correct layout
for (uint32_t i = 0; i < regionCount; ++i) {
- SetImageLayout(cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout);
- SetImageLayout(cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
+ SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].srcSubresource, srcImageLayout);
+ SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
}
// Update bindings between images and cmd buffer
AddCommandBufferBindingImage(cb_node, src_image_state);
@@ -3310,45 +3264,63 @@
std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const &globalImageLayoutMap,
std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &overlayLayoutMap) {
bool skip = false;
- for (auto cb_image_data : pCB->imageLayoutMap) {
- VkImageLayout imageLayout;
+ // 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;
+ const auto *image_state = GetImageState(image);
+ if (!image_state) continue; // Can't check layouts of a dead image
+ const auto &subres_map = layout_map_entry.second;
+ ImageSubresourcePair isr_pair;
+ isr_pair.image = image;
+ isr_pair.hasSubresource = true;
- if (FindLayout(overlayLayoutMap, cb_image_data.first, imageLayout) ||
- FindLayout(globalImageLayoutMap, cb_image_data.first, imageLayout)) {
- if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
- // TODO: Set memory invalid which is in mem_tracker currently
- } else if (imageLayout != cb_image_data.second.initialLayout) {
- if (cb_image_data.first.hasSubresource) {
- skip |=
- log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
- HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
- "Submitted command buffer expects image %s (subresource: aspectMask 0x%X array layer %u, mip level "
- "%u) to be in layout %s--instead, image %s's current layout is %s.",
- report_data->FormatHandle(cb_image_data.first.image).c_str(),
- cb_image_data.first.subresource.aspectMask, cb_image_data.first.subresource.arrayLayer,
- cb_image_data.first.subresource.mipLevel, string_VkImageLayout(cb_image_data.second.initialLayout),
- report_data->FormatHandle(cb_image_data.first.image).c_str(), string_VkImageLayout(imageLayout));
- } else {
+ // Validate the initial_uses for each subresource referenced
+ for (auto it_init = subres_map->BeginInitialUse(); !it_init.AtEnd(); ++it_init) {
+ isr_pair.subresource = (*it_init).subresource;
+ VkImageLayout initial_layout = (*it_init).layout;
+ VkImageLayout image_layout;
+ if (FindLayout(overlayLayoutMap, isr_pair, image_layout) || FindLayout(globalImageLayoutMap, isr_pair, image_layout)) {
+ if (initial_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
+ // TODO: Set memory invalid which is in mem_tracker currently
+ } else if (image_layout != initial_layout) {
skip |= log_msg(
report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
- "Submitted command buffer expects image %s to be in layout %s--instead, image %s's current layout is %s.",
- report_data->FormatHandle(cb_image_data.first.image).c_str(),
- string_VkImageLayout(cb_image_data.second.initialLayout),
- report_data->FormatHandle(cb_image_data.first.image).c_str(), string_VkImageLayout(imageLayout));
+ "Submitted command buffer expects image %s (subresource: aspectMask 0x%X array layer %u, mip level %u) "
+ "to be in layout %s--instead, current layout is %s.",
+ report_data->FormatHandle(image).c_str(), isr_pair.subresource.aspectMask, isr_pair.subresource.arrayLayer,
+ isr_pair.subresource.mipLevel, string_VkImageLayout(initial_layout), string_VkImageLayout(image_layout));
}
}
- SetLayout(overlayLayoutMap, cb_image_data.first, cb_image_data.second.layout);
+ }
+
+ // Update all layout set operations (which will be a subset of the initial_layouts
+ for (auto it_set = subres_map->BeginSetLayout(); !it_set.AtEnd(); ++it_set) {
+ VkImageLayout layout = (*it_set).layout;
+ isr_pair.subresource = (*it_set).subresource;
+ SetLayout(overlayLayoutMap, isr_pair, layout);
}
}
+
return skip;
}
void CoreChecks::UpdateCmdBufImageLayouts(GLOBAL_CB_NODE *pCB) {
- for (auto cb_image_data : pCB->imageLayoutMap) {
- VkImageLayout imageLayout;
- FindGlobalLayout(cb_image_data.first, imageLayout);
- SetGlobalLayout(cb_image_data.first, cb_image_data.second.layout);
+ for (const auto &layout_map_entry : pCB->image_layout_map) {
+ const auto image = layout_map_entry.first;
+ const auto *image_state = GetImageState(image);
+ if (!image_state) continue; // Can't set layouts of a dead image
+ const auto &subres_map = layout_map_entry.second;
+ ImageSubresourcePair isr_pair;
+ isr_pair.image = image;
+ isr_pair.hasSubresource = true;
+
+ // Update all layout set operations (which will be a subset of the initial_layouts
+ for (auto it_set = subres_map->BeginSetLayout(); !it_set.AtEnd(); ++it_set) {
+ VkImageLayout layout = (*it_set).layout;
+ isr_pair.subresource = (*it_set).subresource;
+ SetGlobalLayout(isr_pair, layout);
+ }
}
}
@@ -4341,12 +4313,8 @@
const VkAllocationCallbacks *pAllocator, VkImageView *pView, VkResult result) {
if (result != VK_SUCCESS) return;
auto image_view_map = GetImageViewMap();
- (*image_view_map)[*pView] = std::unique_ptr<IMAGE_VIEW_STATE>(new IMAGE_VIEW_STATE(*pView, pCreateInfo));
-
auto image_state = GetImageState(pCreateInfo->image);
- auto &sub_res_range = (*image_view_map)[*pView].get()->create_info.subresourceRange;
- sub_res_range.levelCount = ResolveRemainingLevels(&sub_res_range, image_state->createInfo.mipLevels);
- sub_res_range.layerCount = ResolveRemainingLayers(&sub_res_range, image_state->createInfo.arrayLayers);
+ (*image_view_map)[*pView] = std::unique_ptr<IMAGE_VIEW_STATE>(new IMAGE_VIEW_STATE(image_state, *pView, pCreateInfo));
}
bool CoreChecks::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
@@ -4836,9 +4804,9 @@
auto src_image_state = GetImageState(srcImage);
auto dst_buffer_state = GetBufferState(dstBuffer);
- // Make sure that all image slices are updated to correct layout
+ // Make sure that all image slices record referenced layout
for (uint32_t i = 0; i < regionCount; ++i) {
- SetImageLayout(cb_node, src_image_state, pRegions[i].imageSubresource, srcImageLayout);
+ SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].imageSubresource, srcImageLayout);
}
// Update bindings between buffer/image and cmd buffer
AddCommandBufferBindingImage(cb_node, src_image_state);
@@ -4917,9 +4885,9 @@
auto src_buffer_state = GetBufferState(srcBuffer);
auto dst_image_state = GetImageState(dstImage);
- // Make sure that all image slices are updated to correct layout
+ // Make sure that all image slices are record referenced layout
for (uint32_t i = 0; i < regionCount; ++i) {
- SetImageLayout(cb_node, dst_image_state, pRegions[i].imageSubresource, dstImageLayout);
+ SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].imageSubresource, dstImageLayout);
}
AddCommandBufferBindingBuffer(cb_node, src_buffer_state);
AddCommandBufferBindingImage(cb_node, dst_image_state);