layers: Move image validation support to buffer_val

Moved the new CmdClear[Color/DepthStencil]Image support routines
to the buffer_validation module, along with some related helper
functions.

Change-Id: I76a4b545e696bbc770ef0c672d14c92e4a941e49
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp
index 2dfbf40..e50d643 100644
--- a/layers/buffer_validation.cpp
+++ b/layers/buffer_validation.cpp
@@ -263,3 +263,172 @@
     }
     return skip;
 }
+
+void ResolveRemainingLevelsLayers(core_validation::layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) {
+    // Expects global_lock to be held by caller
+
+    auto image_state = getImageState(dev_data, image);
+    if (image_state) {
+        // If the caller used the special values VK_REMAINING_MIP_LEVELS and VK_REMAINING_ARRAY_LAYERS, resolve them now in our
+        // internal state to the actual values.
+        if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
+            range->levelCount = image_state->createInfo.mipLevels - range->baseMipLevel;
+        }
+
+        if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
+            range->layerCount = image_state->createInfo.arrayLayers - range->baseArrayLayer;
+        }
+    }
+}
+
+// Return the correct layer/level counts if the caller used the special values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS.
+void ResolveRemainingLevelsLayers(core_validation::layer_data *dev_data, uint32_t *levels, uint32_t *layers,
+                                  VkImageSubresourceRange range, VkImage image) {
+    // Expects global_lock to be held by caller
+
+    *levels = range.levelCount;
+    *layers = range.layerCount;
+    auto image_state = getImageState(dev_data, image);
+    if (image_state) {
+        if (range.levelCount == VK_REMAINING_MIP_LEVELS) {
+            *levels = image_state->createInfo.mipLevels - range.baseMipLevel;
+        }
+        if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) {
+            *layers = image_state->createInfo.arrayLayers - range.baseArrayLayer;
+        }
+    }
+}
+
+bool VerifyClearImageLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage image,
+                            VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char *func_name) {
+    bool skip = false;
+    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+
+    VkImageSubresourceRange resolved_range = range;
+    ResolveRemainingLevelsLayers(device_data, &resolved_range, image);
+
+    if (dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+        if (dest_image_layout == VK_IMAGE_LAYOUT_GENERAL) {
+            auto image_state = getImageState(device_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 |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
+                                __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
+                                "%s: Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.", func_name);
+            }
+        } else {
+            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01086;
+            if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
+                error_code = VALIDATION_ERROR_01101;
+            } else {
+                assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
+            }
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, error_code, "DS",
+                        "%s: Layout for cleared image is %s but can only be "
+                        "TRANSFER_DST_OPTIMAL or GENERAL. %s",
+                        func_name, string_VkImageLayout(dest_image_layout), validation_error_map[error_code]);
+        }
+    }
+
+    for (uint32_t level_index = 0; level_index < resolved_range.levelCount; ++level_index) {
+        uint32_t level = level_index + resolved_range.baseMipLevel;
+        for (uint32_t layer_index = 0; layer_index < resolved_range.layerCount; ++layer_index) {
+            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)) {
+                if (node.layout != dest_image_layout) {
+                    UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01085;
+                    if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
+                        error_code = VALIDATION_ERROR_01100;
+                    } 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,
+                                    __LINE__, error_code, "DS",
+                                    "%s: Cannot clear an image whose layout is %s and "
+                                    "doesn't match the current layout %s. %s",
+                                    func_name, string_VkImageLayout(dest_image_layout), string_VkImageLayout(node.layout),
+                                    validation_error_map[error_code]);
+                }
+            }
+        }
+    }
+
+    return skip;
+}
+
+void RecordClearImageLayout(core_validation::layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image,
+                            VkImageSubresourceRange range, VkImageLayout dest_image_layout) {
+    VkImageSubresourceRange resolved_range = range;
+    ResolveRemainingLevelsLayers(dev_data, &resolved_range, image);
+
+    for (uint32_t level_index = 0; level_index < resolved_range.levelCount; ++level_index) {
+        uint32_t level = level_index + resolved_range.baseMipLevel;
+        for (uint32_t layer_index = 0; layer_index < resolved_range.layerCount; ++layer_index) {
+            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));
+            }
+        }
+    }
+}
+
+bool PreCallValidateCmdClearColorImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
+                                       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 image_state = getImageState(dev_data, image);
+    if (cb_node && image_state) {
+        skip |= ValidateMemoryIsBoundToImage(dev_data, image_state, "vkCmdClearColorImage()", VALIDATION_ERROR_02527);
+        skip |= ValidateCmd(dev_data, cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
+        skip |= insideRenderPass(dev_data, cb_node, "vkCmdClearColorImage()", VALIDATION_ERROR_01096);
+        for (uint32_t i = 0; i < rangeCount; ++i) {
+            skip |= ValidateImageAttributes(dev_data, image_state, pRanges[i]);
+            skip |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearColorImage()");
+        }
+    }
+    return skip;
+}
+
+// This state recording routine is shared between ClearColorImage and ClearDepthStencilImage
+void PreCallRecordCmdClearImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
+                                VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges,
+                                CMD_TYPE cmd_type) {
+    auto cb_node = getCBNode(dev_data, commandBuffer);
+    auto image_state = getImageState(dev_data, image);
+    if (cb_node && image_state) {
+        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
+        std::function<bool()> function = [=]() {
+            SetImageMemoryValid(dev_data, image_state, true);
+            return false;
+        };
+        cb_node->validate_functions.push_back(function);
+        UpdateCmdBufferLastCmd(dev_data, cb_node, cmd_type);
+        for (uint32_t i = 0; i < rangeCount; ++i) {
+            RecordClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout);
+        }
+    }
+}
+
+bool PreCallValidateCmdClearDepthStencilImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
+                                              VkImageLayout imageLayout, uint32_t rangeCount,
+                                              const VkImageSubresourceRange *pRanges) {
+    bool skip = false;
+    // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
+    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, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_02528);
+        skip |= ValidateCmd(dev_data, cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
+        skip |= insideRenderPass(dev_data, cb_node, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_01111);
+        for (uint32_t i = 0; i < rangeCount; ++i) {
+            skip |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()");
+        }
+    }
+    return skip;
+}
diff --git a/layers/buffer_validation.h b/layers/buffer_validation.h
index 653057a..acdc8f1 100644
--- a/layers/buffer_validation.h
+++ b/layers/buffer_validation.h
@@ -42,4 +42,26 @@
 
 bool ValidateImageAttributes(core_validation::layer_data *device_data, IMAGE_STATE *image_state, VkImageSubresourceRange range);
 
