layers: Update Image layer to offload view.c validation checks from driver

Moved checks related to ImageView creation from the driver into the Image layer. Added image.h header and ENUMs for various Image error types, along with documenation for each type.
diff --git a/layers/image.cpp b/layers/image.cpp
index 5229732..6aa088b 100644
--- a/layers/image.cpp
+++ b/layers/image.cpp
@@ -30,10 +30,11 @@
 #include <string>
 #include <sstream>
 #include <unordered_map>
+#include <memory>
 
+#include "image.h"
 #include "vk_loader_platform.h"
 #include "vk_layer.h"
-#include "vk_layer_config.h"
 #include "vk_enum_validate_helper.h"
 #include "vk_struct_validate_helper.h"
 //The following is #included again to catch certain OS-specific functions being used:
@@ -41,16 +42,18 @@
 
 #include "vk_layer_table.h"
 #include "vk_layer_data.h"
-#include "vk_layer_logging.h"
 #include "vk_layer_extension_utils.h"
 
+using namespace std;
+
 typedef struct _layer_data {
     debug_report_data *report_data;
     VkDbgMsgCallback logging_callback;
     VkPhysicalDevice physicalDevice;
+    unordered_map<uint64_t, unique_ptr<VkImageCreateInfo>> imageMap;
 } layer_data;
 
-static std::unordered_map<void*, layer_data*> layer_data_map;
+static unordered_map<void*, layer_data*> layer_data_map;
 static device_table_map image_device_table_map;
 static instance_table_map image_instance_table_map;
 
@@ -258,30 +261,39 @@
 
 VK_LAYER_EXPORT VkResult VKAPI vkCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage)
 {
+    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     if(pCreateInfo->format != VK_FORMAT_UNDEFINED)
     {
-        layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
         VkFormatProperties properties;
         VkResult result = get_dispatch_table(image_instance_table_map, device_data->physicalDevice)->GetPhysicalDeviceFormatProperties(
                 device_data->physicalDevice, pCreateInfo->format, &properties);
-        if(result != VK_SUCCESS)
-        {
+        if(result != VK_SUCCESS) {
             char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, cannot be validated";
-            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", str);
+            log_msg(device_data->report_data, VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_FORMAT_UNSUPPORTED, "IMAGE", str);
         }
 
         if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0))
         {
             char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, contains unsupported format";
-            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", str);
+            log_msg(device_data->report_data, VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_FORMAT_UNSUPPORTED, "IMAGE", str);
         }
     }
 
     VkResult result = get_dispatch_table(image_device_table_map, device)->CreateImage(device, pCreateInfo, pImage);
 
+    if(result == VK_SUCCESS) {
+        device_data->imageMap[pImage->handle] = unique_ptr<VkImageCreateInfo>(new VkImageCreateInfo(*pCreateInfo));
+    }
     return result;
 }
 
+VK_LAYER_EXPORT void VKAPI vkDestroyImage(VkDevice device, VkImage image)
+{
+    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    device_data->imageMap.erase(image.handle);
+    get_dispatch_table(image_device_table_map, device)->DestroyImage(device, image);
+}
+
 VK_LAYER_EXPORT VkResult VKAPI vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass)
 {
     for(uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i)
@@ -296,7 +308,7 @@
             {
                 std::stringstream ss;
                 ss << "vkCreateRenderPass parameter, VkFormat in pCreateInfo->pAttachments[" << i << "], cannot be validated";
-                log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", ss.str().c_str());
+                log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_FORMAT_UNSUPPORTED, "IMAGE", ss.str().c_str());
                 continue;
             }
 
@@ -304,7 +316,7 @@
             {
                 std::stringstream ss;
                 ss << "vkCreateRenderPass parameter, VkFormat in pCreateInfo->pAttachments[" << i << "], contains unsupported format";
-                log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", ss.str().c_str());
+                log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_FORMAT_UNSUPPORTED, "IMAGE", ss.str().c_str());
             }
         }
     }
@@ -316,7 +328,7 @@
         {
             std::stringstream ss;
             ss << "vkCreateRenderPass parameter, VkImageLayout in pCreateInfo->pAttachments[" << i << "], is unrecognized";
-            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", ss.str().c_str());
+            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_RENDERPASS_INVALID_ATTACHMENT, "IMAGE", ss.str().c_str());
         }
     }
 
@@ -326,7 +338,7 @@
         {
             std::stringstream ss;
             ss << "vkCreateRenderPass parameter, VkAttachmentLoadOp in pCreateInfo->pAttachments[" << i << "], is unrecognized";
-            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", ss.str().c_str());
+            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_RENDERPASS_INVALID_ATTACHMENT, "IMAGE", ss.str().c_str());
         }
     }
 
@@ -336,7 +348,7 @@
         {
             std::stringstream ss;
             ss << "vkCreateRenderPass parameter, VkAttachmentStoreOp in pCreateInfo->pAttachments[" << i << "], is unrecognized";
-            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", ss.str().c_str());
+            log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_RENDERPASS_INVALID_ATTACHMENT, "IMAGE", ss.str().c_str());
         }
     }
 
