vulkan.h: V136 -- Vulkan Sparse Resource Issues

Totally reworked sparse resources.  This commit also incorporates the
changes for bug 14237.
diff --git a/include/vk_layer.h b/include/vk_layer.h
index 98a636b..c2c5465 100644
--- a/include/vk_layer.h
+++ b/include/vk_layer.h
@@ -43,7 +43,9 @@
     PFN_vkDestroyObject DestroyObject;
     PFN_vkGetObjectMemoryRequirements GetObjectMemoryRequirements;
     PFN_vkBindObjectMemory BindObjectMemory;
+    PFN_vkGetImageSparseMemoryRequirements GetImageSparseMemoryRequirements;
     PFN_vkQueueBindSparseBufferMemory QueueBindSparseBufferMemory;
+    PFN_vkQueueBindSparseImageOpaqueMemory QueueBindSparseImageOpaqueMemory;
     PFN_vkQueueBindSparseImageMemory QueueBindSparseImageMemory;
     PFN_vkCreateFence CreateFence;
     PFN_vkGetFenceStatus GetFenceStatus;
@@ -145,6 +147,7 @@
     PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures;
     PFN_vkGetPhysicalDeviceFormatInfo GetPhysicalDeviceFormatInfo;
     PFN_vkGetPhysicalDeviceLimits GetPhysicalDeviceLimits;
+    PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
     PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
     PFN_vkGetPhysicalDevicePerformance GetPhysicalDevicePerformance;
     PFN_vkGetPhysicalDeviceQueueCount GetPhysicalDeviceQueueCount;
diff --git a/include/vulkan.h b/include/vulkan.h
index 3856792..9f3a8c4 100644
--- a/include/vulkan.h
+++ b/include/vulkan.h
@@ -33,7 +33,7 @@
 #include "vk_platform.h"
 
 // Vulkan API version supported by this file
-#define VK_API_VERSION VK_MAKE_VERSION(0, 121, 0)
+#define VK_API_VERSION VK_MAKE_VERSION(0, 136, 0)
 
 #ifdef __cplusplus
 extern "C"
@@ -205,8 +205,9 @@
     VK_IMAGE_ASPECT_COLOR                                   = 0x00000000,
     VK_IMAGE_ASPECT_DEPTH                                   = 0x00000001,
     VK_IMAGE_ASPECT_STENCIL                                 = 0x00000002,
+    VK_IMAGE_ASPECT_METADATA                                = 0x00000003,
 
-    VK_ENUM_RANGE(IMAGE_ASPECT, COLOR, STENCIL)
+    VK_ENUM_RANGE(IMAGE_ASPECT, COLOR, METADATA)
 } VkImageAspect;
 
 typedef enum VkBufferViewType_
@@ -960,6 +961,8 @@
 typedef enum VkBufferCreateFlagBits_
 {
     VK_BUFFER_CREATE_SPARSE_BIT                             = VK_BIT(0),    // Buffer should support sparse backing
+    VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT                   = VK_BIT(1),    // Buffer should support sparse backing with partial residency
+    VK_BUFFER_CREATE_SPARSE_ALIASED_BIT                     = VK_BIT(2),    // Buffer should support consistent data access to physical memoryblocks mapped into multiple locations of sparse buffers
 } VkBufferCreateFlagBits;
 
 // Shader stage flags
@@ -994,10 +997,12 @@
 typedef VkFlags VkImageCreateFlags;
 typedef enum VkImageCreateFlagBits_
 {
-    VK_IMAGE_CREATE_INVARIANT_DATA_BIT                      = VK_BIT(0),
-    VK_IMAGE_CREATE_SPARSE_BIT                              = VK_BIT(1),    // Image should support sparse backing
-    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT                      = VK_BIT(2),    // Allows image views to have different format than the base image
-    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT                     = VK_BIT(3),    // Allows creating image views with cube type from the created image
+    VK_IMAGE_CREATE_SPARSE_BIT                              = VK_BIT(0),    // Image should support sparse backing
+    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT                    = VK_BIT(1),    // Image should support sparse backing with partial residency
+    VK_IMAGE_CREATE_SPARSE_ALIASED_BIT                      = VK_BIT(2),    // Image should support constant data access to physical memoryblocks mapped into multiple locations fo sparse images
+    VK_IMAGE_CREATE_INVARIANT_DATA_BIT                      = VK_BIT(3),
+    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT                      = VK_BIT(4),    // Allows image views to have different format than the base image
+    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT                     = VK_BIT(5),    // Allows creating image views with cube type from the created image
 } VkImageCreateFlagBits;
 
 // Depth-stencil view creation flags
@@ -1033,6 +1038,22 @@
     VK_FENCE_CREATE_SIGNALED_BIT                            = VK_BIT(0),
 } VkFenceCreateFlagBits;
 
