layers: Add state-dependent image aspect/format checks
diff --git a/layers/image.cpp b/layers/image.cpp
index a49ded8..e03a195 100644
--- a/layers/image.cpp
+++ b/layers/image.cpp
@@ -60,7 +60,7 @@
 };
 
 static unordered_map<void*, layer_data*> layer_data_map;
-static device_table_map image_device_table_map;
+static device_table_map   image_device_table_map;
 static instance_table_map image_instance_table_map;
 
 // "my device data"
@@ -218,7 +218,7 @@
         uint32_t *pCount,
         VkExtensionProperties* pProperties)
 {
-    /* ParamChecker does not have any global extensions */
+    // ParamChecker does not have any global extensions
     return util_GetExtensionProperties(0, NULL, pCount, pProperties);
 }
 
@@ -237,7 +237,7 @@
         uint32_t*                                   pCount,
         VkExtensionProperties*                      pProperties)
 {
-    /* ParamChecker does not have any physical device extensions */
+    // ParamChecker does not have any physical device extensions
     return util_GetExtensionProperties(0, NULL, pCount, pProperties);
 }
 
@@ -246,7 +246,7 @@
         uint32_t*                                   pCount,
         VkLayerProperties*                          pProperties)
 {
-    /* ParamChecker's physical device layers are the same as global */
+    // ParamChecker's physical device layers are the same as global
     return util_GetLayerProperties(ARRAY_SIZE(pc_global_layers), pc_global_layers,
                                    pCount, pProperties);
 }
@@ -392,12 +392,14 @@
     if (imageEntry != device_data->imageMap.end()) {
         if (pCreateInfo->subresourceRange.baseMipLevel >= imageEntry->second->mipLevels) {
             std::stringstream ss;
-            ss << "vkCreateImageView called with baseMipLevel " << pCreateInfo->subresourceRange.baseMipLevel << " for image " << pCreateInfo->image.handle << " that only has " << imageEntry->second->mipLevels << " mip levels.";
+            ss << "vkCreateImageView called with baseMipLevel " << pCreateInfo->subresourceRange.baseMipLevel
+               << " for image " << pCreateInfo->image.handle << " that only has " << imageEntry->second->mipLevels << " mip levels.";
             skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_VIEW_CREATE_ERROR, "IMAGE", ss.str().c_str());
         }
         if (pCreateInfo->subresourceRange.baseArrayLayer >= imageEntry->second->arraySize) {
             std::stringstream ss;
-            ss << "vkCreateImageView called with baseArrayLayer " << pCreateInfo->subresourceRange.baseArrayLayer << " for image " << pCreateInfo->image.handle << " that only has " << imageEntry->second->arraySize << " mip levels.";
+            ss << "vkCreateImageView called with baseArrayLayer " << pCreateInfo->subresourceRange.baseArrayLayer << " for image "
+               << pCreateInfo->image.handle << " that only has " << imageEntry->second->arraySize << " mip levels.";
             skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_VIEW_CREATE_ERROR, "IMAGE", ss.str().c_str());
         }
         if (!pCreateInfo->subresourceRange.numLevels) {
@@ -410,12 +412,77 @@
             ss << "vkCreateImageView called with 0 in pCreateInfo->subresourceRange.arraySize.";
             skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_VIEW_CREATE_ERROR, "IMAGE", ss.str().c_str());
         }
-    }
 
