aboutsummaryrefslogtreecommitdiff
path: root/layers/buffer_validation.cpp
diff options
context:
space:
mode:
authorMark Lobodzinski <mark@lunarg.com>2017-02-01 13:35:48 -0700
committerMark Lobodzinski <mark@lunarg.com>2017-02-03 10:17:10 -0700
commite8c5817289db5d3bb5e3e9e0b08fb06feb611b09 (patch)
treef616c1bea07cbb4d2110691f1e87cac17a18e569 /layers/buffer_validation.cpp
parent4ccc652a0656a09b5baf8b0723dd256ca8293a4d (diff)
downloadusermoji-e8c5817289db5d3bb5e3e9e0b08fb06feb611b09.tar.xz
layers: Move findlayout/setlayout & val helpers
Moved image layout related validation and support routines out of core validation and into the buffer_validation module. Change-Id: I85ce2c5172d9a89e465e29fe2d6abdaab1f99747
Diffstat (limited to 'layers/buffer_validation.cpp')
-rw-r--r--layers/buffer_validation.cpp424
1 files changed, 420 insertions, 4 deletions
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp
index a6d62e5e..e788e88c 100644
--- a/layers/buffer_validation.cpp
+++ b/layers/buffer_validation.cpp
@@ -31,6 +31,422 @@
#include "buffer_validation.h"
+void SetLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair,
+ const VkImageLayout &layout) {
+ if (std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair) !=
+ pCB->imageSubresourceMap[imgpair.image].end()) {
+ pCB->imageLayoutMap[imgpair].layout = layout;
+ } else {
+ assert(imgpair.hasSubresource);
+ IMAGE_CMD_BUF_LAYOUT_NODE node;
+ if (!FindCmdBufLayout(device_data, pCB, imgpair.image, imgpair.subresource, node)) {
+ node.initialLayout = layout;
+ }
+ SetLayout(device_data, pCB, imgpair, {node.initialLayout, layout});
+ }
+}
+template <class OBJECT, class LAYOUT>
+void SetLayout(core_validation::layer_data *device_data, OBJECT *pObject, VkImage image, VkImageSubresource range,
+ const LAYOUT &layout) {
+ ImageSubresourcePair imgpair = {image, true, range};
+ SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
+ SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
+ SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
+ SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
+}
+
+template <class OBJECT, class LAYOUT>
+void SetLayout(core_validation::layer_data *device_data, OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout,
+ VkImageAspectFlags aspectMask) {
+ if (imgpair.subresource.aspectMask & aspectMask) {
+ imgpair.subresource.aspectMask = aspectMask;
+ SetLayout(device_data, pObject, imgpair, layout);
+ }
+}
+
+bool FindLayoutVerifyNode(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair,
+ IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask) {
+ const debug_report_data *report_data = core_validation::GetReportData(device_data);
+
+ 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,
+ reinterpret_cast<uint64_t &>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
+ "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
+ reinterpret_cast<uint64_t &>(imgpair.image), 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,
+ reinterpret_cast<uint64_t &>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
+ "Cannot query for VkImage 0x%" PRIx64
+ " layout when combined aspect mask %d has multiple initial layout types: %s and %s",
+ reinterpret_cast<uint64_t &>(imgpair.image), oldAspectMask, string_VkImageLayout(node.initialLayout),
+ string_VkImageLayout(imgsubIt->second.initialLayout));
+ }
+ node = imgsubIt->second;
+ return true;
+}
+
+bool FindLayoutVerifyLayout(core_validation::layer_data *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout,
+ const VkImageAspectFlags aspectMask) {
+ if (!(imgpair.subresource.aspectMask & aspectMask)) {
+ return false;
+ }
+ const debug_report_data *report_data = core_validation::GetReportData(device_data);
+ VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
+ imgpair.subresource.aspectMask = aspectMask;
+ auto imgsubIt = (*core_validation::GetImageLayoutMap(device_data)).find(imgpair);
+ if (imgsubIt == (*core_validation::GetImageLayoutMap(device_data)).end()) {
+ return false;
+ }
+ if (layout != VK_IMAGE_LAYOUT_MAX_ENUM && layout != imgsubIt->second.layout) {
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
+ "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
+ reinterpret_cast<uint64_t &>(imgpair.image), oldAspectMask, string_VkImageLayout(layout),
+ string_VkImageLayout(imgsubIt->second.layout));
+ }
+ layout = imgsubIt->second.layout;
+ return true;
+}
+
+// Find layout(s) on the command buffer level
+bool FindCmdBufLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *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(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_COLOR_BIT);
+ FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_DEPTH_BIT);
+ FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_STENCIL_BIT);
+ FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_METADATA_BIT);
+ 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 FindGlobalLayout(core_validation::layer_data *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
+ layout = VK_IMAGE_LAYOUT_MAX_ENUM;
+ FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
+ FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
+ FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
+ FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
+ if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
+ imgpair = {imgpair.image, false, VkImageSubresource()};
+ auto imgsubIt = (*core_validation::GetImageLayoutMap(device_data)).find(imgpair);
+ if (imgsubIt == (*core_validation::GetImageLayoutMap(device_data)).end()) return false;
+ layout = imgsubIt->second.layout;
+ }
+ return true;
+}
+
+bool FindLayouts(core_validation::layer_data *device_data, VkImage image, std::vector<VkImageLayout> &layouts) {
+ auto sub_data = (*core_validation::GetImageSubresourceMap(device_data)).find(image);
+ if (sub_data == (*core_validation::GetImageSubresourceMap(device_data)).end()) return false;
+ auto image_state = getImageState(device_data, image);
+ if (!image_state) return false;
+ bool ignoreGlobal = false;
+ // TODO: Make this robust for >1 aspect mask. Now it will just say ignore potential errors in this case.
+ if (sub_data->second.size() >= (image_state->createInfo.arrayLayers * image_state->createInfo.mipLevels + 1)) {
+ ignoreGlobal = true;
+ }
+ for (auto imgsubpair : sub_data->second) {
+ if (ignoreGlobal && !imgsubpair.hasSubresource) continue;
+ auto img_data = (*core_validation::GetImageLayoutMap(device_data)).find(imgsubpair);
+ if (img_data != (*core_validation::GetImageLayoutMap(device_data)).end()) {
+ layouts.push_back(img_data->second.layout);
+ }
+ }
+ return true;
+}
+
+// Set the layout on the global level
+void SetGlobalLayout(core_validation::layer_data *device_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
+ VkImage &image = imgpair.image;
+ (*core_validation::GetImageLayoutMap(device_data))[imgpair].layout = layout;
+ auto &image_subresources = (*core_validation::GetImageSubresourceMap(device_data))[image];
+ auto subresource = std::find(image_subresources.begin(), image_subresources.end(), imgpair);
+ if (subresource == image_subresources.end()) {
+ image_subresources.push_back(imgpair);
+ }
+}
+
+// Set the layout on the cmdbuf level
+void SetLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair,
+ const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
+ pCB->imageLayoutMap[imgpair] = node;
+ auto subresource =
+ std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair);
+ if (subresource == pCB->imageSubresourceMap[imgpair.image].end()) {
+ pCB->imageSubresourceMap[imgpair.image].push_back(imgpair);
+ }
+}
+
+void SetImageViewLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB, VkImageView imageView,
+ const VkImageLayout &layout) {
+ auto view_state = getImageViewState(device_data, imageView);
+ assert(view_state);
+ auto image = view_state->create_info.image;
+ const VkImageSubresourceRange &subRange = view_state->create_info.subresourceRange;
+ // 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};
+ // 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 (subRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ if (vk_format_is_depth_and_stencil(view_state->create_info.format)) {
+ sub.aspectMask |= (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
+ }
+ }
+ SetLayout(device_data, pCB, image, sub, layout);
+ }
+ }
+}
+
+bool VerifyFramebufferAndRenderPassLayouts(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB,
+ const VkRenderPassBeginInfo *pRenderPassBegin,
+ const FRAMEBUFFER_STATE *framebuffer_state) {
+ bool skip_call = false;
+ auto const pRenderPassInfo = getRenderPassState(device_data, pRenderPassBegin->renderPass)->createInfo.ptr();
+ auto const &framebufferInfo = framebuffer_state->createInfo;
+ const auto report_data = core_validation::GetReportData(device_data);
+ if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
+ DRAWSTATE_INVALID_RENDERPASS, "DS",
+ "You cannot start a render pass using a framebuffer "
+ "with a different number of attachments.");
+ }
+ for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
+ const VkImageView &image_view = framebufferInfo.pAttachments[i];
+ auto view_state = getImageViewState(device_data, image_view);
+ assert(view_state);
+ const VkImage &image = view_state->create_info.image;
+ const VkImageSubresourceRange &subRange = view_state->create_info.subresourceRange;
+ IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout,
+ pRenderPassInfo->pAttachments[i].initialLayout};
+ // 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(device_data, pCB, image, sub, node)) {
+ SetLayout(device_data, pCB, image, sub, newNode);
+ continue;
+ }
+ if (newNode.layout != VK_IMAGE_LAYOUT_UNDEFINED && newNode.layout != node.layout) {
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
+ DRAWSTATE_INVALID_RENDERPASS, "DS",
+ "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(newNode.layout), string_VkImageLayout(node.layout));
+ }
+ }
+ }
+ }
+ return skip_call;
+}
+
+void TransitionAttachmentRefLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
+ VkAttachmentReference ref) {
+ if (ref.attachment != VK_ATTACHMENT_UNUSED) {
+ auto image_view = pFramebuffer->createInfo.pAttachments[ref.attachment];
+ SetImageViewLayout(device_data, pCB, image_view, ref.layout);
+ }
+}
+
+void TransitionSubpassLayouts(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB,
+ const VkRenderPassBeginInfo *pRenderPassBegin, const int subpass_index,
+ FRAMEBUFFER_STATE *framebuffer_state) {
+ auto renderPass = getRenderPassState(device_data, pRenderPassBegin->renderPass);
+ if (!renderPass) return;
+
+ if (framebuffer_state) {
+ auto const &subpass = renderPass->createInfo.pSubpasses[subpass_index];
+ for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
+ TransitionAttachmentRefLayout(device_data, pCB, framebuffer_state, subpass.pInputAttachments[j]);
+ }
+ for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
+ TransitionAttachmentRefLayout(device_data, pCB, framebuffer_state, subpass.pColorAttachments[j]);
+ }
+ if (subpass.pDepthStencilAttachment) {
+ TransitionAttachmentRefLayout(device_data, pCB, framebuffer_state, *subpass.pDepthStencilAttachment);
+ }
+ }
+}
+
+bool TransitionImageAspectLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *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(device_data, pCB, mem_barrier->image, sub, node)) {
+ SetLayout(device_data, pCB, mem_barrier->image, sub,
+ IMAGE_CMD_BUF_LAYOUT_NODE(mem_barrier->oldLayout, mem_barrier->newLayout));
+ 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(core_validation::GetReportData(device_data), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
+ 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
+ "You cannot transition the layout of aspect %d from %s when current layout is %s.", aspect,
+ string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
+ }
+ SetLayout(device_data, pCB, mem_barrier->image, sub, mem_barrier->newLayout);
+ return skip;
+}
+
+// TODO: Separate validation and layout state updates
+bool TransitionImageLayouts(core_validation::layer_data *device_data, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
+ const VkImageMemoryBarrier *pImgMemBarriers) {
+ GLOBAL_CB_NODE *pCB = getCBNode(device_data, cmdBuffer);
+ bool skip = false;
+ uint32_t levelCount = 0;
+ uint32_t layerCount = 0;
+
+ for (uint32_t i = 0; i < memBarrierCount; ++i) {
+ auto mem_barrier = &pImgMemBarriers[i];
+ if (!mem_barrier) continue;
+ // TODO: Do not iterate over every possibility - consolidate where possible
+ ResolveRemainingLevelsLayers(device_data, &levelCount, &layerCount, mem_barrier->subresourceRange,
+ getImageState(device_data, mem_barrier->image));
+
+ for (uint32_t j = 0; j < levelCount; j++) {
+ uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j;
+ for (uint32_t k = 0; k < layerCount; k++) {
+ uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k;
+ skip |= TransitionImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_COLOR_BIT);
+ skip |= TransitionImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_DEPTH_BIT);
+ skip |= TransitionImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_STENCIL_BIT);
+ skip |= TransitionImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_METADATA_BIT);
+ }
+ }
+ }
+ return skip;
+}
+
+bool VerifySourceImageLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage srcImage,
+ VkImageSubresourceLayers subLayers, VkImageLayout srcImageLayout,
+ UNIQUE_VALIDATION_ERROR_CODE msgCode) {
+ const auto report_data = core_validation::GetReportData(device_data);
+ bool skip_call = 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(device_data, cb_node, srcImage, sub, node)) {
+ SetLayout(device_data, cb_node, srcImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(srcImageLayout, srcImageLayout));
+ continue;
+ }
+ if (node.layout != srcImageLayout) {
+ // TODO: Improve log message in the next pass
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
+ __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
+ "Cannot copy from an image whose source layout is %s "
+ "and doesn't match the current layout %s.",
+ string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout));
+ }
+ }
+ if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
+ if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
+ // TODO : Can we deal with image node from the top of call tree and avoid map look-up here?
+ auto image_state = getImageState(device_data, srcImage);
+ if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
+ // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
+ __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
+ "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL.");
+ }
+ } else {
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, msgCode,
+ "DS", "Layout for input image is %s but can only be TRANSFER_SRC_OPTIMAL or GENERAL. %s",
+ string_VkImageLayout(srcImageLayout), validation_error_map[msgCode]);
+ }
+ }
+ return skip_call;
+}
+
+bool VerifyDestImageLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage destImage,
+ VkImageSubresourceLayers subLayers, VkImageLayout destImageLayout,
+ UNIQUE_VALIDATION_ERROR_CODE msgCode) {
+ const auto report_data = core_validation::GetReportData(device_data);
+ bool skip_call = 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(device_data, cb_node, destImage, sub, node)) {
+ SetLayout(device_data, cb_node, destImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(destImageLayout, destImageLayout));
+ continue;
+ }
+ if (node.layout != destImageLayout) {
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
+ __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
+ "Cannot copy from an image whose dest layout is %s and "
+ "doesn't match the current layout %s.",
+ string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout));
+ }
+ }
+ if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+ if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
+ auto image_state = getImageState(device_data, destImage);
+ if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
+ // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
+ __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
+ "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL.");
+ }
+ } else {
+ skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, msgCode,
+ "DS", "Layout for output image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL. %s",
+ string_VkImageLayout(destImageLayout), validation_error_map[msgCode]);
+ }
+ }
+ return skip_call;
+}
+
+void TransitionFinalSubpassLayouts(core_validation::layer_data *device_data, GLOBAL_CB_NODE *pCB,
+ const VkRenderPassBeginInfo *pRenderPassBegin, FRAMEBUFFER_STATE *framebuffer_state) {
+ auto renderPass = getRenderPassState(device_data, pRenderPassBegin->renderPass);
+ if (!renderPass) return;
+
+ const VkRenderPassCreateInfo *pRenderPassInfo = renderPass->createInfo.ptr();
+ if (framebuffer_state) {
+ for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
+ auto image_view = framebuffer_state->createInfo.pAttachments[i];
+ SetImageViewLayout(device_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout);
+ }
+ }
+}
+
bool PreCallValidateCreateImage(core_validation::layer_data *device_data, const VkImageCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
bool skip_call = false;
@@ -326,7 +742,7 @@ bool VerifyClearImageLayout(core_validation::layer_data *device_data, GLOBAL_CB_
uint32_t layer = layer_index + resolved_range.baseArrayLayer;
VkImageSubresource sub = {resolved_range.aspectMask, level, layer};
IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (core_validation::FindLayout(cb_node, image_state->image, sub, node)) {
+ if (FindCmdBufLayout(device_data, cb_node, image_state->image, sub, node)) {
if (node.layout != dest_image_layout) {
UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01085;
if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
@@ -359,8 +775,8 @@ void RecordClearImageLayout(core_validation::layer_data *device_data, GLOBAL_CB_
uint32_t layer = layer_index + resolved_range.baseArrayLayer;
VkImageSubresource sub = {resolved_range.aspectMask, level, layer};
IMAGE_CMD_BUF_LAYOUT_NODE node;
- if (!core_validation::FindLayout(cb_node, image, sub, node)) {
- SetLayout(cb_node, image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(dest_image_layout, dest_image_layout));
+ if (!FindCmdBufLayout(device_data, cb_node, image, sub, node)) {
+ SetLayout(device_data, cb_node, image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(dest_image_layout, dest_image_layout));
}
}
}
@@ -370,7 +786,7 @@ bool PreCallValidateCmdClearColorImage(core_validation::layer_data *dev_data, Vk
VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
bool skip = false;
// TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
- auto cb_node = core_validation::getCBNode(dev_data, commandBuffer);
+ auto cb_node = getCBNode(dev_data, commandBuffer);
auto image_state = getImageState(dev_data, image);
if (cb_node && image_state) {
skip |= ValidateMemoryIsBoundToImage(dev_data, image_state, "vkCmdClearColorImage()", VALIDATION_ERROR_02527);