+// Sparse image format flags
+typedef VkFlags VkSparseImageFormatFlags;
+typedef enum VkSparseImageFormatFlagBits_
+{
+    VK_SPARSE_IMAGE_FMT_SINGLE_MIPTAIL_BIT                  = VK_BIT(0),
+    VK_SPARSE_IMAGE_FMT_ALIGNED_MIP_SIZE_BIT                = VK_BIT(1),
+    VK_SPARSE_IMAGE_FMT_NONSTD_BLOCK_SIZE_BIT               = VK_BIT(2),
+} VkSparseImageFormatFlagBits;
+
+// Sparse memory bind flags
+typedef VkFlags VkSparseMemoryBindFlags;
+typedef enum VkSparseMemoryBindFlagBits_
+{
+    VK_SPARSE_MEMORY_BIND_REPLICATE_64KIB_BLOCK_BIT         = VK_BIT(0),
+} VkSparseMemoryBindFlagBits;
+
 // Semaphore creation flags
 typedef VkFlags VkSemaphoreCreateFlags;
 
@@ -1263,6 +1284,23 @@
     bool32_t                                    shaderInt64;
     bool32_t                                    shaderFloat16;
     bool32_t                                    shaderInt16;
+    bool32_t                                    shaderResourceResidency;
+    bool32_t                                    shaderResourceMinLOD;
+    bool32_t                                    sparse;
+    bool32_t                                    sparseResidencyBuffer;
+    bool32_t                                    sparseResidencyImage2D;
+    bool32_t                                    sparseResidencyImage3D;
+    bool32_t                                    sparseResidency2Samples;
+    bool32_t                                    sparseResidency4Samples;
+    bool32_t                                    sparseResidency8Samples;
+    bool32_t                                    sparseResidency16Samples;
+    bool32_t                                    sparseResidencyStandard2DBlockShape;
+    bool32_t                                    sparseResidencyStandard2DMSBlockShape;
+    bool32_t                                    sparseResidencyStandard3DBlockShape;
+    bool32_t                                    sparseResidencyAlignedMipSize;
+    bool32_t                                    sparseResidencyNonResident;
+    bool32_t                                    sparseResidencyNonResidentStrict;
+    bool32_t                                    sparseResidencyAliased;
 } VkPhysicalDeviceFeatures;
 
 typedef struct VkPhysicalDeviceLimits_
@@ -1498,6 +1536,37 @@
     uint32_t                                    memoryTypeBits;             // Bitfield of the allowed memory type indices into memoryTypes[] for this object
 } VkMemoryRequirements;
 
+typedef struct VkSparseImageFormatProperties_
+{
+    VkImageAspect                               aspect;
+    VkExtent3D                                  imageGranularity;
+    VkSparseImageFormatFlags                    flags;
+} VkSparseImageFormatProperties;
+
+typedef struct VkSparseImageMemoryRequirements_
+{
+    VkSparseImageFormatProperties               formatProps;
+    uint32_t                                    imageMipTailStartLOD;
+    VkDeviceSize                                imageMipTailSize;
+    VkDeviceSize                                imageMipTailOffset;
+    VkDeviceSize                                imageMipTailStride;
+} VkSparseImageMemoryRequirements;
+
+typedef struct VkImageSubresource_
+{
+    VkImageAspect                               aspect;
+    uint32_t                                    mipLevel;
+    uint32_t                                    arraySlice;
+} VkImageSubresource;
+
+typedef struct VkSparseMemoryBindInfo
+{
+    VkDeviceSize                                offset;
+    VkDeviceSize                                memOffset;
+    VkDeviceMemory                              mem;
+    VkSparseMemoryBindFlags                     flags;
+} VkSparseMemoryBindInfo;
+
 typedef struct VkFormatProperties_
 {
     VkFormatFeatureFlags                        linearTilingFeatures;       // Format features in case of linear tiling
@@ -1563,13 +1632,6 @@
     VkDeviceSize                                range;                      // View size specified in bytes
 } VkBufferViewCreateInfo;
 
-typedef struct VkImageSubresource_
-{
-    VkImageAspect                               aspect;
-    uint32_t                                    mipLevel;
-    uint32_t                                    arraySlice;
-} VkImageSubresource;
-
 typedef struct VkImageSubresourceRange_
 {
     VkImageAspect                               aspect;
@@ -1695,12 +1757,15 @@
     VkDeviceSize                                copySize;               // Specified in bytes
 } VkBufferCopy;
 
