diff options
| author | Mark Lobodzinski <mark@lunarg.com> | 2017-02-01 13:35:48 -0700 |
|---|---|---|
| committer | Mark Lobodzinski <mark@lunarg.com> | 2017-02-03 10:17:10 -0700 |
| commit | e8c5817289db5d3bb5e3e9e0b08fb06feb611b09 (patch) | |
| tree | f616c1bea07cbb4d2110691f1e87cac17a18e569 /layers/buffer_validation.cpp | |
| parent | 4ccc652a0656a09b5baf8b0723dd256ca8293a4d (diff) | |
| download | usermoji-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.cpp | 424 |
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); |
