layers: Incorporated memory reference handling into MemTracker
authorMark Lobodzinski <mark@lunarg.com>
Tue, 7 Apr 2015 18:38:21 +0000 (13:38 -0500)
committerChia-I Wu <olv@lunarg.com>
Thu, 16 Apr 2015 09:33:29 +0000 (17:33 +0800)
API was changed for handling memory references, updated memtracker
layer to correctly track and validate memory references.

layers/mem_tracker.cpp
layers/mem_tracker.h

index ec84013..83cff67 100644 (file)
@@ -230,55 +230,76 @@ static void retireDeviceFences(XGL_DEVICE device)
     }
 }
 
-//static bool32_t validateCBMemRef(const XGL_CMD_BUFFER cb, uint32_t memRefCount, const XGL_MEMORY_REF* pMemRefs)
-//{
-//    bool32_t result = XGL_TRUE;
-//    MT_CB_INFO* pInfo = getCBInfo(cb);
-//    if (!pInfo) {
-//        char str[1024];
-//        sprintf(str, "Unable to find info for CB %p in order to check memory references", (void*)cb);
-//        layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_INVALID_CB, "MEM", str);
-//        result = XGL_FALSE;
-//    } else {
-//        // Validate that all actual references are accounted for in pMemRefs
-//        uint32_t i;
-//        uint8_t  found = 0;
-//        uint64_t foundCount = 0;
-
-//        for (list<XGL_GPU_MEMORY>::iterator it = pInfo->pMemObjList.begin(); it != pInfo->pMemObjList.end(); ++it) {
-//            for (i = 0; i < memRefCount; i++) {
-//                if ((*it) == pMemRefs[i].mem) {
-//                    char str[1024];
-//                    sprintf(str, "Found Mem Obj %p binding to CB %p", (*it), cb);
-//                    layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_NONE, "MEM", str);
-//                    found = 1;
-//                    foundCount++;
-//                    break;
-//                }
-//            }
-//            if (!found) {
-//                char str[1024];
-//                sprintf(str, "Memory reference list for Command Buffer %p is missing ref to mem obj %p", cb, (*it));
-//                layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_CB_MISSING_MEM_REF, "MEM", str);
-//                result = XGL_FALSE;
-//            }
-//            found = 0;
-//        }
-
-//        if (result == XGL_TRUE) {
-//            char str[1024];
-//            sprintf(str, "Verified all %lu memory dependencies for CB %p are included in pMemRefs list", foundCount, cb);
-//            layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_NONE, "MEM", str);
-//            // TODO : Could report mem refs in pMemRefs that AREN'T in mem list, that would be primarily informational
-//            //   Currently just noting that there is a difference
-//            if (foundCount != memRefCount) {
-//                sprintf(str, "There are %u mem refs included in pMemRefs list, but only %lu are required", memRefCount, foundCount);
-//                layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_NONE, "MEM", str);
-//            }
-//        }
-//    }
-//    return result;
-//}
+// Returns True if a memory reference is present in a Queue's memory reference list
+// Queue is validated by caller
+static bool32_t checkMemRef(
+    XGL_QUEUE      queue,
+    XGL_GPU_MEMORY mem)
+{
+    bool32_t result = XGL_FALSE;
+    list<XGL_GPU_MEMORY>::iterator it;
+    MT_QUEUE_INFO *pQueueInfo = queueMap[queue];
+    for (it = pQueueInfo->pMemRefList.begin(); it != pQueueInfo->pMemRefList.end(); ++it) {
+        if ((*it) == mem) {
+            result = XGL_TRUE; 
+            break; 
+        }
+    }
+    return result;
+}
+
+static bool32_t validateQueueMemRefs(
+    XGL_QUEUE             queue,
+    uint32_t              cmdBufferCount,
+    const XGL_CMD_BUFFER *pCmdBuffers)
+{
+    bool32_t result = XGL_TRUE;
+
+    //  Verify Queue
+    MT_QUEUE_INFO *pQueueInfo = queueMap[queue];
+    if (pQueueInfo == NULL) {
+        char str[1024];
+        sprintf(str, "Unknown Queue %p specified in xglQueueSubmit", queue);
+        layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, queue, 0, MEMTRACK_INVALID_QUEUE, "MEM", str);
+    } 
+    else {
+        //  Iterate through all CBs in pCmdBuffers
+        for (uint32_t i = 0; i < cmdBufferCount; i++) {
+            MT_CB_INFO* pCBInfo = getCBInfo(pCmdBuffers[i]);
+            if (!pCBInfo) {
+                char str[1024];
+                sprintf(str, "Unable to find info for CB %p in order to check memory references in xglQueueSubmit for queue %p", (void*)pCmdBuffers[i], queue);
+                layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, pCmdBuffers[i], 0, MEMTRACK_INVALID_CB, "MEM", str);
+                result = XGL_FALSE;
+            } else {
+                // Validate that all actual references are accounted for in pMemRefs
+                for (list<XGL_GPU_MEMORY>::iterator it = pCBInfo->pMemObjList.begin(); it != pCBInfo->pMemObjList.end(); ++it) {
+                    // Search for each memref in queues memreflist.
+                    if (checkMemRef(queue, *it)) {
+                        char str[1024];
+                        sprintf(str, "Found Mem Obj %p binding to CB %p for queue %p", (*it), pCmdBuffers[i], queue);
+                        layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, pCmdBuffers[i], 0, MEMTRACK_NONE, "MEM", str);
+                    }
+                    else {
+                        char str[1024];
+                        sprintf(str, "Queue %p Memory reference list for Command Buffer %p is missing ref to mem obj %p", queue, pCmdBuffers[i], (*it));
+                        layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, pCmdBuffers[i], 0, MEMTRACK_INVALID_MEM_REF, "MEM", str);
+                        result = XGL_FALSE;
+                    }
+                }
+            }
+        }
+        if (result == XGL_TRUE) {
+            char str[1024];
+            sprintf(str, "Verified all memory dependencies for Queue %p are included in pMemRefs list", queue);
+            layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, queue, 0, MEMTRACK_NONE, "MEM", str);
+            // TODO : Could report mem refs in pMemRefs that AREN'T in mem list, that would be primarily informational
+            //   Currently just noting that there is a difference
+        }
+    }
+
+    return result;
+}
 
 // Return ptr to info in map container containing mem, or NULL if not found
 //  Calls to this function should be wrapped in mutex
