From 8247e999ddb14b8ca7e09e1ddbbf6024d5f0fd83 Mon Sep 17 00:00:00 2001 From: Tobin Ehlis Date: Wed, 4 Mar 2015 08:38:22 -0700 Subject: layers: MemTracker add check to verify CB complete prior to Reset If CB fence has not completed on call to Begin or Reset CB, flag validation error. Various improvements to make sure the CB fence is getting reset as appropriate if the fence completes or is destroyed. --- layers/mem_tracker.c | 132 +++++++++++++++++++++++++++++++++++++++++++-------- layers/mem_tracker.h | 2 + 2 files changed, 114 insertions(+), 20 deletions(-) diff --git a/layers/mem_tracker.c b/layers/mem_tracker.c index e3088b47..7b2e009c 100644 --- a/layers/mem_tracker.c +++ b/layers/mem_tracker.c @@ -197,6 +197,7 @@ static bool32_t validateCBMemRef(const XGL_CMD_BUFFER cb, uint32_t memRefCount, return result; } // Return ptr to node in global LL containing mem, or NULL if not found +// Calls to this function should be wrapped in mutex static GLOBAL_MEM_OBJ_NODE* getGlobalMemNode(const XGL_GPU_MEMORY mem) { GLOBAL_MEM_OBJ_NODE* pTrav = pGlobalMemObjHead; @@ -268,26 +269,31 @@ static bool32_t updateCBBinding(const XGL_CMD_BUFFER cb, const XGL_GPU_MEMORY me } // Clear the CB Binding for mem +// Calls to this function should be wrapped in mutex static void clearCBBinding(const XGL_CMD_BUFFER cb, const XGL_GPU_MEMORY mem) { GLOBAL_MEM_OBJ_NODE* pTrav = getGlobalMemNode(mem); - MINI_NODE* pMiniCB = pTrav->pCmdBufferBindings; - MINI_NODE* pPrev = pMiniCB; - while (pMiniCB && (cb != pMiniCB->cmdBuffer)) { - pPrev = pMiniCB; - pMiniCB = pMiniCB->pNext; - } - if (!pMiniCB) { - char str[1024]; - sprintf(str, "Trying to clear CB binding but CB %p not in binding list for mem obj %p", cb, mem); - layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_INTERNAL_ERROR, "MEM", str); - } - else { // remove node from list & decrement refCount - pPrev->pNext = pMiniCB->pNext; - if (pMiniCB == pTrav->pCmdBufferBindings) - pTrav->pCmdBufferBindings = NULL; - free(pMiniCB); - pTrav->refCount--; + // TODO : Having this check is not ideal, really if mem node was deleted, + // its CB bindings should be cleared and then freeCBBindings wouldn't call + // us here with stale mem objs + if (pTrav) { + MINI_NODE* pMiniCB = pTrav->pCmdBufferBindings; + MINI_NODE* pPrev = pMiniCB; + while (pMiniCB && (cb != pMiniCB->cmdBuffer)) { + pPrev = pMiniCB; + pMiniCB = pMiniCB->pNext; + } + if (!pMiniCB) { + char str[1024]; + sprintf(str, "Trying to clear CB binding but CB %p not in binding list for mem obj %p", cb, mem); + layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, cb, 0, MEMTRACK_INTERNAL_ERROR, "MEM", str); + } else { // remove node from list & decrement refCount + pPrev->pNext = pMiniCB->pNext; + if (pMiniCB == pTrav->pCmdBufferBindings) + pTrav->pCmdBufferBindings = NULL; + free(pMiniCB); + pTrav->refCount--; + } } } @@ -304,9 +310,9 @@ static bool32_t freeCBBindings(const XGL_CMD_BUFFER cb) } else { if ((pCBTrav->fence != NULL) && (pCBTrav->localFlag == XGL_TRUE)) { nextTable.DestroyObject(pCBTrav->fence); - pCBTrav->fence = NULL; pCBTrav->localFlag = XGL_FALSE; } + pCBTrav->fence = NULL; MINI_NODE* pMemTrav = pCBTrav->pMemObjList; MINI_NODE* pDeleteMe = NULL; // We traverse LL in order and free nodes as they're cleared @@ -439,6 +445,20 @@ static bool32_t checkCBCompleted(const XGL_CMD_BUFFER cb) return result; } +static void clearCBFence(const XGL_FENCE fence) +{ + // TODO : This is slow and stupid + // Ultimately would like a quick fence lookup w/ all of the CBs using that fence + // We have to loop every CB for now b/c multiple CBs may use same fence + GLOBAL_CB_NODE* pCBTrav = pGlobalCBHead; + while (pCBTrav) { + if (pCBTrav->fence == fence) { + pCBTrav->fence = NULL; + } + pCBTrav = pCBTrav->pNextGlobalCBNode; + } +} + static bool32_t freeMemNode(XGL_GPU_MEMORY mem) { bool32_t result = XGL_TRUE; @@ -1024,6 +1044,9 @@ XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglDestroyObject(XGL_OBJECT object) clearObjectBinding(object); } } + if (XGL_STRUCTURE_TYPE_FENCE_CREATE_INFO == pTrav->sType) { + clearCBFence((XGL_FENCE)object); + } if (pGlobalObjectHead == pTrav) // update HEAD if needed pGlobalObjectHead = pTrav->pNext; // Delete the obj node from global list @@ -1060,6 +1083,50 @@ XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglBindObjectMemory(XGL_OBJECT object, uint32 return result; } +XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglCreateFence(XGL_DEVICE device, const XGL_FENCE_CREATE_INFO* pCreateInfo, XGL_FENCE* pFence) +{ + XGL_RESULT result = nextTable.CreateFence(device, pCreateInfo, pFence); + if (XGL_SUCCESS == result) { + loader_platform_thread_lock_mutex(&globalLock); + insertGlobalObjectNode(*pFence, pCreateInfo->sType, pCreateInfo, sizeof(XGL_FENCE_CREATE_INFO), "fence"); + loader_platform_thread_unlock_mutex(&globalLock); + } + return result; +} + +XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglGetFenceStatus(XGL_FENCE fence) +{ + XGL_RESULT result = nextTable.GetFenceStatus(fence); + if (XGL_SUCCESS == result) { + // TODO : Properly we should add validation to make sure app is checking fence + // on CB before Reset/Begin CB call is made + clearCBFence(fence); + } + return result; +} + +XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglWaitForFences(XGL_DEVICE device, uint32_t fenceCount, const XGL_FENCE* pFences, bool32_t waitAll, uint64_t timeout) +{ + XGL_RESULT result = nextTable.WaitForFences(device, fenceCount, pFences, waitAll, timeout); + if (XGL_SUCCESS == result) { + // TODO : Properly we should add validation to make sure app is checking fence + // on CB before Reset/Begin CB call is made + if (waitAll) { // Clear all the fences + for(uint32_t i = 0; i < fenceCount; i++) { + clearCBFence(pFences[i]); + } + } + else { // Clear only completed fences + for(uint32_t i = 0; i < fenceCount; i++) { + if (XGL_SUCCESS == nextTable.GetFenceStatus(pFences[i])) { + clearCBFence(pFences[i]); + } + } + } + } + return result; +} + XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglCreateEvent(XGL_DEVICE device, const XGL_EVENT_CREATE_INFO* pCreateInfo, XGL_EVENT* pEvent) { XGL_RESULT result = nextTable.CreateEvent(device, pCreateInfo, pEvent); @@ -1245,7 +1312,16 @@ XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglCreateCommandBuffer(XGL_DEVICE device, con XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglBeginCommandBuffer(XGL_CMD_BUFFER cmdBuffer, const XGL_CMD_BUFFER_BEGIN_INFO* pBeginInfo) { - // This implicitly resets the Cmd Buffer so clear memory references + // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references + GLOBAL_CB_NODE* pCBTrav = getGlobalCBNode(cmdBuffer); + if (pCBTrav && pCBTrav->fence) { + bool32_t cbDone = checkCBCompleted(cmdBuffer); + if (XGL_FALSE == cbDone) { + char str[1024]; + sprintf(str, "Calling xglBeginCommandBuffer() on active CB %p before it has completed. You must check CB flag before this call.", cmdBuffer); + layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, cmdBuffer, 0, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM", str); + } + } XGL_RESULT result = nextTable.BeginCommandBuffer(cmdBuffer, pBeginInfo); loader_platform_thread_lock_mutex(&globalLock); freeCBBindings(cmdBuffer); @@ -1262,7 +1338,17 @@ XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglEndCommandBuffer(XGL_CMD_BUFFER cmdBuffer) XGL_LAYER_EXPORT XGL_RESULT XGLAPI xglResetCommandBuffer(XGL_CMD_BUFFER cmdBuffer) { - // Clear memory references as this point. Anything else to do here? + // Verify that CB is complete (not in-flight) + GLOBAL_CB_NODE* pCBTrav = getGlobalCBNode(cmdBuffer); + if (pCBTrav && pCBTrav->fence) { + bool32_t cbDone = checkCBCompleted(cmdBuffer); + if (XGL_FALSE == cbDone) { + char str[1024]; + sprintf(str, "Resetting CB %p before it has completed. You must check CB flag before calling xglResetCommandBuffer().", cmdBuffer); + layerCbMsg(XGL_DBG_MSG_ERROR, XGL_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); @@ -1749,6 +1835,12 @@ XGL_LAYER_EXPORT void* XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const char* f return (void*) xglGetObjectInfo; if (!strcmp(funcName, "xglBindObjectMemory")) return (void*) xglBindObjectMemory; + if (!strcmp(funcName, "xglCreateFence")) + return (void*) xglCreateFence; + if (!strcmp(funcName, "xglGetFenceStatus")) + return (void*) xglGetFenceStatus; + if (!strcmp(funcName, "xglWaitForFences")) + return (void*) xglWaitForFences; if (!strcmp(funcName, "xglCreateEvent")) return (void*) xglCreateEvent; if (!strcmp(funcName, "xglCreateQueryPool")) diff --git a/layers/mem_tracker.h b/layers/mem_tracker.h index 930d9721..ad46bc77 100644 --- a/layers/mem_tracker.h +++ b/layers/mem_tracker.h @@ -41,6 +41,7 @@ typedef enum _MEM_TRACK_ERROR MEMTRACK_OUT_OF_MEMORY_ERROR = 13, // malloc failed 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 } MEM_TRACK_ERROR; /* @@ -119,6 +120,7 @@ typedef struct _GLOBAL_OBJECT_NODE { XGL_GRAPHICS_PIPELINE_CREATE_INFO graphics_pipeline_create_info; XGL_COMPUTE_PIPELINE_CREATE_INFO compute_pipeline_create_info; XGL_SAMPLER_CREATE_INFO sampler_create_info; + XGL_FENCE_CREATE_INFO fence_create_info; #ifndef _WIN32 XGL_WSI_X11_PRESENTABLE_IMAGE_CREATE_INFO wsi_x11_presentable_image_create_info; #endif // _WIN32 -- cgit v1.2.3