From 99083d9988b723c998906460eca72ad55b3766e8 Mon Sep 17 00:00:00 2001 From: Tobin Ehlis Date: Tue, 15 Sep 2015 15:02:17 -0600 Subject: layers: Improve invalid object checks of ObjectTracker ObjectTracker now correctly stores queried PhysicalDevice and Queue information and validates that these objects are correct whenever passed in as params. Now handling arrays of Objects passed into API functions as parameters. Removed special exceptions for VkFence, VkDeviceMemory, and VkImage types that were causing them to skip some checks. Moved a few validation tests that had been under MemTracker into ObjectTracker as it now catches the invalid VkImage and VkDeviceMemory cases. Updated master document to reflect this. --- layers/object_track.h | 114 +++++++++++++++++++++++++++++++++- layers/vk_validation_layer_details.md | 4 +- vk-layer-generate.py | 29 ++++++--- 3 files changed, 134 insertions(+), 13 deletions(-) diff --git a/layers/object_track.h b/layers/object_track.h index bfb9cd42..ad997d27 100644 --- a/layers/object_track.h +++ b/layers/object_track.h @@ -387,12 +387,19 @@ initObjectTracker( // Forward declares of generated routines // +static void create_obj(VkInstance dispatchable_object, VkPhysicalDevice vkObj, VkDbgObjectType objType); static void create_obj(VkInstance dispatchable_object, VkInstance object, VkDbgObjectType objType); static void create_obj(VkDevice dispatchable_object, VkDevice object, VkDbgObjectType objType); static void create_obj(VkDevice dispatchable_object, VkDescriptorSet object, VkDbgObjectType objType); +static void create_obj(VkDevice dispatchable_object, VkQueue vkObj, VkDbgObjectType objType); +static VkBool32 validate_object(VkQueue dispatchable_object, VkImage object); +static VkBool32 validate_object(VkCmdBuffer dispatchable_object, VkImage object); +static VkBool32 validate_object(VkQueue dispatchable_object, VkCmdBuffer object); +static VkBool32 validate_object(VkCmdBuffer dispatchable_object, VkDescriptorSet object); static VkBool32 validate_object(VkInstance dispatchable_object, VkInstance object); static VkBool32 validate_object(VkDevice dispatchable_object, VkDevice object); static VkBool32 validate_object(VkDevice dispatchable_object, VkDescriptorPool object); +static VkBool32 validate_object(VkDevice dispatchable_object, VkDescriptorSetLayout object); static void destroy_obj(VkInstance dispatchable_object, VkInstance object); static void destroy_obj(VkDevice dispatchable_object, VkDeviceMemory object); static void destroy_obj(VkDevice dispatchable_object, VkDescriptorSet object); @@ -403,12 +410,52 @@ static VkBool32 validate_status(VkDevice dispatchable_object, VkFence object, Vk ObjectStatusFlags status_mask, ObjectStatusFlags status_flag, VkFlags msg_flags, OBJECT_TRACK_ERROR error_code, const char *fail_msg); #endif +extern unordered_map VkPhysicalDeviceMap; +extern unordered_map VkImageMap; +extern unordered_map VkQueueMap; +extern unordered_map VkDescriptorSetMap; extern unordered_map VkBufferMap; extern unordered_map VkFenceMap; extern unordered_map VkSemaphoreMap; extern unordered_map VkCmdBufferMap; extern unordered_map VkSwapchainKHRMap; +static VkBool32 validate_object(VkQueue dispatchable_object, VkImage object) +{ + if (VkImageMap.find((void*)object.handle) == VkImageMap.end()) { + return log_msg(mdd(dispatchable_object), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType) 0, object.handle, 0, OBJTRACK_INVALID_OBJECT, "OBJTRACK", + "Invalid VkImage Object %p", object.handle); + } + return VK_FALSE; +} + +static VkBool32 validate_object(VkCmdBuffer dispatchable_object, VkImage object) +{ + if (VkImageMap.find((void*)object.handle) == VkImageMap.end()) { + return log_msg(mdd(dispatchable_object), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType) 0, object.handle, 0, OBJTRACK_INVALID_OBJECT, "OBJTRACK", + "Invalid VkImage Object %p", object.handle); + } + return VK_FALSE; +} + +static VkBool32 validate_object(VkQueue dispatchable_object, VkCmdBuffer object) +{ + if (VkCmdBufferMap.find(object) == VkCmdBufferMap.end()) { + return log_msg(mdd(dispatchable_object), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType) 0, reinterpret_cast(object), 0, OBJTRACK_INVALID_OBJECT, "OBJTRACK", + "Invalid VkCmdBuffer Object %p",reinterpret_cast(object)); + } + return VK_FALSE; +} + +static VkBool32 validate_object(VkCmdBuffer dispatchable_object, VkDescriptorSet object) +{ + if (VkDescriptorSetMap.find((void*)object.handle) == VkDescriptorSetMap.end()) { + return log_msg(mdd(dispatchable_object), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType) 0, object.handle, 0, OBJTRACK_INVALID_OBJECT, "OBJTRACK", + "Invalid VkDescriptorSet Object %p", object.handle); + } + return VK_FALSE; +} + static VkBool32 validate_object(VkQueue dispatchable_object, VkBuffer object) { if (VkBufferMap.find((void*)object.handle) != VkBufferMap.end()) { @@ -454,6 +501,22 @@ static VkBool32 validate_object(VkDevice dispatchable_object, VkCmdBuffer object return VK_FALSE; } +static void create_obj(VkInstance dispatchable_object, VkPhysicalDevice vkObj, VkDbgObjectType objType) +{ + log_msg(mdd(dispatchable_object), VK_DBG_REPORT_INFO_BIT, objType, reinterpret_cast(vkObj), 0, OBJTRACK_NONE, "OBJTRACK", + "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64 , object_track_index++, string_VkDbgObjectType(objType), + reinterpret_cast(vkObj)); + + OBJTRACK_NODE* pNewObjNode = new OBJTRACK_NODE; + pNewObjNode->objType = objType; + pNewObjNode->status = OBJSTATUS_NONE; + pNewObjNode->vkObj = reinterpret_cast(vkObj); + VkPhysicalDeviceMap[vkObj] = pNewObjNode; + uint32_t objIndex = objTypeToIndex(objType); + numObjs[objIndex]++; + numTotalObjs++; +} + static void create_obj(VkDevice dispatchable_object, VkCmdBuffer vkObj, VkDbgObjectType objType) { log_msg(mdd(dispatchable_object), VK_DBG_REPORT_INFO_BIT, objType, reinterpret_cast(vkObj), 0, OBJTRACK_NONE, "OBJTRACK", @@ -484,6 +547,21 @@ static void create_obj(VkDevice dispatchable_object, VkSwapchainKHR vkObj, VkDbg numObjs[objIndex]++; numTotalObjs++; } +static void create_obj(VkDevice dispatchable_object, VkQueue vkObj, VkDbgObjectType objType) +{ + log_msg(mdd(dispatchable_object), VK_DBG_REPORT_INFO_BIT, objType, reinterpret_cast(vkObj), 0, OBJTRACK_NONE, "OBJTRACK", + "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64 , object_track_index++, string_VkDbgObjectType(objType), + reinterpret_cast(vkObj)); + + OBJTRACK_NODE* pNewObjNode = new OBJTRACK_NODE; + pNewObjNode->objType = objType; + pNewObjNode->status = OBJSTATUS_NONE; + pNewObjNode->vkObj = reinterpret_cast(vkObj); + VkQueueMap[vkObj] = pNewObjNode; + uint32_t objIndex = objTypeToIndex(objType); + numObjs[objIndex]++; + numTotalObjs++; +} static void destroy_obj(VkDevice dispatchable_object, VkSwapchainKHR object) { if (VkSwapchainKHRMap.find((void*) object.handle) != VkSwapchainKHRMap.end()) { @@ -568,6 +646,27 @@ explicit_CreateDevice( return result; } +VkResult explicit_EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) +{ + VkBool32 skipCall = VK_FALSE; + loader_platform_thread_lock_mutex(&objLock); + skipCall |= validate_object(instance, instance); + loader_platform_thread_unlock_mutex(&objLock); + if (skipCall) + return VK_ERROR_VALIDATION_FAILED; + VkResult result = get_dispatch_table(ObjectTracker_instance_table_map, instance)->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices); + loader_platform_thread_lock_mutex(&objLock); + if (result == VK_SUCCESS) { + if (pPhysicalDevices) { + for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) { + create_obj(instance, pPhysicalDevices[i], VK_OBJECT_TYPE_PHYSICAL_DEVICE); + } + } + } + loader_platform_thread_unlock_mutex(&objLock); + return result; +} + VkResult explicit_GetDeviceQueue( VkDevice device, @@ -582,7 +681,10 @@ explicit_GetDeviceQueue( VkResult result = get_dispatch_table(ObjectTracker_device_table_map, device)->GetDeviceQueue(device, queueNodeIndex, queueIndex, pQueue); loader_platform_thread_lock_mutex(&objLock); - addQueueInfo(queueNodeIndex, *pQueue); + if (VK_SUCCESS == result) { + addQueueInfo(queueNodeIndex, *pQueue); + create_obj(device, *pQueue, VK_OBJECT_TYPE_QUEUE); + } loader_platform_thread_unlock_mutex(&objLock); return result; @@ -681,10 +783,16 @@ explicit_AllocDescriptorSets( const VkDescriptorSetLayout *pSetLayouts, VkDescriptorSet *pDescriptorSets) { + VkBool32 skipCall = VK_FALSE; loader_platform_thread_lock_mutex(&objLock); - validate_object(device, device); - validate_object(device, descriptorPool); + skipCall |= validate_object(device, device); + skipCall |= validate_object(device, descriptorPool); + for (uint32_t i = 0; i < count; i++) { + skipCall |= validate_object(device, pSetLayouts[i]); + } loader_platform_thread_unlock_mutex(&objLock); + if (skipCall) + return VK_ERROR_VALIDATION_FAILED; VkResult result = get_dispatch_table(ObjectTracker_device_table_map, device)->AllocDescriptorSets( device, descriptorPool, setUsage, count, pSetLayouts, pDescriptorSets); diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md index a297f145..332c1706 100644 --- a/layers/vk_validation_layer_details.md +++ b/layers/vk_validation_layer_details.md @@ -132,7 +132,7 @@ The MemTracker layer tracks memory objects and references and validates that the | Free Referenced Memory | Checks to see if memory being freed still has current references | FREED_MEM_REF | vmFreeMemory | FreeBoundMemory | NA | | Memory Properly Bound | Validate that the memory object referenced in the call was properly created, is currently valid, and is properly bound to the object | MISSING_MEM_BINDINGS | vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage | NA | NA | | Valid Object | Verifies that the specified Vulkan object was created properly and is currently valid | INVALID_OBJECT | vkCmdBindPipeline vkCmdBindDynamicViewportState vkCmdBindDynamicLineWidthState vkCmdBindDynamicDepthBiasState vkCmdBindDynamicBlendState vkCmdBindDynamicDepthBoundsState vkCmdBindDynamicStencilState vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage | NA | NA | -| Bind Invalid Memory | Validate that memory object was correctly created, that the command buffer object was correctly created, and that both are currently valid objects. | MEMORY_BINDING_ERROR | vkQueueBindSparseImageOpaqueMemory vkQueueBindSparseImageMemory vkQueueBindSparseBufferMemory vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage | BindInvalidMemory BindMemoryToDestroyedObject | This is probably redundant, as these checks are performed at a lower level. | +| Bind Invalid Memory | Validate that memory object was correctly created, that the command buffer object was correctly created, and that both are currently valid objects. | MEMORY_BINDING_ERROR | vkQueueBindSparseImageOpaqueMemory vkQueueBindSparseImageMemory vkQueueBindSparseBufferMemory vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage | NA | The valid Object checks are primarily the responsibilty of ObjectTracker layer, so these checks are more of a backup in case ObjectTracker is not enabled | | Objects Not Destroyed | Verify all objects destroyed at DestroyDevice time | MEMORY_LEAK | vkDestroyDevice | NA | NA | | Memory Mapping State | Verifies that mapped memory is CPU-visible | INVALID_STATE | vkMapMemory | MapMemWithoutHostVisibleBit | NA | | Command Buffer Synchronization | Command Buffer must be complete before BeginCommandBuffer or ResetCommandBuffer can be called | RESET_CB_WHILE_IN_FLIGHT | vkBeginCommandBuffer vkResetCommandBuffer | CallBeginCmdBufferBeforeCompletion CallBeginCmdBufferBeforeCompletion | NA | @@ -198,7 +198,7 @@ The ObjectTracker layer maintains a record of all Vulkan objects. It flags error | Check | Overview | ENUM OBJTRACK_* | Relevant API | Testname | Notes/TODO | | ----- | -------- | ---------------- | ------------ | -------- | ---------- | -| Valid Object | Validates that referenced object was properly created and is currently valid. | INVALID_OBJECT | vkAcquireNextImageKHR vkAllocDescriptorSets vkAllocMemory vkBeginCommandBuffer vkBindBufferMemory vkBindImageMemory vkCmdBeginQuery vkCmdBeginRenderPass vkCmdBindDescriptorSets vkCmdBindDynamicViewportState vkCmdBindDynamicLineWidthState vkCmdBindDynamicDepthBiasState vkCmdBindDynamicBlendState vkCmdBindDynamicDepthBoundsState vkCmdBindDynamicStencilState vkCmdBindIndexBuffer vkCmdBindPipeline vkCmdBindVertexBuffers vkCmdBlitImage vkCmdClearColorAttachment vkCmdClearColorImage vkCmdClearDepthStencilAttachment vkCmdClearDepthStencilImage vkCmdCopyBuffer vkCmdCopyBufferToImage vkCmdCopyImage vkCmdCopyImageToBuffer vkCmdCopyQueryPoolResults vkCmdDispatch vkCmdDispatchIndirect vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndexedIndirect vkCmdDrawIndirect vkCmdEndQuery vkCmdEndRenderPass vkCmdExecuteCommands vkCmdFillBuffer vkCmdNextSubpass vkCmdPipelineBarrier vkCmdPushConstants vkCmdResetEvent vkCmdResetQueryPool vkCmdResolveImage vkCmdSetEvent vkCmdUpdateBuffer vkCmdWaitEvents vkCmdWriteTimestamp vkCreateBuffer vkCreateBufferView vkCreateCommandBuffer vkCreateCommandPool vkCreateComputePipelines vkCreateDescriptorPool vkCreateDescriptorSetLayout vkCreateDynamicViewportState vkCreateDynamicLineWidthState vkCreateDynamicDepthBiasState vkCreateDynamicBlendState vkCreateDynamicDepthBoundsState vkCreateDynamicStencilState vkCreateEvent vkCreateFence vkCreateFramebuffer vkCreateGraphicsPipelines vkCreateImage vkCreateImageView vkCreatePipelineCache vkCreatePipelineLayout vkCreateQueryPool vkCreateRenderPass vkCreateSampler vkCreateSemaphore vkCreateShader vkCreateShaderModule vkCreateSwapchainKHR vkDestroyBuffer vkDestroyBufferView vkDestroyCommandBuffer vkDestroyCommandPool vkDestroyDescriptorPool vkDestroyDescriptorSetLayout vkDestroyDynamicBlendState vkDestroyDynamicLineWidthState vkDestroyDynamicDepthBiasState vkDestroyDynamicDepthBoundsState vkDestroyDynamicStencilState vkDestroyDynamicViewportState vkDestroyEvent vkDestroyFence vkDestroyFramebuffer vkDestroyImage vkDestroyImageView vkDestroyPipeline vkDestroyPipelineCache vkDestroyPipelineLayout vkDestroyQueryPool vkDestroyRenderPass vkDestroySampler vkDestroySemaphore vkDestroyShader vkDestroyShaderModule vkDestroySwapchainKHR vkDeviceWaitIdle vkEndCommandBuffer vkEnumeratePhysicalDevices vkFreeDescriptorSets vkFreeMemory vkFreeMemory vkGetBufferMemoryRequirements vkGetDeviceMemoryCommitment vkGetDeviceQueue vkGetEventStatus vkGetFenceStatus vkGetImageMemoryRequirements vkGetImageSparseMemoryRequirements vkGetImageSubresourceLayout vkGetPhysicalDeviceSurfaceSupportKHR vkGetPipelineCacheData vkGetPipelineCacheSize vkGetQueryPoolResults vkGetRenderAreaGranularity vkInvalidateMappedMemoryRanges vkMapMemory vkMergePipelineCaches vkQueueBindSparseBufferMemory vkQueueSignalSemaphore vkQueueWaitSemaphore vkResetCommandBuffer vkResetCommandPool vkResetDescriptorPool vkResetEvent vkResetFences vkSetEvent vkUnmapMemory vkUpdateDescriptorSets vkWaitForFences | ? | Every VkObject class of parameter will be run through this check. This check may ultimately supersede UNKNOWN_OBJECT | +| Valid Object | Validates that referenced object was properly created and is currently valid. | INVALID_OBJECT | vkAcquireNextImageKHR vkAllocDescriptorSets vkAllocMemory vkBeginCommandBuffer vkBindBufferMemory vkBindImageMemory vkCmdBeginQuery vkCmdBeginRenderPass vkCmdBindDescriptorSets vkCmdBindDynamicViewportState vkCmdBindDynamicLineWidthState vkCmdBindDynamicDepthBiasState vkCmdBindDynamicBlendState vkCmdBindDynamicDepthBoundsState vkCmdBindDynamicStencilState vkCmdBindIndexBuffer vkCmdBindPipeline vkCmdBindVertexBuffers vkCmdBlitImage vkCmdClearColorAttachment vkCmdClearColorImage vkCmdClearDepthStencilAttachment vkCmdClearDepthStencilImage vkCmdCopyBuffer vkCmdCopyBufferToImage vkCmdCopyImage vkCmdCopyImageToBuffer vkCmdCopyQueryPoolResults vkCmdDispatch vkCmdDispatchIndirect vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndexedIndirect vkCmdDrawIndirect vkCmdEndQuery vkCmdEndRenderPass vkCmdExecuteCommands vkCmdFillBuffer vkCmdNextSubpass vkCmdPipelineBarrier vkCmdPushConstants vkCmdResetEvent vkCmdResetQueryPool vkCmdResolveImage vkCmdSetEvent vkCmdUpdateBuffer vkCmdWaitEvents vkCmdWriteTimestamp vkCreateBuffer vkCreateBufferView vkCreateCommandBuffer vkCreateCommandPool vkCreateComputePipelines vkCreateDescriptorPool vkCreateDescriptorSetLayout vkCreateDynamicViewportState vkCreateDynamicLineWidthState vkCreateDynamicDepthBiasState vkCreateDynamicBlendState vkCreateDynamicDepthBoundsState vkCreateDynamicStencilState vkCreateEvent vkCreateFence vkCreateFramebuffer vkCreateGraphicsPipelines vkCreateImage vkCreateImageView vkCreatePipelineCache vkCreatePipelineLayout vkCreateQueryPool vkCreateRenderPass vkCreateSampler vkCreateSemaphore vkCreateShader vkCreateShaderModule vkCreateSwapchainKHR vkDestroyBuffer vkDestroyBufferView vkDestroyCommandBuffer vkDestroyCommandPool vkDestroyDescriptorPool vkDestroyDescriptorSetLayout vkDestroyDynamicBlendState vkDestroyDynamicLineWidthState vkDestroyDynamicDepthBiasState vkDestroyDynamicDepthBoundsState vkDestroyDynamicStencilState vkDestroyDynamicViewportState vkDestroyEvent vkDestroyFence vkDestroyFramebuffer vkDestroyImage vkDestroyImageView vkDestroyPipeline vkDestroyPipelineCache vkDestroyPipelineLayout vkDestroyQueryPool vkDestroyRenderPass vkDestroySampler vkDestroySemaphore vkDestroyShader vkDestroyShaderModule vkDestroySwapchainKHR vkDeviceWaitIdle vkEndCommandBuffer vkEnumeratePhysicalDevices vkFreeDescriptorSets vkFreeMemory vkFreeMemory vkGetBufferMemoryRequirements vkGetDeviceMemoryCommitment vkGetDeviceQueue vkGetEventStatus vkGetFenceStatus vkGetImageMemoryRequirements vkGetImageSparseMemoryRequirements vkGetImageSubresourceLayout vkGetPhysicalDeviceSurfaceSupportKHR vkGetPipelineCacheData vkGetPipelineCacheSize vkGetQueryPoolResults vkGetRenderAreaGranularity vkInvalidateMappedMemoryRanges vkMapMemory vkMergePipelineCaches vkQueueBindSparseBufferMemory vkQueueSignalSemaphore vkQueueWaitSemaphore vkResetCommandBuffer vkResetCommandPool vkResetDescriptorPool vkResetEvent vkResetFences vkSetEvent vkUnmapMemory vkUpdateDescriptorSets vkWaitForFences | BindInvalidMemory BindMemoryToDestroyedObject | Every VkObject class of parameter will be run through this check. This check may ultimately supersede UNKNOWN_OBJECT | | Object Cleanup | Verify that object properly destroyed | DESTROY_OBJECT_FAILED | vkDestroyInstance, vkDestroyDevice, vkFreeMemory | ? | NA | | Objects Leak | When an Instance or Device object is destroyed, validates that all objects belonging to that device/instance have previously been destroyed | OBJECT_LEAK | vkDestroyDevice vkDestroyInstance | ? | NA | | Object Count | Flag error if number of objects requested from extenstion functions exceeds max number of actual objects | OBJCOUNT_MAX_EXCEEDED | objTrackGetObjects objTrackGetObjectsOfType | ? | NA | diff --git a/vk-layer-generate.py b/vk-layer-generate.py index d7ffe71f..a22d6ff9 100755 --- a/vk-layer-generate.py +++ b/vk-layer-generate.py @@ -1161,6 +1161,12 @@ class ObjectTrackerSubcommand(Subcommand): procs_txt.append('}') procs_txt.append('') procs_txt.append('%s' % self.lineinfo.get()) + # TODO : This is not complete and currently requires some hand-coded function in the header + # Really we want to capture the set of all objects and their associated dispatchable objects + # that are bound by the API calls: + # foreach API Call + # foreach object type seen by call + # create validate_object(disp_obj, object) if o in vulkan.object_dispatch_list: procs_txt.append('static VkBool32 validate_object(%s dispatchable_object, %s object)' % (o, o)) else: @@ -1437,14 +1443,12 @@ class ObjectTrackerSubcommand(Subcommand): explicit_object_tracker_functions = [ "CreateInstance", + "EnumeratePhysicalDevices", "GetPhysicalDeviceQueueFamilyProperties", "CreateDevice", "GetDeviceQueue", - #"QueueSubmit", "QueueBindSparseImageMemory", "QueueBindSparseBufferMemory", - #"GetFenceStatus", - #"WaitForFences", "AllocDescriptorSets", "FreeDescriptorSets", "MapMemory", @@ -1466,18 +1470,24 @@ class ObjectTrackerSubcommand(Subcommand): valid_null_object_names = {'CreateGraphicsPipelines' : ['basePipelineHandle'], 'CreateComputePipelines' : ['basePipelineHandle'], 'BeginCommandBuffer' : ['renderPass', 'framebuffer'], + 'QueueSubmit' : ['fence'], } # TODO : A few of the skipped types are just "hard" cases that need some more work to support # Need to handle NULL fences on queue submit, binding null memory, and WSI Image objects param_count = 'NONE' # keep track of arrays passed directly into API functions for p in proto.params: + base_type = p.ty.replace('const ', '').strip('*') if 'count' in p.name.lower(): param_count = p.name - if p.ty in vulkan.core.objects and p.ty not in ['VkPhysicalDevice', 'VkQueue', 'VkFence', 'VkImage', 'VkDeviceMemory']: - if proto.name not in valid_null_object_names or p.name not in valid_null_object_names[proto.name]: + if base_type in vulkan.core.objects: + # This is an object to potentially check for validity. First see if it's an array + if '*' in p.ty and 'const' in p.ty and param_count != 'NONE': + loop_params[param_count].append(p.name) + # Not an array, check for just a base Object that's not in exceptions + elif '*' not in p.ty and (proto.name not in valid_null_object_names or p.name not in valid_null_object_names[proto.name]): loop_params[0].append(p.name) - elif vk_helper.is_type(p.ty.replace('const ', '').strip('*'), 'struct'): - struct_type = p.ty.replace('const ', '').strip('*') + elif vk_helper.is_type(base_type, 'struct'): + struct_type = base_type if vk_helper.typedef_rev_dict[struct_type] in vk_helper.struct_dict: struct_type = vk_helper.typedef_rev_dict[struct_type] for m in sorted(vk_helper.struct_dict[struct_type]): @@ -1540,7 +1550,10 @@ class ObjectTrackerSubcommand(Subcommand): else: base_param = loop_params[lc][0].split('-')[0].split('[')[0] using_line += ' if (%s) {\n' % base_param - using_line += ' for (uint32_t i=0; i<%s; i++) {\n' % lc + if 'setCount' == lc: # TODO : Hacky. This is one case where loop doesn't start from 0 + using_line += ' for (uint32_t i=firstSet; i<%s; i++) {\n' % lc + else: + using_line += ' for (uint32_t i=0; i<%s; i++) {\n' % lc for opn in loop_params[lc]: if '[' in opn: # API func param is array using_line += ' skipCall |= validate_object(%s, %s);\n' % (param0_name, opn) -- cgit v1.2.3