-    // TODO: Image aspect mask must be only VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT
-    //       if the format is a color, depth-only or stencil-only format respectively. If using a depth/stencil format,
-    //       aspectMask must include at least one of VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT, and may include both.
-    //       Add after image/buffer state tracking is implemented.
+        // Validate correct image aspect bits for desired formats and format consistency
+        VkFormat           imageFormat = imageEntry->second->format;
+        VkFormat           ivciFormat  = pCreateInfo->format;
+        VkImageAspectFlags aspectMask  = pCreateInfo->subresourceRange.aspectMask;
+
+        if (vk_format_is_color(imageFormat)) {
+            if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+            if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != aspectMask) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Color image formats must have ONLY the VK_IMAGE_ASPECT_COLOR_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+            if (VK_FALSE == vk_format_is_color(ivciFormat)) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: The image view's format can differ from the parent image's format, but both must be "
+                   << "color formats.  ImageFormat is " << string_VkFormat(imageFormat) << " ImageViewFormat is " << string_VkFormat(ivciFormat);
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_FORMAT, "IMAGE", ss.str().c_str());
+            }
+            // TODO:  Uncompressed formats are compatible if they occupy they same number of bits per pixel.
+            //        Compressed formats are compatible if the only difference between them is the numerical type of
+            //        the uncompressed pixels (e.g. signed vs. unsigned, or sRGB vs. UNORM encoding).
+        } else  if (vk_format_is_depth_and_stencil(imageFormat)) {
+            if ((aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
+                              (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Combination depth/stencil image formats must have both VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+            if ((aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspectMask) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Combination depth/stencil image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+        } else  if (vk_format_is_depth_only(imageFormat)) {
+            if ((aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Depth-only image formats must have the VK_IMAGE_ASPECT_DEPTH_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+            if ((aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspectMask) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Depth-only image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+        } else  if (vk_format_is_stencil_only(imageFormat)) {
+            if ((aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Stencil-only image formats must have the VK_IMAGE_ASPECT_STENCIL_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+            if ((aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspectMask) {
+                std::stringstream ss;
+                ss << "vkCreateImageView: Stencil-only image formats can have only the VK_IMAGE_ASPECT_STENCIL_BIT set";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)pCreateInfo->image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+        }
+    }
 
     if (skipCall)
         return VK_ERROR_VALIDATION_FAILED;
@@ -608,7 +675,6 @@
     }
 }
 
-
 VK_LAYER_EXPORT void VKAPI vkCmdCopyBufferToImage(
     VkCmdBuffer              cmdBuffer,
     VkBuffer                 srcBuffer,
@@ -648,13 +714,91 @@
     const VkImageBlit *pRegions,
     VkTexFilter        filter)
 {
-    // TODO: From the spec -- these validation items will require the image layer to maintain image/buffer state.
-    //       If one of srcImage and destImage images has signed integer format, the other one must also have be signed integer format.
-    //       If one of srcImage and destImage images has unsigned integer format, the other one must also have be an unsigned integer format.
-    //       If the format of srcImage is a depth, stencil, depth stencil or integer-based format then filter must be VK_TEX_FILTER_NEAREST.
-    //       If one of srcImage and destImage images has a format of depth, stencil or depth stencil, the other one must have exactly the same format.
-    //           Additionally the allowed aspect bits in srcSubresource and destSubresource are only VK_IMAGE_ASPECT_DEPTH_BIT and
-    //           VK_IMAGE_ASPECT_STENCIL_BIT and the given aspect must exist in the format of both srcImage and destImage images.
+    VkBool32    skipCall    = VK_FALSE;
+    layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+
+    auto srcImageEntry  = device_data->imageMap.find(srcImage.handle);
+    auto destImageEntry = device_data->imageMap.find(destImage.handle);
+
+    if ((srcImageEntry  != device_data->imageMap.end()) &&
+        (destImageEntry != device_data->imageMap.end())) {
+
+        VkFormat srcFormat = srcImageEntry->second->format;
+        VkFormat dstFormat = destImageEntry->second->format;
+
+        // Validate consistency for signed and unsigned formats
+        if ((vk_format_is_sint(srcFormat) && !vk_format_is_sint(dstFormat)) ||
+            (vk_format_is_uint(srcFormat) && !vk_format_is_uint(dstFormat))) {
+            std::stringstream ss;
+            ss << "vkCmdBlitImage: If one of srcImage and destImage images has signed/unsigned integer format, "
+               << "the other one must also have signed/unsigned integer format.  "
+               << "Source format is " << string_VkFormat(srcFormat) << " Destinatino format is " << string_VkFormat(dstFormat);
+            skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+                               (uint64_t)cmdBuffer, 0, IMAGE_INVALID_FORMAT, "IMAGE", ss.str().c_str());
+        }
+
+        // Validate aspect bits and formats for depth/stencil images
+        if (vk_format_is_depth_or_stencil(srcFormat) ||
+            vk_format_is_depth_or_stencil(dstFormat)) {
+            if (srcFormat != dstFormat) {
+                std::stringstream ss;
+                ss << "vkCmdBlitImage: If one of srcImage and destImage images has a format of depth, stencil or depth "
+                   << "stencil, the other one must have exactly the same format.  "
+                   << "Source format is " << string_VkFormat(srcFormat) << " Destinatino format is " << string_VkFormat(dstFormat);
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+                                   (uint64_t)cmdBuffer, 0, IMAGE_INVALID_FORMAT, "IMAGE", ss.str().c_str());
+            }
+
+            for (uint32_t i = 0; i < regionCount; i++) {
+                VkImageAspectFlags srcAspect = pRegions[i].srcSubresource.aspect;
+                VkImageAspectFlags dstAspect = pRegions[i].destSubresource.aspect;
+
+                if (srcAspect != dstAspect) {
+                    std::stringstream ss;
+                    ss << "vkCmdBlitImage: Image aspects of depth/stencil images should match";
+                    skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+                                       (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+                }
+                if (vk_format_is_depth_and_stencil(srcFormat)) {
+                    if (srcAspect != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+                        std::stringstream ss;
+                        ss << "vkCmdBlitImage: Combination depth/stencil image formats must have both VK_IMAGE_ASPECT_DEPTH_BIT "
+                           << "and VK_IMAGE_ASPECT_STENCIL_BIT set in both the srcImage and destImage";
+                        skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+                                           (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+                    }
+                } else if (vk_format_is_stencil_only(srcFormat)) {
+                    if (srcAspect != VK_IMAGE_ASPECT_STENCIL_BIT) {
+                        std::stringstream ss;
+                        ss << "vkCmdBlitImage: Stencil-only image formats must have only the VK_IMAGE_ASPECT_STENCIL_BIT "
+                           << "set in both the srcImage and destImage";
+                        skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+                                           (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+                    }
+                } else if (vk_format_is_depth_only(srcFormat)) {
+                    if (srcAspect != VK_IMAGE_ASPECT_DEPTH_BIT) {
+                        std::stringstream ss;
+                        ss << "vkCmdBlitImage: Depth-only image formats must have only the VK_IMAGE_ASPECT_DEPTH "
+                           << "set in both the srcImage and destImage";
+                        skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+                                           (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+                    }
+                }
+            }
+        }
+
+        // Validate filter
+        if (vk_format_is_depth_or_stencil(srcFormat) ||
+            vk_format_is_int(srcFormat)) {
+            if (filter != VK_TEX_FILTER_NEAREST) {
+                std::stringstream ss;
+                ss << "vkCmdBlitImage: If the format of srcImage is a depth, stencil, depth stencil or integer-based format "
+                   << "then filter must be VK_TEX_FILTER_NEAREST.";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+                                   (uint64_t)cmdBuffer, 0, IMAGE_INVALID_FILTER, "IMAGE", ss.str().c_str());
+            }
+        }
+    }
 
     get_dispatch_table(image_device_table_map, cmdBuffer)->CmdBlitImage(cmdBuffer, srcImage,
         srcImageLayout, destImage, destImageLayout, regionCount, pRegions, filter);
@@ -684,8 +828,8 @@
         }
     }
 
-    if ((srcImageEntry != device_data->imageMap.end())
-    && (destImageEntry != device_data->imageMap.end())) {
+    if ((srcImageEntry  != device_data->imageMap.end()) &&
+        (destImageEntry != device_data->imageMap.end())) {
         if (srcImageEntry->second->format != destImageEntry->second->format) {
             char const str[] =  "vkCmdResolveImage called with unmatched source and dest formats.";
             skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
@@ -720,11 +864,38 @@
     const VkImageSubresource *pSubresource,
     VkSubresourceLayout      *pLayout)
 {
-    get_dispatch_table(image_device_table_map, device)->GetImageSubresourceLayout(device,
-         image, pSubresource, pLayout);
+    VkBool32    skipCall    = VK_FALSE;
+    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkFormat    format;
 
-    // TODO: After state tracking for images/buffers is implemented, validate that returned aspects match
-    //       the created formats -- color for color formats, depth|stencil for ds formats
+    auto imageEntry = device_data->imageMap.find(image.handle);
+
+    // Validate that image aspects match formats
+    if (imageEntry != device_data->imageMap.end()) {
+        format = imageEntry->second->format;
+        if (vk_format_is_color(format)) {
+            if (pSubresource->aspect != VK_IMAGE_ASPECT_COLOR_BIT) {
+                std::stringstream ss;
+                ss << "vkGetImageSubresourceLayout: For color formats, the aspect field of VkImageSubresource must be VK_IMAGE_ASPECT_COLOR.";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+        } else if (vk_format_is_depth_or_stencil(format)) {
+            if ((pSubresource->aspect != VK_IMAGE_ASPECT_DEPTH_BIT) &&
+                (pSubresource->aspect != VK_IMAGE_ASPECT_STENCIL_BIT)) {
+                std::stringstream ss;
+                ss << "vkGetImageSubresourceLayout: For depth/stencil formats, the aspect selects either the depth or stencil image aspect.";
+                skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE,
+                                   (uint64_t)image.handle, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", ss.str().c_str());
+            }
+        }
+    }
+
+    if (VK_FALSE == skipCall) {
+        get_dispatch_table(image_device_table_map, device)->GetImageSubresourceLayout(device,
+                           image, pSubresource, pLayout);
+    }
+
 }
 
 VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
@@ -733,7 +904,7 @@
         return NULL;
     }
 
-    /* loader uses this to force layer initialization; device object is wrapped */
+    // loader uses this to force layer initialization; device object is wrapped
     if (!strcmp(funcName, "vkGetDeviceProcAddr")) {
         initDeviceTable(image_device_table_map, (const VkBaseLayerObject *) device);
         return (PFN_vkVoidFunction) vkGetDeviceProcAddr;
@@ -780,7 +951,7 @@
         return NULL;
     }
 
-    /* loader uses this to force layer initialization; instance object is wrapped */
+    // loader uses this to force layer initialization; instance object is wrapped
     if (!strcmp(funcName, "vkGetInstanceProcAddr")) {
         initInstanceTable(image_instance_table_map, (const VkBaseLayerObject *) instance);
         return (PFN_vkVoidFunction) vkGetInstanceProcAddr;
diff --git a/layers/image.h b/layers/image.h
index cce4b9c..1392d51 100644
--- a/layers/image.h
+++ b/layers/image.h
@@ -40,22 +40,26 @@
     IMAGE_MISMATCHED_IMAGE_TYPE,            // Image types for source and dest images do not match
     IMAGE_MISMATCHED_IMAGE_FORMAT,          // Image formats for source and dest images do not match
     IMAGE_INVALID_RESOLVE_SAMPLES,          // Image resolve source samples less than two or dest samples greater than one
+    IMAGE_INVALID_FORMAT,                   // Operation specifies an invalid format, or there is a format mismatch
+    IMAGE_INVALID_FILTER,                   // Operation specifies an invalid filter setting
 } IMAGE_ERROR;
 
 typedef struct _IMAGE_STATE
 {
-    uint32_t mipLevels;
-    uint32_t arraySize;
-    VkFormat format;
-    uint32_t samples;
+    uint32_t    mipLevels;
+    uint32_t    arraySize;
+    VkFormat    format;
+    uint32_t    samples;
     VkImageType imageType;
-    _IMAGE_STATE():mipLevels(0), arraySize(0), format(VK_FORMAT_UNDEFINED), samples(0), imageType(VK_IMAGE_TYPE_NUM) {};
+    VkExtent3D  extent;
+    _IMAGE_STATE():mipLevels(0), arraySize(0), format(VK_FORMAT_UNDEFINED), samples(0), imageType(VK_IMAGE_TYPE_NUM), extent{0} {};
     _IMAGE_STATE(const VkImageCreateInfo* pCreateInfo):
         mipLevels(pCreateInfo->mipLevels),
         arraySize(pCreateInfo->arrayLayers),
         format(pCreateInfo->format),
         samples(pCreateInfo->samples),
-        imageType(pCreateInfo->imageType)
+        imageType(pCreateInfo->imageType),
+        extent(pCreateInfo->extent)
         {};
 } IMAGE_STATE;
 
diff --git a/layers/vk_layer_utils.cpp b/layers/vk_layer_utils.cpp
index c4d10f6..b0a483a 100644
--- a/layers/vk_layer_utils.cpp
+++ b/layers/vk_layer_utils.cpp
@@ -210,16 +210,20 @@
     { 4, 4 },  //    [VK_FORMAT_B10G10R10A2_SINT]
 };
 
-// Return true if format is a depth-stencil format
-bool vk_format_is_ds(VkFormat format)
+// Return true if format is a depth or stencil format
+bool vk_format_is_depth_or_stencil(VkFormat format)
+{
+    return (vk_format_is_depth_and_stencil(format) ||
+            vk_format_is_depth_only(format)        ||
+            vk_format_is_stencil_only(format));
+}
+
+// Return true if format contains depth and stencil information
+bool vk_format_is_depth_and_stencil(VkFormat format)
 {
     bool is_ds = false;
 
     switch (format) {
-    case VK_FORMAT_D16_UNORM:
-    case VK_FORMAT_D24_UNORM_X8:
-    case VK_FORMAT_D32_SFLOAT:
-    case VK_FORMAT_S8_UINT:
     case VK_FORMAT_D16_UNORM_S8_UINT:
     case VK_FORMAT_D24_UNORM_S8_UINT:
     case VK_FORMAT_D32_SFLOAT_S8_UINT:
@@ -228,10 +232,33 @@
     default:
         break;
     }
-
     return is_ds;
 }
 
+// Return true if format is a stencil-only format
+bool vk_format_is_stencil_only(VkFormat format)
+{
+    return (format == VK_FORMAT_S8_UINT);
+}
+
+// Return true if format is a depth-only format
+bool vk_format_is_depth_only(VkFormat format)
+{
+    bool is_depth = false;
+
+    switch (format) {
+    case VK_FORMAT_D16_UNORM:
+    case VK_FORMAT_D24_UNORM_X8:
+    case VK_FORMAT_D32_SFLOAT:
+        is_depth = true;
+        break;
+    default:
+        break;
+    }
+
+    return is_depth;
+}
+
 // Return true if format is of time UNORM
 bool vk_format_is_norm(VkFormat format)
 {
@@ -305,51 +332,73 @@
     return is_norm;
 };
 
+
 // Return true if format is an integer format
 bool vk_format_is_int(VkFormat format)
 {
-    bool is_int = false;
+    return (vk_format_is_sint(format) || vk_format_is_uint(format));
+}
+
+// Return true if format is an unsigned integer format
+bool vk_format_is_uint(VkFormat format)
+{
+    bool is_uint = false;
 
     switch (format) {
     case VK_FORMAT_R8_UINT:
-    case VK_FORMAT_R8_SINT:
     case VK_FORMAT_R8G8_UINT:
-    case VK_FORMAT_R8G8_SINT:
     case VK_FORMAT_R8G8B8_UINT:
-    case VK_FORMAT_R8G8B8_SINT:
     case VK_FORMAT_R8G8B8A8_UINT:
-    case VK_FORMAT_R8G8B8A8_SINT:
     case VK_FORMAT_R10G10B10A2_UINT:
-    case VK_FORMAT_R10G10B10A2_SINT:
     case VK_FORMAT_R16_UINT:
-    case VK_FORMAT_R16_SINT:
     case VK_FORMAT_R16G16_UINT:
-    case VK_FORMAT_R16G16_SINT:
     case VK_FORMAT_R16G16B16_UINT:
-    case VK_FORMAT_R16G16B16_SINT:
     case VK_FORMAT_R16G16B16A16_UINT:
-    case VK_FORMAT_R16G16B16A16_SINT:
     case VK_FORMAT_R32_UINT:
-    case VK_FORMAT_R32_SINT:
     case VK_FORMAT_R32G32_UINT:
-    case VK_FORMAT_R32G32_SINT:
     case VK_FORMAT_R32G32B32_UINT:
-    case VK_FORMAT_R32G32B32_SINT:
     case VK_FORMAT_R32G32B32A32_UINT:
-    case VK_FORMAT_R32G32B32A32_SINT:
     case VK_FORMAT_B8G8R8_UINT:
-    case VK_FORMAT_B8G8R8_SINT:
     case VK_FORMAT_B8G8R8A8_UINT:
-    case VK_FORMAT_B8G8R8A8_SINT:
     case VK_FORMAT_B10G10R10A2_UINT:
-    case VK_FORMAT_B10G10R10A2_SINT:
-        is_int = true;
+        is_uint = true;
         break;
     default:
         break;
     }
 
-    return is_int;
+    return is_uint;
+}
+
+// Return true if format is a signed integer format
+bool vk_format_is_sint(VkFormat format)
+{
+    bool is_sint = false;
+
+    switch (format) {
+    case VK_FORMAT_R8_SINT:
+    case VK_FORMAT_R8G8_SINT:
+    case VK_FORMAT_R8G8B8_SINT:
+    case VK_FORMAT_R8G8B8A8_SINT:
+    case VK_FORMAT_R10G10B10A2_SINT:
+    case VK_FORMAT_R16_SINT:
+    case VK_FORMAT_R16G16_SINT:
+    case VK_FORMAT_R16G16B16_SINT:
+    case VK_FORMAT_R16G16B16A16_SINT:
+    case VK_FORMAT_R32_SINT:
+    case VK_FORMAT_R32G32_SINT:
+    case VK_FORMAT_R32G32B32_SINT:
+    case VK_FORMAT_R32G32B32A32_SINT:
+    case VK_FORMAT_B8G8R8_SINT:
+    case VK_FORMAT_B8G8R8A8_SINT:
+    case VK_FORMAT_B10G10R10A2_SINT:
+        is_sint = true;
+        break;
+    default:
+        break;
+    }
+
+    return is_sint;
 }
 
 // Return true if format is a floating-point format
diff --git a/layers/vk_layer_utils.h b/layers/vk_layer_utils.h
index bd5eac8..376f81b 100644
--- a/layers/vk_layer_utils.h
+++ b/layers/vk_layer_utils.h
@@ -37,15 +37,20 @@
     return (format == VK_FORMAT_UNDEFINED);
 }
 
-bool vk_format_is_ds(VkFormat format);
+bool vk_format_is_depth_or_stencil(VkFormat format);
+bool vk_format_is_depth_and_stencil(VkFormat format);
+bool vk_format_is_depth_only(VkFormat format);
+bool vk_format_is_stencil_only(VkFormat format);
 
 static inline bool vk_format_is_color(VkFormat format)
 {
-    return !(vk_format_is_undef(format) || vk_format_is_ds(format));
+    return !(vk_format_is_undef(format) || vk_format_is_depth_or_stencil(format));
 }
 
 bool   vk_format_is_norm(VkFormat format);
 bool   vk_format_is_int(VkFormat format);
+bool   vk_format_is_sint(VkFormat format);
+bool   vk_format_is_uint(VkFormat format);
 bool   vk_format_is_float(VkFormat format);
 bool   vk_format_is_srgb(VkFormat format);
 bool   vk_format_is_compressed(VkFormat format);
diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md
index 132bd6d..6fcbcd9 100644
--- a/layers/vk_validation_layer_details.md
+++ b/layers/vk_validation_layer_details.md
@@ -112,11 +112,11 @@
 
 ## Image
 
-### Image Overview
+### Image Layer Overview
 
 The Image layer is responsible for validating format-related information and enforcing format restrictions.
 
-### Image Details Table
+### Image Layer Details Table
 
 DETAILS TABLE PENDING
 
@@ -126,11 +126,13 @@
 | RenderPass Attachments | Validates that attachment image layouts, loadOps, and storeOps are valid Vulkan values | RENDERPASS_INVALID_ATTACHMENT | vkCreateRenderPass | TBD | NA |
 | Subpass DS Settings | Verifies that if there is no depth attachment then the subpass attachment is set to VK_ATTACHMENT_UNUSED | RENDERPASS_INVALID_DS_ATTACHMENT | vkCreateRenderPass | TBD | NA |
 | View Creation | Verify that requested Image View Creation parameters are reasonable for the image that the view is being created for | VIEW_CREATE_ERROR | vkCreateImageView | TBD | NA |
-| Image Aspects | Verify that Image commands are using valid Image Aspect flags | INVALID_IMAGE_ASPECT | vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdCopyImage vkCmdCopyImageToBuffer vkCmdCopyBufferToImage vkCmdResolveImage | TBD | NA |
+| Image Aspects | Verify that Image commands are using valid Image Aspect flags | INVALID_IMAGE_ASPECT | vkCreateImageView vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdCopyImage vkCmdCopyImageToBuffer vkCmdCopyBufferToImage vkCmdResolveImage vkCmdBlitImage | InvalidImageViewAspect | NA |
 | Image Aspect Mismatch | Verify that Image commands with source and dest images use matching aspect flags | MISMATCHED_IMAGE_ASPECT | vkCmdCopyImage | TBD | NA |
 | Image Type Mismatch | Verify that Image commands with source and dest images use matching types | MISMATCHED_IMAGE_TYPE | vkCmdCopyImage vkCmdResolveImage | CopyImageTypeMismatch ResolveImageTypeMismatch | NA |
 | Image Format Mismatch | Verify that Image commands with source and dest images use matching formats | MISMATCHED_IMAGE_FORMAT | vkCmdCopyImage vkCmdResolveImage | CopyImageDepthStencilFormatMismatch ResolveImageFormatMismatch | NA |
 | Resolve Sample Count | Verifies that source and dest images sample counts are valid | INVALID_RESOLVE_SAMPLES | vkCmdResolveImage | ResolveImageHighSampleCount ResolveImageLowSampleCount | NA |
+| Verify Format | Verifies the formats are valid for this image operation | INVALID_FORMAT | vkCreateImageView vkCmdBlitImage | TBD | NA |
+| Verify Correct Image Filter| Verifies that specified filter is valid | INVALID_FILTER | vkCmdBlitImage | TBD | NA |
 | NA | Enum used for informational messages | NONE | | NA | None |
 
 ### Image Pending Work
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index 3863611..08a6479 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -4343,6 +4343,7 @@
         image_view_create_info.subresourceRange.numLayers = 1;
         image_view_create_info.subresourceRange.baseMipLevel = 10; // cause an error
         image_view_create_info.subresourceRange.numLevels = 1;
+        image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
     VkImageView view;
     err = vkCreateImageView(m_device->device(), &image_view_create_info, &view);
@@ -4354,6 +4355,59 @@
     }
 }
 
+TEST_F(VkLayerTest, InvalidImageViewAspect)
+{
+    VkFlags         msgFlags;
+    std::string     msgString;
+    VkResult        err;
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    m_errorMonitor->ClearState();
+
+    // Create an image and try to create a view with an invalid aspectMask
+    VkImage               image;
+
+    const VkFormat tex_format      = VK_FORMAT_B8G8R8A8_UNORM;
+    const int32_t  tex_width       = 32;
+    const int32_t  tex_height      = 32;
+
+    VkImageCreateInfo image_create_info = {};
+        image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+        image_create_info.pNext = NULL;
+        image_create_info.imageType = VK_IMAGE_TYPE_2D;
+        image_create_info.format = tex_format;
+        image_create_info.extent.width = tex_width;
+        image_create_info.extent.height = tex_height;
+        image_create_info.extent.depth = 1;
+        image_create_info.mipLevels = 1;
+        image_create_info.samples = 1;
+        image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
+        image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+        image_create_info.flags = 0;
+
+    err = vkCreateImage(m_device->device(), &image_create_info, &image);
+    ASSERT_VK_SUCCESS(err);
+
+    VkImageViewCreateInfo image_view_create_info = {};
+        image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+        image_view_create_info.image = image;
+        image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+        image_view_create_info.format = tex_format;
+        image_view_create_info.subresourceRange.baseMipLevel = 0;
+        image_view_create_info.subresourceRange.numLevels = 1;
+        // Cause an error by setting an invalid image aspect
+        image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_METADATA_BIT;
+
+    VkImageView view;
+    err = vkCreateImageView(m_device->device(), &image_view_create_info, &view);
+
+    msgFlags = m_errorMonitor->GetState(&msgString);
+    ASSERT_TRUE(0 != (msgFlags & VK_DBG_REPORT_ERROR_BIT)) << "Did not receive an error when specifying an invalid ImageView aspect";
+    if (!strstr(msgString.c_str(),"vkCreateImageView: Color image formats must have ONLY the VK_IMAGE_ASPECT_COLOR_BIT set")) {
+        FAIL() << "Error received was not 'VkCreateImageView: Color image formats must have ...' but instead '" << msgString.c_str() << "'";
+    }
+}
+
 TEST_F(VkLayerTest, CopyImageTypeMismatch)
 {
     VkFlags         msgFlags;