layers: Tuning MemTracker
authorMike Stroyan <mike@LunarG.com>
Tue, 19 May 2015 21:16:08 +0000 (15:16 -0600)
committerMark Lobodzinski <mark@lunarg.com>
Tue, 2 Jun 2015 14:43:27 +0000 (09:43 -0500)
Reverse sense of fenceMap using VkFence instead of fenceID as key.
 This eliminates iterating over all of fenceMap.
Stop creating internal fences and let vkQueueSubmit pass NULL fence.
Track lastSubmittedFence and lastSubmittedQueue in command buffer info.
Use unordered_map instead of map for better performance.
Reuse iterator returned by map find whenever available.
 It is faster than repeating a find operation with "[]" notation.
Remove map entries at time of VkDestroy instead of other calls such as Wait.

layers/mem_tracker.cpp
layers/mem_tracker.h

index bce0cb8..62b00fb 100644 (file)
@@ -28,7 +28,7 @@
 #include <string.h>
 #include <assert.h>
 #include <list>
-#include <map>
+#include <unordered_map>
 #include <vector>
 using namespace std;
 
@@ -51,12 +51,12 @@ static loader_platform_thread_mutex globalLock;
 
 #define MAX_BINDING 0xFFFFFFFF
 
-map<VkCmdBuffer,    MT_CB_INFO*>          cbMap;
-map<VkDeviceMemory, MT_MEM_OBJ_INFO*>     memObjMap;
-map<VkObject,       MT_OBJ_INFO*>         objectMap;
-map<uint64_t,       MT_FENCE_INFO*>       fenceMap;    // Map fenceId to fence info
-map<VkQueue,        MT_QUEUE_INFO*>       queueMap;
-map<VkSwapChainWSI, MT_SWAP_CHAIN_INFO*>  swapChainMap;
+unordered_map<VkCmdBuffer,    MT_CB_INFO*>          cbMap;
+unordered_map<VkDeviceMemory, MT_MEM_OBJ_INFO*>     memObjMap;
+unordered_map<VkObject,       MT_OBJ_INFO*>         objectMap;
+unordered_map<VkFence,        MT_FENCE_INFO*>       fenceMap;    // Map fence to fence info
+unordered_map<VkQueue,        MT_QUEUE_INFO*>       queueMap;
+unordered_map<VkSwapChainWSI, MT_SWAP_CHAIN_INFO*>  swapChainMap;
 
 // TODO : Add per-device fence completion
 static uint64_t   g_currentFenceId  = 1;