-typedef struct VkImageMemoryBindInfo_
+typedef struct VkSparseImageMemoryBindInfo_
 {
     VkImageSubresource                          subresource;
     VkOffset3D                                  offset;
     VkExtent3D                                  extent;
-} VkImageMemoryBindInfo;
+    VkDeviceSize                                memOffset;
+    VkDeviceMemory                              mem;
+    VkSparseMemoryBindFlags                     flags;
+} VkSparseImageMemoryBindInfo;
 
 typedef struct VkImageCopy_
 {
@@ -2180,7 +2245,7 @@
 typedef VkResult (VKAPI *PFN_vkGetPhysicalDevicePerformance)(VkPhysicalDevice physicalDevice, VkPhysicalDevicePerformance* pPerformance);
 typedef VkResult (VKAPI *PFN_vkGetPhysicalDeviceQueueCount)(VkPhysicalDevice physicalDevice, uint32_t* pCount);
 typedef VkResult (VKAPI *PFN_vkGetPhysicalDeviceQueueProperties)(VkPhysicalDevice physicalDevice, uint32_t count, VkPhysicalDeviceQueueProperties* pQueueProperties);
-typedef VkResult (VKAPI *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperies);
+typedef VkResult (VKAPI *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties);
 typedef VkResult (VKAPI *PFN_vkGetGlobalExtensionProperties)(const char * pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties);
 typedef VkResult (VKAPI *PFN_vkGetPhysicalDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t *pCount, VkExtensionProperties* pProperties);
 typedef VkResult (VKAPI *PFN_vkGetGlobalLayerProperties)(uint32_t* pCount, VkLayerProperties* pProperties);
@@ -2198,8 +2263,11 @@
 typedef VkResult (VKAPI *PFN_vkDestroyObject)(VkDevice device, VkObjectType objType, VkObject object);
 typedef VkResult (VKAPI *PFN_vkGetObjectMemoryRequirements)(VkDevice device, VkObjectType objType, VkObject object, VkMemoryRequirements* pMemoryRequirements);
 typedef VkResult (VKAPI *PFN_vkBindObjectMemory)(VkDevice device, VkObjectType objType, VkObject object, VkDeviceMemory mem, VkDeviceSize offset);
-typedef VkResult (VKAPI *PFN_vkQueueBindSparseBufferMemory)(VkQueue queue, VkBuffer buffer, VkDeviceSize rangeOffset, VkDeviceSize rangeSize, VkDeviceMemory mem, VkDeviceSize memOffset);
-typedef VkResult (VKAPI *PFN_vkQueueBindSparseImageMemory)(VkQueue queue, VkImage image, const VkImageMemoryBindInfo* pBindInfo, VkDeviceMemory mem, VkDeviceSize memOffset);
+typedef VkResult (VKAPI *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements);
+typedef VkResult (VKAPI *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, uint32_t samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pNumProperties, VkSparseImageFormatProperties* pProperties);
+typedef VkResult (VKAPI *PFN_vkQueueBindSparseBufferMemory)(VkQueue queue, VkBuffer buffer, uint32_t numBindings, const VkSparseMemoryBindInfo* pBindInfo);
+typedef VkResult (VKAPI *PFN_vkQueueBindSparseImageOpaqueMemory)(VkQueue queue, VkImage image, uint32_t numBindings, const VkSparseMemoryBindInfo* pBindInfo);
+typedef VkResult (VKAPI *PFN_vkQueueBindSparseImageMemory)(VkQueue queue, VkImage image, uint32_t numBindings, const VkSparseImageMemoryBindInfo* pBindInfo);
 typedef VkResult (VKAPI *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, VkFence* pFence);
 typedef VkResult (VKAPI *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences);
 typedef VkResult (VKAPI *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence);
@@ -2445,20 +2513,39 @@
     VkObject                                    object,
     VkMemoryRequirements*                       pMemoryRequirements);
 
+VkResult VKAPI vkGetImageSparseMemoryRequirements(
+    VkDevice                                    device,
+    VkImage                                     image,
+    uint32_t*                                   pNumRequirements,
+    VkSparseImageMemoryRequirements*            pSparseMemoryRequirements);
+
+VkResult VKAPI vkGetPhysicalDeviceSparseImageFormatProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkImageType                                 type,
+    uint32_t                                    samples,
+    VkImageUsageFlags                           usage,
+    VkImageTiling                               tiling,
+    uint32_t*                                   pNumProperties,
+    VkSparseImageFormatProperties*              pProperties);
+
 VkResult VKAPI vkQueueBindSparseBufferMemory(
     VkQueue                                     queue,
     VkBuffer                                    buffer,
-    VkDeviceSize                                rangeOffset,
-    VkDeviceSize                                rangeSize,
-    VkDeviceMemory                              mem,
-    VkDeviceSize                                memOffset);
+    uint32_t                                    numBindings,
+    const VkSparseMemoryBindInfo*               pBindInfo);
+
+VkResult VKAPI vkQueueBindSparseImageOpaqueMemory(
+    VkQueue                                     queue,
+    VkImage                                     image,
+    uint32_t                                    numBindings,
+    const VkSparseMemoryBindInfo*               pBindInfo);
 
 VkResult VKAPI vkQueueBindSparseImageMemory(
     VkQueue                                     queue,
     VkImage                                     image,
-    const VkImageMemoryBindInfo*                pBindInfo,
-    VkDeviceMemory                              mem,
-    VkDeviceSize                                memOffset);
+    uint32_t                                    numBindings,
+    const VkSparseImageMemoryBindInfo*          pBindInfo);
 
 // Fence functions
 