+void ResolveRemainingLevelsLayers(core_validation::layer_data *dev_data, VkImageSubresourceRange *range, VkImage image);
+
+void ResolveRemainingLevelsLayers(core_validation::layer_data *dev_data, uint32_t *levels, uint32_t *layers,
+                                  VkImageSubresourceRange range, VkImage image);
+
+bool VerifyClearImageLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage image,
+                            VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char *func_name);
+
+void RecordClearImageLayout(core_validation::layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image,
+                            VkImageSubresourceRange range, VkImageLayout dest_image_layout);
+
+bool PreCallValidateCmdClearColorImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
+                                       VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges);
+
+void PreCallRecordCmdClearImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
+                                VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges,
+                                CMD_TYPE cmd_type);
+
+bool PreCallValidateCmdClearDepthStencilImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
+                                              VkImageLayout imageLayout, uint32_t rangeCount,
+                                              const VkImageSubresourceRange *pRanges);
+
 #endif  // CORE_VALIDATION_BUFFER_VALIDATION_H_
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index a4cde25..4ab0038 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -418,7 +418,7 @@
     return nullptr;
 }
 // prototype
-static GLOBAL_CB_NODE *getCBNode(layer_data const *, const VkCommandBuffer);
+GLOBAL_CB_NODE *getCBNode(layer_data const *, const VkCommandBuffer);
 
 // Helper function to validate correct usage bits set for buffers or images
 //  Verify that (actual & desired) flags != 0 or,
