layers: Implement VU 00303-00308

Implement Valid Usages 00303-00308 with new function
ValidateBarrierLayoutToImageUsage() which verifies an
ImageMemoryBarrier's old/new ImageLayouts are compatible with its
Image's ImageUsageFlags.

Rename ValidateImageLayouts() to ValidateBarriersToImages().

Rename some variables:
- internal vars to use Google style.
- vars passed verbatim from Vulkan to use Vulkan names.

Fix issues revealed in layer tests due to these new checks:
- 2 new Unexpected messages in VkLayerTest.
- 1 failing VkPositiveTest.

Update VU database for check_implemented = Y.

Change-Id: I8723f99d515fbea707299b4d1fcf33a4da6b7b0b
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp
index 355eba8..f237d64 100644
--- a/layers/buffer_validation.cpp
+++ b/layers/buffer_validation.cpp
@@ -373,30 +373,93 @@
     SetLayout(device_data, pCB, mem_barrier->image, sub, mem_barrier->newLayout);
 }
 
-bool ValidateImageLayouts(layer_data *device_data, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
-                          const VkImageMemoryBarrier *pImgMemBarriers) {
+// Verify an ImageMemoryBarrier's old/new ImageLayouts are compatible with the Image's ImageUsageFlags.
+bool ValidateBarrierLayoutToImageUsage(layer_data *device_data, const VkImageMemoryBarrier *img_barrier, bool new_not_old,
+                                       VkImageUsageFlags usage_flags, const char *func_name) {
+    const auto report_data = core_validation::GetReportData(device_data);
+    bool skip = false;
+    const VkImageLayout layout = (new_not_old) ? img_barrier->newLayout : img_barrier->oldLayout;
+    UNIQUE_VALIDATION_ERROR_CODE msg_code = VALIDATION_ERROR_UNDEFINED;  // sentinel value meaning "no error"
+
+    switch (layout) {
+        case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+            if ((usage_flags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0) {
+                msg_code = VALIDATION_ERROR_00303;
+            }
+            break;
+        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+            if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
+                msg_code = VALIDATION_ERROR_00304;
+            }
+            break;
+        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
+            if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
+                msg_code = VALIDATION_ERROR_00305;
+            }
+            break;
+        case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+            if ((usage_flags & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) == 0) {
+                msg_code = VALIDATION_ERROR_00306;
+            }
+            break;
+        case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+            if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0) {
+                msg_code = VALIDATION_ERROR_00307;
+            }
+            break;
+        case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+            if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
+                msg_code = VALIDATION_ERROR_00308;
+            }
+            break;
+        default:
+            // Other VkImageLayout values do not have VUs defined in this context.
+            break;
+    }
+
+    if (msg_code != VALIDATION_ERROR_UNDEFINED) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, msg_code,
+                        "DS", "%s: Image barrier 0x%p %sLayout=%s is not compatible with image 0x%" PRIx64 " usage flags 0x%" PRIx32
+                              ". %s",
+                        func_name, img_barrier, ((new_not_old) ? "new" : "old"), string_VkImageLayout(layout),
+                        (uint64_t)(img_barrier->image), usage_flags, validation_error_map[msg_code]);
+    }
+    return skip;
+}
+
+// Verify image barriers are compatible with the images they reference.
+bool ValidateBarriersToImages(layer_data *device_data, VkCommandBuffer cmdBuffer, uint32_t imageMemoryBarrierCount,
+                              const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name) {
     GLOBAL_CB_NODE *pCB = GetCBNode(device_data, cmdBuffer);
     bool skip = false;
-    uint32_t levelCount = 0;
-    uint32_t layerCount = 0;
+    uint32_t level_count = 0;
+    uint32_t layer_count = 0;
 
-    for (uint32_t i = 0; i < memBarrierCount; ++i) {
-        auto mem_barrier = &pImgMemBarriers[i];
-        if (!mem_barrier) continue;
+    for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) {
+        auto img_barrier = &pImageMemoryBarriers[i];
+        if (!img_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));
+        ResolveRemainingLevelsLayers(device_data, &level_count, &layer_count, img_barrier->subresourceRange,
+                                     GetImageState(device_data, img_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 |= ValidateImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_COLOR_BIT);
-                skip |= ValidateImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_DEPTH_BIT);
-                skip |= ValidateImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_STENCIL_BIT);
-                skip |= ValidateImageAspectLayout(device_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_METADATA_BIT);
+        for (uint32_t j = 0; j < level_count; j++) {
+            uint32_t level = img_barrier->subresourceRange.baseMipLevel + j;
+            for (uint32_t k = 0; k < layer_count; k++) {
+                uint32_t layer = img_barrier->subresourceRange.baseArrayLayer + k;
+                skip |= ValidateImageAspectLayout(device_data, pCB, img_barrier, level, layer, VK_IMAGE_ASPECT_COLOR_BIT);
+                skip |= ValidateImageAspectLayout(device_data, pCB, img_barrier, level, layer, VK_IMAGE_ASPECT_DEPTH_BIT);
+                skip |= ValidateImageAspectLayout(device_data, pCB, img_barrier, level, layer, VK_IMAGE_ASPECT_STENCIL_BIT);
+                skip |= ValidateImageAspectLayout(device_data, pCB, img_barrier, level, layer, VK_IMAGE_ASPECT_METADATA_BIT);
             }
         }
+
+        IMAGE_STATE *image_state = GetImageState(device_data, img_barrier->image);
+        if (image_state) {
+            VkImageUsageFlags usage_flags = image_state->createInfo.usage;
+            skip |= ValidateBarrierLayoutToImageUsage(device_data, img_barrier, false, usage_flags, func_name);
+            skip |= ValidateBarrierLayoutToImageUsage(device_data, img_barrier, true, usage_flags, func_name);
+        }
     }
     return skip;
 }