@@ -77,7 +77,7 @@ static void deleteQueueInfoList(
     // Process queue list, cleaning up each entry before deleting
     if (queueMap.size() <= 0)
         return;
-    for (map<VkQueue, MT_QUEUE_INFO*>::iterator ii=queueMap.begin(); ii!=queueMap.end(); ++ii) {
+    for (unordered_map<VkQueue, MT_QUEUE_INFO*>::iterator ii=queueMap.begin(); ii!=queueMap.end(); ++ii) {
         (*ii).second->pQueueCmdBuffers.clear();
     }
     queueMap.clear();
@@ -104,23 +104,24 @@ static void addCBInfo(
 static MT_CB_INFO* getCBInfo(
     const VkCmdBuffer cb)
 {
-    MT_CB_INFO* pCBInfo = NULL;
-    if (cbMap.find(cb) != cbMap.end()) {
-        pCBInfo = cbMap[cb];
+    unordered_map<VkCmdBuffer, MT_CB_INFO*>::iterator item = cbMap.find(cb);
+    if (item != cbMap.end()) {
+        return (*item).second;
+    } else {
+        return NULL;
     }
-    return pCBInfo;
 }
 
 // Return object info for 'object' or return NULL if no info exists
 static MT_OBJ_INFO* getObjectInfo(
     const VkObject object)
 {
-    MT_OBJ_INFO* pObjInfo = NULL;
-
-    if (objectMap.find(object) != objectMap.end()) {
-        pObjInfo = objectMap[object];
+    unordered_map<VkObject, MT_OBJ_INFO*>::iterator item = objectMap.find(object);
+    if (item != objectMap.end()) {
+        return (*item).second;
+    } else {
+        return NULL;
     }
-    return pObjInfo;
 }
 
 static MT_OBJ_INFO* addObjectInfo(
@@ -149,20 +150,13 @@ static uint64_t addFenceInfo(
     VkQueue queue)
 {
     // Create fence object
-    MT_FENCE_INFO* pFenceInfo = new MT_FENCE_INFO;
     MT_QUEUE_INFO* pQueueInfo = queueMap[queue];
     uint64_t       fenceId    = g_currentFenceId++;
-    memset(pFenceInfo, 0, sizeof(MT_FENCE_INFO));
-    // If no fence, create an internal fence to track the submissions
-    if (fence == NULL) {
-        VkFenceCreateInfo fci;
-        fci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
-        fci.pNext = NULL;
-        fci.flags = static_cast<VkFenceCreateFlags>(0);
-        nextTable.CreateFence(globalDevice, &fci, &pFenceInfo->fence);
-        addObjectInfo(pFenceInfo->fence, fci.sType, &fci, sizeof(VkFenceCreateInfo), "internalFence");
-        pFenceInfo->localFence = VK_TRUE;
-    } else {
+    if (fence != NULL) {
+        MT_FENCE_INFO* pFenceInfo = new MT_FENCE_INFO;
+        pFenceInfo->fenceId = fenceId;
+        pFenceInfo->queue = queue;
+        fenceMap[fence] = pFenceInfo;
         // Validate that fence is in UNSIGNALED state
         MT_OBJ_INFO* pObjectInfo = getObjectInfo(fence);
         if (pObjectInfo != NULL) {
@@ -172,107 +166,51 @@ static uint64_t addFenceInfo(
                 layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, fence, 0, MEMTRACK_INVALID_FENCE_STATE, "MEM", str);
             }
         }
-        pFenceInfo->localFence = VK_FALSE;
-        pFenceInfo->fence      = fence;
     }
-    pFenceInfo->queue = queue;
-    fenceMap[fenceId] = pFenceInfo;
-    // Update most recently submitted fenceId for Queue
+    // Update most recently submitted fence and fenceId for Queue
     pQueueInfo->lastSubmittedId = fenceId;
     return fenceId;
 }
 
 // Remove a fenceInfo from our list of fences/fenceIds
 static void deleteFenceInfo(
-    uint64_t fenceId)
-{
-    if (fenceId != 0) {
-        if (fenceMap.find(fenceId) != fenceMap.end()) {
-            map<uint64_t, MT_FENCE_INFO*>::iterator item;
-            MT_FENCE_INFO* pDelInfo = fenceMap[fenceId];
-            if (pDelInfo != NULL) {
-                if (pDelInfo->localFence == VK_TRUE) {
-                    nextTable.DestroyObject(globalDevice, VK_OBJECT_TYPE_FENCE, pDelInfo->fence);
-                }
-                delete pDelInfo;
-            }
-            item = fenceMap.find(fenceId);
-            fenceMap.erase(item);
+    VkFence fence)
+{
+    unordered_map<VkFence, MT_FENCE_INFO*>::iterator item;
+    item = fenceMap.find(fence);
+    if (item != fenceMap.end()) {
+        MT_FENCE_INFO* pDelInfo = (*item).second;
+        if (pDelInfo != NULL) {
+            delete pDelInfo;
         }
+        fenceMap.erase(item);
     }
 }
 
-// Search through list for this fence, deleting all items before it (with lower IDs) and updating lastRetiredId
+// Record information when a fence is known to be signalled
 static void updateFenceTracking(
     VkFence fence)
 {
-    MT_FENCE_INFO *pCurFenceInfo = NULL;
-    uint64_t       fenceId       = 0;
-    VkQueue        queue         = NULL;
-    bool           found         = false;
-
-    if (fenceMap.size() <= 0)
-        return;
-    for (map<uint64_t, MT_FENCE_INFO*>::iterator ii=fenceMap.begin(); !found && ii!=fenceMap.end();) {
-        if ((*ii).second != NULL) {
-            if (fence == ((*ii).second)->fence) {
-                queue = ((*ii).second)->queue;
-                MT_QUEUE_INFO *pQueueInfo = queueMap[queue];
-                pQueueInfo->lastRetiredId = (*ii).first;
-                found = true;
-            } else {
-               // Update iterator before deleting item it referred to
-               uint64_t fenceId = (*ii).first;
-               ++ii;
-                deleteFenceInfo(fenceId);
-            }
-            // Update fence state in fenceCreateInfo structure
-            MT_OBJ_INFO* pObjectInfo = getObjectInfo(fence);
-            if (pObjectInfo != NULL) {
-                pObjectInfo->create_info.fence_create_info.flags =
-                    static_cast<VkFenceCreateFlags>(
-                        pObjectInfo->create_info.fence_create_info.flags | VK_FENCE_CREATE_SIGNALED_BIT);
+    unordered_map<VkFence, MT_FENCE_INFO*>::iterator fence_item = fenceMap.find(fence);
+    if (fence_item != fenceMap.end()) {
+        MT_FENCE_INFO *pCurFenceInfo = (*fence_item).second;
+        VkQueue queue = pCurFenceInfo->queue;
+        unordered_map<VkQueue, MT_QUEUE_INFO*>::iterator queue_item = queueMap.find(queue);
+        if (queue_item != queueMap.end()) {
+            MT_QUEUE_INFO *pQueueInfo = (*queue_item).second;
+            if (pQueueInfo->lastRetiredId < pCurFenceInfo->fenceId) {
+                pQueueInfo->lastRetiredId = pCurFenceInfo->fenceId;
             }
         }
     }
-}
-
-// Utility function that determines if a fenceId has been retired yet
-static bool32_t fenceRetired(
-    uint64_t fenceId)
-{
-    bool32_t result = VK_FALSE;
-    if (fenceMap.find(fenceId) != fenceMap.end()) {
-        MT_FENCE_INFO* pFenceInfo = fenceMap[fenceId];
-        MT_QUEUE_INFO* pQueueInfo = queueMap[pFenceInfo->queue];
-        if (fenceId <= pQueueInfo->lastRetiredId)
-        {
-             result = VK_TRUE;
-        }
-    } else {                 // If not in list, fence has been retired and deleted
-       result = VK_TRUE;
-    }
-    return result;
-}
 
-// Return the fence associated with a fenceId
-static VkFence getFenceFromId(
-    uint64_t fenceId)
-{
-    VkFence fence = NULL;
-    if (fenceId != 0) {
-        // Search for an item with this fenceId
-        if (fenceMap.find(fenceId) != fenceMap.end()) {
-            MT_FENCE_INFO* pFenceInfo = fenceMap[fenceId];
-            if (pFenceInfo != NULL) {
-                MT_QUEUE_INFO* pQueueInfo = queueMap[pFenceInfo->queue];
-                if (fenceId > pQueueInfo->lastRetiredId) {
-                    fence = pFenceInfo->fence;
-                }
-            }
-        }
+    // Update fence state in fenceCreateInfo structure
+    MT_OBJ_INFO* pObjectInfo = getObjectInfo(fence);
+    if (pObjectInfo != NULL) {
+        pObjectInfo->create_info.fence_create_info.flags =
+            static_cast<VkFenceCreateFlags>(
+                pObjectInfo->create_info.fence_create_info.flags | VK_FENCE_CREATE_SIGNALED_BIT);
     }
-    return fence;
 }
 
 // Helper routine that updates the fence list for a specific queue to all-retired
@@ -280,20 +218,8 @@ static void retireQueueFences(
     VkQueue queue)
 {
     MT_QUEUE_INFO *pQueueInfo = queueMap[queue];
+    // Set Queue's lastRetired to lastSubmitted
     pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId;
-    // Set Queue's lastRetired to lastSubmitted, free items in queue's fence list
-    map<uint64_t, MT_FENCE_INFO*>::iterator it = fenceMap.begin();
-    map<uint64_t, MT_FENCE_INFO*>::iterator temp;
-    while (fenceMap.size() > 0 && it != fenceMap.end()) {
-        if ((((*it).second) != NULL) && ((*it).second)->queue == queue) {
-            temp = it;
-            ++temp;
-            deleteFenceInfo((*it).first);
-            it = temp;
-        } else {
-            ++it;
-        }
-    }
 }
 
 // Helper routine that updates fence list for all queues to all-retired
@@ -304,7 +230,7 @@ static void retireDeviceFences(
     // TODO: Add multiple device support
     if (queueMap.size() <= 0)
         return;
-    for (map<VkQueue, MT_QUEUE_INFO*>::iterator ii=queueMap.begin(); ii!=queueMap.end(); ++ii) {
+    for (unordered_map<VkQueue, MT_QUEUE_INFO*>::iterator ii=queueMap.begin(); ii!=queueMap.end(); ++ii) {
         retireQueueFences((*ii).first);
     }
 }
@@ -314,12 +240,12 @@ static void retireDeviceFences(
 static MT_MEM_OBJ_INFO* getMemObjInfo(
     const VkDeviceMemory mem)
 {
-    MT_MEM_OBJ_INFO* pMemObjInfo = NULL;
-
-    if (memObjMap.find(mem) != memObjMap.end()) {
-        pMemObjInfo = memObjMap[mem];
+    unordered_map<VkDeviceMemory, MT_MEM_OBJ_INFO*>::iterator item = memObjMap.find(mem);
+    if (item != memObjMap.end()) {
+        return (*item).second;
+    } else {
+        return NULL;
     }
-    return pMemObjInfo;
 }
 
 static void addMemObjInfo(
@@ -426,10 +352,6 @@ static bool32_t freeCBBindings(
         layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_INVALID_CB, "MEM", str);
         result = VK_FALSE;
     } else {
-        if (!fenceRetired(pCBInfo->fenceId)) {
-            deleteFenceInfo(pCBInfo->fenceId);
-        }
-
         if (pCBInfo->pMemObjList.size() > 0) {
             list<VkDeviceMemory> mem_obj_list = pCBInfo->pMemObjList;
             for (list<VkDeviceMemory>::iterator it=mem_obj_list.begin(); it!=mem_obj_list.end(); ++it) {
@@ -443,7 +365,6 @@ static bool32_t freeCBBindings(
 
 // Delete CBInfo from list along with all of it's mini MemObjInfo
 //   and also clear mem references to CB
-// TODO : When should this be called?  There's no Destroy of CBs that I see
 static bool32_t deleteCBInfo(
     const VkCmdBuffer cb)
 {
@@ -467,7 +388,7 @@ static bool32_t deleteCBInfoList(
     bool32_t result = VK_TRUE;
     if (cbMap.size() <= 0)
         return result;
-    for (map<VkCmdBuffer, MT_CB_INFO*>::iterator ii=cbMap.begin(); ii!=cbMap.end(); ++ii) {
+    for (unordered_map<VkCmdBuffer, MT_CB_INFO*>::iterator ii=cbMap.begin(); ii!=cbMap.end(); ++ii) {
         freeCBBindings((*ii).first);
         delete (*ii).second;
     }
@@ -513,10 +434,11 @@ static void reportMemReferencesAndCleanUp(
 static void deleteMemObjInfo(
     VkDeviceMemory mem)
 {
-    if (memObjMap.find(mem) != memObjMap.end()) {
-        MT_MEM_OBJ_INFO* pDelInfo = memObjMap[mem];
+    unordered_map<VkDeviceMemory, MT_MEM_OBJ_INFO*>::iterator item = memObjMap.find(mem);
+    if (item != memObjMap.end()) {
+        MT_MEM_OBJ_INFO* pDelInfo = (*item).second;
         delete pDelInfo;
-        memObjMap.erase(mem);
+        memObjMap.erase(item);
     }
     else {
         char str[1024];
@@ -536,11 +458,13 @@ static bool32_t checkCBCompleted(
         sprintf(str, "Unable to find global CB info %p to check for completion", cb);
         layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_INVALID_CB, "MEM", str);
         result = VK_FALSE;
-    } else {
-        if (!fenceRetired(pCBInfo->fenceId)) {
+    } else if (pCBInfo->lastSubmittedQueue != NULL) {
+        VkQueue queue = pCBInfo->lastSubmittedQueue;
+        MT_QUEUE_INFO *pQueueInfo = queueMap[queue];
+        if (pCBInfo->fenceId > pQueueInfo->lastRetiredId) {
             char str[1024];
-            sprintf(str, "FenceId %" PRIx64", fence %p for CB %p has not been checked for completion",
-                pCBInfo->fenceId, getFenceFromId(pCBInfo->fenceId), cb);
+            sprintf(str, "fence %p for CB %p has not been checked for completion",
+                (void*)pCBInfo->lastSubmittedFence, cb);
             layerCbMsg(VK_DBG_MSG_UNKNOWN, VK_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_NONE, "MEM", str);
             result = VK_FALSE;
         }
@@ -718,7 +642,7 @@ static void printObjList(
     layerCbMsg(VK_DBG_MSG_UNKNOWN, VK_VALIDATION_LEVEL_0, NULL, 0, MEMTRACK_NONE, "MEM", str);
     if (objectMap.size() <= 0)
         return;
-    for (map<VkObject, MT_OBJ_INFO*>::iterator ii=objectMap.begin(); ii!=objectMap.end(); ++ii) {
+    for (unordered_map<VkObject, MT_OBJ_INFO*>::iterator ii=objectMap.begin(); ii!=objectMap.end(); ++ii) {
         pInfo = (*ii).second;
         sprintf(str, "    ObjInfo %p has object %p, pMemObjInfo %p", pInfo, pInfo->object, pInfo->pMemObjInfo);
         layerCbMsg(VK_DBG_MSG_UNKNOWN, VK_VALIDATION_LEVEL_0, pInfo->object, 0, MEMTRACK_NONE, "MEM", str);
@@ -765,7 +689,7 @@ static void printMemList(
     if (memObjMap.size() <= 0)
         return;
 
-    for (map<VkDeviceMemory, MT_MEM_OBJ_INFO*>::iterator ii=memObjMap.begin(); ii!=memObjMap.end(); ++ii) {
+    for (unordered_map<VkDeviceMemory, MT_MEM_OBJ_INFO*>::iterator ii=memObjMap.begin(); ii!=memObjMap.end(); ++ii) {
         pInfo = (*ii).second;
 
         sprintf(str, "    ===MemObjInfo at %p===", (void*)pInfo);
@@ -807,7 +731,7 @@ static void printMemList(
 static void printCBList(
     void)
 {
-    char str[1024] = {0};
+    char str[1024];
     MT_CB_INFO* pCBInfo = NULL;
     if (g_reportingLevel > VK_DBG_LAYER_LEVEL_INFO) {
         return;
@@ -818,12 +742,12 @@ static void printCBList(
     if (cbMap.size() <= 0)
         return;
 
-    for (map<VkCmdBuffer, MT_CB_INFO*>::iterator ii=cbMap.begin(); ii!=cbMap.end(); ++ii) {
+    for (unordered_map<VkCmdBuffer, MT_CB_INFO*>::iterator ii=cbMap.begin(); ii!=cbMap.end(); ++ii) {
         pCBInfo = (*ii).second;
 
         sprintf(str, "    CB Info (%p) has CB %p, fenceId %" PRIx64", and fence %p",
             (void*)pCBInfo, (void*)pCBInfo->cmdBuffer, pCBInfo->fenceId,
-            (void*)getFenceFromId(pCBInfo->fenceId));
+            (void*)pCBInfo->lastSubmittedFence);
         layerCbMsg(VK_DBG_MSG_UNKNOWN, VK_VALIDATION_LEVEL_0, NULL, 0, MEMTRACK_NONE, "MEM", str);
 
         if (pCBInfo->pMemObjList.size() <= 0)
@@ -904,7 +828,7 @@ VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(
     // Report any memory leaks
     MT_MEM_OBJ_INFO* pInfo = NULL;
     if (memObjMap.size() > 0) {
-        for (map<VkDeviceMemory, MT_MEM_OBJ_INFO*>::iterator ii=memObjMap.begin(); ii!=memObjMap.end(); ++ii) {
+        for (unordered_map<VkDeviceMemory, MT_MEM_OBJ_INFO*>::iterator ii=memObjMap.begin(); ii!=memObjMap.end(); ++ii) {
             pInfo = (*ii).second;
 
             if (pInfo->allocInfo.allocationSize != 0) {
@@ -1035,6 +959,8 @@ VK_LAYER_EXPORT VkResult VKAPI vkQueueSubmit(
     for (uint32_t i = 0; i < cmdBufferCount; i++) {
         pCBInfo = getCBInfo(pCmdBuffers[i]);
         pCBInfo->fenceId = fenceId;
+        pCBInfo->lastSubmittedFence = fence;
+        pCBInfo->lastSubmittedQueue = queue;
     }
 
     loader_platform_thread_unlock_mutex(&globalLock);
@@ -1170,15 +1096,23 @@ VK_LAYER_EXPORT VkResult VKAPI vkDestroyObject(
     VkObjectType objType,
     VkObject     object)
 {
+    unordered_map<VkObject, MT_OBJ_INFO*>::iterator item;
     loader_platform_thread_lock_mutex(&globalLock);
 
-    // First check if this is a CmdBuffer
-    if (NULL != getCBInfo((VkCmdBuffer)object)) {
+    // First check if this is a CmdBuffer or fence
+    switch (objType) {
+    case VK_OBJECT_TYPE_COMMAND_BUFFER:
         deleteCBInfo((VkCmdBuffer)object);
+        break;
+    case VK_OBJECT_TYPE_FENCE:
+        deleteFenceInfo((VkFence)object);
+        break;
+    default:
+        break;
     }
 
-    if (objectMap.find(object) != objectMap.end()) {
-        MT_OBJ_INFO* pDelInfo = objectMap[object];
+    if ((item = objectMap.find(object)) != objectMap.end()) {
+        MT_OBJ_INFO* pDelInfo = (*item).second;
         if (pDelInfo->pMemObjInfo) {
             // Wsi allocated Memory is tied to image object so clear the binding and free that memory automatically
             if (0 == pDelInfo->pMemObjInfo->allocInfo.allocationSize) { // Wsi allocated memory has NULL allocInfo w/ 0 size
@@ -1187,18 +1121,20 @@ VK_LAYER_EXPORT VkResult VKAPI vkDestroyObject(
                 freeMemObjInfo(memToFree, true);
             }
             else {
+                #if 0
                 char str[1024];
                 sprintf(str, "Destroying obj %p that is still bound to memory object %p\nYou should first clear binding "
                              "by calling vkBindObjectMemory(queue, %p, 0, VK_NULL_HANDLE, 0)",
                              object, (void*)pDelInfo->pMemObjInfo->mem, object);
                 layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, object, 0, MEMTRACK_DESTROY_OBJECT_ERROR, "MEM", str);
+                #endif
                 // From the spec : If an object has previous memory binding, it is required to unbind memory
                 // from an API object before it is destroyed.
                 clearObjectBinding(object);
             }
         }
         delete pDelInfo;
-        objectMap.erase(object);
+        objectMap.erase(item);
     }
 
     loader_platform_thread_unlock_mutex(&globalLock);
@@ -1632,17 +1568,15 @@ VK_LAYER_EXPORT VkResult VKAPI vkBeginCommandBuffer(
     VkCmdBuffer                 cmdBuffer,
     const VkCmdBufferBeginInfo *pBeginInfo)
 {
+    loader_platform_thread_lock_mutex(&globalLock);
     // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
-    MT_CB_INFO* pCBInfo = getCBInfo(cmdBuffer);
-    if (pCBInfo && (!fenceRetired(pCBInfo->fenceId))) {
-        bool32_t cbDone = checkCBCompleted(cmdBuffer);
-        if (VK_FALSE == cbDone) {
-            char str[1024];
-            sprintf(str, "Calling vkBeginCommandBuffer() on active CB %p before it has completed. "
-                         "You must check CB flag before this call.", cmdBuffer);
-            layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, cmdBuffer, 0, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", str);
-        }
+    if (!checkCBCompleted(cmdBuffer)) {
+        char str[1024];
+        sprintf(str, "Calling vkBeginCommandBuffer() on active CB %p before it has completed. "
+                     "You must check CB flag before this call.", cmdBuffer);
+        layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, cmdBuffer, 0, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", str);
     }
+    loader_platform_thread_unlock_mutex(&globalLock);
     VkResult result = nextTable.BeginCommandBuffer(cmdBuffer, pBeginInfo);
     loader_platform_thread_lock_mutex(&globalLock);
     freeCBBindings(cmdBuffer);
@@ -1661,19 +1595,15 @@ VK_LAYER_EXPORT VkResult VKAPI vkEndCommandBuffer(
 VK_LAYER_EXPORT VkResult VKAPI vkResetCommandBuffer(
     VkCmdBuffer cmdBuffer)
 {
+    loader_platform_thread_lock_mutex(&globalLock);
     // Verify that CB is complete (not in-flight)
-    MT_CB_INFO* pCBInfo = getCBInfo(cmdBuffer);
-    if (pCBInfo && (!fenceRetired(pCBInfo->fenceId))) {
-        bool32_t cbDone = checkCBCompleted(cmdBuffer);
-        if (VK_FALSE == cbDone) {
-            char str[1024];
-            sprintf(str, "Resetting CB %p before it has completed. You must check CB flag before "
-                         "calling vkResetCommandBuffer().", cmdBuffer);
-            layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, cmdBuffer, 0, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", str);
-        }
+    if (!checkCBCompleted(cmdBuffer)) {
+        char str[1024];
+        sprintf(str, "Resetting CB %p before it has completed. You must check CB flag before "
+                     "calling vkResetCommandBuffer().", cmdBuffer);
+        layerCbMsg(VK_DBG_MSG_ERROR, VK_VALIDATION_LEVEL_0, cmdBuffer, 0, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", str);
     }
     // Clear memory references as this point.
-    loader_platform_thread_lock_mutex(&globalLock);
     freeCBBindings(cmdBuffer);
     loader_platform_thread_unlock_mutex(&globalLock);
     VkResult result = nextTable.ResetCommandBuffer(cmdBuffer);
index 84df08e..2972d44 100644 (file)
@@ -123,15 +123,16 @@ struct MT_CB_INFO {
     VkDepthStencilBindInfo      dsBindInfo;
     VkCmdBuffer                 cmdBuffer;
     uint64_t                    fenceId;
+    VkFence                     lastSubmittedFence;
+    VkQueue                     lastSubmittedQueue;
     // Order dependent, stl containers must be at end of struct
     list<VkDeviceMemory>        pMemObjList; // List container of Mem objs referenced by this CB
 };
 
 // Associate fenceId with a fence object
 struct MT_FENCE_INFO {
-    VkFence   fence;            // Handle to fence object
-    VkQueue   queue;            // Queue that this fence is submitted against
-    bool32_t    localFence;     // Is fence created by layer?
+    uint64_t  fenceId;          // Sequence number for fence at last submit
+    VkQueue   queue;            // Queue that this fence is submitted against or NULL
 };
 
 // Track Queue information