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":