layers: ObjTracker -- free each queue's memRefs

Cleanup and free memRef-related resources for each queue upon device
destruction.

TODO: Verify vk-layer-generation.py
TODO: APIDump layer needs some help
diff --git a/vk-layer-generate.py b/vk-layer-generate.py
index c924cfd..266319c 100755
--- a/vk-layer-generate.py
+++ b/vk-layer-generate.py
@@ -832,11 +832,162 @@
         header_txt.append('    struct _objNode *pNextObj;')
         header_txt.append('    struct _objNode *pNextGlobal;')
         header_txt.append('} objNode;')
-        header_txt.append('static objNode *pObjectHead[VK_NUM_OBJECT_TYPE] = {0};')
+        header_txt.append('')
+        header_txt.append('static objNode *pObjectHead[VkNumObjectType] = {0};')
         header_txt.append('static objNode *pGlobalHead = NULL;')
-        header_txt.append('static uint64_t numObjs[VK_NUM_OBJECT_TYPE] = {0};')
+        header_txt.append('static uint64_t numObjs[VkNumObjectType] = {0};')
         header_txt.append('static uint64_t numTotalObjs = 0;')
         header_txt.append('static uint32_t maxMemReferences = 0;')
+        header_txt.append('')
+        header_txt.append('// For each Queue\'s doubly linked-list of mem refs')
+        header_txt.append('typedef struct _OT_MEM_INFO {')
+        header_txt.append('    VkGpuMemory        mem;')
+        header_txt.append('    struct _OT_MEM_INFO *pNextMI;')
+        header_txt.append('    struct _OT_MEM_INFO *pPrevMI;')
+        header_txt.append('')
+        header_txt.append('} OT_MEM_INFO;')
+        header_txt.append('')
+        header_txt.append('// Track Queue information')
+        header_txt.append('typedef struct _OT_QUEUE_INFO {')
+        header_txt.append('    OT_MEM_INFO           *pMemRefList;')
+        header_txt.append('    struct _OT_QUEUE_INFO *pNextQI;')
+        header_txt.append('    VkQueue               queue;')
+        header_txt.append('    uint32_t               refCount;')
+        header_txt.append('} OT_QUEUE_INFO;')
+        header_txt.append('')
+        header_txt.append('// Global list of QueueInfo structures, one per queue')
+        header_txt.append('static OT_QUEUE_INFO *g_pQueueInfo;')
+        header_txt.append('')
+        header_txt.append('// Add new queue to head of global queue list')
+        header_txt.append('static void addQueueInfo(VkQueue queue)')
+        header_txt.append('{')
+        header_txt.append('    OT_QUEUE_INFO *pQueueInfo = malloc(sizeof(OT_QUEUE_INFO));')
+        header_txt.append('    memset(pQueueInfo, 0, sizeof(OT_QUEUE_INFO));')
+        header_txt.append('    pQueueInfo->queue = queue;')
+        header_txt.append('')
+        header_txt.append('    if (pQueueInfo != NULL) {')
+        header_txt.append('        pQueueInfo->pNextQI   = g_pQueueInfo;')
+        header_txt.append('        g_pQueueInfo          = pQueueInfo;')
+        header_txt.append('    }')
+        header_txt.append('    else {')
+        header_txt.append('        char str[1024];')
+        header_txt.append('        sprintf(str, "ERROR:  VK_ERROR_OUT_OF_MEMORY -- could not allocate memory for Queue Information");')
+        header_txt.append('        layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, queue, 0, OBJTRACK_INTERNAL_ERROR, "OBJTRACK", str);')
+        header_txt.append('    }')
+        header_txt.append('}')
+        header_txt.append('')
+        header_txt.append('// Returns pointer to this queue\'s mem ref data')
+        header_txt.append('static OT_QUEUE_INFO* getQueueInfo(VkQueue queue)')
+        header_txt.append('{')
+        header_txt.append('    OT_QUEUE_INFO *pQueueInfo = g_pQueueInfo;')
+        header_txt.append('    OT_QUEUE_INFO *pFound     = NULL;')
+        header_txt.append('    while (pQueueInfo != NULL) {')
+        header_txt.append('        if (pQueueInfo->queue != queue) {')
+        header_txt.append('            pQueueInfo = pQueueInfo->pNextQI;')
+        header_txt.append('        }')
+        header_txt.append('        else {')
+        header_txt.append('            pFound = pQueueInfo;')
+        header_txt.append('            break;')
+        header_txt.append('        }')
+        header_txt.append('    }')
+        header_txt.append('    return pFound;')
+        header_txt.append('}')
+        header_txt.append('')
+        header_txt.append('// Returns pointer to a specific memory reference in a queue\'s mem ref list')
+        header_txt.append('static OT_MEM_INFO* findMemRefInQueueList(VkQueue queue, VkGpuMemory mem)')
+        header_txt.append('{')
+        header_txt.append('    // Get pointer to queue\'s list')
+        header_txt.append('    OT_QUEUE_INFO *pQueueInfo = getQueueInfo(queue);')
+        header_txt.append('    OT_MEM_INFO   *pMemInfo   = pQueueInfo->pMemRefList;')
+        header_txt.append('    OT_MEM_INFO   *pFound     = NULL;')
+        header_txt.append('')
+        header_txt.append('    while (pMemInfo != NULL) {')
+        header_txt.append('        if (pMemInfo->mem != mem) {')
+        header_txt.append('            pMemInfo = pMemInfo->pNextMI;')
+        header_txt.append('        }')
+        header_txt.append('        else {')
+        header_txt.append('            pFound = pMemInfo;')
+        header_txt.append('            break;')
+        header_txt.append('        }')
+        header_txt.append('    }')
+        header_txt.append('    return pFound;')
+        header_txt.append('}')
+        header_txt.append('')
+        header_txt.append('// Add memory reference to queue\'s mem ref list')
+        header_txt.append('static void addMemRef(VkQueue queue, VkGpuMemory mem)')
+        header_txt.append('{')
+        header_txt.append('    // if ref not already in queue\'s list, add to front.')
+        header_txt.append('    OT_QUEUE_INFO *pQueueInfo = getQueueInfo(queue);')
+        header_txt.append('    OT_MEM_INFO   *pMemInfo   = findMemRefInQueueList(queue, mem);')
+        header_txt.append('    if (pMemInfo == NULL) {')
+        header_txt.append('        // Not in list, add to front')
+        header_txt.append('        pMemInfo = malloc(sizeof(OT_MEM_INFO));')
+        header_txt.append('        memset(pMemInfo, 0, sizeof(OT_MEM_INFO));')
+        header_txt.append('')
+        header_txt.append('        if (pMemInfo != NULL) {')
+        header_txt.append('            pMemInfo->mem                    = mem;')
+        header_txt.append('            pMemInfo->pNextMI                = pQueueInfo->pMemRefList;')
+        header_txt.append('            pMemInfo->pPrevMI                = NULL;')
+        header_txt.append('            if (pQueueInfo->pMemRefList != NULL) {')
+        header_txt.append('                pQueueInfo->pMemRefList->pPrevMI = pMemInfo;')
+        header_txt.append('            }')
+        header_txt.append('            pQueueInfo->pMemRefList          = pMemInfo;')
+        header_txt.append('            pQueueInfo->refCount++;')
+        header_txt.append('        }')
+        header_txt.append('        else {')
+        header_txt.append('            char str[1024];')
+        header_txt.append('            sprintf(str, "ERROR:  VK_ERROR_OUT_OF_MEMORY -- could not allocate memory for memory reference Information");')
+        header_txt.append('            layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, queue, 0, OBJTRACK_INTERNAL_ERROR, "OBJTRACK", str);')
+        header_txt.append('        }')
+        header_txt.append('    }')
+        header_txt.append('}')
+        header_txt.append('')
+        header_txt.append('static void deleteMemRef(VkQueue queue, VkGpuMemory mem)')
+        header_txt.append('{')
+        header_txt.append('    // Search queue\'s list for mem, remove from list')
+        header_txt.append('    OT_QUEUE_INFO *pQueueInfo = getQueueInfo(queue);')
+        header_txt.append('    OT_MEM_INFO   *pMemInfo   = findMemRefInQueueList(queue, mem);')
+        header_txt.append('')
+        header_txt.append('    if (pMemInfo != NULL) {')
+        header_txt.append('        // Remove pMemInfo from doubly-linked list')
+        header_txt.append('        if (pQueueInfo->pMemRefList == pMemInfo) {')
+        header_txt.append('            // update head of list, which is being removed')
+        header_txt.append('            pQueueInfo->pMemRefList = pMemInfo->pNextMI;')
+        header_txt.append('        }')
+        header_txt.append('        if (pMemInfo->pNextMI != NULL) {')
+        header_txt.append('            pMemInfo->pNextMI->pPrevMI = pMemInfo->pPrevMI;')
+        header_txt.append('        }')
+        header_txt.append('        if (pMemInfo->pPrevMI != NULL) {')
+        header_txt.append('            pMemInfo->pPrevMI->pNextMI = pMemInfo->pNextMI;')
+        header_txt.append('        }')
+        header_txt.append('        free(pMemInfo);')
+        header_txt.append('        pQueueInfo->refCount--;')
+        header_txt.append('    }')
+        header_txt.append('    else {')
+        header_txt.append('        char str[1024];')
+        header_txt.append('        sprintf(str, "vkQueueRemoveReference called to remove a memory reference %p from queue %p that was not added", mem, queue);')
+        header_txt.append('        layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, queue, 0, OBJTRACK_MISSING_OBJECT, "OBJTRACK", str);')
+        header_txt.append('    }')
+        header_txt.append('}')
+        header_txt.append('')
+        header_txt.append('// Destroy memRef lists and free all memory')
+        header_txt.append('static void destroyQueueMemRefLists()')
+        header_txt.append('{')
+        header_txt.append('    OT_QUEUE_INFO *pQueueInfo    = g_pQueueInfo;')
+        header_txt.append('    OT_QUEUE_INFO *pDelQueueInfo = NULL;')
+        header_txt.append('    while (pQueueInfo != NULL) {')
+        header_txt.append('        OT_MEM_INFO *pMemInfo = pQueueInfo->pMemRefList;')
+        header_txt.append('        while (pMemInfo != NULL) {')
+        header_txt.append('            OT_MEM_INFO *pDelMemInfo = pMemInfo;')
+        header_txt.append('            pMemInfo = pMemInfo->pNextMI;')
+        header_txt.append('            free(pDelMemInfo);')
+        header_txt.append('        }')
+        header_txt.append('        pDelQueueInfo = pQueueInfo;')
+        header_txt.append('        pQueueInfo    = pQueueInfo->pNextQI;')
+        header_txt.append('        free(pDelQueueInfo);')
+        header_txt.append('    }')
+        header_txt.append('}')
+        header_txt.append('')
         header_txt.append('// Debug function to print global list and each individual object list')
         header_txt.append('static void ll_print_lists()')
         header_txt.append('{')
