layers: MR139, draw_state VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT checks

Added a set to track which secondary cmdBuffers are contained within a primary cmdBuffer.
Added new DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE enum value for new error/warning
cases, along with line in documentation.
New validation issues and state updates are listed below.

While tracking cmdBuffers at QueueSubmit time:
 1. Flag an error if a cmdBuffer is already in flight and does not have
    VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set
 2. Account for tracking of secondary cmdBuffers (and their in_use resources)
    that are submitted within a primary command buffer

When submitting secondary command buffers into primary command buffer at
    CmdExecuteCommands time:
 1. Flag an error if secondary cmdBuffer is in flight and doesn't have
 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.
 2. Warn user if secondary cmdBuffer doesn't have
 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set but primary cmdBuffer does.
 This causes primary cmdBuffer to be treated as if
 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT isn't set.
 3. Add secondary cmdBuffers to set off of primary cmdBuffer for tracking purposes
 4. Add secondary cmdBuffers to inFlight set
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 416995d..f8c7208 100644
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -2605,6 +2605,7 @@
         pCB->waitedEvents.clear();
         pCB->waitedEventsBeforeQueryReset.clear();
         pCB->queryToStateMap.clear();
+        pCB->secondaryCommandBuffers.clear();
     }
 }
 
@@ -3184,17 +3185,26 @@
         my_data->fenceMap[fence].priorFence = priorFence;
         my_data->fenceMap[fence].needsSignaled = true;
         for (uint32_t i = 0; i < cmdBufferCount; ++i) {
+            for (auto secondaryCmdBuffer : my_data->commandBufferMap[pCmdBuffers[i]]->secondaryCommandBuffers) {
+                my_data->fenceMap[fence].cmdBuffers.push_back(secondaryCmdBuffer);
+            }
             my_data->fenceMap[fence].cmdBuffers.push_back(pCmdBuffers[i]);
         }
     } else {
         if (queue_data != my_data->queueMap.end()) {
             for (uint32_t i = 0; i < cmdBufferCount; ++i) {
+                for (auto secondaryCmdBuffer : my_data->commandBufferMap[pCmdBuffers[i]]->secondaryCommandBuffers) {
+                   queue_data->second.untrackedCmdBuffers.push_back(secondaryCmdBuffer);
+                }
                 queue_data->second.untrackedCmdBuffers.push_back(pCmdBuffers[i]);
             }
         }
     }
     if (queue_data != my_data->queueMap.end()) {
         for (uint32_t i = 0; i < cmdBufferCount; ++i) {
+            for (auto secondaryCmdBuffer : my_data->commandBufferMap[pCmdBuffers[i]]->secondaryCommandBuffers) {
+                my_data->inFlightCmdBuffers.insert(secondaryCmdBuffer);
+            }
             my_data->inFlightCmdBuffers.insert(pCmdBuffers[i]);
         }
     }
@@ -3205,8 +3215,6 @@
     VkBool32 skipCall = VK_FALSE;
     GLOBAL_CB_NODE* pCB = NULL;
     layer_data* dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
-    // TODO : Any pCommandBuffers must have USAGE_SIMULTANEOUS_USE_BIT set or cannot already be executing on device
-    //    Same goes for any secondary CBs under the primary CB
     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
         const VkSubmitInfo *submit = &pSubmits[submit_idx];
         for (uint32_t i=0; i < submit->waitSemaphoreCount; ++i) {
@@ -3231,7 +3239,13 @@
             pCB = getCBNode(dev_data, submit->pCommandBuffers[i]);
             loader_platform_thread_lock_mutex(&globalLock);
             pCB->submitCount++; // increment submit count
+            // Track in-use for resources off of primary and any secondary CBs
             skipCall |= validateAndIncrementResources(dev_data, pCB);
+            if (!pCB->secondaryCommandBuffers.empty()) {
+                for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
+                    skipCall |= validateAndIncrementResources(dev_data, dev_data->commandBufferMap[secondaryCmdBuffer]);
+                }
+            }
             if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) {
                 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
                         "CB %#" PRIxLEAST64 " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT set, but has been submitted %#" PRIxLEAST64 " times.",
@@ -3244,6 +3258,13 @@
                 loader_platform_thread_unlock_mutex(&globalLock);
                 return VK_ERROR_VALIDATION_FAILED_EXT;
             }
+            // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing on device
+            if (!(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
+                if (dev_data->inFlightCmdBuffers.find(pCB->commandBuffer) != dev_data->inFlightCmdBuffers.end()) {
+                    skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
+                        "Attempt to simultaneously execute CB %#" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set!", reinterpret_cast<uint64_t>(pCB->commandBuffer));
+                }
+            }
             loader_platform_thread_unlock_mutex(&globalLock);
         }
         trackCommandBuffers(dev_data, queue, submit->commandBufferCount, submit->pCommandBuffers, fence);
@@ -3314,6 +3335,7 @@
 {
     layer_data* dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
     decrementResources(dev_data, queue);
+    // TODO : Is this a bug? Can't clear all device CmdBuffers on QueueWaitIdle
     for (auto cmdBuffer : dev_data->inFlightCmdBuffers) {
         cleanInFlightCmdBuffer(dev_data, cmdBuffer);
     }
@@ -5869,6 +5891,22 @@
                     }
                 }
             }
+            // Secondary cmdBuffers are considered pending execution starting w/ being recorded
+            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
+                if (dev_data->inFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->inFlightCmdBuffers.end()) {
+                    skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
+                            "Attempt to simultaneously execute CB %#" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set!", reinterpret_cast<uint64_t>(pCB->commandBuffer));
+                }
+                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
+                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
+                    skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARN_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
+                            "vkCmdExecuteCommands(): Secondary Command Buffer (%#" PRIxLEAST64 ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer (%#" PRIxLEAST64 ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set, even though it does.",
+                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), reinterpret_cast<uint64_t>(pCB->commandBuffer));
+                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+                }
+            }
+            pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
+            dev_data->inFlightCmdBuffers.insert(pSubCB->commandBuffer);
         }
         skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands");
         skipCall |= addCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");