@@ -353,7 +365,7 @@
             if (pCreateInfo->pSubpasses[i].depthStencilAttachment.attachment != VK_ATTACHMENT_UNUSED) {
                 std::stringstream ss;
                 ss << "vkCreateRenderPass has no depth/stencil attachment, yet subpass[" << i << "] has VkSubpassDescription::depthStencilAttachment value that is not VK_ATTACHMENT_UNUSED";
-                log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, 1, "IMAGE", ss.str().c_str());
+                log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_RENDERPASS_INVALID_DS_ATTACHMENT, "IMAGE", ss.str().c_str());
             }
         }
     }
@@ -363,6 +375,39 @@
     return result;
 }
 
+VK_LAYER_EXPORT VkResult VKAPI vkCreateImageView(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, VkImageView* pView)
+{
+    VkBool32 skipCall = VK_FALSE;
+    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    auto imageEntry = device_data->imageMap.find(pCreateInfo->image.handle);
+    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.";
+            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.";
+            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.mipLevels) {
+            std::stringstream ss;
+            ss << "vkCreateImageView called with 0 in pCreateInfo->subresourceRange.mipLevels.";
+            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.arraySize) {
+            std::stringstream ss;
+            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());
+        }
+    }
+    if (skipCall)
+        return VK_ERROR_VALIDATION_FAILED;
+    VkResult result = get_dispatch_table(image_device_table_map, device)->CreateImageView(device, pCreateInfo, pView);
+    return result;
+}
+
 VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
 {
     if (device == NULL) {
diff --git a/layers/image.h b/layers/image.h
new file mode 100644
index 0000000..631d1c6
--- /dev/null
+++ b/layers/image.h
@@ -0,0 +1,40 @@
+/*
+ * Vulkan
+ *
+ * Copyright (C) 2015 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef IMAGE_H
+#define IMAGE_H
+#include "vulkan.h"
+#include "vk_layer_config.h"
+#include "vk_layer_logging.h"
+
+// Draw State ERROR codes
+typedef enum _IMAGE_ERROR
+{
+    IMAGE_NONE,                             // Used for INFO & other non-error messages
+    IMAGE_FORMAT_UNSUPPORTED,               // Request to create Image or RenderPass with a format that is not supported
+    IMAGE_RENDERPASS_INVALID_ATTACHMENT,    // Invalid image layouts and/or load/storeOps for an attachment when creating RenderPass
+    IMAGE_RENDERPASS_INVALID_DS_ATTACHMENT, // If no depth attachment for a RenderPass, verify that subpass DS attachment is set to UNUSED
+    IMAGE_VIEW_CREATE_ERROR,                // Error occurred trying to create Image View
+} IMAGE_ERROR;
+
+#endif // IMAGE_H
diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md
index 15ab5b0..9e757fa 100644
--- a/layers/vk_validation_layer_details.md
+++ b/layers/vk_validation_layer_details.md
@@ -113,10 +113,13 @@
 
 DETAILS TABLE PENDING
 
-| Check | Overview | ENUM | Relevant API | Testname | Notes/TODO |
+| Check | Overview | ENUM IMAGE_* | Relevant API | Testname | Notes/TODO |
 | ----- | -------- | ---------------- | ------------ | -------- | ---------- |
-| Image Format | Verifies returned format to ensure that it is a supported Vulkan format | NA | vkCreateImage vkCreateRenderPass | TBD | NA |
-| Image Format | Validates that attachment image layouts, loadOps, and storeOps are valid Vulkan values; Verifies that if there is no depth attachment then the subpass attachment is set to VK_ATTACHMENT_UNUSED | NA | vkCreateRenderPass | TBD | NA |
+| Image Format | Verifies that requested format is a supported Vulkan format on this device | FORMAT_UNSUPPORTED | vkCreateImage vkCreateRenderPass | TBD | NA |
+| 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 |
+| NA | Enum used for informational messages | NONE | | NA | None |
 
 ### Image Pending Work
 Additional work to be done
diff --git a/vk_layer_documentation_generate.py b/vk_layer_documentation_generate.py
index d058181..a233c98 100755
--- a/vk_layer_documentation_generate.py
+++ b/vk_layer_documentation_generate.py
@@ -74,9 +74,13 @@
                                 'generated' : True,
                                 'error_enum' : 'OBJECT_TRACK_ERROR',},
                  'device_limits' : {'header' : 'layers/device_limits.h',
-                                'source' : 'dbuild/layers/device_limits.cpp',
-                                'generated' : False,
-                                'error_enum' : 'DEV_LIMITS_ERROR',},
+                                    'source' : 'layers/device_limits.cpp',
+                                    'generated' : False,
+                                    'error_enum' : 'DEV_LIMITS_ERROR',},
+                 'image' : {'header' : 'layers/image.h',
+                            'source' : 'layers/image.cpp',
+                            'generated' : False,
+                            'error_enum' : 'IMAGE_ERROR',},
     }
 
 builtin_headers = [layer_inputs[ln]['header'] for ln in layer_inputs]