layers: Migrate Fence checks from ObjectTracker to MemTracker
diff --git a/layers/mem_tracker.cpp b/layers/mem_tracker.cpp
index 6042f8e..1373419 100644
--- a/layers/mem_tracker.cpp
+++ b/layers/mem_tracker.cpp
@@ -2049,10 +2049,30 @@
return result;
}
+static inline VkBool32 verifyFenceStatus(VkDevice device, VkFence fence, const char* apiCall)
+{
+ VkBool32 skipCall = VK_FALSE;
+ auto pFenceInfo = fenceMap.find(fence.handle);
+ if (pFenceInfo != fenceMap.end()) {
+ if (pFenceInfo->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT) {
+ skipCall |= log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_FENCE, fence.handle, 0, MEMTRACK_INVALID_FENCE_STATE, "MEM",
+ "%s specified fence %#" PRIxLEAST64 " already in SIGNALED state.", apiCall, fence.handle);
+ }
+ if (!pFenceInfo->second.queue) { // Checking status of unsubmitted fence
+ skipCall |= log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_FENCE, fence.handle, 0, MEMTRACK_INVALID_FENCE_STATE, "MEM",
+ "%s called for fence %#" PRIxLEAST64 " which has not been submitted on a Queue.", apiCall, fence.handle);
+ }
+ }
+ return skipCall;
+}
+
VK_LAYER_EXPORT VkResult VKAPI vkGetFenceStatus(
VkDevice device,
VkFence fence)
{
+ VkBool32 skipCall = verifyFenceStatus(device, fence, "vkGetFenceStatus");
+ if (skipCall)
+ return VK_ERROR_VALIDATION_FAILED;
VkResult result = get_dispatch_table(mem_tracker_device_table_map, device)->GetFenceStatus(device, fence);
if (VK_SUCCESS == result) {
loader_platform_thread_lock_mutex(&globalLock);
@@ -2069,16 +2089,13 @@
VkBool32 waitAll,
uint64_t timeout)
{
+ VkBool32 skipCall = VK_FALSE;
// Verify fence status of submitted fences
for(uint32_t i = 0; i < fenceCount; i++) {
- auto pFenceInfo = fenceMap.find(pFences[i].handle);
- if (pFenceInfo != fenceMap.end()) {
- if (pFenceInfo->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT) {
- log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_FENCE, pFences[i].handle, 0, MEMTRACK_INVALID_FENCE_STATE, "MEM",
- "VkWaitForFences specified fence %#" PRIxLEAST64 " already in SIGNALED state.", pFences[i].handle);
- }
- }
+ skipCall |= verifyFenceStatus(device, pFences[i], "vkWaitForFences");
}
+ if (skipCall)
+ return VK_ERROR_VALIDATION_FAILED;
VkResult result = get_dispatch_table(mem_tracker_device_table_map, device)->WaitForFences(device, fenceCount, pFences, waitAll, timeout);
loader_platform_thread_lock_mutex(&globalLock);
diff --git a/layers/object_track.h b/layers/object_track.h
index 141d0d9..bfb9cd4 100644
--- a/layers/object_track.h
+++ b/layers/object_track.h
@@ -35,7 +35,6 @@
OBJTRACK_DESTROY_OBJECT_FAILED, // Couldn't find object to be destroyed
OBJTRACK_OBJECT_LEAK, // OBJECT was not correctly freed/destroyed
OBJTRACK_OBJCOUNT_MAX_EXCEEDED, // Request for Object data in excess of max obj count
- OBJTRACK_INVALID_FENCE, // Requested status of unsubmitted fence object
OBJTRACK_INVALID_OBJECT, // Object used that has never been created
} OBJECT_TRACK_ERROR;
@@ -590,25 +589,6 @@
}
VkResult
-explicit_QueueSubmit(
- VkQueue queue,
- uint32_t cmdBufferCount,
- const VkCmdBuffer *pCmdBuffers,
- VkFence fence)
-{
- loader_platform_thread_lock_mutex(&objLock);
- set_status(queue, fence, VK_OBJECT_TYPE_FENCE, OBJSTATUS_FENCE_IS_SUBMITTED);
- // TODO: Fix for updated memory reference mechanism
- // validate_memory_mapping_status(pMemRefs, memRefCount);
- // validate_mem_ref_count(memRefCount);
- loader_platform_thread_unlock_mutex(&objLock);
-
- VkResult result = get_dispatch_table(ObjectTracker_device_table_map, queue)->QueueSubmit(queue, cmdBufferCount, pCmdBuffers, fence);
-
- return result;
-}
-
-VkResult
explicit_MapMemory(
VkDevice device,
VkDeviceMemory mem,
@@ -693,49 +673,6 @@
}
VkResult
-explicit_GetFenceStatus(
- VkDevice device,
- VkFence fence)
-{
- loader_platform_thread_lock_mutex(&objLock);
- // Warn if submitted_flag is not set
-#if 0
- validate_status(device, fence, VK_OBJECT_TYPE_FENCE, OBJSTATUS_FENCE_IS_SUBMITTED, OBJSTATUS_FENCE_IS_SUBMITTED,
- VK_DBG_REPORT_ERROR_BIT, OBJTRACK_INVALID_FENCE, "Status Requested for Unsubmitted Fence");
-#endif
- validate_object(device, device);
- loader_platform_thread_unlock_mutex(&objLock);
-
- VkResult result = get_dispatch_table(ObjectTracker_device_table_map, device)->GetFenceStatus(device, fence);
-
- return result;
-}
-
-VkResult
-explicit_WaitForFences(
- VkDevice device,
- uint32_t fenceCount,
- const VkFence *pFences,
- VkBool32 waitAll,
- uint64_t timeout)
-{
- loader_platform_thread_lock_mutex(&objLock);
-#if 0
- // Warn if waiting on unsubmitted fence
- for (uint32_t i = 0; i < fenceCount; i++) {
- validate_status(device, pFences[i], VK_OBJECT_TYPE_FENCE, OBJSTATUS_FENCE_IS_SUBMITTED, OBJSTATUS_FENCE_IS_SUBMITTED,
- VK_DBG_REPORT_ERROR_BIT, OBJTRACK_INVALID_FENCE, "Waiting for Unsubmitted Fence");
- }
-#endif
- validate_object(device, device);
- loader_platform_thread_unlock_mutex(&objLock);
-
- VkResult result = get_dispatch_table(ObjectTracker_device_table_map, device)->WaitForFences(device, fenceCount, pFences, waitAll, timeout);
-
- return result;
-}
-
-VkResult
explicit_AllocDescriptorSets(
VkDevice device,
VkDescriptorPool descriptorPool,
diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md
index 82f8a45..a297f14 100644
--- a/layers/vk_validation_layer_details.md
+++ b/layers/vk_validation_layer_details.md
@@ -136,7 +136,7 @@
| 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 |
-| Submitted Fence Status | Verifies that: The fence is not submitted in an already signaled state, and that ResetFences is not called with a fence in an unsignaled state | INVALID_FENCE_STATE | vkResetFences vkWaitForFences vkQueueSubmit | SubmitSignaledFence ResetUnsignaledFence | NA |
+| Submitted Fence Status | Verifies that: The fence is not submitted in an already signaled state, that ResetFences is not called with a fence in an unsignaled state, and that fences being checked have been submitted | INVALID_FENCE_STATE | vkResetFences vkWaitForFences vkQueueSubmit vkGetFenceStatus | SubmitSignaledFence ResetUnsignaledFence | Create test(s) for case where an unsubmitted fence is having its status checked |
| Immutable Memory Binding | Validates that non-sparse memory bindings are immutable, so objects are not re-boundt | REBIND_OBJECT | vkBindBufferMemory, vkBindImageMemory | RebindMemory | NA |
| Image/Buffer Usage bits | Verify correct USAGE bits set based on how Images and Buffers are used | INVALID_USAGE_FLAG | vkCreateImage, vkCreateBuffer, vkCreateBufferView, vkCmdCopyBuffer, vkCmdCopyImage, vkCmdBlitImage, vkCmdCopyBufferToImage, vkCmdCopyImageToBuffer, vkCmdUpdateBuffer, vkCmdFillBuffer | InvalidUsageBits | NA |
| Objects Not Destroyed Warning | Warns if any memory objects have not been freed before their objects are destroyed | MEM_OBJ_CLEAR_EMPTY_BINDINGS | vkDestroyDevice | TBD | NA |
@@ -202,7 +202,6 @@
| 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 |
-| Valid Fence for Wait | Flag error if waiting on unsubmitted fence object | INVALID_FENCE | vkGetFenceStatus | WaitForUnsubmittedFence | NA |
| Valid Destroy Object | Validates that an object pass into a destroy function was properly created and is currently valid | NONE | vkDestroyInstance vkDestroyDevice vkDestroyFence vkDestroySemaphore vkDestroyEvent vkDestroyQueryPool vkDestroyBuffer vkDestroyBufferView vkDestroyImage vkDestroyImageView vkDestroyShaderModule vkDestroyShader vkDestroyPipelineCache vkDestroyPipeline vkDestroyPipelineLayout vkDestroySampler vkDestroyDescriptorSetLayout vkDestroyDescriptorPool vkDestroyDynamicViewportState vkDestroyDynamicBlendState vkDestroyDynamicLineWidthState vkDestroyDynamicDepthBiasState vkDestroyDynamicDepthBoundsState vkDestroyDynamicStencilState vkDestroyCommandPool vkDestroyCommandBuffer vkDestroyFramebuffer vkDestroyRenderPass vkDestroySwapchainKHR | TBD | These cases need to be moved to a more appropriate error enum |
| Unknown object | Internal layer errors when it attempts to update use count for an object that's not in its internal tracking datastructures. | UNKNOWN_OBJECT | | NA | This may be irrelevant due to INVALID_OBJECT error, need to look closely and merge this with that error as appropriate. |
| NA | Enum used for informational messages | NONE | | NA | None |