layers: Add command pool validation to DrawState
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 5a9a3bf..9e3f9e9 100644
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -33,6 +33,7 @@
 #include <memory>
 #include <unordered_map>
 #include <unordered_set>
+#include <list>
 
 #include "vk_loader_platform.h"
 #include "vk_dispatch_table_helper.h"
@@ -68,22 +69,23 @@
     VkLayerInstanceDispatchTable* instance_dispatch_table;
     devExts device_extensions;
     // Layer specific data
-    unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> sampleMap;
-    unordered_map<VkImageView, unique_ptr<VkImageViewCreateInfo>> imageViewMap;
-    unordered_map<VkImage, unique_ptr<VkImageCreateInfo>> imageMap;
-    unordered_map<VkBufferView, unique_ptr<VkBufferViewCreateInfo>> bufferViewMap;
-    unordered_map<VkBuffer, unique_ptr<VkBufferCreateInfo>> bufferMap;
-    unordered_map<VkPipeline, PIPELINE_NODE*> pipelineMap;
-    unordered_map<VkDescriptorPool, POOL_NODE*> poolMap;
-    unordered_map<VkDescriptorSet, SET_NODE*> setMap;
-    unordered_map<VkDescriptorSetLayout, LAYOUT_NODE*> layoutMap;
-    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
-    unordered_map<VkDeviceMemory, VkImage> memImageMap;
+    unordered_map<VkSampler,             unique_ptr<SAMPLER_NODE>>           sampleMap;
+    unordered_map<VkImageView,           unique_ptr<VkImageViewCreateInfo>>  imageViewMap;
+    unordered_map<VkImage,               unique_ptr<VkImageCreateInfo>>      imageMap;
+    unordered_map<VkBufferView,          unique_ptr<VkBufferViewCreateInfo>> bufferViewMap;
+    unordered_map<VkBuffer,              unique_ptr<VkBufferCreateInfo>>     bufferMap;
+    unordered_map<VkPipeline,            PIPELINE_NODE*>                     pipelineMap;
+    unordered_map<VkCommandPool,         list<VkCommandBuffer>>              commandPoolMap;
+    unordered_map<VkDescriptorPool,      DESCRIPTOR_POOL_NODE*>              descriptorPoolMap;
+    unordered_map<VkDescriptorSet,       SET_NODE*>                          setMap;
+    unordered_map<VkDescriptorSetLayout, LAYOUT_NODE*>                       layoutMap;
+    unordered_map<VkPipelineLayout,      PIPELINE_LAYOUT_NODE>               pipelineLayoutMap;
+    unordered_map<VkDeviceMemory,        VkImage>                            memImageMap;
     // Map for layout chains
-    unordered_map<void*, GLOBAL_CB_NODE*> commandBufferMap;
-    unordered_map<VkFramebuffer, VkFramebufferCreateInfo*> frameBufferMap;
-    unordered_map<VkImage, IMAGE_NODE*> imageLayoutMap;
-    unordered_map<VkRenderPass, RENDER_PASS_NODE*> renderPassMap;
+    unordered_map<void*,                 GLOBAL_CB_NODE*>                    commandBufferMap;
+    unordered_map<VkFramebuffer,         VkFramebufferCreateInfo*>           frameBufferMap;
+    unordered_map<VkImage,               IMAGE_NODE*>                        imageLayoutMap;
+    unordered_map<VkRenderPass,          RENDER_PASS_NODE*>                  renderPassMap;
     // Current render pass
     VkRenderPassBeginInfo renderPassBeginInfo;
     uint32_t currentSubpass;
@@ -646,15 +648,15 @@
 // Block of code at start here specifically for managing/tracking DSs
 
 // Return Pool node ptr for specified pool or else NULL
-static POOL_NODE* getPoolNode(layer_data* my_data, const VkDescriptorPool pool)
+static DESCRIPTOR_POOL_NODE* getPoolNode(layer_data* my_data, const VkDescriptorPool pool)
 {
     loader_platform_thread_lock_mutex(&globalLock);
-    if (my_data->poolMap.find(pool) == my_data->poolMap.end()) {
+    if (my_data->descriptorPoolMap.find(pool) == my_data->descriptorPoolMap.end()) {
         loader_platform_thread_unlock_mutex(&globalLock);
         return NULL;
     }
     loader_platform_thread_unlock_mutex(&globalLock);
-    return my_data->poolMap[pool];
+    return my_data->descriptorPoolMap[pool];
 }
 // Return Set node ptr for specified set or else NULL
 static SET_NODE* getSetNode(layer_data* my_data, const VkDescriptorSet set)
@@ -1132,7 +1134,7 @@
     return skipCall;
 }
 // Verify that given pool has descriptors that are being requested for allocation
