#include <string.h>
#include <assert.h>
#include <list>
-#include <map>
+#include <unordered_map>
#include <vector>
using namespace std;
#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;
// 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();
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(
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) {
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
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
// 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);
}
}
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(
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) {
// 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)
{
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;
}
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];
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;
}
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);
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);
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;
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)
// 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) {
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);
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
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);
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);
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);