diff --git a/layers/mem_tracker.cpp b/layers/mem_tracker.cpp
index f873a82..e7a5500 100644
--- a/layers/mem_tracker.cpp
+++ b/layers/mem_tracker.cpp
@@ -1191,20 +1191,18 @@
 }
 
 VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseBufferMemory(
-    VkQueue        queue,
-    VkBuffer       buffer,
-    VkDeviceSize   rangeOffset,
-    VkDeviceSize   rangeSize,
-    VkDeviceMemory mem,
-    VkDeviceSize   memOffset)
+    VkQueue                       queue,
+    VkBuffer                      buffer,
+    uint32_t                      numBindings,
+    const VkSparseMemoryBindInfo* pBindInfo)
 {
     VkResult result = get_dispatch_table(mem_tracker_device_table_map, queue)->QueueBindSparseBufferMemory(
-        queue, buffer, rangeOffset, rangeSize, mem, memOffset);
+        queue, buffer, numBindings, pBindInfo);
     loader_platform_thread_lock_mutex(&globalLock);
     // Track objects tied to memory
-    if (VK_FALSE == set_sparse_buffer_binding(buffer, mem)) {
+    if (VK_FALSE == set_sparse_buffer_binding(buffer, pBindInfo->mem)) {
         log_msg(mdd(queue), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_BUFFER, buffer, 0, MEMTRACK_MEMORY_BINDING_ERROR, "MEM",
-                "Unable to set object %p binding to mem obj %p", (void*)buffer, (void*)mem);
+                "Unable to set object %p binding to mem obj %p", (void*)buffer, (void*)pBindInfo->mem);
     }
     print_object_list(queue);
     print_mem_list(queue);
diff --git a/layers/object_track.h b/layers/object_track.h
index 8dcffcf..cc75187 100644
--- a/layers/object_track.h
+++ b/layers/object_track.h
@@ -688,38 +688,49 @@
 
 VkResult
 explicit_QueueBindSparseBufferMemory(
-    VkQueue        queue,
-    VkBuffer       buffer,
-    VkDeviceSize   rangeOffset,
-    VkDeviceSize   rangeSize,
-    VkDeviceMemory mem,
-    VkDeviceSize   memOffset)
+    VkQueue                       queue,
+    VkBuffer                      buffer,
+    uint32_t                      numBindings,
+    const VkSparseMemoryBindInfo* pBindInfo)
 {
     loader_platform_thread_lock_mutex(&objLock);
     validateQueueFlags(queue, "QueueBindSparseBufferMemory");
     validate_object(queue, buffer);
     loader_platform_thread_unlock_mutex(&objLock);
 
-    VkResult result = get_dispatch_table(ObjectTracker_device_table_map, queue)->QueueBindSparseBufferMemory(queue, buffer, rangeOffset, rangeSize, mem, memOffset);
+    VkResult result = get_dispatch_table(ObjectTracker_device_table_map, queue)->QueueBindSparseBufferMemory(queue, buffer, numBindings, pBindInfo);
     return result;
 }
 
 VkResult
 explicit_QueueBindSparseImageMemory(
-    VkQueue                      queue,
-    VkImage                      image,
-    const VkImageMemoryBindInfo *pBindInfo,
-    VkDeviceMemory               mem,
-    VkDeviceSize                 memOffset)
+    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, pBindInfo, mem, memOffset);
+    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);
+    return result;
+}
 
 VkResult
 explicit_GetFenceStatus(
diff --git a/layers/param_checker.cpp b/layers/param_checker.cpp
index 8d53751..1f55e38 100644
--- a/layers/param_checker.cpp
+++ b/layers/param_checker.cpp
@@ -2888,10 +2888,8 @@
 void PostQueueBindSparseBufferMemory(
     VkQueue queue,
     VkBuffer buffer,
-    VkDeviceSize rangeOffset,
-    VkDeviceSize rangeSize,
-    VkDeviceMemory mem,
-    VkDeviceSize memOffset,
+    uint32_t numBindings,
+    const VkSparseMemoryBindInfo* pBindInfo,
     VkResult result)
 {
     if(queue == nullptr)
@@ -2908,16 +2906,6 @@
         return;
     }
 
-
-
-    if(mem == nullptr)
-    {
-        log_msg(mdd(queue), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkQueueBindSparseBufferMemory parameter, VkDeviceMemory mem, is null pointer");
-        return;
-    }
-
-
     if(result != VK_SUCCESS)
     {
         std::string reason = "vkQueueBindSparseBufferMemory parameter, VkResult result, is " + EnumeratorString(result);
@@ -2927,24 +2915,22 @@
 }
 
 VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseBufferMemory(
-    VkQueue queue,
-    VkBuffer buffer,
-    VkDeviceSize rangeOffset,
-    VkDeviceSize rangeSize,
-    VkDeviceMemory mem,
-    VkDeviceSize memOffset)
+    VkQueue                       queue,
+    VkBuffer                      buffer,
+    uint32_t                      numBindings,
+    const VkSparseMemoryBindInfo* pBindInfo)
 {
     PreQueueBindSparseBufferMemory(queue);
-    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparseBufferMemory(queue, buffer, rangeOffset, rangeSize, mem, memOffset);
+    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparseBufferMemory(queue, buffer, numBindings, pBindInfo);
 
-    PostQueueBindSparseBufferMemory(queue, buffer, rangeOffset, rangeSize, mem, memOffset, result);
+    PostQueueBindSparseBufferMemory(queue, buffer, numBindings, pBindInfo, result);
 
     return result;
 }
 
 void PreQueueBindSparseImageMemory(
     VkQueue queue,
-    const VkImageMemoryBindInfo* pBindInfo)
+    const VkSparseImageMemoryBindInfo* pBindInfo)
 {
     if(queue == nullptr)
     {
@@ -2959,13 +2945,6 @@
         "vkQueueBindSparseImageMemory parameter, const VkImageMemoryBindInfo* pBindInfo, is null pointer");
         return;
     }
