bug 14848: Verifying Sparse Behavior (WIP)

Merge vkQueueBindSparse*() to one.

https://cvs.khronos.org/bugzilla/show_bug.cgi?id=14848
diff --git a/include/vk_layer.h b/include/vk_layer.h
index 76d3e36..8fc494f 100644
--- a/include/vk_layer.h
+++ b/include/vk_layer.h
@@ -47,9 +47,7 @@
     PFN_vkGetBufferMemoryRequirements GetBufferMemoryRequirements;
     PFN_vkBindImageMemory BindImageMemory;
     PFN_vkBindBufferMemory BindBufferMemory;
-    PFN_vkQueueBindSparseBufferMemory QueueBindSparseBufferMemory;
-    PFN_vkQueueBindSparseImageOpaqueMemory QueueBindSparseImageOpaqueMemory;
-    PFN_vkQueueBindSparseImageMemory QueueBindSparseImageMemory;
+    PFN_vkQueueBindSparse QueueBindSparse;
     PFN_vkCreateFence CreateFence;
     PFN_vkDestroyFence DestroyFence;
     PFN_vkGetFenceStatus GetFenceStatus;
diff --git a/include/vulkan.h b/include/vulkan.h
index a7f6140..740c9b6 100644
--- a/include/vulkan.h
+++ b/include/vulkan.h
@@ -182,9 +182,10 @@
     VK_STRUCTURE_TYPE_SUBMIT_INFO = 48,
     VK_STRUCTURE_TYPE_LAYER_INSTANCE_CREATE_INFO = 49,
     VK_STRUCTURE_TYPE_LAYER_DEVICE_CREATE_INFO = 50,
+    VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 51,
     VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
-    VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LAYER_DEVICE_CREATE_INFO,
-    VK_STRUCTURE_TYPE_NUM = (VK_STRUCTURE_TYPE_LAYER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
+    VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,
+    VK_STRUCTURE_TYPE_NUM = (VK_STRUCTURE_TYPE_BIND_SPARSE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
     VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
 } VkStructureType;
 
@@ -1395,7 +1396,19 @@
     VkDeviceSize                                memOffset;
     VkDeviceMemory                              mem;
     VkSparseMemoryBindFlags                     flags;
-} VkSparseMemoryBindInfo;
+} VkSparseMemoryBind;
+
+typedef struct {
+    VkBuffer                                    buffer;
+    uint32_t                                    bindCount;
+    const VkSparseMemoryBind*                   pBinds;
+} VkSparseBufferMemoryBindInfo;
+
+typedef struct {
+    VkImage                                     image;
+    uint32_t                                    bindCount;
+    const VkSparseMemoryBind*                   pBinds;
+} VkSparseImageOpaqueMemoryBindInfo;
 
 typedef struct {
     VkImageAspectFlagBits                       aspect;
@@ -1416,11 +1429,32 @@
     VkDeviceSize                                memOffset;
     VkDeviceMemory                              mem;
     VkSparseMemoryBindFlags                     flags;
+} VkSparseImageMemoryBind;
+
+typedef struct {
+    VkImage                                     image;
+    uint32_t                                    bindCount;
+    const VkSparseImageMemoryBind*              pBinds;
 } VkSparseImageMemoryBindInfo;
 
 typedef struct {
     VkStructureType                             sType;
     const void*                                 pNext;
+    uint32_t                                    waitSemaphoreCount;
+    const VkSemaphore*                          pWaitSemaphores;
+    uint32_t                                    bufferBindCount;
+    const VkSparseBufferMemoryBindInfo*         pBufferBinds;
+    uint32_t                                    imageOpaqueBindCount;
+    const VkSparseImageOpaqueMemoryBindInfo*    pImageOpaqueBinds;
+    uint32_t                                    imageBindCount;
+    const VkSparseImageMemoryBindInfo*          pImageBinds;
+    uint32_t                                    signalSemaphoreCount;
+    const VkSemaphore*                          pSignalSemaphores;
+} VkBindSparseInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
     VkFenceCreateFlags                          flags;
 } VkFenceCreateInfo;
 
@@ -2110,9 +2144,7 @@
 typedef void (VKAPI *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements);
 typedef void (VKAPI *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements);
 typedef void (VKAPI *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, uint32_t samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties);
-typedef VkResult (VKAPI *PFN_vkQueueBindSparseBufferMemory)(VkQueue queue, VkBuffer buffer, uint32_t bindInfoCount, const VkSparseMemoryBindInfo* pBindInfo);
-typedef VkResult (VKAPI *PFN_vkQueueBindSparseImageOpaqueMemory)(VkQueue queue, VkImage image, uint32_t bindInfoCount, const VkSparseMemoryBindInfo* pBindInfo);
-typedef VkResult (VKAPI *PFN_vkQueueBindSparseImageMemory)(VkQueue queue, VkImage image, uint32_t bindInfoCount, const VkSparseImageMemoryBindInfo* pBindInfo);
+typedef VkResult (VKAPI *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence);
 typedef VkResult (VKAPI *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocCallbacks* pAllocator, VkFence* pFence);
 typedef void (VKAPI *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocCallbacks* pAllocator);
 typedef VkResult (VKAPI *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences);
@@ -2396,23 +2428,11 @@
     uint32_t*                                   pPropertyCount,
     VkSparseImageFormatProperties*              pProperties);
 
