From 4d43c6ad27495c79dbdde0b3504727a4907ac783 Mon Sep 17 00:00:00 2001
From: Chris Forbes <chrisforbes@google.com>
Date: Fri, 19 May 2017 09:49:49 -0700
Subject: [PATCH] layers: Use CB invalidation mechanism for VU135.

Makes more sense to use command buffer invalidation to drive this than
maintaining parallel logic and only picking this up at draw time.

Drops some additional TODOs in around areas that need some more work to
make this nice.
---
 layers/core_validation.cpp     | 29 ++++++++++++++---------------
 layers/core_validation_types.h |  4 +---
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 172cdbf08..877c50896 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -1736,7 +1736,6 @@ static void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
         pCB->drawData.clear();
         pCB->currentDrawData.buffers.clear();
         pCB->vertex_buffer_used = false;
-        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
         // If secondary, invalidate any primary command buffer that may call us.
         if (pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
             invalidateCommandBuffers(dev_data,
@@ -2509,6 +2508,8 @@ static bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NO
     // Track in-use for resources off of primary and any secondary CBs
     bool skip = false;
 
+    // TODO: inline this function into sole caller
+
     // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
     // on device
     skip |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
@@ -2517,16 +2518,6 @@ static bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NO
 
     for (auto pSubCB : pCB->linkedCommandBuffers) {
         skip |= validateResources(dev_data, pSubCB);
-        // TODO: replace with invalidateCommandBuffers() at recording.
-        if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
-            !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
-            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
-                    __LINE__, VALIDATION_ERROR_31a00092, "DS",
-                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
-                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
-                    pCB->commandBuffer, pSubCB->commandBuffer, pSubCB->primaryCommandBuffer,
-                    validation_error_map[VALIDATION_ERROR_31a00092]);
-        }
     }
 
     skip |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count, VALIDATION_ERROR_31a00090);
@@ -4109,7 +4100,7 @@ VKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount,
 }
 
 // For given cb_nodes, invalidate them and track object causing invalidation
-void invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
+void invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj, bool track_invalidator) {
     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,
@@ -4120,11 +4111,13 @@ void invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLO
         else {
             cb_node->state = CB_INVALID_COMPLETE;
         }
-        cb_node->broken_bindings.push_back(obj);
+        if (track_invalidator) {
+            cb_node->broken_bindings.push_back(obj);
+        }
 
         // if secondary, then propagate the invalidation to the primaries that will call us.
         if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
-            invalidateCommandBuffers(dev_data, cb_node->linkedCommandBuffers, obj);
+            invalidateCommandBuffers(dev_data, cb_node->linkedCommandBuffers, obj, track_invalidator);
         }
     }
 }
@@ -8320,6 +8313,13 @@ VKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uin
                         pCommandBuffers[i], pCB->commandBuffer);
                     pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
                 }
+                if (pSubCB->linkedCommandBuffers.size()) {
+                    // TODO: adjust message support so we can report an accurate error message for this.
+                    invalidateCommandBuffers(dev_data, pSubCB->linkedCommandBuffers,
+                                             {HandleToUint64(pCommandBuffers[i]), kVulkanObjectTypeCommandBuffer},
+                                             false /* don't track invalidator. we've already complained. */);
+                    // TODO: consistent strategy for removing links.
+                }
             }
             if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
                 skip |=
@@ -8336,7 +8336,6 @@ VKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uin
             for (auto ilm_entry : pSubCB->imageLayoutMap) {
                 SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
             }
-            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
             pCB->linkedCommandBuffers.insert(pSubCB);
             pSubCB->linkedCommandBuffers.insert(pCB);
             for (auto &function : pSubCB->queryUpdates) {
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index 16548682b..0cb6ecee4 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -671,7 +671,6 @@ struct GLOBAL_CB_NODE : public BASE_NODE {
     std::vector<DRAW_DATA> drawData;
     DRAW_DATA currentDrawData;
     bool vertex_buffer_used;  // Track for perf warning to make sure any bound vtx buffer used
-    VkCommandBuffer primaryCommandBuffer;
     // Track images and buffers that are updated by this CB at the point of a draw
     std::unordered_set<VkImageView> updateImages;
     std::unordered_set<VkBuffer> updateBuffers;
@@ -787,7 +786,6 @@ const PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_da
 const VkPhysicalDeviceFeatures *GetEnabledFeatures(const layer_data *device_data);
 const DeviceExtensions *GetEnabledExtensions(const layer_data *device_data);
 
-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);
 void AddCommandBufferBindingSampler(GLOBAL_CB_NODE *, SAMPLER_STATE *);
@@ -796,7 +794,7 @@ void AddCommandBufferBindingImageView(const layer_data *, GLOBAL_CB_NODE *, IMAG
 void AddCommandBufferBindingBuffer(const layer_data *, GLOBAL_CB_NODE *, BUFFER_STATE *);
 void AddCommandBufferBindingBufferView(const layer_data *, GLOBAL_CB_NODE *, BUFFER_VIEW_STATE *);
 bool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct, UNIQUE_VALIDATION_ERROR_CODE error_code);
-void invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj);
+void invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj, bool track_invalidator=true);
 void RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info);
 void RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info);
 bool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VulkanObjectType type);
-- 
GitLab