-    if(pBindInfo->subresource.aspect < VK_IMAGE_ASPECT_BEGIN_RANGE ||
-        pBindInfo->subresource.aspect > VK_IMAGE_ASPECT_END_RANGE)
-    {
-        log_msg(mdd(queue), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkQueueBindSparseImageMemory parameter, VkImageAspect pBindInfo->subresource.aspect, is unrecognized enumerator");
-        return;
-    }
 }
 
 void PostQueueBindSparseImageMemory(
@@ -3006,16 +2985,15 @@
 }
 
 VK_LAYER_EXPORT VkResult VKAPI vkQueueBindSparseImageMemory(
-    VkQueue queue,
-    VkImage image,
-    const VkImageMemoryBindInfo* pBindInfo,
-    VkDeviceMemory mem,
-    VkDeviceSize memOffset)
+    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, pBindInfo, mem, memOffset);
+    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparseImageMemory(queue, image, numBindings, pBindInfo);
 
-    PostQueueBindSparseImageMemory(queue, image, mem, memOffset, result);
+    PostQueueBindSparseImageMemory(queue, image, pBindInfo->mem, pBindInfo->memOffset, result);
 
     return result;
 }
diff --git a/loader/gpa_helper.h b/loader/gpa_helper.h
index 65c52d4..a54f63b 100644
--- a/loader/gpa_helper.h
+++ b/loader/gpa_helper.h
@@ -69,6 +69,8 @@
         return (void*) vkGetGlobalLayerProperties;
     if (!strcmp(name, "GetPhysicalDeviceLayerProperties"))
         return (void*) vkGetPhysicalDeviceLayerProperties;
+    if (!strcmp(name, "GetPhysicalDeviceSparseImageFormatProperties"))
+        return (void*) vkGetPhysicalDeviceSparseImageFormatProperties;
     if (!strcmp(name, "GetDeviceQueue"))
         return (void*) vkGetDeviceQueue;
     if (!strcmp(name, "QueueSubmit"))
@@ -99,6 +101,10 @@
         return (void*) vkQueueBindSparseBufferMemory;
     if (!strcmp(name, "QueueBindSparseImageMemory"))
         return (void*) vkQueueBindSparseImageMemory;
+    if (!strcmp(name, "QueueBindSparseImageOpaqueMemory"))
+        return (void*) vkQueueBindSparseImageOpaqueMemory;
+    if (!strcmp(name, "GetImageSparseMemoryRequirements"))
+        return (void*) vkGetImageSparseMemoryRequirements;
     if (!strcmp(name, "CreateFence"))
         return (void*) vkCreateFence;
     if (!strcmp(name, "ResetFences"))
@@ -293,6 +299,8 @@
         return (void*) vkGetPhysicalDeviceMemoryProperties;
     if (!strcmp(name, "GetPhysicalDeviceProperties"))
         return (void*) vkGetPhysicalDeviceProperties;