-VkResult VKAPI vkQueueBindSparseBufferMemory(
+VkResult VKAPI vkQueueBindSparse(
     VkQueue                                     queue,
-    VkBuffer                                    buffer,
     uint32_t                                    bindInfoCount,
-    const VkSparseMemoryBindInfo*               pBindInfo);
-
-VkResult VKAPI vkQueueBindSparseImageOpaqueMemory(
-    VkQueue                                     queue,
-    VkImage                                     image,
-    uint32_t                                    bindInfoCount,
-    const VkSparseMemoryBindInfo*               pBindInfo);
-
-VkResult VKAPI vkQueueBindSparseImageMemory(
-    VkQueue                                     queue,
-    VkImage                                     image,
-    uint32_t                                    bindInfoCount,
-    const VkSparseImageMemoryBindInfo*          pBindInfo);
+    const VkBindSparseInfo*                     pBindInfo,
+    VkFence                                     fence);
 
 VkResult VKAPI vkCreateFence(
     VkDevice                                    device,
diff --git a/layers/mem_tracker.cpp b/layers/mem_tracker.cpp
index 644c17d..7860486 100644
--- a/layers/mem_tracker.cpp
+++ b/layers/mem_tracker.cpp
@@ -1372,61 +1372,53 @@
     my_data->device_dispatch_table->GetImageMemoryRequirements(device, image, pMemoryRequirements);
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseImageOpaqueMemory(
+VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparse(
     VkQueue                                     queue,
-    VkImage                                     image,
-    uint32_t                                    numBindings,
-    const VkSparseMemoryBindInfo*               pBindInfo)
+    uint32_t                                    bindInfoCount,
+    const VkBindSparseInfo*                     pBindInfo,
+    VkFence                                     fence)
 {
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
     VkResult result = VK_ERROR_VALIDATION_FAILED;
-    loader_platform_thread_lock_mutex(&globalLock);
-    // Track objects tied to memory
-    VkBool32 skipCall = set_sparse_mem_binding(my_data, queue, pBindInfo->mem, (uint64_t)image, VK_OBJECT_TYPE_IMAGE, "vkQueueBindSparseImageOpaqeMemory");
-    print_mem_list(my_data, queue);
-    loader_platform_thread_unlock_mutex(&globalLock);
-    if (VK_FALSE == skipCall) {
-        result = my_data->device_dispatch_table->QueueBindSparseImageOpaqueMemory( queue, image, numBindings, pBindInfo);
-    }
-    return result;
-}
+    VkBool32 skipCall = VK_FALSE;
 
-VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseImageMemory(
-    VkQueue                                     queue,
-    VkImage                                     image,
-    uint32_t                                    numBindings,
-    const VkSparseImageMemoryBindInfo*          pBindInfo)
-{
-    layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED;
     loader_platform_thread_lock_mutex(&globalLock);
-    // Track objects tied to memory
-    VkBool32 skipCall = set_sparse_mem_binding(my_data, queue, pBindInfo->mem, (uint64_t)image, VK_OBJECT_TYPE_IMAGE, "vkQueueBindSparseImageMemory");
-    print_mem_list(my_data, queue);
-    loader_platform_thread_unlock_mutex(&globalLock);
-    if (VK_FALSE == skipCall) {
-        VkResult result = my_data->device_dispatch_table->QueueBindSparseImageMemory(
-                              queue, image, numBindings, pBindInfo);
-    }
-    return result;
-}
 
-VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseBufferMemory(
-    VkQueue                       queue,
-    VkBuffer                      buffer,
-    uint32_t                      numBindings,
-    const VkSparseMemoryBindInfo* pBindInfo)
-{
-    layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED;
-    loader_platform_thread_lock_mutex(&globalLock);
-    // Track objects tied to memory
-    VkBool32 skipCall = set_sparse_mem_binding(my_data, queue, pBindInfo->mem, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER, "VkQueueBindSparseBufferMemory");
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        // Track objects tied to memory
+        for (uint32_t j = 0; j < pBindInfo[i].bufferBindCount; j++) {
+            for (uint32_t k = 0; k < pBindInfo[i].pBufferBinds[j].bindCount; k++) {
+                if (set_sparse_mem_binding(my_data, queue,
+                            pBindInfo[i].pBufferBinds[j].pBinds[k].mem,
+                            (uint64_t) pBindInfo[i].pBufferBinds[j].buffer,
+                            VK_OBJECT_TYPE_BUFFER, "vkQueueBindSparse"))
+                    skipCall = VK_TRUE;
+            }
+        }
+        for (uint32_t j = 0; j < pBindInfo[i].imageOpaqueBindCount; j++) {
+            for (uint32_t k = 0; k < pBindInfo[i].pImageOpaqueBinds[j].bindCount; k++) {
+                if (set_sparse_mem_binding(my_data, queue,
+                            pBindInfo[i].pImageOpaqueBinds[j].pBinds[k].mem,
+                            (uint64_t) pBindInfo[i].pImageOpaqueBinds[j].image,
+                            VK_OBJECT_TYPE_IMAGE, "vkQueueBindSparse"))
+                    skipCall = VK_TRUE;
+            }
+        }
+        for (uint32_t j = 0; j < pBindInfo[i].imageBindCount; j++) {
+            for (uint32_t k = 0; k < pBindInfo[i].pImageBinds[j].bindCount; k++) {
+                if (set_sparse_mem_binding(my_data, queue,
+                            pBindInfo[i].pImageBinds[j].pBinds[k].mem,
+                            (uint64_t) pBindInfo[i].pImageBinds[j].image,
+                            VK_OBJECT_TYPE_IMAGE, "vkQueueBindSparse"))
+                    skipCall = VK_TRUE;
+            }
+        }
+    }
+
     print_mem_list(my_data, queue);
     loader_platform_thread_unlock_mutex(&globalLock);
     if (VK_FALSE == skipCall) {
-        VkResult result = my_data->device_dispatch_table->QueueBindSparseBufferMemory(
-                              queue, buffer, numBindings, pBindInfo);
+        result = my_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
     }
     return result;
 }