@@ -846,7 +997,7 @@
         header_txt.append('        printf("   ObjNode (%p) w/ %s obj %p has pNextGlobal %p\\n", (void*)pTrav, string_VK_OBJECT_TYPE(pTrav->obj.objType), pTrav->obj.pObj, (void*)pTrav->pNextGlobal);')
         header_txt.append('        pTrav = pTrav->pNextGlobal;')
         header_txt.append('    }')
-        header_txt.append('    for (uint32_t i = 0; i < VK_NUM_OBJECT_TYPE; i++) {')
+        header_txt.append('    for (uint32_t i = 0; i < VkNumObjectType; i++) {')
         header_txt.append('        pTrav = pObjectHead[i];')
         header_txt.append('        if (pTrav) {')
         header_txt.append('            printf("=====%s OBJECT LIST (%lu objs):\\n", string_VK_OBJECT_TYPE(pTrav->obj.objType), numObjs[i]);')
@@ -889,7 +1040,7 @@
         header_txt.append('    char str[1024];')
         header_txt.append('    sprintf(str, "Attempting look-up on obj %p but it is NOT in the global list!", (void*)object);')
         header_txt.append('    layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, object, 0, OBJTRACK_MISSING_OBJECT, "OBJTRACK", str);')
-        header_txt.append('    return VK_OBJECT_TYPE_UNKNOWN;')
+        header_txt.append('    return VkObjectTypeUnknown;')
         header_txt.append('}')
         header_txt.append('#if 0')
         header_txt.append('static uint64_t ll_get_obj_uses(void* pObj, VK_OBJECT_TYPE objType) {')