+    if (!strcmp(name, "GetPhysicalDeviceSparseImageFormatProperties"))
+        return (void*) vkGetPhysicalDeviceSparseImageFormatProperties;
     if (!strcmp(name, "GetInstanceProcAddr"))
         return (void*) vkGetInstanceProcAddr;
     if (!strcmp(name, "GetDeviceProcAddr"))
diff --git a/loader/loader.c b/loader/loader.c
index 9c72502..8dc0af7 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -98,6 +98,7 @@
     .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
     .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
     .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
+    .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties,
     .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
     .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
 };
@@ -1086,6 +1087,7 @@
     LOOKUP(GetPhysicalDeviceQueueCount);
     LOOKUP(GetPhysicalDeviceQueueProperties);
     LOOKUP(GetPhysicalDeviceExtensionProperties);
+    LOOKUP(GetPhysicalDeviceSparseImageFormatProperties);
     LOOKUP(DbgCreateMsgCallback);
     LOOKUP(DbgDestroyMsgCallback);
 #undef LOOKUP
@@ -2727,6 +2729,26 @@
     return res;
 }
 
+VkResult loader_GetPhysicalDeviceSparseImageFormatProperties(
+        VkPhysicalDevice                        physicalDevice,
+        VkFormat                                format,
+        VkImageType                             type,
+        uint32_t                                samples,
+        VkImageUsageFlags                       usage,
+        VkImageTiling                           tiling,
+        uint32_t*                               pNumProperties,
+        VkSparseImageFormatProperties*          pProperties)
+{
+    uint32_t gpu_index;
+    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
+    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
+
+    if (icd->GetPhysicalDeviceSparseImageFormatProperties)
+        res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
+
+    return res;
+}
+
 VkResult loader_CreateDevice(
         VkPhysicalDevice                        gpu,
         const VkDeviceCreateInfo*               pCreateInfo,
diff --git a/loader/loader.h b/loader/loader.h
index e240ce8..24c0d3b 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -154,6 +154,7 @@
     PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties;
     PFN_vkGetPhysicalDeviceExtensionProperties GetPhysicalDeviceExtensionProperties;
     PFN_vkGetPhysicalDeviceLayerProperties GetPhysicalDeviceLayerProperties;
+    PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
     PFN_vkDbgCreateMsgCallback DbgCreateMsgCallback;
     PFN_vkDbgDestroyMsgCallback DbgDestroyMsgCallback;
 
@@ -370,6 +371,15 @@
         VkPhysicalDevice                        physicalDevice,
         VkPhysicalDeviceLimits*                 pLimits);
 
+VkResult loader_GetPhysicalDeviceSparseImageFormatProperties(
+        VkPhysicalDevice                        physicalDevice,
+        VkFormat                                format,
+        VkImageType                             type,
+        uint32_t                                samples,
+        VkImageUsageFlags                       usage,
+        VkImageTiling                           tiling,
+        uint32_t*                               pNumProperties,
+        VkSparseImageFormatProperties*          pProperties);
 
 VkResult loader_GetPhysicalDeviceProperties (
         VkPhysicalDevice physicalDevice,
diff --git a/loader/table_ops.h b/loader/table_ops.h
index 430d811..4f3b501 100644
--- a/loader/table_ops.h
+++ b/loader/table_ops.h
@@ -54,6 +54,8 @@
     table->BindObjectMemory = (PFN_vkBindObjectMemory) gpa(dev, "vkBindObjectMemory");
     table->QueueBindSparseBufferMemory = (PFN_vkQueueBindSparseBufferMemory) gpa(dev, "vkQueueBindSparseBufferMemory");
     table->QueueBindSparseImageMemory = (PFN_vkQueueBindSparseImageMemory) gpa(dev, "vkQueueBindSparseImageMemory");
+    table->QueueBindSparseImageOpaqueMemory = (PFN_vkQueueBindSparseImageOpaqueMemory) gpa(dev, "vkQueueBindSparseImageOpaqueMemory");
+    table->GetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements) gpa(dev, "vkGetImageSparseMemoryRequirements");
     table->CreateFence = (PFN_vkCreateFence) gpa(dev, "vkCreateFence");
     table->ResetFences = (PFN_vkResetFences) gpa(dev, "vkResetFences");
     table->GetFenceStatus = (PFN_vkGetFenceStatus) gpa(dev, "vkGetFenceStatus");
@@ -187,6 +189,10 @@
         return (void *) table->QueueBindSparseBufferMemory;
     if (!strcmp(name, "QueueBindSparseImageMemory"))
         return (void *) table->QueueBindSparseImageMemory;
+    if (!strcmp(name, "QueueBindSparseImageOpaqueMemory"))
+        return (void *) table->QueueBindSparseImageOpaqueMemory;
+    if (!strcmp(name, "GetImageSparseMemoryRequirements"))
+        return (void *) table->GetImageSparseMemoryRequirements;
     if (!strcmp(name, "CreateFence"))
         return (void *) table->CreateFence;
     if (!strcmp(name, "ResetFences"))