-static VkBool32 validate_descriptor_availability_in_pool(layer_data* dev_data, POOL_NODE* pPoolNode, uint32_t count, const VkDescriptorSetLayout* pSetLayouts)
+static VkBool32 validate_descriptor_availability_in_pool(layer_data* dev_data, DESCRIPTOR_POOL_NODE* pPoolNode, uint32_t count, const VkDescriptorSetLayout* pSetLayouts)
 {
     VkBool32 skipCall = VK_FALSE;
     uint32_t i = 0, j = 0;
@@ -1218,9 +1220,9 @@
 // NOTE : Calls to this function should be wrapped in mutex
 static void deletePools(layer_data* my_data)
 {
-    if (my_data->poolMap.size() <= 0)
+    if (my_data->descriptorPoolMap.size() <= 0)
         return;
-    for (auto ii=my_data->poolMap.begin(); ii!=my_data->poolMap.end(); ++ii) {
+    for (auto ii=my_data->descriptorPoolMap.begin(); ii!=my_data->descriptorPoolMap.end(); ++ii) {
         SET_NODE* pSet = (*ii).second->pSets;
         SET_NODE* pFreeSet = pSet;
         while (pSet) {
@@ -1236,7 +1238,7 @@
         }
         delete (*ii).second;
     }
-    my_data->poolMap.clear();
+    my_data->descriptorPoolMap.clear();
 }
 // WARN : Once deleteLayouts() called, any layout ptrs in Pool/Set data structure will be invalid
 // NOTE : Calls to this function should be wrapped in mutex
@@ -1273,7 +1275,7 @@
 
 static void clearDescriptorPool(layer_data* my_data, const VkDevice device, const VkDescriptorPool pool, VkDescriptorPoolResetFlags flags)
 {
-    POOL_NODE* pPool = getPoolNode(my_data, pool);
+    DESCRIPTOR_POOL_NODE* pPool = getPoolNode(my_data, pool);
     if (!pPool) {
         log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t) pool, 0, DRAWSTATE_INVALID_POOL, "DS",
                 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkResetDescriptorPool() call", (uint64_t) pool);
@@ -1488,7 +1490,7 @@
     GLOBAL_CB_NODE* pCB = getCBNode(my_data, cb);
     if (pCB && pCB->lastBoundDescriptorSet) {
         SET_NODE* pSet = getSetNode(my_data, pCB->lastBoundDescriptorSet);
-        POOL_NODE* pPool = getPoolNode(my_data, pSet->pool);
+        DESCRIPTOR_POOL_NODE* pPool = getPoolNode(my_data, pSet->pool);
         // Print out pool details
         skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_INFO_BIT, (VkDbgObjectType) 0, 0, 0, DRAWSTATE_NONE, "DS",
                 "Details for pool %#" PRIxLEAST64 ".", (uint64_t) pPool->pool);
@@ -1948,8 +1950,50 @@
 
 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t count, const VkCommandBuffer *pCommandBuffers)
 {
-    get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->FreeCommandBuffers(device, commandPool, count, pCommandBuffers);
-    // TODO : Clean up any internal data structures using this obj.
+    layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+
+    for (auto i = 0; i < count; i++) {
+        // Delete CB information structure, and remove from commandBufferMap
+        auto cb = dev_data->commandBufferMap.find(pCommandBuffers[i]);
+        if (cb != dev_data->commandBufferMap.end()) {
+            delete (*cb).second;
+            dev_data->commandBufferMap.erase(cb);
+        }
+
+        // Remove commandBuffer reference from commandPoolMap
+        dev_data->commandPoolMap[commandPool].remove(pCommandBuffers[i]);
+    }
+
+    dev_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, count, pCommandBuffers);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool)
+{
+    layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+
+    VkResult result = dev_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
+
+    if (VK_SUCCESS == result) {
+        dev_data->commandPoolMap[*pCommandPool];
+    }
+    return result;
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator)
+{
+    layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+
+    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandPoolMap
+    if (dev_data->commandPoolMap.find(commandPool) != dev_data->commandPoolMap.end()) {
+        for (auto poolCb = dev_data->commandPoolMap[commandPool].begin(); poolCb != dev_data->commandPoolMap[commandPool].end();) {
+            auto del_cb = dev_data->commandBufferMap.find(*poolCb);
+            delete (*del_cb).second;                                        // delete CB info structure
+            dev_data->commandBufferMap.erase(del_cb);                       // Remove this command buffer from cbMap
+            poolCb = dev_data->commandPoolMap[commandPool].erase(poolCb);   // Remove CB reference from commandPoolMap's list
+        }
+    }
+    dev_data->commandPoolMap.erase(commandPool);
+    dev_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator);
 }
 
 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator)
@@ -2205,13 +2249,13 @@
                 "Created Descriptor Pool %#" PRIxLEAST64, (uint64_t) *pDescriptorPool))
             return VK_ERROR_VALIDATION_FAILED;
         loader_platform_thread_lock_mutex(&globalLock);
