Core validation: add an errror message when wrong layout is used for clearing
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 126ddcf..b7cc517 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -8242,6 +8242,52 @@
     return skip_call;
 }
 
+static bool VerifyClearImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image, VkImageSubresourceRange range,
+                                   VkImageLayout destImageLayout) {
+    bool skip_call = false;
+
+    VkImageSubresourceRange resolvedRange = range;
+    ResolveRemainingLevelsLayers(dev_data, &resolvedRange, image);
+
+    for (uint32_t levelIdx = 0; levelIdx < range.levelCount; ++levelIdx) {
+        uint32_t level = levelIdx + range.baseMipLevel;
+        for (uint32_t layerIdx = 0; layerIdx < range.layerCount; ++layerIdx) {
+            uint32_t layer = layerIdx + range.baseArrayLayer;
+            VkImageSubresource sub = {range.aspectMask, level, layer};
+            IMAGE_CMD_BUF_LAYOUT_NODE node;
+            if (!FindLayout(cb_node, image, sub, node)) {
+                SetLayout(cb_node, image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(destImageLayout, destImageLayout));
+                continue;
+            }
+            if (node.layout != destImageLayout) {
+                skip_call |=
+                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
+                            __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot clear an image whose 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(dev_data, image);
+            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(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
+                                     (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
+                                     "Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.");
+            }
+        } else {
+            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
+                                 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for cleared image is %s but can only be "
+                                                                       "TRANSFER_DST_OPTIMAL or GENERAL.",
+                                 string_VkImageLayout(destImageLayout));
+        }
+    }
+    return skip_call;
+}
+
 // Test if two VkExtent3D structs are equivalent
 static inline bool IsExtentEqual(const VkExtent3D *extent, const VkExtent3D *other_extent) {
     bool result = true;
@@ -8799,6 +8845,9 @@
     } else {
         assert(0);
     }
+    for (uint32_t i = 0; i < rangeCount; ++i) {
+        skip_call |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout);
+    }
     lock.unlock();
     if (!skip_call)
         dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
@@ -8829,6 +8878,9 @@
     } else {
         assert(0);
     }
+    for (uint32_t i = 0; i < rangeCount; ++i) {
+        skip_call |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout);
+    }
     lock.unlock();
     if (!skip_call)
         dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index 90509ab..7b70b3e 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -10473,6 +10473,26 @@
         "Layout for output image is VK_IMAGE_LAYOUT_UNDEFINED but can only be TRANSFER_DST_OPTIMAL or GENERAL.");
     m_commandBuffer->CopyImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_UNDEFINED, 1, &copyRegion);
     m_errorMonitor->VerifyFound();
+
+    VkClearColorValue clearValue = {};
+    VkImageSubresourceRange clearRange;
+    clearRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    clearRange.baseMipLevel = 0;
+    clearRange.baseArrayLayer = 0;
+    clearRange.layerCount = 1;
+    clearRange.levelCount = 1;
+
+    m_errorMonitor->SetDesiredFailureMsg(
+        VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        "Layout for cleared image is VK_IMAGE_LAYOUT_UNDEFINED but can only be TRANSFER_DST_OPTIMAL or GENERAL.");
+    m_commandBuffer->ClearColorImage(dst_image, VK_IMAGE_LAYOUT_UNDEFINED, &clearValue, 1, &clearRange);
+    m_errorMonitor->VerifyFound();
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Cannot clear an image whose layout is "
+                                                                        "VK_IMAGE_LAYOUT_UNDEFINED and doesn't match the current "
+                                                                        "layout VK_IMAGE_LAYOUT_GENERAL.");
+    m_commandBuffer->ClearColorImage(dst_image, VK_IMAGE_LAYOUT_UNDEFINED, &clearValue, 1, &clearRange);
+    m_errorMonitor->VerifyFound();
+
     // Now cause error due to bad image layout transition in PipelineBarrier
     VkImageMemoryBarrier image_barrier[1] = {};
     image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
diff --git a/tests/vkrenderframework.cpp b/tests/vkrenderframework.cpp
index 78df418..2f764a2 100644
--- a/tests/vkrenderframework.cpp
+++ b/tests/vkrenderframework.cpp
@@ -1410,6 +1410,16 @@
     vkCmdResolveImage(handle(), srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
 }
 
+void VkCommandBufferObj::ClearColorImage(VkImage image, VkImageLayout imageLayout, const VkClearColorValue *pColor,
+                                         uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
+    vkCmdClearColorImage(handle(), image, imageLayout, pColor, rangeCount, pRanges);
+}
+
+void VkCommandBufferObj::ClearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue *pColor,
+                                                uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
+    vkCmdClearDepthStencilImage(handle(), image, imageLayout, pColor, rangeCount, pRanges);
+}
+
 void VkCommandBufferObj::PrepareAttachments() {
     uint32_t i;
     const VkFlags output_mask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
diff --git a/tests/vkrenderframework.h b/tests/vkrenderframework.h
index 8bfbf12..6c8c014 100644
--- a/tests/vkrenderframework.h
+++ b/tests/vkrenderframework.h
@@ -186,6 +186,10 @@
                    uint32_t regionCount, const VkImageCopy *pRegions);
     void ResolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout,
                       uint32_t regionCount, const VkImageResolve *pRegions);
+    void ClearColorImage(VkImage image, VkImageLayout imageLayout, const VkClearColorValue *pColor, uint32_t rangeCount,
+                         const VkImageSubresourceRange *pRanges);
+    void ClearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue *pColor,
+                                uint32_t rangeCount, const VkImageSubresourceRange *pRanges);
 
   protected:
     VkDeviceObj *m_device;