@@ -371,6 +377,7 @@
     table->GetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties) gpa(inst, "vkGetPhysicalDeviceMemoryProperties");
     table->GetPhysicalDeviceExtensionProperties = (PFN_vkGetPhysicalDeviceExtensionProperties) gpa(inst, "vkGetPhysicalDeviceExtensionProperties");
     table->GetPhysicalDeviceLayerProperties = (PFN_vkGetPhysicalDeviceLayerProperties) gpa(inst, "vkGetPhysicalDeviceLayerProperties");
+    table->GetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties) gpa(inst, "vkGetPhysicalDeviceSparseImageFormatProperties");
 }
 
 static inline void loader_init_instance_extension_dispatch_table(
@@ -402,6 +409,8 @@
         return (void *) table->GetPhysicalDeviceFormatInfo;
     if (!strcmp(name, "GetPhysicalDeviceLimits"))
         return (void *) table->GetPhysicalDeviceLimits;
+    if (!strcmp(name, "GetPhysicalDeviceSparseImageFormatProperties"))
+        return (void *) table->GetPhysicalDeviceSparseImageFormatProperties;
     if (!strcmp(name, "GetPhysicalDeviceProperties"))
         return (void *) table->GetPhysicalDeviceProperties;
     if (!strcmp(name, "GetPhysicalDevicePerformance"))
diff --git a/loader/trampoline.c b/loader/trampoline.c
index 71943da..19f1cbb 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -447,22 +447,49 @@
     return disp->BindObjectMemory(device, objType, object, mem, offset);
 }
 
-LOADER_EXPORT VkResult VKAPI vkQueueBindSparseBufferMemory(VkQueue queue, VkBuffer buffer, VkDeviceSize rangeOffset, VkDeviceSize rangeSize, VkDeviceMemory mem, VkDeviceSize memOffset)
+LOADER_EXPORT VkResult VKAPI vkGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements)
 {
     const VkLayerDispatchTable *disp;
 
-    disp = loader_get_dispatch(queue);
+    disp = loader_get_dispatch(device);
 
-    return disp->QueueBindSparseBufferMemory(queue, buffer, rangeOffset, rangeSize, mem, memOffset);
+    return disp->GetImageSparseMemoryRequirements(device, image, pNumRequirements, pSparseMemoryRequirements);
 }
 
-LOADER_EXPORT VkResult VKAPI vkQueueBindSparseImageMemory(VkQueue queue, VkImage image, const VkImageMemoryBindInfo* pBindInfo, VkDeviceMemory mem, VkDeviceSize memOffset)
+LOADER_EXPORT VkResult VKAPI vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, uint32_t samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pNumProperties, VkSparseImageFormatProperties* pProperties)
+{
+    const VkLayerInstanceDispatchTable *disp;
+
+    disp = loader_get_instance_dispatch(physicalDevice);
+
+    return disp->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
+}
+
+LOADER_EXPORT VkResult VKAPI vkQueueBindSparseImageOpaqueMemory(VkQueue queue, VkImage image, uint32_t numBindings, const VkSparseMemoryBindInfo* pBindInfo)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(queue);
 
-    return disp->QueueBindSparseImageMemory(queue, image, pBindInfo, mem, memOffset);
+    return disp->QueueBindSparseImageOpaqueMemory(queue, image, numBindings, pBindInfo);
+}
+
+LOADER_EXPORT VkResult VKAPI vkQueueBindSparseBufferMemory(VkQueue queue, VkBuffer buffer, uint32_t numBindings, const VkSparseMemoryBindInfo* pBindInfo)
+{
+    const VkLayerDispatchTable *disp;
+
+    disp = loader_get_dispatch(queue);
+
+    return disp->QueueBindSparseBufferMemory(queue, buffer, numBindings, pBindInfo);
+}
+
+LOADER_EXPORT VkResult VKAPI vkQueueBindSparseImageMemory(VkQueue queue, VkImage image, uint32_t numBindings, const VkSparseImageMemoryBindInfo* pBindInfo)
+{
+    const VkLayerDispatchTable *disp;
+
+    disp = loader_get_dispatch(queue);
+
+    return disp->QueueBindSparseImageMemory(queue, image, numBindings, pBindInfo);
 }
 
 LOADER_EXPORT VkResult VKAPI vkCreateFence(VkDevice device, const VkFenceCreateInfo* pCreateInfo, VkFence* pFence)