@@ -995,8 +1146,8 @@
         header_txt.append('}')
         header_txt.append('')
         header_txt.append('// Track selected state for an object node')
-        header_txt.append('static void track_object_status(void* pObj, VK_STATE_BIND_POINT stateBindPoint) {')
-        header_txt.append('    objNode *pTrav = pObjectHead[VK_OBJECT_TYPE_CMD_BUFFER];')
+        header_txt.append('static void track_object_status(void* pObj, VkStateBindPoint stateBindPoint) {')
+        header_txt.append('    objNode *pTrav = pObjectHead[VkObjectTypeCmdBuffer];')
         header_txt.append('')
         header_txt.append('    while (pTrav) {')
         header_txt.append('        if (pTrav->obj.pObj == pObj) {')
@@ -1050,7 +1201,7 @@
         header_txt.append('        }')
         header_txt.append('        pTrav = pTrav->pNextObj;')
         header_txt.append('    }')
-        header_txt.append('    if (objType != VK_OBJECT_TYPE_PRESENTABLE_IMAGE_MEMORY) {')
+        header_txt.append('    if (objType != VkObjectTypePresentableImageMemory) {')
         header_txt.append('        // If we do not find it print an error')
         header_txt.append('        char str[1024];')
         header_txt.append('        sprintf(str, "Unable to obtain status for non-existent object %p of %s type", pObj, string_VK_OBJECT_TYPE(objType));')