@@ -577,7 +577,7 @@
 // For given image node
 //  If mem is special swapchain key, then set entire image_state to valid param value
 //  Else set the image's bound memory range to valid param value
-static void SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
+void SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
     if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
         image_state->valid = valid;
     } else {
@@ -3523,29 +3523,6 @@
     }
 }
 
-template <class OBJECT, class LAYOUT>
-void SetLayout(OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout, VkImageAspectFlags aspectMask) {
-    if (imgpair.subresource.aspectMask & aspectMask) {
-        imgpair.subresource.aspectMask = aspectMask;
-        SetLayout(pObject, imgpair, layout);
-    }
-}
-
-template <class OBJECT, class LAYOUT>
-void SetLayout(OBJECT *pObject, VkImage image, VkImageSubresource range, const LAYOUT &layout) {
-    ImageSubresourcePair imgpair = {image, true, range};
-    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
-    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
-    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
-    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
-}
-
-template <class OBJECT, class LAYOUT>
-void SetLayout(OBJECT *pObject, VkImage image, const LAYOUT &layout) {
-    ImageSubresourcePair imgpair = {image, false, VkImageSubresource()};
-    SetLayout(pObject, image, imgpair, layout);
-}
-
 void SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) {
     auto view_state = getImageViewState(dev_data, imageView);
     assert(view_state);
@@ -3632,7 +3609,7 @@
 }
 
 // For given CB object, fetch associated CB Node from map
-static GLOBAL_CB_NODE *getCBNode(layer_data const *my_data, const VkCommandBuffer cb) {
+GLOBAL_CB_NODE *getCBNode(layer_data const *my_data, const VkCommandBuffer cb) {
     auto it = my_data->commandBufferMap.find(cb);
     if (it == my_data->commandBufferMap.end()) {
         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -3701,9 +3678,9 @@
     return false;
 }
 
-// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not
-//  in the recording state or if there's an issue with the Cmd ordering
-static bool ValidateCmd(layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) {
+// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
+// there's an issue with the Cmd ordering
+bool ValidateCmd(layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) {
     bool skip_call = false;
     auto pPool = getCommandPoolNode(my_data, pCB->createInfo.commandPool);
     if (pPool) {
@@ -3774,7 +3751,7 @@
     return skip_call;
 }
 
-static void UpdateCmdBufferLastCmd(layer_data *my_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
+void UpdateCmdBufferLastCmd(layer_data *my_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
     if (cb_state->state == CB_RECORDING) {
         cb_state->last_cmd = cmd;
     }
@@ -3970,10 +3947,9 @@
     }
 }
 
-// Flags validation error if the associated call is made inside a render pass. The apiName
-// routine should ONLY be called outside a render pass.
-static bool insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName,
-                             UNIQUE_VALIDATION_ERROR_CODE msgCode) {
+// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
+// render pass.
+bool insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
     bool inside = false;
     if (pCB->activeRenderPass) {
         inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -6405,42 +6381,6 @@
     return result;
 }
 
-static void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) {
-    // Expects global_lock to be held by caller
-
-    auto image_state = getImageState(dev_data, image);
-    if (image_state) {
-        // If the caller used the special values VK_REMAINING_MIP_LEVELS and VK_REMAINING_ARRAY_LAYERS, resolve them now in our
-        // internal state to the actual values.
-        if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
-            range->levelCount = image_state->createInfo.mipLevels - range->baseMipLevel;
-        }
-
-        if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
-            range->layerCount = image_state->createInfo.arrayLayers - range->baseArrayLayer;
-        }
-    }
-}
-
-// Return the correct layer/level counts if the caller used the special
-// values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS.
-static void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range,
-                                         VkImage image) {
-    // Expects global_lock to be held by caller
-
-    *levels = range.levelCount;
-    *layers = range.layerCount;
-    auto image_state = getImageState(dev_data, image);
-    if (image_state) {
-        if (range.levelCount == VK_REMAINING_MIP_LEVELS) {
-            *levels = image_state->createInfo.mipLevels - range.baseMipLevel;
-        }
-        if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) {
-            *layers = image_state->createInfo.arrayLayers - range.baseArrayLayer;
-        }
-    }
-}
-
 // For the given format verify that the aspect masks make sense
 static bool ValidateImageAspectMask(layer_data *dev_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask,
                                     const char *func_name) {
@@ -8206,83 +8146,6 @@
     return skip_call;
 }
 