@@ -2513,12 +2505,8 @@
         return (PFN_vkVoidFunction) vkGetBufferMemoryRequirements;
     if (!strcmp(funcName, "vkGetImageMemoryRequirements"))
         return (PFN_vkVoidFunction) vkGetImageMemoryRequirements;
-    if (!strcmp(funcName, "vkQueueBindSparseBufferMemory"))
-        return (PFN_vkVoidFunction) vkQueueBindSparseBufferMemory;
-    if (!strcmp(funcName, "vkQueueBindSparseImageOpaqueMemory"))
-        return (PFN_vkVoidFunction) vkQueueBindSparseImageOpaqueMemory;
-    if (!strcmp(funcName, "vkQueueBindSparseImageMemory"))
-        return (PFN_vkVoidFunction) vkQueueBindSparseImageMemory;
+    if (!strcmp(funcName, "vkQueueBindSparse"))
+        return (PFN_vkVoidFunction) vkQueueBindSparse;
     if (!strcmp(funcName, "vkCreateFence"))
         return (PFN_vkVoidFunction) vkCreateFence;
     if (!strcmp(funcName, "vkGetFenceStatus"))
diff --git a/layers/object_track.h b/layers/object_track.h
index ed611e9..a1e4a44 100644
--- a/layers/object_track.h
+++ b/layers/object_track.h
@@ -773,48 +773,27 @@
 }
 
 VkResult
-explicit_QueueBindSparseBufferMemory(
+explicit_QueueBindSparse(
     VkQueue                       queue,
-    VkBuffer                      buffer,
-    uint32_t                      numBindings,
-    const VkSparseMemoryBindInfo* pBindInfo)
+    uint32_t                                    bindInfoCount,
+    const VkBindSparseInfo*                     pBindInfo,
+    VkFence                                     fence)
 {
     loader_platform_thread_lock_mutex(&objLock);
-    validateQueueFlags(queue, "QueueBindSparseBufferMemory");
-    validate_object(queue, buffer);
+    validateQueueFlags(queue, "QueueBindSparse");
+
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        for (uint32_t j = 0; j < pBindInfo[i].bufferBindCount; j++)
+            validate_object(queue, pBindInfo[i].pBufferBinds[j].buffer);
+        for (uint32_t j = 0; j < pBindInfo[i].imageOpaqueBindCount; j++)
+            validate_object(queue, pBindInfo[i].pImageOpaqueBinds[j].image);
+        for (uint32_t j = 0; j < pBindInfo[i].imageBindCount; j++)
+            validate_object(queue, pBindInfo[i].pImageBinds[j].image);
+    }
+
     loader_platform_thread_unlock_mutex(&objLock);
 
-    VkResult result = get_dispatch_table(ObjectTracker_device_table_map, queue)->QueueBindSparseBufferMemory(queue, buffer, numBindings, pBindInfo);
-    return result;
-}
-
-VkResult
-explicit_QueueBindSparseImageMemory(
-    VkQueue                            queue,
-    VkImage                            image,
-    uint32_t                           numBindings,
-    const VkSparseImageMemoryBindInfo* pBindInfo)
-{
-    loader_platform_thread_lock_mutex(&objLock);
-    validateQueueFlags(queue, "QueueBindSparseImageMemory");
-    loader_platform_thread_unlock_mutex(&objLock);
-
-    VkResult result = get_dispatch_table(ObjectTracker_device_table_map, queue)->QueueBindSparseImageMemory(queue, image, numBindings, pBindInfo);
-    return result;
-}
-
-VkResult
-explicit_QueueBindSparseImageOpaqueMemory(
-    VkQueue                            queue,
-    VkImage                            image,
-    uint32_t                           numBindings,
-    const VkSparseMemoryBindInfo* pBindInfo)
-{
-    loader_platform_thread_lock_mutex(&objLock);
-    validateQueueFlags(queue, "QueueBindSparseImageOpaqueMemory");
-    loader_platform_thread_unlock_mutex(&objLock);
-
-    VkResult result = get_dispatch_table(ObjectTracker_device_table_map, queue)->QueueBindSparseImageOpaqueMemory(queue, image, numBindings, pBindInfo);
+    VkResult result = get_dispatch_table(ObjectTracker_device_table_map, queue)->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
     return result;
 }
 
diff --git a/layers/param_checker.cpp b/layers/param_checker.cpp
index d407c16..2849efb 100644
--- a/layers/param_checker.cpp
+++ b/layers/param_checker.cpp
@@ -2693,9 +2693,10 @@
     PostGetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
 }
 