@@ -821,7 +842,7 @@ XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglDestroyDevice(XGL_DEVICE device)
     // Report any memory leaks
     MT_MEM_OBJ_INFO* pInfo = NULL;
     for (map<XGL_GPU_MEMORY, MT_MEM_OBJ_INFO*>::iterator ii=memObjMap.begin(); ii!=memObjMap.end(); ++ii) {
-        pInfo = (*ii).second; 
+        pInfo = (*ii).second;
 
         if (pInfo->allocInfo.allocationSize != 0) {
             sprintf(str, "Mem Object %p has not been freed. You should clean up this memory by calling xglFreeMemory(%p) prior to xglDestroyDevice().",
@@ -863,32 +884,92 @@ XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size
 XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglGetDeviceQueue(XGL_DEVICE device, uint32_t queueNodeIndex, uint32_t queueIndex, XGL_QUEUE* pQueue)
 {
     XGL_RESULT result = nextTable.GetDeviceQueue(device, queueNodeIndex, queueIndex, pQueue);
-    addQueueInfo(*pQueue);
+    if (result == XGL_SUCCESS) {
+        loader_platform_thread_lock_mutex(&globalLock);
+        addQueueInfo(*pQueue);
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
+    return result;
+}
+
+XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglQueueAddMemReference(XGL_QUEUE queue, XGL_GPU_MEMORY mem)
+{
+    XGL_RESULT result = nextTable.QueueAddMemReference(queue, mem);
+    if (result == XGL_SUCCESS) {
+        loader_platform_thread_lock_mutex(&globalLock);
+
+        MT_QUEUE_INFO *pQueueInfo = queueMap[queue];
+        if (pQueueInfo == NULL) {
+            char str[1024];
+            sprintf(str, "Unknown Queue %p", queue);
+            layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, queue, 0, MEMTRACK_INVALID_QUEUE, "MEM", str);
+        } 
+        else {
+            if (checkMemRef(queue, mem) == XGL_TRUE) {
+                // Alread in list, just warn 
+                char str[1024];
+                sprintf(str, "Request to add a memory reference (%p) to Queue %p -- ref is already present in the queue's reference list", mem, queue);
+                layerCbMsg(XGL_DBG_MSG_WARNING, XGL_VALIDATION_LEVEL_0, mem, 0, MEMTRACK_INVALID_MEM_REF, "MEM", str);
+            }
+            else {
+                // Add to queue's memory reference list
+                pQueueInfo->pMemRefList.push_front(mem);
+            }
+        }
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
+    return result;
+}
+
+XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglQueueRemoveMemReference(XGL_QUEUE queue, XGL_GPU_MEMORY mem)
+{
+    // TODO : Decrement ref count for this memory reference on this queue. Remove if ref count is zero.
+    XGL_RESULT result = nextTable.QueueRemoveMemReference(queue, mem);
+    if (result == XGL_SUCCESS) {
+        loader_platform_thread_lock_mutex(&globalLock);
+       
+        MT_QUEUE_INFO *pQueueInfo = queueMap[queue];
+        if (pQueueInfo == NULL) {
+            char str[1024];
+            sprintf(str, "Unknown Queue %p", queue);
+            layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, queue, 0, MEMTRACK_INVALID_QUEUE, "MEM", str);
+        } 
+        else {
+            for (list<XGL_GPU_MEMORY>::iterator it = pQueueInfo->pMemRefList.begin(); it != pQueueInfo->pMemRefList.end(); ++it) {
+                if ((*it) == mem) {
+                    it = pQueueInfo->pMemRefList.erase(it);
+                }
+            }
+        }
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
     return result;
 }
 
-XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglQueueSubmit(XGL_QUEUE queue, uint32_t cmdBufferCount, const XGL_CMD_BUFFER* pCmdBuffers, XGL_FENCE fence)
+XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglQueueSubmit(
+    XGL_QUEUE             queue,
+    uint32_t              cmdBufferCount,
+    const XGL_CMD_BUFFER *pCmdBuffers,
+    XGL_FENCE             fence)
 {
     loader_platform_thread_lock_mutex(&globalLock);
     // TODO : Need to track fence and clear mem references when fence clears
     MT_CB_INFO* pCBInfo = NULL;
     uint64_t    fenceId = addFenceInfo(fence, queue);
-    char        str[1024];
-    sprintf(str, "In xglQueueSubmit(), checking %u cmdBuffers memRefs", cmdBufferCount);
-    layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, queue, 0, MEMTRACK_NONE, "MEM", str);
+
     printMemList();
     printCBList();
     for (uint32_t i = 0; i < cmdBufferCount; i++) {
         pCBInfo = getCBInfo(pCmdBuffers[i]);
         pCBInfo->fenceId = fenceId;
-        sprintf(str, "Verifying mem refs for CB %p", pCmdBuffers[i]);
-        layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, pCmdBuffers[i], 0, MEMTRACK_NONE, "MEM", str);
-//        if (XGL_FALSE == validateCBMemRef(pCmdBuffers[i], memRefCount, pMemRefs)) {
-//            sprintf(str, "Unable to verify memory references for CB %p", (void*)pCmdBuffers[i]);
-//            layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, pCmdBuffers[i], 0, MEMTRACK_CB_MISSING_MEM_REF, "MEM", str);
-//        }
     }
-    printCBList();
+
+    if (XGL_FALSE == validateQueueMemRefs(queue, cmdBufferCount, pCmdBuffers)) {
+        char str[1024];
+        sprintf(str, "Unable to verify memory references for Queue %p", queue);
+        layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, queue, 0, MEMTRACK_INVALID_MEM_REF, "MEM", str);
+    }
+
     loader_platform_thread_unlock_mutex(&globalLock);
     XGL_RESULT result = nextTable.QueueSubmit(queue, cmdBufferCount, pCmdBuffers, getFenceFromId(fenceId));
     return result;
@@ -1911,6 +1992,10 @@ XGL_LAYER_EXPORT void* XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const char* f
         return (void*) xglDbgUnregisterMsgCallback;
     if (!strcmp(funcName, "xglGetDeviceQueue"))
         return (void*) xglGetDeviceQueue;
+    if (!strcmp(funcName, "xglQueueAddMemReference"))
+        return (void*) xglQueueAddMemReference;
+    if (!strcmp(funcName, "xglQueueRemoveMemReference"))
+        return (void*) xglQueueRemoveMemReference;
 #if !defined(WIN32)
     if (!strcmp(funcName, "xglWsiX11CreatePresentableImage"))
         return (void*) xglWsiX11CreatePresentableImage;
index eb4deb4..91cc434 100644 (file)
@@ -31,16 +31,16 @@ extern "C" {
 // Mem Tracker ERROR codes
 typedef enum _MEM_TRACK_ERROR
 {
-    MEMTRACK_NONE                          = 0, // Used for INFO & other non-error messages
-    MEMTRACK_INVALID_CB                    = 1, // Cmd Buffer invalid
-    MEMTRACK_CB_MISSING_MEM_REF            = 2, // pMemRefs for CB is missing a mem ref
-    MEMTRACK_INVALID_MEM_OBJ               = 3, // Invalid Memory Object
-    MEMTRACK_INTERNAL_ERROR                = 4, // Bug in Mem Track Layer internal data structures
-    MEMTRACK_CB_MISSING_FENCE              = 5, // Cmd Buffer does not have fence
-    MEMTRACK_FREED_MEM_REF                 = 6, // MEM Obj freed while it still has obj and/or CB refs
-    MEMTRACK_MEM_OBJ_CLEAR_EMPTY_BINDINGS  = 7, // Clearing bindings on mem obj that doesn't have any bindings
-    MEMTRACK_MISSING_MEM_BINDINGS          = 8, // Trying to retrieve mem bindings, but none found (may be internal error)
-    MEMTRACK_INVALID_OBJECT                = 9, // Attempting to reference generic XGL Object that is invalid
+    MEMTRACK_NONE                          = 0,  // Used for INFO & other non-error messages
+    MEMTRACK_INVALID_CB                    = 1,  // Cmd Buffer invalid
+    MEMTRACK_INVALID_MEM_REF               = 2,  // Requested mem ref is missing or invalid
+    MEMTRACK_INVALID_MEM_OBJ               = 3,  // Invalid Memory Object
+    MEMTRACK_INTERNAL_ERROR                = 4,  // Bug in Mem Track Layer internal data structures
+    MEMTRACK_CB_MISSING_FENCE              = 5,  // Cmd Buffer does not have fence
+    MEMTRACK_FREED_MEM_REF                 = 6,  // MEM Obj freed while it still has obj and/or CB refs
+    MEMTRACK_MEM_OBJ_CLEAR_EMPTY_BINDINGS  = 7,  // Clearing bindings on mem obj that doesn't have any bindings
+    MEMTRACK_MISSING_MEM_BINDINGS          = 8,  // Trying to retrieve mem bindings, but none found (may be internal error)
+    MEMTRACK_INVALID_OBJECT                = 9,  // Attempting to reference generic XGL Object that is invalid
     MEMTRACK_FREE_MEM_ERROR                = 10, // Error while calling xglFreeMemory
     MEMTRACK_DESTROY_OBJECT_ERROR          = 11, // Destroying an object that has a memory reference
     MEMTRACK_MEMORY_BINDING_ERROR          = 12, // Error during one of many calls that bind memory to object or CB
@@ -48,6 +48,7 @@ typedef enum _MEM_TRACK_ERROR
     MEMTRACK_MEMORY_LEAK                   = 14, // Failure to call xglFreeMemory on Mem Obj prior to DestroyDevice
     MEMTRACK_INVALID_STATE                 = 15, // Memory not in the correct state
     MEMTRACK_RESET_CB_WHILE_IN_FLIGHT      = 16, // xglResetCommandBuffer() called on a CB that hasn't completed
+    MEMTRACK_INVALID_QUEUE                 = 17, // Invalid queue requested or selected
 } MEM_TRACK_ERROR;
 
 /*
@@ -138,6 +139,7 @@ struct MT_QUEUE_INFO {
     uint64_t                      lastRetiredId;
     uint64_t                      lastSubmittedId;
     list<XGL_CMD_BUFFER>          pQueueCmdBuffers;
+    list<XGL_GPU_MEMORY>          pMemRefList;
 };
 
 #ifdef __cplusplus