-static bool VerifyClearImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image, VkImageSubresourceRange range,
-                                   VkImageLayout dest_image_layout, const char *func_name) {
-    bool skip = false;
-
-    VkImageSubresourceRange resolved_range = range;
-    ResolveRemainingLevelsLayers(dev_data, &resolved_range, image);
-
-    if (dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
-        if (dest_image_layout == 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 |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
-                                0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
-                                "%s: Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.", func_name);
-            }
-        } else {
-            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01086;
-            if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
-                error_code = VALIDATION_ERROR_01101;
-            } else {
-                assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
-            }
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
-                            error_code, "DS",
-                            "%s: Layout for cleared image is %s but can only be "
-                            "TRANSFER_DST_OPTIMAL or GENERAL. %s",
-                            func_name, string_VkImageLayout(dest_image_layout), validation_error_map[error_code]);
-        }
-    }
-
-    for (uint32_t level_index = 0; level_index < resolved_range.levelCount; ++level_index) {
-        uint32_t level = level_index + resolved_range.baseMipLevel;
-        for (uint32_t layer_index = 0; layer_index < resolved_range.layerCount; ++layer_index) {
-            uint32_t layer = layer_index + resolved_range.baseArrayLayer;
-            VkImageSubresource sub = {resolved_range.aspectMask, level, layer};
-            IMAGE_CMD_BUF_LAYOUT_NODE node;
-            if (FindLayout(cb_node, image, sub, node)) {
-                if (node.layout != dest_image_layout) {
-                    UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01085;
-                    if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
-                        error_code = VALIDATION_ERROR_01100;
-                    } else {
-                        assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
-                    }
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, error_code, "DS",
-                                    "%s: Cannot clear an image whose layout is %s and "
-                                    "doesn't match the current layout %s. %s",
-                                    func_name, string_VkImageLayout(dest_image_layout), string_VkImageLayout(node.layout),
-                                    validation_error_map[error_code]);
-                }
-            }
-        }
-    }
-
-    return skip;
-}
-
-static void RecordClearImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image, VkImageSubresourceRange range,
-                                   VkImageLayout dest_image_layout) {
-    VkImageSubresourceRange resolved_range = range;
-    ResolveRemainingLevelsLayers(dev_data, &resolved_range, image);
-
-    for (uint32_t level_index = 0; level_index < resolved_range.levelCount; ++level_index) {
-        uint32_t level = level_index + resolved_range.baseMipLevel;
-        for (uint32_t layer_index = 0; layer_index < resolved_range.layerCount; ++layer_index) {
-            uint32_t layer = layer_index + resolved_range.baseArrayLayer;
-            VkImageSubresource sub = {resolved_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(dest_image_layout, dest_image_layout));
-            }
-        }
-    }
-}
-
 // Test if two VkExtent3D structs are equivalent
 static inline bool IsExtentEqual(const VkExtent3D *extent, const VkExtent3D *other_extent) {
     bool result = true;
@@ -8867,45 +8730,6 @@
     if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
 }
 
-static bool PreCallValidateCmdClearColorImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
-                                              VkImageLayout imageLayout, uint32_t rangeCount,
-                                              const VkImageSubresourceRange *pRanges) {
-    bool skip = false;
-    // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
-    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);
-        skip |= ValidateCmd(dev_data, cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
-        skip |= insideRenderPass(dev_data, cb_node, "vkCmdClearColorImage()", VALIDATION_ERROR_01096);
-        for (uint32_t i = 0; i < rangeCount; ++i) {
-            skip |= ValidateImageAttributes(dev_data, image_state, pRanges[i]);
-            skip |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearColorImage()");
-        }
-    }
-    return skip;
-}
-
-// This state recording routine is shared between ClearColorImage and ClearDepthStencilImage
-static void PreCallRecordCmdClearImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
-                                       VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges,
-                                       CMD_TYPE cmd_type) {
-    auto cb_node = getCBNode(dev_data, commandBuffer);
-    auto image_state = getImageState(dev_data, image);
-    if (cb_node && image_state) {
-        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
-        std::function<bool()> function = [=]() {
-            SetImageMemoryValid(dev_data, image_state, true);
-            return false;
-        };
-        cb_node->validate_functions.push_back(function);
-        UpdateCmdBufferLastCmd(dev_data, cb_node, cmd_type);
-        for (uint32_t i = 0; i < rangeCount; ++i) {
-            RecordClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout);
-        }
-    }
-}
-
 VKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
                                               const VkClearColorValue *pColor, uint32_t rangeCount,
                                               const VkImageSubresourceRange *pRanges) {
@@ -8920,24 +8744,6 @@
     }
 }
 
-static bool PreCallValidateCmdClearDepthStencilImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
-                                                     VkImageLayout imageLayout, uint32_t rangeCount,
-                                                     const VkImageSubresourceRange *pRanges) {
-    bool skip = false;
-    // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
-    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, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_02528);
-        skip |= ValidateCmd(dev_data, cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
-        skip |= insideRenderPass(dev_data, cb_node, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_01111);
-        for (uint32_t i = 0; i < rangeCount; ++i) {
-            skip |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()");
-        }
-    }
-    return skip;
-}
-
 VKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
                                                      const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
                                                      const VkImageSubresourceRange *pRanges) {
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index b93ad66..e592485 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -721,6 +721,7 @@
 IMAGE_VIEW_STATE *getImageViewState(const layer_data *, VkImageView);
 VkSwapchainKHR getSwapchainFromImage(const layer_data *, VkImage);
 SWAPCHAIN_NODE *getSwapchainNode(const layer_data *, VkSwapchainKHR);
+GLOBAL_CB_NODE *getCBNode(layer_data const *my_data, const VkCommandBuffer cb);
 void invalidateCommandBuffers(const layer_data *, std::unordered_set<GLOBAL_CB_NODE *> const &, VK_OBJECT);
 bool ValidateMemoryIsBoundToBuffer(const layer_data *, const BUFFER_STATE *, const char *, UNIQUE_VALIDATION_ERROR_CODE);
 bool ValidateMemoryIsBoundToImage(const layer_data *, const IMAGE_STATE *, const char *, UNIQUE_VALIDATION_ERROR_CODE);
@@ -733,6 +734,14 @@
 void invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj);
 void RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info);
 bool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type);
+bool ValidateCmd(layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name);
+bool insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode);
+bool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node);
+void SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid);
+void UpdateCmdBufferLastCmd(layer_data *my_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd);
+void SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node);
+void SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout);
+
 
 // Prototypes for layer_data accessor functions.  These should be in their own header file at some point
 PFN_vkGetPhysicalDeviceFormatProperties GetFormatPropertiesPointer(layer_data *);
@@ -746,4 +755,29 @@
 std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *);
 }
 
+
+
+template <class OBJECT, class LAYOUT>
+void SetLayout(OBJECT *pObject, VkImage image, VkImageSubresource range, const LAYOUT &layout) {
+    ImageSubresourcePair imgpair = { image, true, range };
+    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
+    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
+    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
+    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
+}
+
+template <class OBJECT, class LAYOUT>
+void SetLayout(OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout, VkImageAspectFlags aspectMask) {
+    if (imgpair.subresource.aspectMask & aspectMask) {
+        imgpair.subresource.aspectMask = aspectMask;
+        core_validation::SetLayout(pObject, imgpair, layout);
+    }
+}
+
+template <class OBJECT, class LAYOUT>
+void SetLayout(OBJECT *pObject, VkImage image, const LAYOUT &layout) {
+    ImageSubresourcePair imgpair = { image, false, VkImageSubresource() };
+    SetLayout(pObject, image, imgpair, layout);
+}
+
 #endif  // CORE_VALIDATION_TYPES_H_