-        POOL_NODE* pNewNode = new POOL_NODE(*pDescriptorPool, pCreateInfo);
+        DESCRIPTOR_POOL_NODE* pNewNode = new DESCRIPTOR_POOL_NODE(*pDescriptorPool, pCreateInfo);
         if (NULL == pNewNode) {
             if (log_msg(dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t) *pDescriptorPool, 0, DRAWSTATE_OUT_OF_MEMORY, "DS",
-                    "Out of memory while attempting to allocate POOL_NODE in vkCreateDescriptorPool()"))
+                    "Out of memory while attempting to allocate DESCRIPTOR_POOL_NODE in vkCreateDescriptorPool()"))
                 return VK_ERROR_VALIDATION_FAILED;
         } else {
-            dev_data->poolMap[*pDescriptorPool] = pNewNode;
+            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
         }
         loader_platform_thread_unlock_mutex(&globalLock);
     } else {
@@ -2235,7 +2279,7 @@
     VkBool32 skipCall = VK_FALSE;
     layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     // Verify that requested descriptorSets are available in pool
-    POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
+    DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
     if (!pPoolNode) {
         skipCall |= log_msg(dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t) pAllocateInfo->descriptorPool, 0, DRAWSTATE_INVALID_POOL, "DS",
                 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call", (uint64_t) pAllocateInfo->descriptorPool);
@@ -2246,7 +2290,7 @@
         return VK_ERROR_VALIDATION_FAILED;
     VkResult result = dev_data->device_dispatch_table->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
     if (VK_SUCCESS == result) {
-        POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
+        DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
         if (pPoolNode) {
             if (pAllocateInfo->setLayoutCount == 0) {
                 log_msg(dev_data->report_data, VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, pAllocateInfo->setLayoutCount, 0, DRAWSTATE_NONE, "DS",
@@ -2296,7 +2340,7 @@
 {
     VkBool32 skipCall = VK_FALSE;
     layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
-    POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
+    DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
     if (pPoolNode && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pPoolNode->createInfo.flags)) {
         // Can't Free from a NON_FREE pool
         skipCall |= log_msg(dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, (uint64_t)device, 0, DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, "DS",
@@ -2336,15 +2380,22 @@
     layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     VkResult result = dev_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
     if (VK_SUCCESS == result) {
-        loader_platform_thread_lock_mutex(&globalLock);
-        GLOBAL_CB_NODE* pCB = new GLOBAL_CB_NODE;
-        dev_data->commandBufferMap[*pCommandBuffer] = pCB;
-        loader_platform_thread_unlock_mutex(&globalLock);
-        resetCB(dev_data, *pCommandBuffer);
-        pCB->commandBuffer = *pCommandBuffer;
-        pCB->createInfo    = *pCreateInfo;
-        pCB->level         = pCreateInfo->level;
-        updateCBTracking(pCB);
+        for (auto i = 0; i < pCreateInfo->bufferCount; i++) {
+            // Validate command pool
+            if (dev_data->commandPoolMap.find(pCreateInfo->commandPool) != dev_data->commandPoolMap.end()) {
+                // Add command buffer to its commandPool map
+                dev_data->commandPoolMap[pCreateInfo->commandPool].push_back(pCommandBuffer[i]);
+
+                GLOBAL_CB_NODE* pCB = new GLOBAL_CB_NODE;
+                // Add command buffer to map
+                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
+                resetCB(dev_data, pCommandBuffer[i]);
+                pCB->commandBuffer = pCommandBuffer[i];
+                pCB->createInfo    = *pCreateInfo;
+                pCB->level         = pCreateInfo->level;
+                updateCBTracking(pCB);
+            }
+        }
     }
     return result;
 }
@@ -4387,8 +4438,6 @@
         return (PFN_vkVoidFunction) vkDestroyDescriptorSetLayout;
     if (!strcmp(funcName, "vkDestroyDescriptorPool"))
         return (PFN_vkVoidFunction) vkDestroyDescriptorPool;
-    if (!strcmp(funcName, "vkFreeCommandBuffers"))
-        return (PFN_vkVoidFunction) vkFreeCommandBuffers;
     if (!strcmp(funcName, "vkDestroyFramebuffer"))
         return (PFN_vkVoidFunction) vkDestroyFramebuffer;
     if (!strcmp(funcName, "vkDestroyRenderPass"))
@@ -4427,8 +4476,14 @@
         return (PFN_vkVoidFunction) vkFreeDescriptorSets;
     if (!strcmp(funcName, "vkUpdateDescriptorSets"))
         return (PFN_vkVoidFunction) vkUpdateDescriptorSets;
+    if (!strcmp(funcName, "vkCreateCommandPool"))
+        return (PFN_vkVoidFunction) vkCreateCommandPool;
+    if (!strcmp(funcName, "vkDestroyCommandPool"))
+        return (PFN_vkVoidFunction) vkDestroyCommandPool;
     if (!strcmp(funcName, "vkAllocateCommandBuffers"))
         return (PFN_vkVoidFunction) vkAllocateCommandBuffers;
+    if (!strcmp(funcName, "vkFreeCommandBuffers"))
+        return (PFN_vkVoidFunction) vkFreeCommandBuffers;
     if (!strcmp(funcName, "vkBeginCommandBuffer"))
         return (PFN_vkVoidFunction) vkBeginCommandBuffer;
     if (!strcmp(funcName, "vkEndCommandBuffer"))