@@ -1060,14 +1211,45 @@
         header_txt.append('}')
         header_txt.append('')
         header_txt.append('static void validate_draw_state_flags(void* pObj) {')
-        header_txt.append('    validate_status((void*)pObj, VK_OBJECT_TYPE_CMD_BUFFER, OBJSTATUS_VIEWPORT_BOUND,      OBJSTATUS_VIEWPORT_BOUND,      VK_DBG_MSG_ERROR,    OBJTRACK_VIEWPORT_NOT_BOUND,      "Viewport object not bound to this command buffer");')
-        header_txt.append('    validate_status((void*)pObj, VK_OBJECT_TYPE_CMD_BUFFER, OBJSTATUS_RASTER_BOUND,        OBJSTATUS_RASTER_BOUND,        VK_DBG_MSG_ERROR,    OBJTRACK_RASTER_NOT_BOUND,        "Raster object not bound to this command buffer");')
-        header_txt.append('    validate_status((void*)pObj, VK_OBJECT_TYPE_CMD_BUFFER, OBJSTATUS_COLOR_BLEND_BOUND,   OBJSTATUS_COLOR_BLEND_BOUND,   VK_DBG_MSG_UNKNOWN,  OBJTRACK_COLOR_BLEND_NOT_BOUND,   "Color-blend object not bound to this command buffer");')
-        header_txt.append('    validate_status((void*)pObj, VK_OBJECT_TYPE_CMD_BUFFER, OBJSTATUS_DEPTH_STENCIL_BOUND, OBJSTATUS_DEPTH_STENCIL_BOUND, VK_DBG_MSG_UNKNOWN,  OBJTRACK_DEPTH_STENCIL_NOT_BOUND, "Depth-stencil object not bound to this command buffer");')
+        header_txt.append('    validate_status((void*)pObj, VkObjectTypeCmdBuffer, OBJSTATUS_VIEWPORT_BOUND,      OBJSTATUS_VIEWPORT_BOUND,      VK_DBG_MSG_ERROR,    OBJTRACK_VIEWPORT_NOT_BOUND,      "Viewport object not bound to this command buffer");')
+        header_txt.append('    validate_status((void*)pObj, VkObjectTypeCmdBuffer, OBJSTATUS_RASTER_BOUND,        OBJSTATUS_RASTER_BOUND,        VK_DBG_MSG_ERROR,    OBJTRACK_RASTER_NOT_BOUND,        "Raster object not bound to this command buffer");')
+        header_txt.append('    validate_status((void*)pObj, VkObjectTypeCmdBuffer, OBJSTATUS_COLOR_BLEND_BOUND,   OBJSTATUS_COLOR_BLEND_BOUND,   VK_DBG_MSG_UNKNOWN,  OBJTRACK_COLOR_BLEND_NOT_BOUND,   "Color-blend object not bound to this command buffer");')
+        header_txt.append('    validate_status((void*)pObj, VkObjectTypeCmdBuffer, OBJSTATUS_DEPTH_STENCIL_BOUND, OBJSTATUS_DEPTH_STENCIL_BOUND, VK_DBG_MSG_UNKNOWN,  OBJTRACK_DEPTH_STENCIL_NOT_BOUND, "Depth-stencil object not bound to this command buffer");')
+        header_txt.append('}')
+        header_txt.append('')
+        header_txt.append('static void validate_memory_mapping_status(VkQueue queue)')
+        header_txt.append('{')
+        header_txt.append('    OT_QUEUE_INFO *pQueueInfo = getQueueInfo(queue);')
+        header_txt.append('    OT_MEM_INFO   *pMemInfo   = pQueueInfo->pMemRefList;')
+        header_txt.append('')
+        header_txt.append('    while (pMemInfo != NULL) {')
+        header_txt.append('        // If mem reference is in a presentable image memory list, skip the check of the GPU_MEMORY list')
+        header_txt.append('        if (!validate_status((void *)pMemInfo->mem, VkObjectTypePresentableImageMemory, OBJSTATUS_NONE,')
+        header_txt.append('                 OBJSTATUS_NONE, VK_DBG_MSG_UNKNOWN, OBJTRACK_NONE, NULL) == VK_TRUE) {')
+        header_txt.append('            validate_status((void *)pMemInfo->mem, VkObjectTypeGpuMemory, OBJSTATUS_GPU_MEM_MAPPED, OBJSTATUS_NONE,')
+        header_txt.append('                VK_DBG_MSG_ERROR, OBJTRACK_GPU_MEM_MAPPED, "A Mapped Memory Object was referenced in a command buffer");')
+        header_txt.append('        }')
+        header_txt.append('        pMemInfo = pMemInfo->pNextMI;')
+        header_txt.append('    }')
+        header_txt.append('}')
+        header_txt.append('')
+        header_txt.append('static void validate_mem_ref_count(VkQueue queue) {')
+        header_txt.append('    if (maxMemReferences == 0) {')
+        header_txt.append('        char str[1024];')
+        header_txt.append('        sprintf(str, "vkQueueSubmit called before calling vkGetGpuInfo");')
+        header_txt.append('        layerCbMsg(VK_DBG_MSG_WARNING, VK_VALIDATION_LEVEL_0, NULL, 0, OBJTRACK_GETGPUINFO_NOT_CALLED, "OBJTRACK", str);')
+        header_txt.append('    } else {')
+        header_txt.append('        OT_QUEUE_INFO *pQueueInfo = getQueueInfo(queue);')
+        header_txt.append('        if (pQueueInfo->refCount > maxMemReferences) {')
+        header_txt.append('            char str[1024];')
+        header_txt.append('            sprintf(str, "vkQueueSubmit Memory reference count (%d) exceeds allowable GPU limit (%d)", pQueueInfo->refCount, maxMemReferences);')
+        header_txt.append('            layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, NULL, 0, OBJTRACK_MEMREFCOUNT_MAX_EXCEEDED, "OBJTRACK", str);')
+        header_txt.append('        }')
+        header_txt.append('    }')
         header_txt.append('}')
         header_txt.append('')
         header_txt.append('static void setGpuQueueInfoState(void *pData) {')
-        header_txt.append('    maxMemReferences = ((VkPhysicalGpu_QUEUE_PROPERTIES *)pData)->maxMemReferences;')
+        header_txt.append('    maxMemReferences = ((VkPhysicalGpuQueueProperties *)pData)->maxMemReferences;')
         header_txt.append('}')
         return "\n".join(header_txt)
 
@@ -1154,6 +1336,10 @@
                 destroy_line += '            pTrav = pTrav->pNextGlobal;\n'
                 destroy_line += '        }\n'
                 destroy_line += '    }\n'
+                destroy_line += '    // Clean up Queue\'s MemRef Linked Lists\n'
+                destroy_line += '    destroyQueueMemRefLists();\n'
+            if 'GetDeviceQueue' in proto.name:
+                destroy_line = '    addQueueInfo(*pQueue);\n'
         ret_val = ''
         stmt = ''
         if proto.ret != "void":