layers:Warn on cmd buffer invalidate

From Mikko Strandborg

When a resource gets deleted, any command buffer that references it
gets invalidated, and an error gets thrown whenever that command buffer
is submitted. However, for a developer, it's quite hard to deduce what
exactly caused that to happen. This patch emits a warning whenever a
command buffer that's in CB_RECORDING state (meaning that it has had
its vkBeginCommandBuffer called but not End). This way the developer
can set a breakpoint on that to see exactly what causes the buffer to
be invalidated.

Destroying a resource that's being used in an open command buffer is
almost certainly a bug, but there might still be cases where it might
be valid behavior (for example, when the application decides to abort
an operation), therefore it's not an error but a warning instead.
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index e2be92b..4a081ea 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -5181,7 +5181,7 @@
         }
     }
     // Any bound cmd buffers are now invalid
-    invalidateCommandBuffers(mem_info->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
     dev_data->memObjMap.erase(mem);
 }
 
@@ -5495,7 +5495,7 @@
 }
 
 static void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
-    invalidateCommandBuffers(event_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
     dev_data->eventMap.erase(event);
 }
 
@@ -5523,7 +5523,7 @@
         VK_OBJECT obj_struct = {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT};
         skip |= ValidateObjectNotInUse(dev_data, qp_node, obj_struct, VALIDATION_ERROR_01012);
         // Any bound cmd buffers are now invalid
-        invalidateCommandBuffers(qp_node->cb_bindings, obj_struct);
+        invalidateCommandBuffers(dev_data, qp_node->cb_bindings, obj_struct);
     }
     if (!skip) {
         dev_data->queryPoolMap.erase(queryPool);
@@ -5771,7 +5771,7 @@
         auto buffer_state = getBufferState(dev_data, buffer);
         if (buffer_state) {
             // Any bound cmd buffers are now invalid
-            invalidateCommandBuffers(buffer_state->cb_bindings,
+            invalidateCommandBuffers(dev_data, buffer_state->cb_bindings,
                                      {reinterpret_cast<uint64_t &>(buffer_state->buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT});
             for (auto mem_binding : buffer_state->GetBoundMemory()) {
                 auto mem_info = getMemObjInfo(dev_data, mem_binding);
@@ -5803,7 +5803,7 @@
 static void PostCallRecordDestroyBufferView(layer_data *dev_data, VkBufferView buffer_view, BUFFER_VIEW_STATE *buffer_view_state,
                                             VK_OBJECT obj_struct) {
     // Any bound cmd buffers are now invalid
-    invalidateCommandBuffers(buffer_view_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, buffer_view_state->cb_bindings, obj_struct);
     dev_data->bufferViewMap.erase(buffer_view);
 }
 
@@ -5837,7 +5837,7 @@
 }
 
 static void PostCallRecordDestroyImage(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VK_OBJECT obj_struct) {
-    invalidateCommandBuffers(image_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, image_state->cb_bindings, obj_struct);
     // Clean up memory mapping, bindings and range references for image
     for (auto mem_binding : image_state->GetBoundMemory()) {
         auto mem_info = getMemObjInfo(dev_data, mem_binding);
@@ -6013,7 +6013,7 @@
 static void PostCallRecordDestroyImageView(layer_data *dev_data, VkImageView image_view, IMAGE_VIEW_STATE *image_view_state,
                                            VK_OBJECT obj_struct) {
     // Any bound cmd buffers are now invalid
-    invalidateCommandBuffers(image_view_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, image_view_state->cb_bindings, obj_struct);
     dev_data->imageViewMap.erase(image_view);
 }
 
@@ -6060,7 +6060,7 @@
 static void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
                                           VK_OBJECT obj_struct) {
     // Any bound cmd buffers are now invalid
-    invalidateCommandBuffers(pipeline_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
     dev_data->pipelineMap.erase(pipeline);
 }
 
@@ -6106,7 +6106,7 @@
                                          VK_OBJECT obj_struct) {
     // Any bound cmd buffers are now invalid
     if (sampler_state)
-        invalidateCommandBuffers(sampler_state->cb_bindings, obj_struct);
+        invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
     dev_data->samplerMap.erase(sampler);
 }
 
@@ -6148,7 +6148,7 @@
 static void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
                                                 DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
     // Any bound cmd buffers are now invalid
-    invalidateCommandBuffers(desc_pool_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
     // Free sets that were in this pool
     for (auto ds : desc_pool_state->sets) {
         freeDescriptorSet(dev_data, ds);
@@ -6384,8 +6384,13 @@
 }
 
 // For given cb_nodes, invalidate them and track object causing invalidation
-void invalidateCommandBuffers(std::unordered_set<GLOBAL_CB_NODE *> cb_nodes, VK_OBJECT obj) {
+void invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> cb_nodes, VK_OBJECT obj) {
     for (auto cb_node : cb_nodes) {
+        if (cb_node->state == CB_RECORDING) {
+            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    (uint64_t)(cb_node), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
+                    "Invalidating a command buffer that's currently being recorded: 0x%" PRIx64 ".", (uint64_t)(cb_node));
+        }
         cb_node->state = CB_INVALID;
         cb_node->broken_bindings.push_back(obj);
     }
@@ -6406,7 +6411,7 @@
 
 static void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
                                              VK_OBJECT obj_struct) {
-    invalidateCommandBuffers(framebuffer_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
     dev_data->frameBufferMap.erase(framebuffer);
 }
 
@@ -6440,7 +6445,7 @@
 
 static void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
                                             VK_OBJECT obj_struct) {
-    invalidateCommandBuffers(rp_state->cb_bindings, obj_struct);
+    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
     dev_data->renderPassMap.erase(render_pass);
 }
 
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index 44938d0..14ed5e7 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -656,7 +656,7 @@
 IMAGE_VIEW_STATE *getImageViewState(const layer_data *, VkImageView);
 VkSwapchainKHR getSwapchainFromImage(const layer_data *, VkImage);
 SWAPCHAIN_NODE *getSwapchainNode(const layer_data *, VkSwapchainKHR);
-void invalidateCommandBuffers(std::unordered_set<GLOBAL_CB_NODE *>, VK_OBJECT);
+void invalidateCommandBuffers(const layer_data *, std::unordered_set<GLOBAL_CB_NODE *>, VK_OBJECT);
 bool ValidateMemoryIsBoundToBuffer(const layer_data *, const BUFFER_STATE *, const char *);
 bool ValidateMemoryIsBoundToImage(const layer_data *, const IMAGE_STATE *, const char *);
 void AddCommandBufferBindingSampler(GLOBAL_CB_NODE *, SAMPLER_STATE *);
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index f2326dc..2a6b73e 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -541,7 +541,7 @@
 }
 // Set is being deleted or updates so invalidate all bound cmd buffers
 void cvdescriptorset::DescriptorSet::InvalidateBoundCmdBuffers() {
-    core_validation::invalidateCommandBuffers(cb_bindings,
+    core_validation::invalidateCommandBuffers(device_data_, cb_bindings,
                                               {reinterpret_cast<uint64_t &>(set_), VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT});
 }
 // Perform write update in given update struct