-bool PreQueueBindSparseBufferMemory(
+bool PreQueueBindSparse(
     VkQueue queue,
-    const VkSparseMemoryBindInfo* pBindInfo)
+    uint32_t                                    bindInfoCount,
+    const VkBindSparseInfo*                     pBindInfo)
 {
     if(pBindInfo != nullptr)
     {
@@ -2704,10 +2705,11 @@
     return true;
 }
 
-bool PostQueueBindSparseBufferMemory(
+bool PostQueueBindSparse(
     VkQueue queue,
-    VkBuffer buffer,
-    uint32_t numBindings,
+    uint32_t bindInfoCount,
+    const VkBindSparseInfo* pBindInfo,
+    VkFence fence,
     VkResult result)
 {
 
@@ -2715,7 +2717,7 @@
 
     if(result < VK_SUCCESS)
     {
-        std::string reason = "vkQueueBindSparseBufferMemory parameter, VkResult result, is " + EnumeratorString(result);
+        std::string reason = "vkQueueBindSparse parameter, VkResult result, is " + EnumeratorString(result);
         log_msg(mdd(queue), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, 1, "PARAMCHECK", reason.c_str());
         return false;
     }
@@ -2723,114 +2725,17 @@
     return true;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseBufferMemory(
+VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparse(
     VkQueue queue,
-    VkBuffer buffer,
-    uint32_t numBindings,
-    const VkSparseMemoryBindInfo* pBindInfo)
+    uint32_t bindInfoCount,
+    const VkBindSparseInfo* pBindInfo,
+    VkFence fence)
 {
-    PreQueueBindSparseBufferMemory(queue, pBindInfo);
+    PreQueueBindSparse(queue, bindInfoCount, pBindInfo);
 
-    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparseBufferMemory(queue, buffer, numBindings, pBindInfo);
+    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
 
-    PostQueueBindSparseBufferMemory(queue, buffer, numBindings, result);
-
-    return result;
-}
-
-bool PreQueueBindSparseImageOpaqueMemory(
-    VkQueue queue,
-    const VkSparseMemoryBindInfo* pBindInfo)
-{
-    if(pBindInfo != nullptr)
-    {
-    }
-
-    return true;
-}
-
-bool PostQueueBindSparseImageOpaqueMemory(
-    VkQueue queue,
-    VkImage image,
-    uint32_t numBindings,
-    VkResult result)
-{
-
-
-
-    if(result < VK_SUCCESS)
-    {
-        std::string reason = "vkQueueBindSparseImageOpaqueMemory parameter, VkResult result, is " + EnumeratorString(result);
-        log_msg(mdd(queue), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, 1, "PARAMCHECK", reason.c_str());
-        return false;
-    }
-
-    return true;
-}
-
-VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseImageOpaqueMemory(
-    VkQueue queue,
-    VkImage image,
-    uint32_t numBindings,
-    const VkSparseMemoryBindInfo* pBindInfo)
-{
-    PreQueueBindSparseImageOpaqueMemory(queue, pBindInfo);
-
-    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparseImageOpaqueMemory(queue, image, numBindings, pBindInfo);
-
-    PostQueueBindSparseImageOpaqueMemory(queue, image, numBindings, result);
-
-    return result;
-}
-
-bool PreQueueBindSparseImageMemory(
-    VkQueue queue,
-    const VkSparseImageMemoryBindInfo* pBindInfo)
-{
-    if(pBindInfo != nullptr)
-    {
-    if ((pBindInfo->subresource.aspect &
-       (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0)
-    {
-        log_msg(mdd(queue), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, 1, "PARAMCHECK",
-        "vkQueueBindSparseImageMemory parameter, VkImageAspect pBindInfo->subresource.aspect, is an unrecognized enumerator");
-        return false;
-    }
-    }
-
-    return true;
-}
-
-bool PostQueueBindSparseImageMemory(
-    VkQueue queue,
-    VkImage image,
-    uint32_t numBindings,
-    VkResult result)
-{
-
-
-
-    if(result < VK_SUCCESS)
-    {
-        std::string reason = "vkQueueBindSparseImageMemory parameter, VkResult result, is " + EnumeratorString(result);
-        log_msg(mdd(queue), VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, 1, "PARAMCHECK", reason.c_str());
-        return false;
-    }
-
-    return true;
-}
-
-VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseImageMemory(
-    VkQueue queue,
-    VkImage image,
-    uint32_t numBindings,
-    const VkSparseImageMemoryBindInfo* pBindInfo)
-{
-    PreQueueBindSparseImageMemory(queue, pBindInfo);
-
-    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparseImageMemory(queue, image, numBindings, pBindInfo);
-
-    PostQueueBindSparseImageMemory(queue, image, numBindings, result);
+    PostQueueBindSparse(queue, bindInfoCount, pBindInfo, fence, result);
 
     return result;
 }
diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md
index f958c90..bbeb0fa 100644
--- a/layers/vk_validation_layer_details.md
+++ b/layers/vk_validation_layer_details.md
@@ -99,8 +99,8 @@
 
 | Check | Overview | ENUM | Relevant API | Testname | Notes/TODO |
 | ----- | -------- | ---------------- | ------------ | -------- | ---------- |
-| Input Parameters | Pointers in structures are recursively validated to be non-null. Enumerated types are validated against min and max enum values. Structure Types are verified to be correct. | NA | vkQueueSubmit vkAllocMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkQueueBindSparseBufferMemory vkQueueBindSparseImageOpaqueMemory vkQueueBindSparseImageMemory vkCreateFence vkResetFences vkWaitForFences vkCreateSemaphore vkCreateEvent vkCreateQueryPool vkCreateBuffer vkCreateBufferView vkCreateImage vkGetImageSubresourceLayout vkCreateImageView vkCreateShader vkCreatePipelineCache vkMergePipelineCaches vkCreateGraphicsPipelines vkCreateComputePipelines vkCreatePipelineLayout vkCreateSampler vkCreateDescriptorSetLayout( vkCreateDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkUpdateDescriptorSets vkCreateFramebuffer vkCreateRenderPass vkCreateCommandPool vkAllocCommandBuffers vkBeginCommandBuffer vkCmdBindDescriptorSets vkCmdBindVertexBuffers vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdWaitEvents vkCmdPipelineBarrier vkCmdPushConstants vkCmdBeginRenderPass vkCmdExecuteCommands | TBD | NA |
-| Call results, Output Parameters | Return values are checked for VK_SUCCESS, returned pointers are checked to be NON-NULL, enumerated types of return values are checked to be within the defined range. | NA | vkEnumeratePhysicalDevices vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceLimits vkGetPhysicalDeviceProperties vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceMemoryProperties vkGetDeviceQueue vkQueueSubmit vkQueueWaitIdle vkDeviceWaitIdle vkAllocMemory vkFreeMemory vkMapMemory vkUnmapMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkGetDeviceMemoryCommitment vkBindBufferMemory vkBindImageMemory vkGetBufferMemoryRequirements vkGetImageMemoryRequirements vkGetImageSparseMemoryRequirements vkGetPhysicalDeviceSparseImageFormatProperties vkQueueBindSparseBufferMemory vkQueueBindSparseImageOpaqueMemory vkQueueBindSparseImageMemory vkCreateFence vkDestroyFence vkResetFences vkGetFenceStatus vkWaitForFences vkCreateSemaphore vkDestroySemaphore vkCreateEvent vkDestroyEvent vkGetEventStatus vkSetEvent vkResetEvent vkCreateQueryPool vkDestroyQueryPool vkGetQueryPoolResults vkCreateBuffer vkDestroyBuffer vkCreateBufferView vkDestroyBufferView vkCreateImage vkDestroyImage vkGetImageSubresourceLayout vkCreateImageView vkDestroyImageView vkDestroyShaderModule vkCreateShader vkDestroyShader vkCreatePipelineCache vkDestroyPipelineCache vkGetPipelineCacheData vkMergePipelineCaches vkCreateGraphicsPipelines vkCreateComputePipelines vkDestroyPipeline vkCreatePipelineLayout vkDestroyPipelineLayout vkCreateSampler vkDestroySampler vkCreateDescriptorSetLayout vkDestroyDescriptorSetLayout vkCreateDescriptorPool vkDestroyDescriptorPool vkResetDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkUpdateDescriptorSets vkCreateFramebuffer vkDestroyFramebuffer vkCreateRenderPass vkDestroyRenderPass vkGetRenderAreaGranularity vkCreateCommandPool vkDestroyCommandPool vkResetCommandPool vkAllocCommandBuffers vkFreeCommandBuffers vkBeginCommandBuffer vkEndCommandBuffer vkResetCommandBuffer vkCmdBindPipeline vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdCopyQueryPoolResults vkCmdPushConstants vkCmdBeginRenderPass vkCmdNextSubpass vkCmdEndRenderPass vkCmdExecuteCommands | TBD | NA |
+| Input Parameters | Pointers in structures are recursively validated to be non-null. Enumerated types are validated against min and max enum values. Structure Types are verified to be correct. | NA | vkQueueSubmit vkAllocMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkQueueBindSparse vkCreateFence vkResetFences vkWaitForFences vkCreateSemaphore vkCreateEvent vkCreateQueryPool vkCreateBuffer vkCreateBufferView vkCreateImage vkGetImageSubresourceLayout vkCreateImageView vkCreateShader vkCreatePipelineCache vkMergePipelineCaches vkCreateGraphicsPipelines vkCreateComputePipelines vkCreatePipelineLayout vkCreateSampler vkCreateDescriptorSetLayout( vkCreateDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkUpdateDescriptorSets vkCreateFramebuffer vkCreateRenderPass vkCreateCommandPool vkAllocCommandBuffers vkBeginCommandBuffer vkCmdBindDescriptorSets vkCmdBindVertexBuffers vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdWaitEvents vkCmdPipelineBarrier vkCmdPushConstants vkCmdBeginRenderPass vkCmdExecuteCommands | TBD | NA |
+| Call results, Output Parameters | Return values are checked for VK_SUCCESS, returned pointers are checked to be NON-NULL, enumerated types of return values are checked to be within the defined range. | NA | vkEnumeratePhysicalDevices vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceLimits vkGetPhysicalDeviceProperties vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceMemoryProperties vkGetDeviceQueue vkQueueSubmit vkQueueWaitIdle vkDeviceWaitIdle vkAllocMemory vkFreeMemory vkMapMemory vkUnmapMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkGetDeviceMemoryCommitment vkBindBufferMemory vkBindImageMemory vkGetBufferMemoryRequirements vkGetImageMemoryRequirements vkGetImageSparseMemoryRequirements vkGetPhysicalDeviceSparseImageFormatProperties vkQueueBindSparse vkCreateFence vkDestroyFence vkResetFences vkGetFenceStatus vkWaitForFences vkCreateSemaphore vkDestroySemaphore vkCreateEvent vkDestroyEvent vkGetEventStatus vkSetEvent vkResetEvent vkCreateQueryPool vkDestroyQueryPool vkGetQueryPoolResults vkCreateBuffer vkDestroyBuffer vkCreateBufferView vkDestroyBufferView vkCreateImage vkDestroyImage vkGetImageSubresourceLayout vkCreateImageView vkDestroyImageView vkDestroyShaderModule vkCreateShader vkDestroyShader vkCreatePipelineCache vkDestroyPipelineCache vkGetPipelineCacheData vkMergePipelineCaches vkCreateGraphicsPipelines vkCreateComputePipelines vkDestroyPipeline vkCreatePipelineLayout vkDestroyPipelineLayout vkCreateSampler vkDestroySampler vkCreateDescriptorSetLayout vkDestroyDescriptorSetLayout vkCreateDescriptorPool vkDestroyDescriptorPool vkResetDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkUpdateDescriptorSets vkCreateFramebuffer vkDestroyFramebuffer vkCreateRenderPass vkDestroyRenderPass vkGetRenderAreaGranularity vkCreateCommandPool vkDestroyCommandPool vkResetCommandPool vkAllocCommandBuffers vkFreeCommandBuffers vkBeginCommandBuffer vkEndCommandBuffer vkResetCommandBuffer vkCmdBindPipeline vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdCopyQueryPoolResults vkCmdPushConstants vkCmdBeginRenderPass vkCmdNextSubpass vkCmdEndRenderPass vkCmdExecuteCommands | TBD | NA |
 | NA | Enum used for informational messages | NONE | | NA | None |
 
 ### ParamChecker Pending Work
@@ -155,11 +155,11 @@
 | Check | Overview | ENUM MEMTRACK_* | Relevant API | Testname | Notes/TODO |
 | ----- | -------- | ---------------- | ------------ | -------- | ---------- |
 | Valid Command Buffer | Verifies that the command buffer was properly created and is currently valid | INVALID_CB | vkCmdBindPipeline vkCmdSetViewport vkCmdSetLineWidth vkCmdSetDepthBias vkCmdSetBlendConstants vkCmdSetDepthBounds vkCmdSetStencilCompareMask vkCmdSetStencilWriteMask vkCmdSetStencilReference vkBeginCommandBuffer vkResetCommandBuffer vkDestroyDevice vkFreeMemory | NA | NA |
-| Valid Memory Object | Verifies that the memory object was properly created and is currently valid | INVALID_MEM_OBJ | vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage vkFreeMemory vkBindBufferMemory vkBindImageMemory vkQueueBindSparseImageOpaqueMemory vkQueueBindSparseImageMemory vkQueueBindSparseBufferMemory | NA | NA |
+| Valid Memory Object | Verifies that the memory object was properly created and is currently valid | INVALID_MEM_OBJ | vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage vkFreeMemory vkBindBufferMemory vkBindImageMemory vkQueueBindSparse | NA | NA |
 | 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 vkCmdCopyQueryPoolResults 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 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 | 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 | 
+| 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 | vkQueueBindSparse 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 |
@@ -226,7 +226,7 @@
 
 | 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 vkCmdBindIndexBuffer vkCmdBindPipeline vkCmdBindVertexBuffers vkCmdBlitImage vkCmdClearAttachments vkCmdClearColorImage 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 vkAllocCommandBuffers vkCreateCommandPool vkCreateComputePipelines vkCreateDescriptorPool vkCreateDescriptorSetLayout vkCreateEvent vkCreateFence vkCreateFramebuffer vkCreateGraphicsPipelines vkCreateImage vkCreateImageView vkCreatePipelineCache vkCreatePipelineLayout vkCreateQueryPool vkCreateRenderPass vkCreateSampler vkCreateSemaphore vkCreateShader vkCreateShaderModule vkCreateSwapchainKHR vkDestroyBuffer vkDestroyBufferView vkFreeCommandBuffers vkDestroyCommandPool vkDestroyDescriptorPool vkDestroyDescriptorSetLayout 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 vkGetQueryPoolResults vkGetRenderAreaGranularity vkInvalidateMappedMemoryRanges vkMapMemory vkMergePipelineCaches vkQueueBindSparseBufferMemory 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 |
+| Valid Object | Validates that referenced object was properly created and is currently valid. | INVALID_OBJECT | vkAcquireNextImageKHR vkAllocDescriptorSets vkAllocMemory vkBeginCommandBuffer vkBindBufferMemory vkBindImageMemory vkCmdBeginQuery vkCmdBeginRenderPass vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindPipeline vkCmdBindVertexBuffers vkCmdBlitImage vkCmdClearAttachments vkCmdClearColorImage 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 vkAllocCommandBuffers vkCreateCommandPool vkCreateComputePipelines vkCreateDescriptorPool vkCreateDescriptorSetLayout vkCreateEvent vkCreateFence vkCreateFramebuffer vkCreateGraphicsPipelines vkCreateImage vkCreateImageView vkCreatePipelineCache vkCreatePipelineLayout vkCreateQueryPool vkCreateRenderPass vkCreateSampler vkCreateSemaphore vkCreateShader vkCreateShaderModule vkCreateSwapchainKHR vkDestroyBuffer vkDestroyBufferView vkFreeCommandBuffers vkDestroyCommandPool vkDestroyDescriptorPool vkDestroyDescriptorSetLayout 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 vkGetQueryPoolResults vkGetRenderAreaGranularity vkInvalidateMappedMemoryRanges vkMapMemory vkMergePipelineCaches vkQueueBindSparse 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 |
@@ -273,8 +273,8 @@
 
 | Check | Overview | ENUM THREADING_CHECKER_* | Relevant API | Testname | Notes/TODO |
 | ----- | -------- | ---------------- | ---------------- | -------- | ---------- |
-| Thread Collision | Detects and notifies user if multiple threads are modifying thes same object | MULTIPLE_THREADS | vkQueueSubmit vkFreeMemory vkMapMemory vkUnmapMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkBindBufferMemory vkBindImageMemory vkQueueBindSparseBufferMemory vkQueueBindSparseImageOpaqueMemory vkQueueBindSparseImageMemory vkDestroySemaphore vkDestroyBuffer vkDestroyImage vkDestroyDescriptorPool vkResetDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkFreeCommandBuffers vkBeginCommandBuffer vkEndCommandBuffer vkResetCommandBuffer vkCmdBindPipeline vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdCopyQueryPoolResults vkCmdBeginRenderPass vkCmdNextSubpass vkCmdPushConstants vkCmdEndRenderPass vkCmdExecuteCommands | ??? | NA |
-| Thread Reentrancy | Detects cases of a single thread calling Vulkan reentrantly | SINGLE_THREAD_REUSE | vkQueueSubmit vkFreeMemory vkMapMemory vkUnmapMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkBindBufferMemory vkBindImageMemory vkQueueBindSparseBufferMemory vkQueueBindSparseImageOpaqueMemory vkQueueBindSparseImageMemory vkDestroySemaphore vkDestroyBuffer vkDestroyImage vkDestroyDescriptorPool vkResetDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkFreeCommandBuffers vkBeginCommandBuffer vkEndCommandBuffer vkResetCommandBuffer vkCmdBindPipeline vkCmdSetViewport vkCmdSetBlendConstants vkCmdSetLineWidth vkCmdSetDepthBias vkCmdSetDepthBounds vkCmdSetStencilCompareMask vkCmdSetStencilWriteMask vkCmdSetStencilReference vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdCopyQueryPoolResults vkCmdBeginRenderPass vkCmdNextSubpass vkCmdPushConstants vkCmdEndRenderPass vkCmdExecuteCommands | ??? | NA |
+| Thread Collision | Detects and notifies user if multiple threads are modifying thes same object | MULTIPLE_THREADS | vkQueueSubmit vkFreeMemory vkMapMemory vkUnmapMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkBindBufferMemory vkBindImageMemory vkQueueBindSparse vkDestroySemaphore vkDestroyBuffer vkDestroyImage vkDestroyDescriptorPool vkResetDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkFreeCommandBuffers vkBeginCommandBuffer vkEndCommandBuffer vkResetCommandBuffer vkCmdBindPipeline vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdCopyQueryPoolResults vkCmdBeginRenderPass vkCmdNextSubpass vkCmdPushConstants vkCmdEndRenderPass vkCmdExecuteCommands | ??? | NA |
+| Thread Reentrancy | Detects cases of a single thread calling Vulkan reentrantly | SINGLE_THREAD_REUSE | vkQueueSubmit vkFreeMemory vkMapMemory vkUnmapMemory vkFlushMappedMemoryRanges vkInvalidateMappedMemoryRanges vkBindBufferMemory vkBindImageMemory vkQueueBindSparse vkDestroySemaphore vkDestroyBuffer vkDestroyImage vkDestroyDescriptorPool vkResetDescriptorPool vkAllocDescriptorSets vkFreeDescriptorSets vkFreeCommandBuffers vkBeginCommandBuffer vkEndCommandBuffer vkResetCommandBuffer vkCmdBindPipeline vkCmdSetViewport vkCmdSetBlendConstants vkCmdSetLineWidth vkCmdSetDepthBias vkCmdSetDepthBounds vkCmdSetStencilCompareMask vkCmdSetStencilWriteMask vkCmdSetStencilReference vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdClearAttachments vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdCopyQueryPoolResults vkCmdBeginRenderPass vkCmdNextSubpass vkCmdPushConstants vkCmdEndRenderPass vkCmdExecuteCommands | ??? | NA |
 | NA | Enum used for informational messages | NONE | | NA | None |
 
 ### Threading Pending Work
diff --git a/loader/gpa_helper.h b/loader/gpa_helper.h
index c9673f0..f572c36 100644
--- a/loader/gpa_helper.h
+++ b/loader/gpa_helper.h
@@ -99,12 +99,8 @@
         return (void*) vkGetImageSparseMemoryRequirements;
     if (!strcmp(name, "GetPhysicalDeviceSparseImageFormatProperties"))
         return (void*) vkGetPhysicalDeviceSparseImageFormatProperties;
-    if (!strcmp(name, "QueueBindSparseBufferMemory"))
-        return (void*) vkQueueBindSparseBufferMemory;
-    if (!strcmp(name, "QueueBindSparseImageOpaqueMemory"))
-        return (void*) vkQueueBindSparseImageOpaqueMemory;
-    if (!strcmp(name, "QueueBindSparseImageMemory"))
-        return (void*) vkQueueBindSparseImageMemory;
+    if (!strcmp(name, "QueueBindSparse"))
+        return (void*) vkQueueBindSparse;
     if (!strcmp(name, "CreateFence"))
         return (void*) vkCreateFence;
     if (!strcmp(name, "DestroyFence"))
diff --git a/loader/table_ops.h b/loader/table_ops.h
index 6f135c7..d4a167e 100644
--- a/loader/table_ops.h
+++ b/loader/table_ops.h
@@ -55,9 +55,7 @@
     table->GetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements) gpa(dev, "vkGetImageMemoryRequirements");
     table->BindBufferMemory = (PFN_vkBindBufferMemory) gpa(dev, "vkBindBufferMemory");
     table->BindImageMemory = (PFN_vkBindImageMemory) gpa(dev, "vkBindImageMemory");
-    table->QueueBindSparseBufferMemory = (PFN_vkQueueBindSparseBufferMemory) gpa(dev, "vkQueueBindSparseBufferMemory");
-    table->QueueBindSparseImageMemory = (PFN_vkQueueBindSparseImageMemory) gpa(dev, "vkQueueBindSparseImageMemory");
-    table->QueueBindSparseImageOpaqueMemory = (PFN_vkQueueBindSparseImageOpaqueMemory) gpa(dev, "vkQueueBindSparseImageOpaqueMemory");
+    table->QueueBindSparse = (PFN_vkQueueBindSparse) gpa(dev, "vkQueueBindSparse");
     table->CreateFence = (PFN_vkCreateFence) gpa(dev, "vkCreateFence");
     table->DestroyFence = (PFN_vkDestroyFence) gpa(dev, "vkDestroyFence");
     table->ResetFences = (PFN_vkResetFences) gpa(dev, "vkResetFences");
@@ -221,12 +219,8 @@
         return (void *) table->BindBufferMemory;
     if (!strcmp(name, "BindImageMemory"))
         return (void *) table->BindImageMemory;
-    if (!strcmp(name, "QueueBindSparseBufferMemory"))
-        return (void *) table->QueueBindSparseBufferMemory;
-    if (!strcmp(name, "QueueBindSparseImageMemory"))
-        return (void *) table->QueueBindSparseImageMemory;
-    if (!strcmp(name, "QueueBindSparseImageOpaqueMemory"))
-        return (void *) table->QueueBindSparseImageOpaqueMemory;
+    if (!strcmp(name, "QueueBindSparse"))
+        return (void *) table->QueueBindSparse;
     if (!strcmp(name, "CreateFence"))
         return (void *) table->CreateFence;
     if (!strcmp(name, "DestroyFence"))
diff --git a/loader/trampoline.c b/loader/trampoline.c
index 4613630..ecf7f17 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -483,31 +483,13 @@
     disp->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pPropertyCount, pProperties);
 }
 
-LOADER_EXPORT VkResult VKAPI vkQueueBindSparseBufferMemory(VkQueue queue, VkBuffer buffer, uint32_t bindInfoCount, const VkSparseMemoryBindInfo* pBindInfo)
+LOADER_EXPORT VkResult VKAPI vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(queue);
 
-    return disp->QueueBindSparseBufferMemory(queue, buffer, bindInfoCount, pBindInfo);
-}
-
-LOADER_EXPORT VkResult VKAPI vkQueueBindSparseImageOpaqueMemory(VkQueue queue, VkImage image, uint32_t bindInfoCount, const VkSparseMemoryBindInfo* pBindInfo)
-{
-    const VkLayerDispatchTable *disp;
-
-    disp = loader_get_dispatch(queue);
-
-    return disp->QueueBindSparseImageOpaqueMemory(queue, image, bindInfoCount, pBindInfo);
-}
-
-LOADER_EXPORT VkResult VKAPI vkQueueBindSparseImageMemory(VkQueue queue, VkImage image, uint32_t bindInfoCount, const VkSparseImageMemoryBindInfo* pBindInfo)
-{
-    const VkLayerDispatchTable *disp;
-
-    disp = loader_get_dispatch(queue);
-
-    return disp->QueueBindSparseImageMemory(queue, image, bindInfoCount, pBindInfo);
+    return disp->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
 }
 
 LOADER_EXPORT VkResult VKAPI vkCreateFence(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocCallbacks* pAllocator, VkFence* pFence)
diff --git a/vk-layer-generate.py b/vk-layer-generate.py
index 65b737a..13a1510 100755
--- a/vk-layer-generate.py
+++ b/vk-layer-generate.py
@@ -1489,8 +1489,7 @@
             "GetPhysicalDeviceQueueFamilyProperties",
             "CreateDevice",
             "GetDeviceQueue",
-            "QueueBindSparseImageMemory",
-            "QueueBindSparseBufferMemory",
+            "QueueBindSparse",
             "AllocDescriptorSets",
             "FreeDescriptorSets",
             "MapMemory",
diff --git a/vulkan.py b/vulkan.py
index ea7a650..84f4b5a 100755
--- a/vulkan.py
+++ b/vulkan.py
@@ -388,23 +388,11 @@
              Param("uint32_t*", "pPropertyCount"),
              Param("VkSparseImageFormatProperties*", "pProperties")]),
 
-        Proto("VkResult", "QueueBindSparseBufferMemory",
+        Proto("VkResult", "QueueBindSparse",
             [Param("VkQueue", "queue"),
-             Param("VkBuffer", "buffer"),
              Param("uint32_t", "bindInfoCount"),
-             Param("const VkSparseMemoryBindInfo*", "pBindInfo")]),
-
-        Proto("VkResult", "QueueBindSparseImageOpaqueMemory",
-            [Param("VkQueue", "queue"),
-             Param("VkImage", "image"),
-             Param("uint32_t", "bindInfoCount"),
-             Param("const VkSparseMemoryBindInfo*", "pBindInfo")]),
-
-        Proto("VkResult", "QueueBindSparseImageMemory",
-            [Param("VkQueue", "queue"),
-             Param("VkImage", "image"),
-             Param("uint32_t", "bindInfoCount"),
-             Param("const VkSparseImageMemoryBindInfo*", "pBindInfo")]),
+             Param("const VkBindSparseInfo*", "pBindInfo"),
+             Param("VkFence", "fence")]),
 
         Proto("VkResult", "CreateFence",
             [Param("VkDevice", "device"),