diff --git a/layers/buffer_validation.h b/layers/buffer_validation.h
index e83ee9b..c318fb2 100644
--- a/layers/buffer_validation.h
+++ b/layers/buffer_validation.h
@@ -111,8 +111,11 @@
 void TransitionImageAspectLayout(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier, uint32_t level,
                                  uint32_t layer, VkImageAspectFlags aspect);
 
-bool ValidateImageLayouts(layer_data *device_data, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
-                          const VkImageMemoryBarrier *pImgMemBarriers);
+bool ValidateBarrierLayoutToImageUsage(layer_data *device_data, const VkImageMemoryBarrier *img_barrier, bool new_not_old,
+                                       VkImageUsageFlags usage, const char *func_name);
+
+bool ValidateBarriersToImages(layer_data *device_data, VkCommandBuffer cmdBuffer, uint32_t imageMemoryBarrierCount,
+                              const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name);
 
 void TransitionImageLayouts(layer_data *device_data, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
                             const VkImageMemoryBarrier *pImgMemBarriers);
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 17f0b20..f64a4b7 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -8386,7 +8386,8 @@
         cb_state->eventUpdates.push_back(event_update);
         skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
         UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
-        skip |= ValidateImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
+        skip |=
+            ValidateBarriersToImages(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
         if (!skip) {
             TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
         }
@@ -8414,7 +8415,8 @@
                                          VALIDATION_ERROR_00267);
     skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00266,
                                          VALIDATION_ERROR_00268);
-    skip |= ValidateImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
+    skip |= ValidateBarriersToImages(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers,
+                                     "vkCmdPipelineBarrier()");
     skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
                              pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
     return skip;
diff --git a/layers/vk_validation_error_database.txt b/layers/vk_validation_error_database.txt
index 526da22..c6973e1 100644
--- a/layers/vk_validation_error_database.txt
+++ b/layers/vk_validation_error_database.txt
@@ -304,12 +304,12 @@
 VALIDATION_ERROR_00300~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If image was created with a sharing mode of VK_SHARING_MODE_EXCLUSIVE, and srcQueueFamilyIndex and dstQueueFamilyIndex are valid queue families, at least one of them must be the same as the family of the queue that will execute this barrier' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
 VALIDATION_ERROR_00301~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'subresourceRange must be a valid image subresource range for the image (see [resources-image-views])' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
 VALIDATION_ERROR_00302~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If image has a depth/stencil format with both depth and stencil components, then aspectMask member of subresourceRange must include both VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
-VALIDATION_ERROR_00303~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL then image must have been created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
-VALIDATION_ERROR_00304~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL then image must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
-VALIDATION_ERROR_00305~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then image must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
-VALIDATION_ERROR_00306~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL then image must have been created with VK_IMAGE_USAGE_SAMPLED_BIT or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
-VALIDATION_ERROR_00307~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL then image must have been created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
-VALIDATION_ERROR_00308~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL then image must have been created with VK_IMAGE_USAGE_TRANSFER_DST_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
+VALIDATION_ERROR_00303~^~Y~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL then image must have been created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
+VALIDATION_ERROR_00304~^~Y~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL then image must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
+VALIDATION_ERROR_00305~^~Y~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then image must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
+VALIDATION_ERROR_00306~^~Y~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL then image must have been created with VK_IMAGE_USAGE_SAMPLED_BIT or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
+VALIDATION_ERROR_00307~^~Y~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL then image must have been created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
+VALIDATION_ERROR_00308~^~Y~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'If either oldLayout or newLayout is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL then image must have been created with VK_IMAGE_USAGE_TRANSFER_DST_BIT set' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~
 VALIDATION_ERROR_00309~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'sType must be VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~implicit, TBD in parameter validation layer.
 VALIDATION_ERROR_00310~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'pNext must be NULL' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~implicit, TBD in parameter validation layer.
 VALIDATION_ERROR_00311~^~N~^~Unknown~^~vkCmdPipelineBarrier~^~For more information refer to Vulkan Spec Section '6.6.3. Image Memory Barriers' which states 'srcAccessMask must be a valid combination of VkAccessFlagBits values' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkImageMemoryBarrier)~^~implicit
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index b7918ea..adb25fd 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -9188,7 +9188,8 @@
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "must have required access bit");
     ASSERT_NO_FATAL_FAILURE(InitState());
     VkImageObj image(m_device);
-    image.init(128, 128, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
+    image.init(128, 128, VK_FORMAT_B8G8R8A8_UNORM, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT),
+               VK_IMAGE_TILING_OPTIMAL, 0);
     ASSERT_TRUE(image.initialized());
 
     VkImageMemoryBarrier barrier = {};
@@ -11839,6 +11840,7 @@
                                          "You cannot transition the layout of aspect 1 from "
                                          "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL when "
                                          "current layout is VK_IMAGE_LAYOUT_GENERAL.");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, VALIDATION_ERROR_00305);
     vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0,
                          NULL, 0, NULL, 1, image_barrier);
     m_errorMonitor->VerifyFound();
@@ -18961,7 +18963,9 @@
     alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
     vkAllocateCommandBuffers(m_device->device(), &alloc_info, cmd_bufs);
     VkImageObj image(m_device);
-    image.init(128, 128, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
+    image.init(128, 128, VK_FORMAT_B8G8R8A8_UNORM,
+               (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT),
+               VK_IMAGE_TILING_OPTIMAL, 0);
     ASSERT_TRUE(image.initialized());
     VkCommandBufferBeginInfo cb_binfo;
     cb_binfo.pNext = NULL;