diff --git a/tests/vktestbinding.cpp b/tests/vktestbinding.cpp
index 8882835..9d0a4c1 100644
--- a/tests/vktestbinding.cpp
+++ b/tests/vktestbinding.cpp
@@ -679,7 +679,12 @@
                          const GpuMemory &mem, VkDeviceSize mem_offset)
 {
     VkQueue queue = dev_->graphics_queues()[0]->obj();
-    EXPECT(vkQueueBindSparseBufferMemory(queue, obj(), offset, size, mem.obj(), mem_offset) == VK_SUCCESS);
+    VkSparseMemoryBindInfo bindInfo;
+    memset(&bindInfo, 0, sizeof(VkSparseMemoryBindInfo));
+    bindInfo.offset    = offset;
+    bindInfo.memOffset = mem_offset;
+    bindInfo.mem       = mem.obj();
+    EXPECT(vkQueueBindSparseBufferMemory(queue, obj(), 1, &bindInfo) == VK_SUCCESS);
 }
 
 void BufferView::init(const Device &dev, const VkBufferViewCreateInfo &info)
@@ -718,11 +723,11 @@
     }
 }
 
-void Image::bind_memory(const Device &dev, const VkImageMemoryBindInfo &info,
+void Image::bind_memory(const Device &dev, const VkSparseImageMemoryBindInfo &info,
                         const GpuMemory &mem, VkDeviceSize mem_offset)
 {
     VkQueue queue = dev.graphics_queues()[0]->obj();
-    EXPECT(vkQueueBindSparseImageMemory(queue, obj(), &info, mem.obj(), mem_offset) == VK_SUCCESS);
+    EXPECT(vkQueueBindSparseImageMemory(queue, obj(), 1, &info) == VK_SUCCESS);
 }
 
 VkSubresourceLayout Image::subresource_layout(const VkImageSubresource &subres) const
diff --git a/tests/vktestbinding.h b/tests/vktestbinding.h
index b902628..2dffa3c 100644
--- a/tests/vktestbinding.h
+++ b/tests/vktestbinding.h
@@ -424,7 +424,7 @@
     void init_no_mem(const Device &dev, const VkImageCreateInfo &info);
 
     // vkQueueBindSparseImageMemory()
-    void bind_memory(const Device &dev, const VkImageMemoryBindInfo &info,
+    void bind_memory(const Device &dev, const VkSparseImageMemoryBindInfo &info,
                      const GpuMemory &mem, VkDeviceSize mem_offset);
 
     // vkGetImageSubresourceLayout()
diff --git a/vulkan.py b/vulkan.py
index b3b6975..01112c7 100755
--- a/vulkan.py
+++ b/vulkan.py
@@ -367,20 +367,39 @@
              Param("VkDeviceMemory", "mem"),
              Param("VkDeviceSize", "offset")]),
 
+        Proto("VkResult", "GetImageSparseMemoryRequirements",
+            [Param("VkDevice", "device"),
+             Param("VkImage", "image"),
+             Param("uint32_t*", "pNumRequirements"),
+             Param("VkSparseImageMemoryRequirements*", "pSparseMemoryRequirements"),]),
+
+        Proto("VkResult", "GetPhysicalDeviceSparseImageFormatProperties",
+            [Param("VkPhysicalDevice", "physicalDevice"),
+             Param("VkFormat", "format"),
+             Param("VkImageType", "type"),
+             Param("uint32_t", "samples"),
+             Param("VkImageUsageFlags", "usage"),
+             Param("VkImageTiling", "tiling"),
+             Param("uint32_t*", "pNumProperties"),
+             Param("VkSparseImageFormatProperties*", "pProperties"),]),
+
         Proto("VkResult", "QueueBindSparseBufferMemory",
             [Param("VkQueue", "queue"),
              Param("VkBuffer", "buffer"),
-             Param("VkDeviceSize", "rangeOffset"),
-             Param("VkDeviceSize", "rangeSize"),
-             Param("VkDeviceMemory", "mem"),
-             Param("VkDeviceSize", "memOffset")]),
+             Param("uint32_t", "numBindings"),
+             Param("const VkSparseMemoryBindInfo*", "pBindInfo"),]),
+
+        Proto("VkResult", "QueueBindSparseImageOpaqueMemory",
+            [Param("VkQueue", "queue"),
+             Param("VkImage", "image"),
+             Param("uint32_t", "numBindings"),
+             Param("const VkSparseMemoryBindInfo*", "pBindInfo"),]),
 
         Proto("VkResult", "QueueBindSparseImageMemory",
             [Param("VkQueue", "queue"),
              Param("VkImage", "image"),
-             Param("const VkImageMemoryBindInfo*", "pBindInfo"),
-             Param("VkDeviceMemory", "mem"),
-             Param("VkDeviceSize", "memOffset")]),
+             Param("uint32_t", "numBindings"),
+             Param("const VkSparseImageMemoryBindInfo*", "pBindInfo"),]),
 
         Proto("VkResult", "CreateFence",
             [Param("VkDevice", "device"),