Fix loader phys dev termin for physical device extensions.
authorMark Young <marky@lunarg.com>
Wed, 15 Dec 2021 17:06:00 +0000 (10:06 -0700)
committerMark Young <marky@lunarg.com>
Fri, 7 Jan 2022 23:56:38 +0000 (16:56 -0700)
Fix some loader terminator functions for instance physical device
functions (that were pre-Vulkan 1.1).  At that point in the API, we
didn't treat VkPhysicalDevices like VkDevices.  Now, you must first
query the device for extension support for even VkPhysicalDevice calls.
Back then, the loader had to emulate the functionality.

Added tests to validate many of these functions.

loader/generated/vk_loader_extensions.c
loader/terminator.c
loader/wsi.c
scripts/loader_extension_generator.py
tests/CMakeLists.txt
tests/framework/icd/physical_device.h
tests/framework/icd/test_icd.cpp
tests/framework/test_util.h
tests/loader_handle_validation_tests.cpp
tests/loader_phys_dev_inst_ext_tests.cpp [new file with mode: 0644]
tests/loader_regression_tests.cpp

index 6fb1d516be24c36916ddb2a46a7ca57046945e7b..848afce3b56745b6f8224d639b87f47dae088da7 100644 (file)
@@ -5679,6 +5679,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_AcquireDrmDisplayEXT(
     if (NULL == icd_term->dispatch.AcquireDrmDisplayEXT) {
         loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
                    "ICD associated with VkPhysicalDevice does not support AcquireDrmDisplayEXT");
+        return VK_ERROR_INITIALIZATION_FAILED;
     }
     return icd_term->dispatch.AcquireDrmDisplayEXT(phys_dev_term->phys_dev, drmFd, display);
 }
@@ -5710,6 +5711,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDrmDisplayEXT(
     if (NULL == icd_term->dispatch.GetDrmDisplayEXT) {
         loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
                    "ICD associated with VkPhysicalDevice does not support GetDrmDisplayEXT");
+        return VK_ERROR_INITIALIZATION_FAILED;
     }
     return icd_term->dispatch.GetDrmDisplayEXT(phys_dev_term->phys_dev, drmFd, connectorId, display);
 }
index ab9a32d523a51b3dfa0802d0506b7f16a183f5d0..10fd13a8fc9047ed47c103b036dc588a9fc53900 100644 (file)
@@ -128,15 +128,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2(VkPhysicalDevic
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceFeatures2 fpGetPhysicalDeviceFeatures2 = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
-        fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2KHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2;
+    } else if (inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+        fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2KHR;
     }
 
-    if (fpGetPhysicalDeviceFeatures2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+    if (fpGetPhysicalDeviceFeatures2 != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceFeatures2(phys_dev_term->phys_dev, pFeatures);
     } else {
@@ -181,15 +183,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2(VkPhysicalDev
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceProperties2 fpGetPhysicalDeviceProperties2 = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
-        fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2KHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2;
+    } else if (inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+        fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2KHR;
     }
 
-    if (fpGetPhysicalDeviceProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+    if (fpGetPhysicalDeviceProperties2 != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceProperties2(phys_dev_term->phys_dev, pProperties);
     } else {
@@ -241,15 +245,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties2(VkPhysi
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceFormatProperties2 fpGetPhysicalDeviceFormatProperties2 = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
-        fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2KHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2;
+    } else if (inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+        fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2KHR;
     }
 
-    if (fpGetPhysicalDeviceFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+    if (fpGetPhysicalDeviceFormatProperties2 != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceFormatProperties2(phys_dev_term->phys_dev, format, pFormatProperties);
     } else {
@@ -276,15 +282,17 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceImageFormatProperties2 fpGetPhysicalDeviceImageFormatProperties2 = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
-        fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2KHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2;
+    } else if (inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+        fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2KHR;
     }
 
-    if (fpGetPhysicalDeviceImageFormatProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+    if (fpGetPhysicalDeviceImageFormatProperties2 != NULL) {
         // Pass the call to the driver
         return fpGetPhysicalDeviceImageFormatProperties2(phys_dev_term->phys_dev, pImageFormatInfo, pImageFormatProperties);
     } else {
@@ -313,15 +321,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties2(Vk
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fpGetPhysicalDeviceQueueFamilyProperties2 = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
-        fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2KHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2;
+    } else if (inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+        fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2KHR;
     }
 
-    if (fpGetPhysicalDeviceQueueFamilyProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+    if (fpGetPhysicalDeviceQueueFamilyProperties2 != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceQueueFamilyProperties2(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pQueueFamilyProperties);
     } else {
@@ -368,15 +378,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties2(VkPhysi
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceMemoryProperties2 fpGetPhysicalDeviceMemoryProperties2 = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
-        fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2KHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2;
+    } else if (inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+        fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2KHR;
     }
 
-    if (fpGetPhysicalDeviceMemoryProperties2 != NULL || !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+    if (fpGetPhysicalDeviceMemoryProperties2 != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceMemoryProperties2(phys_dev_term->phys_dev, pMemoryProperties);
     } else {
@@ -403,16 +415,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperti
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 fpGetPhysicalDeviceSparseImageFormatProperties2 = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
-        fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2KHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2;
+    } else if (inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+        fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2KHR;
     }
 
-    if (fpGetPhysicalDeviceSparseImageFormatProperties2 != NULL ||
-        !inst->enabled_known_extensions.khr_get_physical_device_properties2) {
+    if (fpGetPhysicalDeviceSparseImageFormatProperties2 != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceSparseImageFormatProperties2(phys_dev_term->phys_dev, pFormatInfo, pPropertyCount, pProperties);
     } else {
@@ -470,15 +483,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalBufferProperties(
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceExternalBufferProperties fpGetPhysicalDeviceExternalBufferProperties = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_external_memory_capabilities) {
-        fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferPropertiesKHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferProperties;
+    } else if (inst->enabled_known_extensions.khr_external_memory_capabilities) {
+        fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferPropertiesKHR;
     }
 
-    if (fpGetPhysicalDeviceExternalBufferProperties || !inst->enabled_known_extensions.khr_external_memory_capabilities) {
+    if (fpGetPhysicalDeviceExternalBufferProperties) {
         // Pass the call to the driver
         fpGetPhysicalDeviceExternalBufferProperties(phys_dev_term->phys_dev, pExternalBufferInfo, pExternalBufferProperties);
     } else {
@@ -510,16 +525,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalSemaphoreProperti
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceExternalSemaphoreProperties fpGetPhysicalDeviceExternalSemaphoreProperties = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
-        fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphorePropertiesKHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphoreProperties;
+    } else if (inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
+        fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphorePropertiesKHR;
     }
 
-    if (fpGetPhysicalDeviceExternalSemaphoreProperties != NULL ||
-        !inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
+    if (fpGetPhysicalDeviceExternalSemaphoreProperties != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceExternalSemaphoreProperties(phys_dev_term->phys_dev, pExternalSemaphoreInfo,
                                                        pExternalSemaphoreProperties);
@@ -554,15 +570,17 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalFenceProperties(
     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
     const struct loader_instance *inst = icd_term->this_instance;
 
+    assert(inst != NULL);
+
     // Get the function pointer to use to call into the ICD. This could be the core or KHR version
     PFN_vkGetPhysicalDeviceExternalFenceProperties fpGetPhysicalDeviceExternalFenceProperties = NULL;
-    if (inst != NULL && inst->enabled_known_extensions.khr_external_fence_capabilities) {
-        fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFencePropertiesKHR;
-    } else {
+    if (inst->app_api_major_version > 1 || inst->app_api_major_version >= 1) {
         fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFenceProperties;
+    } else if (inst->enabled_known_extensions.khr_external_fence_capabilities) {
+        fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFencePropertiesKHR;
     }
 
-    if (fpGetPhysicalDeviceExternalFenceProperties != NULL || !inst->enabled_known_extensions.khr_external_fence_capabilities) {
+    if (fpGetPhysicalDeviceExternalFenceProperties != NULL) {
         // Pass the call to the driver
         fpGetPhysicalDeviceExternalFenceProperties(phys_dev_term->phys_dev, pExternalFenceInfo, pExternalFenceProperties);
     } else {
index 6eb312ec91fd972db0510aebb45b14afa1eabbf4..f7fb167282d845af4c24ca9224e175f012e6609a 100644 (file)
@@ -1686,6 +1686,8 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceDisplayPropertiesKHR(
     }
 
     if (NULL == icd_term->dispatch.GetPhysicalDeviceDisplayPropertiesKHR) {
+        loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
+                   "ICD for selected physical device is not exporting vkGetPhysicalDeviceDisplayPropertiesKHR!\n");
         *pPropertyCount = 0;
         return VK_SUCCESS;
     }
@@ -1722,6 +1724,8 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceDisplayPlanePropertie
     }
 
     if (NULL == icd_term->dispatch.GetPhysicalDeviceDisplayPlanePropertiesKHR) {
+        loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
+                   "ICD for selected physical device is not exporting vkGetPhysicalDeviceDisplayPlanePropertiesKHR!\n");
         *pPropertyCount = 0;
         return VK_SUCCESS;
     }
@@ -1758,9 +1762,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDisplayPlaneSupportedDisplaysKHR(Vk
     }
 
     if (NULL == icd_term->dispatch.GetDisplayPlaneSupportedDisplaysKHR) {
-        loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
+        loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
                    "ICD for selected physical device is not exporting vkGetDisplayPlaneSupportedDisplaysKHR!\n");
-        abort();
+        *pDisplayCount = 0;
+        return VK_SUCCESS;
     }
 
     return icd_term->dispatch.GetDisplayPlaneSupportedDisplaysKHR(phys_dev_term->phys_dev, planeIndex, pDisplayCount, pDisplays);
@@ -1796,9 +1801,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDisplayModePropertiesKHR(VkPhysical
     }
 
     if (NULL == icd_term->dispatch.GetDisplayModePropertiesKHR) {
-        loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
+        loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
                    "ICD for selected physical device is not exporting vkGetDisplayModePropertiesKHR!\n");
-        abort();
+        *pPropertyCount = 0;
+        return VK_SUCCESS;
     }
 
     return icd_term->dispatch.GetDisplayModePropertiesKHR(phys_dev_term->phys_dev, display, pPropertyCount, pProperties);
@@ -1835,9 +1841,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDisplayModeKHR(VkPhysicalDevice
     }
 
     if (NULL == icd_term->dispatch.CreateDisplayModeKHR) {
+        // Can't emulate, so return an appropriate error
         loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
                    "ICD for selected physical device is not exporting vkCreateDisplayModeKHR!\n");
-        abort();
+        return VK_ERROR_INITIALIZATION_FAILED;
     }
 
     return icd_term->dispatch.CreateDisplayModeKHR(phys_dev_term->phys_dev, display, pCreateInfo, pAllocator, pMode);
@@ -1873,9 +1880,13 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDisplayPlaneCapabilitiesKHR(VkPhysi
     }
 
     if (NULL == icd_term->dispatch.GetDisplayPlaneCapabilitiesKHR) {
-        loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
+        // Emulate support
+        loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
                    "ICD for selected physical device is not exporting vkGetDisplayPlaneCapabilitiesKHR!\n");
-        abort();
+        if (pCapabilities) {
+            memset(pCapabilities, 0, sizeof(VkDisplayPlaneCapabilitiesKHR));
+        }
+        return VK_SUCCESS;
     }
 
     return icd_term->dispatch.GetDisplayPlaneCapabilitiesKHR(phys_dev_term->phys_dev, mode, planeIndex, pCapabilities);
index 497d81b1359638b3914e0f15128b8915e4fb6e83..fe11e0d824f98cd35affae72e7937316d88abec1 100644 (file)
@@ -1137,6 +1137,11 @@ class LoaderExtensionOutputGenerator(OutputGenerator):
                     funcs += '                   "ICD associated with VkPhysicalDevice does not support '
                     funcs += base_name
                     funcs += '");\n'
+
+                    # If this is an instance function taking a physical device (i.e. pre Vulkan 1.1), we need to behave and not crash so return an
+                    # error here.
+                    if ext_cmd.ext_type =='instance' and has_return_type:
+                        funcs += '        return VK_ERROR_INITIALIZATION_FAILED;\n'
                     funcs += '    }\n'
 
                     if has_surface == 1:
index 0c5e33115ec375238f79e5a2e67251fd8b8c9b0c..207796abbe51dca0397ff3a557405a88babd59ac 100644 (file)
@@ -32,6 +32,7 @@ add_executable(
         loader_handle_validation_tests.cpp
         loader_layer_tests.cpp
         loader_regression_tests.cpp
+        loader_phys_dev_inst_ext_tests.cpp
         loader_version_tests.cpp
         loader_unknown_ext_tests.cpp)
 target_link_libraries(test_regression PRIVATE testing_dependencies)
index 6fc4ddf9179b3218e1f481176b3b6541a7a6a738..eeeff0e7833344479f485b4849462e32c4948adc 100644 (file)
@@ -40,9 +40,14 @@ struct PhysicalDevice {
     BUILDER_VALUE(PhysicalDevice, VkPhysicalDeviceProperties, properties, {})
     BUILDER_VALUE(PhysicalDevice, VkPhysicalDeviceFeatures, features, {})
     BUILDER_VALUE(PhysicalDevice, VkPhysicalDeviceMemoryProperties, memory_properties, {})
+    BUILDER_VALUE(PhysicalDevice, VkImageFormatProperties, image_format_properties, {})
+    BUILDER_VALUE(PhysicalDevice, VkExternalMemoryProperties, external_memory_properties, {})
+    BUILDER_VALUE(PhysicalDevice, VkExternalSemaphoreProperties, external_semaphore_properties, {})
+    BUILDER_VALUE(PhysicalDevice, VkExternalFenceProperties, external_fence_properties, {})
 
     BUILDER_VECTOR(PhysicalDevice, MockQueueFamilyProperties, queue_family_properties, queue_family_properties)
     BUILDER_VECTOR(PhysicalDevice, VkFormatProperties, format_properties, format_properties)
+    BUILDER_VECTOR(PhysicalDevice, VkSparseImageFormatProperties, sparse_image_format_properties, sparse_image_format_properties)
 
     BUILDER_VECTOR(PhysicalDevice, Extension, extensions, extension)
 
@@ -50,6 +55,13 @@ struct PhysicalDevice {
     BUILDER_VECTOR(PhysicalDevice, VkSurfaceFormatKHR, surface_formats, surface_format)
     BUILDER_VECTOR(PhysicalDevice, VkPresentModeKHR, surface_present_modes, surface_present_mode)
 
+    BUILDER_VECTOR(PhysicalDevice, VkDisplayPropertiesKHR, display_properties, display_properties)
+    BUILDER_VECTOR(PhysicalDevice, VkDisplayPlanePropertiesKHR, display_plane_properties, display_plane_properties)
+    BUILDER_VECTOR(PhysicalDevice, VkDisplayKHR, displays, displays)
+    BUILDER_VECTOR(PhysicalDevice, VkDisplayModePropertiesKHR, display_mode_properties, display_mode_properties)
+    BUILDER_VALUE(PhysicalDevice, VkDisplayModeKHR, display_mode, {})
+    BUILDER_VALUE(PhysicalDevice, VkDisplayPlaneCapabilitiesKHR, display_plane_capabilities, {})
+
     // VkDevice handles created from this physical device
     std::vector<VkDevice> device_handles;
 
index 9faf49d40039f67b42150a82800045c99d3ca106..497b9d3507e0b89ccda601b8da120cce203f7947 100644 (file)
@@ -545,6 +545,7 @@ VKAPI_ATTR void VKAPI_CALL test_vkDestroySwapchainKHR(VkDevice device, VkSwapcha
     }
 }
 
+// VK_KHR_surface
 VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
                                                                          VkSurfaceKHR surface, VkBool32* pSupported) {
     if (nullptr != pSupported) {
@@ -572,46 +573,244 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfacePresentModesKHR(Vk
     return VK_SUCCESS;
 }
 
-//// stubs
+// VK_KHR_display
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice,
+                                                                            uint32_t* pPropertyCount,
+                                                                            VkDisplayPropertiesKHR* pProperties) {
+    FillCountPtr(icd.GetPhysDevice(physicalDevice).display_properties, pPropertyCount, pProperties);
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice,
+                                                                                 uint32_t* pPropertyCount,
+                                                                                 VkDisplayPlanePropertiesKHR* pProperties) {
+    FillCountPtr(icd.GetPhysDevice(physicalDevice).display_plane_properties, pPropertyCount, pProperties);
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                                          uint32_t* pDisplayCount, VkDisplayKHR* pDisplays) {
+    FillCountPtr(icd.GetPhysDevice(physicalDevice).displays, pDisplayCount, pDisplays);
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                                  uint32_t* pPropertyCount,
+                                                                  VkDisplayModePropertiesKHR* pProperties) {
+    FillCountPtr(icd.GetPhysDevice(physicalDevice).display_mode_properties, pPropertyCount, pProperties);
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDisplayModeKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                           const VkDisplayModeCreateInfoKHR* pCreateInfo,
+                                                           const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode) {
+    if (nullptr != pMode) {
+        *pMode = icd.GetPhysDevice(physicalDevice).display_mode;
+    }
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode,
+                                                                     uint32_t planeIndex,
+                                                                     VkDisplayPlaneCapabilitiesKHR* pCapabilities) {
+    if (nullptr != pCapabilities) {
+        *pCapabilities = icd.GetPhysDevice(physicalDevice).display_plane_capabilities;
+    }
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDisplayPlaneSurfaceKHR(VkInstance instance,
+                                                                   const VkDisplaySurfaceCreateInfoKHR* pCreateInfo,
+                                                                   const VkAllocationCallbacks* pAllocator,
+                                                                   VkSurfaceKHR* pSurface) {
+    if (nullptr != pSurface) {
+        uint64_t fake_surf_handle = reinterpret_cast<uint64_t>(new uint8_t);
+        icd.surface_handles.push_back(fake_surf_handle);
+#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || \
+    defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+        *pSurface = reinterpret_cast<VkSurfaceKHR>(fake_surf_handle);
+#else
+        *pSurface = fake_surf_handle;
+#endif
+    }
+    return VK_SUCCESS;
+}
+
+// VK_KHR_get_surface_capabilities2
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
+                                                                               const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+                                                                               VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
+    if (nullptr != pSurfaceInfo && nullptr != pSurfaceCapabilities) {
+        return test_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, pSurfaceInfo->surface,
+                                                              &pSurfaceCapabilities->surfaceCapabilities);
+    }
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
+                                                                          const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+                                                                          uint32_t* pSurfaceFormatCount,
+                                                                          VkSurfaceFormat2KHR* pSurfaceFormats) {
+    if (nullptr != pSurfaceFormatCount) {
+        test_vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount, nullptr);
+        if (nullptr != pSurfaceFormats) {
+            auto& phys_dev = icd.GetPhysDevice(physicalDevice);
+            // Since the structures are different, we have to copy each item over seperately.  Since we have multiple, we
+            // have to manually copy the data here instead of calling the next function
+            for (uint32_t cnt = 0; cnt < *pSurfaceFormatCount; ++cnt) {
+                memcpy(&pSurfaceFormats[cnt].surfaceFormat, &phys_dev.surface_formats[cnt], sizeof(VkSurfaceFormatKHR));
+            }
+        }
+    }
+    return VK_SUCCESS;
+}
+
+// VK_EXT_acquire_drm_display
+VKAPI_ATTR VkResult VKAPI_CALL test_vkAcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice, int32_t drmFd, VkDisplayKHR display) {
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetDrmDisplayEXT(VkPhysicalDevice physicalDevice, int32_t drmFd, uint32_t connectorId,
+                                                       VkDisplayKHR* display) {
+    if (nullptr != display && icd.GetPhysDevice(physicalDevice).displays.size() > 0) {
+        *display = icd.GetPhysDevice(physicalDevice).displays[0];
+    }
+    return VK_SUCCESS;
+}
+
 // 1.0
-VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) {}
+VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) {
+    if (nullptr != pFeatures) {
+        memcpy(pFeatures, &icd.GetPhysDevice(physicalDevice).features, sizeof(VkPhysicalDeviceFeatures));
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
-                                                              VkPhysicalDeviceProperties* pProperties) {}
+                                                              VkPhysicalDeviceProperties* pProperties) {
+    if (nullptr != pProperties) {
+        memcpy(pProperties, &icd.GetPhysDevice(physicalDevice).properties, sizeof(VkPhysicalDeviceProperties));
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
-                                                                    VkPhysicalDeviceMemoryProperties* pMemoryProperties) {}
+                                                                    VkPhysicalDeviceMemoryProperties* pMemoryProperties) {
+    if (nullptr != pMemoryProperties) {
+        memcpy(pMemoryProperties, &icd.GetPhysDevice(physicalDevice).memory_properties, sizeof(VkPhysicalDeviceMemoryProperties));
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
                                                                                VkImageType type, VkSampleCountFlagBits samples,
                                                                                VkImageUsageFlags usage, VkImageTiling tiling,
                                                                                uint32_t* pPropertyCount,
-                                                                               VkSparseImageFormatProperties* pProperties) {}
+                                                                               VkSparseImageFormatProperties* pProperties) {
+    FillCountPtr(icd.GetPhysDevice(physicalDevice).sparse_image_format_properties, pPropertyCount, pProperties);
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
-                                                                    VkFormatProperties* pFormatProperties) {}
+                                                                    VkFormatProperties* pFormatProperties) {
+    if (nullptr != pFormatProperties) {
+        memcpy(pFormatProperties, &icd.GetPhysDevice(physicalDevice).format_properties[static_cast<uint32_t>(format)],
+               sizeof(VkFormatProperties));
+    }
+}
 VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
                                                                              VkImageType type, VkImageTiling tiling,
                                                                              VkImageUsageFlags usage, VkImageCreateFlags flags,
                                                                              VkImageFormatProperties* pImageFormatProperties) {
+    if (nullptr != pImageFormatProperties) {
+        memcpy(pImageFormatProperties, &icd.GetPhysDevice(physicalDevice).image_format_properties, sizeof(VkImageFormatProperties));
+    }
     return VK_SUCCESS;
 }
 
+// 1.1
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
-                                                             VkPhysicalDeviceFeatures2* pFeatures) {}
+                                                             VkPhysicalDeviceFeatures2* pFeatures) {
+    if (nullptr != pFeatures) {
+        test_vkGetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
-                                                               VkPhysicalDeviceProperties2* pProperties) {}
+                                                               VkPhysicalDeviceProperties2* pProperties) {
+    if (nullptr != pProperties) {
+        test_vkGetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
-                                                                     VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {}
+                                                                     VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+    if (nullptr != pMemoryProperties) {
+        test_vkGetPhysicalDeviceMemoryProperties(physicalDevice, &pMemoryProperties->memoryProperties);
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
                                                                           uint32_t* pQueueFamilyPropertyCount,
-                                                                          VkQueueFamilyProperties2* pQueueFamilyProperties) {}
+                                                                          VkQueueFamilyProperties2* pQueueFamilyProperties) {
+    if (nullptr != pQueueFamilyPropertyCount) {
+        test_vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, nullptr);
+        if (nullptr != pQueueFamilyProperties) {
+            auto& phys_dev = icd.GetPhysDevice(physicalDevice);
+            // Since the structures are different, we have to copy each item over seperately.  Since we have multiple, we
+            // have to manually copy the data here instead of calling the next function
+            for (uint32_t queue = 0; queue < *pQueueFamilyPropertyCount; ++queue) {
+                memcpy(&pQueueFamilyProperties[queue].queueFamilyProperties, &phys_dev.queue_family_properties[queue].properties,
+                       sizeof(VkQueueFamilyProperties));
+            }
+        }
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceSparseImageFormatProperties2(
     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount,
-    VkSparseImageFormatProperties2* pProperties) {}
+    VkSparseImageFormatProperties2* pProperties) {
+    if (nullptr != pPropertyCount) {
+        test_vkGetPhysicalDeviceSparseImageFormatProperties(physicalDevice, pFormatInfo->format, pFormatInfo->type,
+                                                            pFormatInfo->samples, pFormatInfo->usage, pFormatInfo->tiling,
+                                                            pPropertyCount, nullptr);
+        if (nullptr != pProperties) {
+            auto& phys_dev = icd.GetPhysDevice(physicalDevice);
+            // Since the structures are different, we have to copy each item over seperately.  Since we have multiple, we
+            // have to manually copy the data here instead of calling the next function
+            for (uint32_t cnt = 0; cnt < *pPropertyCount; ++cnt) {
+                memcpy(&pProperties[cnt].properties, &phys_dev.sparse_image_format_properties[cnt],
+                       sizeof(VkSparseImageFormatProperties));
+            }
+        }
+    }
+}
 VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format,
-                                                                     VkFormatProperties2* pFormatProperties) {}
+                                                                     VkFormatProperties2* pFormatProperties) {
+    if (nullptr != pFormatProperties) {
+        test_vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &pFormatProperties->formatProperties);
+    }
+}
 VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceImageFormatProperties2(
     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
     VkImageFormatProperties2* pImageFormatProperties) {
+    if (nullptr != pImageFormatInfo) {
+        VkImageFormatProperties* ptr = nullptr;
+        if (pImageFormatProperties) {
+            ptr = &pImageFormatProperties->imageFormatProperties;
+        }
+        test_vkGetPhysicalDeviceImageFormatProperties(physicalDevice, pImageFormatInfo->format, pImageFormatInfo->type,
+                                                      pImageFormatInfo->tiling, pImageFormatInfo->usage, pImageFormatInfo->flags,
+                                                      ptr);
+    }
     return VK_SUCCESS;
 }
+VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceExternalBufferProperties(
+    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+    VkExternalBufferProperties* pExternalBufferProperties) {
+    if (nullptr != pExternalBufferProperties) {
+        auto& phys_dev = icd.GetPhysDevice(physicalDevice);
+        memcpy(&pExternalBufferProperties->externalMemoryProperties, &phys_dev.external_memory_properties,
+               sizeof(VkExternalMemoryProperties));
+    }
+}
+VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceExternalSemaphoreProperties(
+    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+    VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+    if (nullptr != pExternalSemaphoreProperties) {
+        auto& phys_dev = icd.GetPhysDevice(physicalDevice);
+        memcpy(pExternalSemaphoreProperties, &phys_dev.external_semaphore_properties, sizeof(VkExternalSemaphoreProperties));
+    }
+}
+VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceExternalFenceProperties(
+    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+    VkExternalFenceProperties* pExternalFenceProperties) {
+    if (nullptr != pExternalFenceProperties) {
+        auto& phys_dev = icd.GetPhysDevice(physicalDevice);
+        memcpy(pExternalFenceProperties, &phys_dev.external_fence_properties, sizeof(VkExternalFenceProperties));
+    }
+}
 
 //// trampolines
 
@@ -633,12 +832,36 @@ PFN_vkVoidFunction get_instance_func_ver_1_2(VkInstance instance, const char* pN
 }
 
 PFN_vkVoidFunction get_physical_device_func_wsi(VkInstance instance, const char* pName) {
-    if (string_eq(pName, "vkGetPhysicalDeviceSurfaceSupportKHR")) return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceSupportKHR);
-    if (string_eq(pName, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"))
-        return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
-    if (string_eq(pName, "vkGetPhysicalDeviceSurfaceFormatsKHR")) return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceFormatsKHR);
-    if (string_eq(pName, "vkGetPhysicalDeviceSurfacePresentModesKHR"))
-        return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfacePresentModesKHR);
+    if (IsInstanceExtensionEnabled("VK_KHR_surface")) {
+        if (string_eq(pName, "vkGetPhysicalDeviceSurfaceSupportKHR")) return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceSupportKHR);
+        if (string_eq(pName, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
+        if (string_eq(pName, "vkGetPhysicalDeviceSurfaceFormatsKHR")) return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceFormatsKHR);
+        if (string_eq(pName, "vkGetPhysicalDeviceSurfacePresentModesKHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfacePresentModesKHR);
+    }
+    if (IsInstanceExtensionEnabled("VK_KHR_get_surface_capabilities2")) {
+        if (string_eq(pName, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceCapabilities2KHR);
+        if (string_eq(pName, "vkGetPhysicalDeviceSurfaceFormats2KHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceSurfaceFormats2KHR);
+    }
+    if (IsInstanceExtensionEnabled("VK_KHR_display")) {
+        if (string_eq(pName, "vkGetPhysicalDeviceDisplayPropertiesKHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceDisplayPropertiesKHR);
+        if (string_eq(pName, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
+        if (string_eq(pName, "vkGetDisplayPlaneSupportedDisplaysKHR"))
+            return TO_VOID_PFN(test_vkGetDisplayPlaneSupportedDisplaysKHR);
+        if (string_eq(pName, "vkGetDisplayModePropertiesKHR")) return TO_VOID_PFN(test_vkGetDisplayModePropertiesKHR);
+        if (string_eq(pName, "vkCreateDisplayModeKHR")) return TO_VOID_PFN(test_vkCreateDisplayModeKHR);
+        if (string_eq(pName, "vkGetDisplayPlaneCapabilitiesKHR")) return TO_VOID_PFN(test_vkGetDisplayPlaneCapabilitiesKHR);
+        if (string_eq(pName, "vkCreateDisplayPlaneSurfaceKHR")) return TO_VOID_PFN(test_vkCreateDisplayPlaneSurfaceKHR);
+    }
+    if (IsInstanceExtensionEnabled("VK_EXT_acquire_drm_display")) {
+        if (string_eq(pName, "vkAcquireDrmDisplayEXT")) return TO_VOID_PFN(test_vkAcquireDrmDisplayEXT);
+        if (string_eq(pName, "vkGetDrmDisplayEXT")) return TO_VOID_PFN(test_vkGetDrmDisplayEXT);
+    }
     return nullptr;
 }
 
@@ -743,21 +966,46 @@ PFN_vkVoidFunction get_physical_device_func(VkInstance instance, const char* pNa
 
     if (icd.icd_api_version >= VK_MAKE_API_VERSION(0, 1, 1, 0) ||
         IsInstanceExtensionEnabled("VK_KHR_get_physical_device_properties2")) {
-        if (string_eq(pName, "vkGetPhysicalDeviceFeatures2")) return TO_VOID_PFN(test_vkGetPhysicalDeviceFeatures2);
-        if (string_eq(pName, "vkGetPhysicalDeviceProperties2")) return TO_VOID_PFN(test_vkGetPhysicalDeviceProperties2);
-        if (string_eq(pName, "vkGetPhysicalDeviceFormatProperties2")) return TO_VOID_PFN(test_vkGetPhysicalDeviceFormatProperties2);
-        if (string_eq(pName, "vkGetPhysicalDeviceMemoryProperties2")) return TO_VOID_PFN(test_vkGetPhysicalDeviceMemoryProperties2);
-
-        if (string_eq(pName, "vkGetPhysicalDeviceQueueFamilyProperties2"))
+        if (string_eq(pName, "vkGetPhysicalDeviceFeatures2") || string_eq(pName, "vkGetPhysicalDeviceFeatures2KHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceFeatures2);
+        if (string_eq(pName, "vkGetPhysicalDeviceProperties2") || string_eq(pName, "vkGetPhysicalDeviceProperties2KHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceProperties2);
+        if (string_eq(pName, "vkGetPhysicalDeviceFormatProperties2") || string_eq(pName, "vkGetPhysicalDeviceFormatProperties2KHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceFormatProperties2);
+        if (string_eq(pName, "vkGetPhysicalDeviceMemoryProperties2") || string_eq(pName, "vkGetPhysicalDeviceMemoryProperties2KHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceMemoryProperties2);
+
+        if (string_eq(pName, "vkGetPhysicalDeviceQueueFamilyProperties2") ||
+            string_eq(pName, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"))
             return TO_VOID_PFN(test_vkGetPhysicalDeviceQueueFamilyProperties2);
 
-        if (string_eq(pName, "vkGetPhysicalDeviceSparseImageFormatProperties2"))
+        if (string_eq(pName, "vkGetPhysicalDeviceSparseImageFormatProperties2") ||
+            string_eq(pName, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"))
             return TO_VOID_PFN(test_vkGetPhysicalDeviceSparseImageFormatProperties2);
 
-        if (string_eq(pName, "vkGetPhysicalDeviceImageFormatProperties2")) {
+        if (string_eq(pName, "vkGetPhysicalDeviceImageFormatProperties2") ||
+            string_eq(pName, "vkGetPhysicalDeviceImageFormatProperties2KHR")) {
             return TO_VOID_PFN(test_vkGetPhysicalDeviceImageFormatProperties2);
         }
     }
+    if (icd.icd_api_version >= VK_MAKE_API_VERSION(0, 1, 1, 0) ||
+        IsInstanceExtensionEnabled("VK_KHR_external_memory_capabilities")) {
+        if (string_eq(pName, "vkGetPhysicalDeviceExternalBufferProperties") ||
+            string_eq(pName, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceExternalBufferProperties);
+    }
+    if (icd.icd_api_version >= VK_MAKE_API_VERSION(0, 1, 1, 0) ||
+        IsInstanceExtensionEnabled("VK_KHR_external_semaphore_capabilities")) {
+        if (string_eq(pName, "vkGetPhysicalDeviceExternalSemaphoreProperties") ||
+            string_eq(pName, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceExternalSemaphoreProperties);
+    }
+    if (icd.icd_api_version >= VK_MAKE_API_VERSION(0, 1, 1, 0) ||
+        IsInstanceExtensionEnabled("VK_KHR_external_fence_capabilities")) {
+        if (string_eq(pName, "vkGetPhysicalDeviceExternalFenceProperties") ||
+            string_eq(pName, "vkGetPhysicalDeviceExternalFencePropertiesKHR"))
+            return TO_VOID_PFN(test_vkGetPhysicalDeviceExternalFenceProperties);
+    }
     if (icd.supports_tooling_info_ext) {
         if (string_eq(pName, "vkGetPhysicalDeviceToolPropertiesEXT")) return TO_VOID_PFN(test_vkGetPhysicalDeviceToolPropertiesEXT);
     }
index fd509f235950d0e6e9a75493d7975ef5aeb1e0dc..490309c1c475c5e046b21e5bb1861693cde980e7 100644 (file)
@@ -589,6 +589,8 @@ struct MockQueueFamilyProperties {
     BUILDER_VALUE(MockQueueFamilyProperties, VkQueueFamilyProperties, properties, {})
     BUILDER_VALUE(MockQueueFamilyProperties, bool, support_present, false)
 
+    MockQueueFamilyProperties() {}
+
     MockQueueFamilyProperties(VkQueueFamilyProperties properties, bool support_present = false)
         : properties(properties), support_present(support_present) {}
 
index d7e053c0b39d6b61c06a9627a730bf34edb3c5e8..8ca26a93694feee08fe4f3fd1173d0eca40e5059 100644 (file)
@@ -516,10 +516,11 @@ TEST_F(LoaderHandleValidTests, BadInstCreateXlibSurf) {
 // ---- Invalid Physical Device tests
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFeature) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -533,10 +534,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFeature) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFormatProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -551,10 +553,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFormatProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevImgFormatProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -571,10 +574,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevImgFormatProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -588,10 +592,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevQueueFamProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -604,10 +609,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevQueueFamProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevDevMemProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -621,10 +627,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevDevMemProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevCreateDevice) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -657,10 +664,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevCreateDevice) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevEnumDevExtProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -673,10 +681,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevEnumDevExtProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevEnumDevLayerProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -689,10 +698,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevEnumDevLayerProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevSparseImgFormatProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -709,10 +719,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevSparseImgFormatProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFeature2) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -728,10 +739,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFeature2) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFormatProps2) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -748,10 +760,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevFormatProps2) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevImgFormatProps2) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -770,10 +783,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevImgFormatProps2) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevProps2) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -789,10 +803,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevProps2) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevQueueFamProps2) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -805,10 +820,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevQueueFamProps2) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevDevMemProps2) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -824,10 +840,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevDevMemProps2) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevSparseImgFormatProps2) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -845,10 +862,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevSparseImgFormatProps2) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevExternFenceProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -865,10 +883,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevExternFenceProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevExternBufferProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
@@ -885,10 +904,11 @@ TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevExternBufferProps) {
 }
 
 TEST_F(LoaderHandleValidTests, BadPhysDevGetPhysDevExternSemaphoreProps) {
-    auto& driver = env->get_test_icd();
-    driver.physical_devices.emplace_back("physical_device_0");
+    env->get_test_icd().physical_devices.push_back({});
+    env->get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 1, 0);
 
     InstWrapper instance(env->vulkan_functions);
+    instance.create_info.set_api_version(1, 1, 0);
     instance.CheckCreate();
 
     struct BadData {
diff --git a/tests/loader_phys_dev_inst_ext_tests.cpp b/tests/loader_phys_dev_inst_ext_tests.cpp
new file mode 100644 (file)
index 0000000..5173d44
--- /dev/null
@@ -0,0 +1,4726 @@
+/*
+ * Copyright (c) 2021 The Khronos Group Inc.
+ * Copyright (c) 2021 Valve Corporation
+ * Copyright (c) 2021 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and/or associated documentation files (the "Materials"), to
+ * deal in the Materials without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Materials, and to permit persons to whom the Materials are
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included in
+ * all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
+ * USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ * Author: Charles Giessen <charles@lunarg.com>
+ * Author: Mark Young <marky@lunarg.com>
+ */
+
+#include "test_environment.h"
+
+// These tests are all instance extension tests that touch physical devices.  This was
+// before the idea that physical device extensions were more appropriately found in the
+// list of device extensions.  Because of that, all these tests need to support devices
+// that don't support the extension and have a fallback path in the loader that needs
+// validation.
+
+class LoaderInstPhysDevExts : public ::testing::Test {
+   protected:
+    virtual void SetUp() {
+        env = std::unique_ptr<FrameworkEnvironment>(new FrameworkEnvironment());
+        env->add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+    }
+
+    virtual void TearDown() { env.reset(); }
+    std::unique_ptr<FrameworkEnvironment> env;
+};
+
+// Fill in random but valid data into the device properties struct for the current physical device
+static void FillInRandomICDInfo(uint32_t& vendor_id, uint32_t& driver_vers) {
+    vendor_id = VK_MAKE_API_VERSION(0, rand() % 64, rand() % 255, rand() % 255);
+    driver_vers = VK_MAKE_API_VERSION(0, rand() % 64, rand() % 255, rand() % 255);
+}
+
+// Fill in random but valid data into the device properties struct for the current physical device
+static void FillInRandomDeviceProps(VkPhysicalDeviceProperties& props, uint32_t api_vers, uint32_t vendor, uint32_t driver_vers) {
+    props.apiVersion = api_vers;
+    props.driverVersion = driver_vers;
+    props.vendorID = vendor;
+    props.deviceID = (static_cast<uint32_t>(rand()) >> 4) + (static_cast<uint32_t>(rand()) << 2);
+    props.deviceType = static_cast<VkPhysicalDeviceType>(rand() % 5);
+    for (uint8_t idx = 0; idx < VK_UUID_SIZE; ++idx) {
+        props.pipelineCacheUUID[idx] = static_cast<uint8_t>(rand() % 255);
+    }
+}
+
+//
+// VK_KHR_get_physical_device_properties2
+//
+
+// Test vkGetPhysicalDeviceProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
+    ASSERT_EQ(GetPhysDevProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevProps2KHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
+    ASSERT_EQ(GetPhysDevProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomDeviceProps(env.get_test_icd(0).physical_devices.back().properties, VK_API_VERSION_1_0, 5, 123);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
+    ASSERT_NE(GetPhysDevProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceProperties props{};
+    instance->vkGetPhysicalDeviceProperties(physical_device, &props);
+    VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
+    GetPhysDevProps2(physical_device, &props2);
+
+    // Both properties should match
+    ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
+    ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
+    ASSERT_EQ(props.vendorID, props2.properties.vendorID);
+    ASSERT_EQ(props.deviceID, props2.properties.deviceID);
+    ASSERT_EQ(props.deviceType, props2.properties.deviceType);
+    ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
+}
+
+// Test vkGetPhysicalDeviceProperties2 where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+    FillInRandomDeviceProps(env.get_test_icd(0).physical_devices.back().properties, VK_API_VERSION_1_1, 5, 123);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+    ASSERT_NE(GetPhysDevProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceProperties props{};
+    instance->vkGetPhysicalDeviceProperties(physical_device, &props);
+    VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
+    GetPhysDevProps2(physical_device, &props2);
+
+    // Both properties should match
+    ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
+    ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
+    ASSERT_EQ(props.vendorID, props2.properties.vendorID);
+    ASSERT_EQ(props.deviceID, props2.properties.deviceID);
+    ASSERT_EQ(props.deviceType, props2.properties.deviceType);
+    ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
+}
+
+// Test vkGetPhysicalDeviceProperties2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevProps2Mixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+    ASSERT_NE(GetPhysDevProps2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &props);
+        VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
+        GetPhysDevProps2(physical_devices[dev], &props2);
+
+        // Both properties should match
+        ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
+        ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
+        ASSERT_EQ(props.vendorID, props2.properties.vendorID);
+        ASSERT_EQ(props.deviceID, props2.properties.deviceID);
+        ASSERT_EQ(props.deviceType, props2.properties.deviceType);
+        ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
+    }
+}
+
+// Fill in random but valid data into the features struct for the current physical device
+static void FillInRandomFeatures(VkPhysicalDeviceFeatures& feats) {
+    uint32_t num_bool_32 = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
+    VkBool32* cur = reinterpret_cast<VkBool32*>(&feats);
+    for (uint32_t val = 0; val < num_bool_32; ++val) {
+        *cur = (rand() % 2 == 0) ? VK_FALSE : VK_TRUE;
+        cur++;
+    }
+}
+
+// Compare the contents of the feature structs
+static void CompareFeatures(const VkPhysicalDeviceFeatures& feats1, const VkPhysicalDeviceFeatures2& feats2) {
+    uint32_t num_bool_32 = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
+    const VkBool32* v1 = reinterpret_cast<const VkBool32*>(&feats1);
+    const VkBool32* v2 = reinterpret_cast<const VkBool32*>(&feats2.features);
+    for (uint32_t val = 0; val < num_bool_32; ++val) {
+        ASSERT_EQ(*v1, *v2);
+        ++v1;
+        ++v2;
+    }
+}
+
+// Test vkGetPhysicalDeviceFeatures2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevFeats2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
+    ASSERT_EQ(GetPhysDevFeats2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceFeatures2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevFeatsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
+    ASSERT_EQ(GetPhysDevFeats2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceFeatures2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevFeats2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomFeatures(env.get_test_icd(0).physical_devices.back().features);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
+    ASSERT_NE(GetPhysDevFeats2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceFeatures feats{};
+    instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
+    VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR};
+    GetPhysDevFeats2(physical_device, &feats2);
+    CompareFeatures(feats, feats2);
+}
+
+// Test vkGetPhysicalDeviceFeatures2 where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevFeats2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+    FillInRandomFeatures(env.get_test_icd(0).physical_devices.back().features);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+    ASSERT_NE(GetPhysDevFeats2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceFeatures feats{};
+    instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
+    VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+    GetPhysDevFeats2(physical_device, &feats2);
+    CompareFeatures(feats, feats2);
+}
+
+// Test vkGetPhysicalDeviceFeatures2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevFeatsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomFeatures(cur_dev.features);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+    ASSERT_NE(GetPhysDevFeats2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceFeatures feats{};
+        instance->vkGetPhysicalDeviceFeatures(physical_devices[dev], &feats);
+        VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+        GetPhysDevFeats2(physical_devices[dev], &feats2);
+        CompareFeatures(feats, feats2);
+    }
+}
+
+// Fill in random but valid data into the format properties struct for the current physical device
+static void FillInRandomFormatProperties(std::vector<VkFormatProperties>& props) {
+    props.resize(5);
+    for (uint8_t form = 0; form < 5; ++form) {
+        props[form].bufferFeatures = static_cast<VkFormatFeatureFlags>(rand());
+        props[form].linearTilingFeatures = static_cast<VkFormatFeatureFlags>(rand());
+        props[form].optimalTilingFeatures = static_cast<VkFormatFeatureFlags>(rand());
+    }
+}
+
+// Test vkGetPhysicalDeviceFormatProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevFormatProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2KHR"));
+    ASSERT_EQ(GetPhysDevFormatProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceFormatProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevFormatPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2KHR"));
+    ASSERT_EQ(GetPhysDevFormatProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceFormatProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevFormatProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomFormatProperties(env.get_test_icd(0).physical_devices.back().format_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2KHR"));
+    ASSERT_NE(GetPhysDevFormatProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkFormatProperties props{};
+    instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
+    VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+    GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
+
+    ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
+    ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
+    ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
+}
+
+// Test vkGetPhysicalDeviceFormatProperties2 where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevFormatProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+    FillInRandomFormatProperties(env.get_test_icd(0).physical_devices.back().format_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2"));
+    ASSERT_NE(GetPhysDevFormatProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkFormatProperties props{};
+    instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
+    VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+    GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
+
+    ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
+    ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
+    ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
+}
+
+// Test vkGetPhysicalDeviceFormatProperties2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevFormatPropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomFormatProperties(cur_dev.format_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2"));
+    ASSERT_NE(GetPhysDevFormatProps2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkFormat format = static_cast<VkFormat>((dev + 1) % 5);
+        VkFormatProperties props{};
+        instance->vkGetPhysicalDeviceFormatProperties(physical_devices[dev], format, &props);
+        VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+        GetPhysDevFormatProps2(physical_devices[dev], format, &props2);
+
+        ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
+        ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
+        ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
+    }
+}
+
+// Fill in random but valid data into the image format data struct for the current physical device
+static void FillInRandomImageFormatData(VkImageFormatProperties& props) {
+    props.maxExtent = {static_cast<uint32_t>(rand() % 512), static_cast<uint32_t>(rand() % 512),
+                       static_cast<uint32_t>(rand() % 512)};
+    props.maxMipLevels = static_cast<uint32_t>(1 << (rand() % 16));
+    props.maxArrayLayers = static_cast<uint32_t>(1 << (rand() % 16));
+    props.sampleCounts = static_cast<VkSampleCountFlags>(1 << (rand() % 7));
+    props.maxResourceSize = static_cast<uint64_t>(rand());
+}
+
+// Test vkGetPhysicalDeviceImageFormatProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevImageFormatProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2KHR"));
+    ASSERT_EQ(GetPhysDevImageFormatProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceImageFormatProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevImageFormatPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2KHR"));
+    ASSERT_EQ(GetPhysDevImageFormatProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceImageFormatProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevImageFormatProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomImageFormatData(env.get_test_icd(0).physical_devices.back().image_format_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2KHR"));
+    ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkImageFormatProperties props{};
+    ASSERT_EQ(VK_SUCCESS,
+              instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+                                                                 VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
+
+    VkPhysicalDeviceImageFormatInfo2 info2{
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
+        nullptr,                                                // pNext
+        VK_FORMAT_R4G4_UNORM_PACK8,                             // format
+        VK_IMAGE_TYPE_2D,                                       // type
+        VK_IMAGE_TILING_OPTIMAL,                                // tiling
+        0,                                                      // usage
+        0,                                                      // flags
+    };
+    VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+    ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
+
+    ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
+    ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
+    ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
+    ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
+    ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
+    ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
+    ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
+}
+
+// Test vkGetPhysicalDeviceImageFormatProperties2 where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevImageFormatProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+    FillInRandomImageFormatData(env.get_test_icd(0).physical_devices.back().image_format_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2"));
+    ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkImageFormatProperties props{};
+    ASSERT_EQ(VK_SUCCESS,
+              instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+                                                                 VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
+
+    VkPhysicalDeviceImageFormatInfo2 info2{
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
+        nullptr,                                                // pNext
+        VK_FORMAT_R4G4_UNORM_PACK8,                             // format
+        VK_IMAGE_TYPE_2D,                                       // type
+        VK_IMAGE_TILING_OPTIMAL,                                // tiling
+        0,                                                      // usage
+        0,                                                      // flags
+    };
+
+    VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+    ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
+
+    ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
+    ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
+    ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
+    ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
+    ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
+    ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
+    ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
+}
+
+// Test vkGetPhysicalDeviceImageFormatProperties2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevImageFormatPropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomImageFormatData(cur_dev.image_format_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2"));
+    ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkImageFormatProperties props{};
+        ASSERT_EQ(VK_SUCCESS,
+                  instance->vkGetPhysicalDeviceImageFormatProperties(physical_devices[dev], VK_FORMAT_R4G4_UNORM_PACK8,
+                                                                     VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
+
+        VkPhysicalDeviceImageFormatInfo2 info2{
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
+            nullptr,                                                // pNext
+            VK_FORMAT_R4G4_UNORM_PACK8,                             // format
+            VK_IMAGE_TYPE_2D,                                       // type
+            VK_IMAGE_TILING_OPTIMAL,                                // tiling
+            0,                                                      // usage
+            0,                                                      // flags
+        };
+        VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+        ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_devices[dev], &info2, &props2));
+
+        ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
+        ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
+        ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
+        ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
+        ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
+        ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
+        ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
+    }
+}
+
+// Test vkGetPhysicalDeviceMemoryProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevMemoryProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2KHR"));
+    ASSERT_EQ(GetPhysDevMemoryProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceMemoryProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevMemoryPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2KHR"));
+    ASSERT_EQ(GetPhysDevMemoryProps2, nullptr);
+}
+
+// Fill in random but valid data into the memory data struct for the current physical device
+static void FillInRandomMemoryData(VkPhysicalDeviceMemoryProperties& props) {
+    props.memoryTypeCount = (rand() % 7) + 1;
+    props.memoryHeapCount = (rand() % 7) + 1;
+    for (uint32_t i = 0; i < props.memoryHeapCount; ++i) {
+        props.memoryHeaps[i].size = (rand() % 728) + (rand() % 728) + 1;
+        props.memoryHeaps[i].flags = (rand() % 2) + 1;
+    }
+    for (uint32_t i = 0; i < props.memoryTypeCount; ++i) {
+        props.memoryTypes[i].propertyFlags = static_cast<VkMemoryPropertyFlags>((rand() % 2) + 1);
+        props.memoryTypes[i].heapIndex = rand() % props.memoryHeapCount;
+    }
+}
+
+// Compare the memory structs
+static void CompareMemoryData(const VkPhysicalDeviceMemoryProperties& props1, const VkPhysicalDeviceMemoryProperties2& props2) {
+    ASSERT_EQ(props1.memoryTypeCount, props2.memoryProperties.memoryTypeCount);
+    ASSERT_EQ(props1.memoryHeapCount, props2.memoryProperties.memoryHeapCount);
+    for (uint32_t i = 0; i < props1.memoryHeapCount; ++i) {
+        ASSERT_EQ(props1.memoryHeaps[i].size, props2.memoryProperties.memoryHeaps[i].size);
+        ASSERT_EQ(props1.memoryHeaps[i].flags, props2.memoryProperties.memoryHeaps[i].flags);
+    }
+    for (uint32_t i = 0; i < props1.memoryTypeCount; ++i) {
+        ASSERT_EQ(props1.memoryTypes[i].propertyFlags, props2.memoryProperties.memoryTypes[i].propertyFlags);
+        ASSERT_EQ(props1.memoryTypes[i].heapIndex, props2.memoryProperties.memoryTypes[i].heapIndex);
+    }
+}
+
+// Test vkGetPhysicalDeviceMemoryProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevMemoryProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomMemoryData(env.get_test_icd(0).physical_devices.back().memory_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2KHR"));
+    ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceMemoryProperties props{};
+    instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
+
+    VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
+    GetPhysDevMemoryProps2(physical_device, &props2);
+    CompareMemoryData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceMemoryProperties2 where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevMemoryProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+    FillInRandomMemoryData(env.get_test_icd(0).physical_devices.back().memory_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2"));
+    ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceMemoryProperties props{};
+    instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
+
+    VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
+    GetPhysDevMemoryProps2(physical_device, &props2);
+    CompareMemoryData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceMemoryProperties2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevMemoryPropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomMemoryData(cur_dev.memory_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2"));
+    ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceMemoryProperties props{};
+        instance->vkGetPhysicalDeviceMemoryProperties(physical_devices[dev], &props);
+
+        VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
+        GetPhysDevMemoryProps2(physical_devices[dev], &props2);
+        CompareMemoryData(props, props2);
+    }
+}
+
+// Test vkGetPhysicalDeviceQueueFamilyProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"));
+    ASSERT_EQ(GetPhysDevQueueFamilyProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceQueueFamilyProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevQueueFamilyPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"));
+    ASSERT_EQ(GetPhysDevQueueFamilyProps2, nullptr);
+}
+
+// Fill in random but valid data into the queue family data struct for the current physical device
+static uint32_t FillInRandomQueueFamilyData(std::vector<MockQueueFamilyProperties>& props) {
+    props.resize((rand() % 4) + 1);
+    for (uint32_t i = 0; i < props.size(); ++i) {
+        props[i].properties.queueFlags = (rand() % 30) + 1;
+        props[i].properties.queueCount = (rand() % 7) + 1;
+        props[i].properties.timestampValidBits = (rand() % 30) + 7;
+        props[i].properties.minImageTransferGranularity.width = (rand() % 30) + 1;
+        props[i].properties.minImageTransferGranularity.height = (rand() % 30) + 1;
+        props[i].properties.minImageTransferGranularity.depth = (rand() % 30) + 1;
+        props[i].support_present = (rand() % 2);
+    }
+    return props.size();
+}
+
+// Compare the queue family structs
+static void CompareQueueFamilyData(const std::vector<VkQueueFamilyProperties>& props1,
+                                   const std::vector<VkQueueFamilyProperties2>& props2) {
+    ASSERT_EQ(props1.size(), props2.size());
+    for (uint32_t i = 0; i < props1.size(); ++i) {
+        ASSERT_EQ(props1[i].queueFlags, props2[i].queueFamilyProperties.queueFlags);
+        ASSERT_EQ(props1[i].queueCount, props2[i].queueFamilyProperties.queueCount);
+        ASSERT_EQ(props1[i].timestampValidBits, props2[i].queueFamilyProperties.timestampValidBits);
+        ASSERT_EQ(props1[i].minImageTransferGranularity.width, props2[i].queueFamilyProperties.minImageTransferGranularity.width);
+        ASSERT_EQ(props1[i].minImageTransferGranularity.height, props2[i].queueFamilyProperties.minImageTransferGranularity.height);
+        ASSERT_EQ(props1[i].minImageTransferGranularity.depth, props2[i].queueFamilyProperties.minImageTransferGranularity.depth);
+    }
+}
+
+// Test vkGetPhysicalDeviceQueueFamilyProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    uint32_t num_fam = FillInRandomQueueFamilyData(env.get_test_icd(0).physical_devices.back().queue_family_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"));
+    ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    uint32_t ret_fam_1 = 0;
+    std::vector<VkQueueFamilyProperties> props{};
+    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
+    ASSERT_EQ(num_fam, ret_fam_1);
+    props.resize(ret_fam_1);
+
+    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
+
+    std::vector<VkQueueFamilyProperties2> props2{};
+    uint32_t ret_fam_2 = 0;
+    GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
+    ASSERT_EQ(ret_fam_1, ret_fam_2);
+    props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
+    GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
+    CompareQueueFamilyData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceQueueFamilyProperties2 where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+    uint32_t num_fam = FillInRandomQueueFamilyData(env.get_test_icd(0).physical_devices.back().queue_family_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2"));
+    ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    uint32_t ret_fam_1 = 0;
+    std::vector<VkQueueFamilyProperties> props{};
+    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
+    ASSERT_EQ(num_fam, ret_fam_1);
+    props.resize(ret_fam_1);
+
+    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
+
+    std::vector<VkQueueFamilyProperties2> props2{};
+    uint32_t ret_fam_2 = 0;
+    GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
+    ASSERT_EQ(ret_fam_1, ret_fam_2);
+    props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
+    GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
+    CompareQueueFamilyData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceQueueFamilyProperties2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevQueueFamilyPropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomQueueFamilyData(cur_dev.queue_family_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2"));
+    ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        uint32_t ret_fam_1 = 0;
+        std::vector<VkQueueFamilyProperties> props{};
+        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[dev], &ret_fam_1, nullptr);
+        props.resize(ret_fam_1);
+        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[dev], &ret_fam_1, props.data());
+
+        std::vector<VkQueueFamilyProperties2> props2{};
+        uint32_t ret_fam_2 = 0;
+        GetPhysDevQueueFamilyProps2(physical_devices[dev], &ret_fam_2, nullptr);
+        ASSERT_EQ(ret_fam_1, ret_fam_2);
+        props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
+        GetPhysDevQueueFamilyProps2(physical_devices[dev], &ret_fam_2, props2.data());
+        CompareQueueFamilyData(props, props2);
+    }
+}
+
+// Test vkGetPhysicalDeviceSparseImageFormatProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"));
+    ASSERT_EQ(GetPhysDevSparseImageFormatProps2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceSparseImageFormatProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevSparseImageFormatPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"));
+    ASSERT_EQ(GetPhysDevSparseImageFormatProps2, nullptr);
+}
+
+// Fill in random but valid data into the sparse image format data struct for the current physical device
+static void FillInRandomSparseImageFormatData(std::vector<VkSparseImageFormatProperties>& props) {
+    props.resize((rand() % 4) + 1);
+    for (uint32_t i = 0; i < props.size(); ++i) {
+        props[i].aspectMask = static_cast<VkImageAspectFlags>((rand() % 0x7FE) + 1);
+        props[i].imageGranularity = {static_cast<uint32_t>(rand() % 512), static_cast<uint32_t>(rand() % 512),
+                                     static_cast<uint32_t>(rand() % 512)};
+        props[i].flags = static_cast<VkSparseImageFormatFlags>((rand() % 6) + 1);
+    }
+}
+
+// Compare the sparse image format structs
+static void CompareSparseImageFormatData(const std::vector<VkSparseImageFormatProperties>& props1,
+                                         const std::vector<VkSparseImageFormatProperties2>& props2) {
+    ASSERT_EQ(props1.size(), props2.size());
+    for (uint32_t i = 0; i < props1.size(); ++i) {
+        ASSERT_EQ(props1[i].aspectMask, props2[i].properties.aspectMask);
+        ASSERT_EQ(props1[i].imageGranularity.width, props2[i].properties.imageGranularity.width);
+        ASSERT_EQ(props1[i].imageGranularity.height, props2[i].properties.imageGranularity.height);
+        ASSERT_EQ(props1[i].imageGranularity.depth, props2[i].properties.imageGranularity.depth);
+        ASSERT_EQ(props1[i].flags, props2[i].properties.flags);
+    }
+}
+
+// Test vkGetPhysicalDeviceSparseImageFormatProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomSparseImageFormatData(env.get_test_icd(0).physical_devices.back().sparse_image_format_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"));
+    ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkSparseImageFormatProperties> props{};
+    uint32_t sparse_count_1 = 0;
+    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
+    ASSERT_NE(sparse_count_1, 0);
+    props.resize(sparse_count_1);
+    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
+    ASSERT_NE(sparse_count_1, 0);
+
+    VkPhysicalDeviceSparseImageFormatInfo2 info2{
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
+        nullptr,                                                       // pNext
+        VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
+        VK_IMAGE_TYPE_2D,                                              // type
+        VK_SAMPLE_COUNT_4_BIT,                                         // samples
+        VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
+        VK_IMAGE_TILING_OPTIMAL,                                       // tiling
+    };
+    std::vector<VkSparseImageFormatProperties2> props2{};
+    uint32_t sparse_count_2 = 0;
+    GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
+    ASSERT_EQ(sparse_count_1, sparse_count_2);
+    props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
+    GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
+    ASSERT_EQ(sparse_count_1, sparse_count_2);
+    CompareSparseImageFormatData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceSparseImageFormatProperties2 where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+    FillInRandomSparseImageFormatData(env.get_test_icd(0).physical_devices.back().sparse_image_format_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2"));
+    ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkSparseImageFormatProperties> props{};
+    uint32_t sparse_count_1 = 0;
+    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
+    ASSERT_NE(sparse_count_1, 0);
+    props.resize(sparse_count_1);
+    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
+    ASSERT_NE(sparse_count_1, 0);
+
+    VkPhysicalDeviceSparseImageFormatInfo2 info2{
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
+        nullptr,                                                       // pNext
+        VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
+        VK_IMAGE_TYPE_2D,                                              // type
+        VK_SAMPLE_COUNT_4_BIT,                                         // samples
+        VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
+        VK_IMAGE_TILING_OPTIMAL,                                       // tiling
+    };
+    std::vector<VkSparseImageFormatProperties2> props2{};
+    uint32_t sparse_count_2 = 0;
+    GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
+    ASSERT_EQ(sparse_count_1, sparse_count_2);
+    props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
+    GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
+    ASSERT_EQ(sparse_count_1, sparse_count_2);
+    CompareSparseImageFormatData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceSparseImageFormatProperties2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevSparseImageFormatPropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomSparseImageFormatData(cur_dev.sparse_image_format_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2"));
+    ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        std::vector<VkSparseImageFormatProperties> props{};
+        uint32_t sparse_count_1 = 0;
+        instance->vkGetPhysicalDeviceSparseImageFormatProperties(
+            physical_devices[dev], VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D, VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+            VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
+        ASSERT_NE(sparse_count_1, 0);
+        props.resize(sparse_count_1);
+        instance->vkGetPhysicalDeviceSparseImageFormatProperties(
+            physical_devices[dev], VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D, VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+            VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
+        ASSERT_NE(sparse_count_1, 0);
+
+        VkPhysicalDeviceSparseImageFormatInfo2 info2{
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
+            nullptr,                                                       // pNext
+            VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
+            VK_IMAGE_TYPE_2D,                                              // type
+            VK_SAMPLE_COUNT_4_BIT,                                         // samples
+            VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
+            VK_IMAGE_TILING_OPTIMAL,                                       // tiling
+        };
+        std::vector<VkSparseImageFormatProperties2> props2{};
+        uint32_t sparse_count_2 = 0;
+        GetPhysDevSparseImageFormatProps2(physical_devices[dev], &info2, &sparse_count_2, nullptr);
+        ASSERT_EQ(sparse_count_1, sparse_count_2);
+        props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
+        GetPhysDevSparseImageFormatProps2(physical_devices[dev], &info2, &sparse_count_2, props2.data());
+        ASSERT_EQ(sparse_count_1, sparse_count_2);
+        CompareSparseImageFormatData(props, props2);
+    }
+}
+
+//
+// VK_KHR_external_memory_capabilities
+//
+
+// Test vkGetPhysicalDeviceExternalBufferPropertiesKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtBufPropsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceExternalBufferProperties, nullptr);
+}
+
+// Test vkGetPhysicalDeviceExternalBufferPropertiesKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtBufPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceExternalBufferProperties, nullptr);
+}
+
+// Fill in random but valid data into the external memorydata struct for the current physical device
+static void FillInRandomExtMemoryData(VkExternalMemoryProperties& props) {
+    props.externalMemoryFeatures = static_cast<VkExternalMemoryFeatureFlags>((rand() % 6) + 1);
+    props.exportFromImportedHandleTypes = static_cast<VkExternalMemoryHandleTypeFlags>((rand() % 0x1FFE) + 1);
+    props.compatibleHandleTypes = static_cast<VkExternalMemoryHandleTypeFlags>((rand() % 0x1FFE) + 1);
+}
+
+// Compare the external memory data structs
+static void CompareExtMemoryData(const VkExternalMemoryProperties& props1, const VkExternalMemoryProperties& props2,
+                                 bool supported = true) {
+    if (supported) {
+        ASSERT_EQ(props1.externalMemoryFeatures, props2.externalMemoryFeatures);
+        ASSERT_EQ(props1.exportFromImportedHandleTypes, props2.exportFromImportedHandleTypes);
+        ASSERT_EQ(props1.compatibleHandleTypes, props2.compatibleHandleTypes);
+    } else {
+        ASSERT_EQ(0, props2.externalMemoryFeatures);
+        ASSERT_EQ(0, props2.exportFromImportedHandleTypes);
+        ASSERT_EQ(0, props2.compatibleHandleTypes);
+    }
+}
+
+// Test vkGetPhysicalDeviceExternalBufferPropertiesKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtBufProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceExternalBufferInfoKHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR};
+    VkExternalBufferPropertiesKHR props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR};
+    GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
+    CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties, props.externalMemoryProperties);
+}
+
+// Test vkGetPhysicalDeviceExternalBufferProperties where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtBufProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 0});
+    FillInRandomExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferProperties"));
+    ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
+    VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
+    GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
+    CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties, props.externalMemoryProperties);
+}
+
+// Test vkGetPhysicalDeviceExternalBufferProperties where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevExtBufPropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomExtMemoryData(cur_dev.external_memory_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferProperties"));
+    ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
+                    VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
+                    GetPhysicalDeviceExternalBufferProperties(physical_devices[dev], &info, &props);
+                    // No driver support for extension or 1.1 for ICD 1, all others support
+                    CompareExtMemoryData(cur_dev.external_memory_properties, props.externalMemoryProperties, icd != 1);
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+//
+// VK_KHR_external_semaphore_capabilities
+//
+
+// Test vkGetPhysicalDeviceExternalSemaphorePropertiesKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtSemPropsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
+}
+
+// Test vkGetPhysicalDeviceExternalSemaphorePropertiesKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtSemPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
+}
+
+// Fill in random but valid data into the external semaphore data struct for the current physical device
+static void FillInRandomExtSemData(VkExternalSemaphoreProperties& props) {
+    props.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES;
+    props.pNext = nullptr;
+    props.exportFromImportedHandleTypes = static_cast<VkExternalSemaphoreHandleTypeFlags>((rand() % 0xFFF) + 1);
+    props.compatibleHandleTypes = static_cast<VkExternalSemaphoreHandleTypeFlags>((rand() % 0xFFF) + 1);
+    props.externalSemaphoreFeatures = static_cast<VkExternalSemaphoreFeatureFlags>((rand() % 0xFFF) + 1);
+}
+
+// Compare the external semaphore data structs
+static void CompareExtSemaphoreData(const VkExternalSemaphoreProperties& props1, const VkExternalSemaphoreProperties& props2,
+                                    bool supported = true) {
+    if (supported) {
+        ASSERT_EQ(props1.externalSemaphoreFeatures, props2.externalSemaphoreFeatures);
+        ASSERT_EQ(props1.exportFromImportedHandleTypes, props2.exportFromImportedHandleTypes);
+        ASSERT_EQ(props1.compatibleHandleTypes, props2.compatibleHandleTypes);
+    } else {
+        ASSERT_EQ(0, props2.externalSemaphoreFeatures);
+        ASSERT_EQ(0, props2.exportFromImportedHandleTypes);
+        ASSERT_EQ(0, props2.compatibleHandleTypes);
+    }
+}
+
+// Test vkGetPhysicalDeviceExternalSemaphorePropertiesKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtSemProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomExtSemData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceExternalSemaphoreInfoKHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR};
+    VkExternalSemaphorePropertiesKHR props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR};
+    GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
+    CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props);
+}
+
+// Test vkGetPhysicalDeviceExternalSemaphoreProperties where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtSemProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, 0});
+    FillInRandomExtSemData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
+    ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
+    VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
+    GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
+    CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props);
+}
+
+// Test vkGetPhysicalDeviceExternalSemaphoreProperties where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevExtSemPropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomExtSemData(cur_dev.external_semaphore_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
+    ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
+                    VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
+                    GetPhysicalDeviceExternalSemaphoreProperties(physical_devices[dev], &info, &props);
+                    // No driver support for extension or 1.1 for ICD 1, all others support
+                    CompareExtSemaphoreData(cur_dev.external_semaphore_properties, props, icd != 1);
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+//
+// VK_KHR_external_fence_capabilities
+//
+
+// Test vkGetPhysicalDeviceExternalFencePropertiesKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtFencePropsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFencePropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceExternalFenceProperties, nullptr);
+}
+
+// Test vkGetPhysicalDeviceExternalFencePropertiesKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtFencePropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFencePropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceExternalFenceProperties, nullptr);
+}
+
+// Fill in random but valid data into the external fence data struct for the current physical device
+static void FillInRandomExtFenceData(VkExternalFenceProperties& props) {
+    props.sType = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES;
+    props.pNext = nullptr;
+    props.exportFromImportedHandleTypes = static_cast<VkExternalFenceHandleTypeFlags>((rand() % 0xFFF) + 1);
+    props.compatibleHandleTypes = static_cast<VkExternalFenceHandleTypeFlags>((rand() % 0xFFF) + 1);
+    props.externalFenceFeatures = static_cast<VkExternalFenceFeatureFlags>((rand() % 0xFFF) + 1);
+}
+
+// Compare the external fence data structs
+static void CompareExtFenceData(const VkExternalFenceProperties& props1, const VkExternalFenceProperties& props2,
+                                bool supported = true) {
+    if (supported) {
+        ASSERT_EQ(props1.externalFenceFeatures, props2.externalFenceFeatures);
+        ASSERT_EQ(props1.exportFromImportedHandleTypes, props2.exportFromImportedHandleTypes);
+        ASSERT_EQ(props1.compatibleHandleTypes, props2.compatibleHandleTypes);
+    } else {
+        ASSERT_EQ(0, props2.externalFenceFeatures);
+        ASSERT_EQ(0, props2.exportFromImportedHandleTypes);
+        ASSERT_EQ(0, props2.compatibleHandleTypes);
+    }
+}
+
+// Test vkGetPhysicalDeviceExternalFencePropertiesKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtFenceProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFencePropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceExternalFenceInfoKHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR};
+    VkExternalFencePropertiesKHR props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR};
+    GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
+    CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props);
+}
+
+// Test vkGetPhysicalDeviceExternalFenceProperties where instance supports, an ICD, and a device under that ICD
+// also support, so everything should work and return properly.
+TEST_F(LoaderInstPhysDevExts, PhysDevExtFenceProps2Simple) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
+    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, 0});
+    FillInRandomExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFenceProperties"));
+    ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
+    VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
+    GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
+    CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props);
+}
+
+// Test vkGetPhysicalDeviceExternalFenceProperties where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevExtFencePropsMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
+        } else {
+            cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomExtFenceData(cur_dev.external_fence_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.set_api_version(VK_API_VERSION_1_1);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFenceProperties"));
+    ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
+                    VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
+                    GetPhysicalDeviceExternalFenceProperties(physical_devices[dev], &info, &props);
+                    // No driver support for extension or 1.1 for ICD 1, all others support
+                    CompareExtFenceData(cur_dev.external_fence_properties, props, icd != 1);
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+//
+// VK_KHR_get_surface_capabilities2
+//
+
+// Test vkGetPhysicalDeviceSurfaceCapabilities2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceSurfaceCapabilities2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceSurfaceCapabilities2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceSurfaceCapabilities2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceSurfaceCapabilities2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceSurfaceCapabilities2, nullptr);
+}
+
+// Fill in random but valid data into the surface capability data struct for the current physical device
+static void FillInRandomSurfaceCapsData(VkSurfaceCapabilitiesKHR& props) {
+    props.minImageCount = (rand() % 0xFFF) + 1;
+    props.maxImageCount = (rand() % 0xFFF) + 1;
+    props.currentExtent.width = (rand() % 0xFFF) + 1;
+    props.currentExtent.height = (rand() % 0xFFF) + 1;
+    props.minImageExtent.width = (rand() % 0xFFF) + 1;
+    props.minImageExtent.height = (rand() % 0xFFF) + 1;
+    props.maxImageExtent.width = (rand() % 0xFFF) + 1;
+    props.maxImageExtent.height = (rand() % 0xFFF) + 1;
+    props.maxImageArrayLayers = (rand() % 0xFFF) + 1;
+    props.supportedTransforms = static_cast<VkSurfaceTransformFlagsKHR>((rand() % 0xFFF) + 1);
+    props.currentTransform = static_cast<VkSurfaceTransformFlagBitsKHR>((rand() % 0xFFF) + 1);
+    props.supportedCompositeAlpha = static_cast<VkCompositeAlphaFlagsKHR>((rand() % 0xFFF) + 1);
+    props.supportedUsageFlags = static_cast<VkImageUsageFlags>((rand() % 0xFFF) + 1);
+}
+
+// Compare the surface capability data structs
+static void CompareSurfaceCapsData(const VkSurfaceCapabilitiesKHR& props1, const VkSurfaceCapabilitiesKHR& props2,
+                                   bool supported = true) {
+    if (supported) {
+        ASSERT_EQ(props1.minImageCount, props2.minImageCount);
+        ASSERT_EQ(props1.maxImageCount, props2.maxImageCount);
+        ASSERT_EQ(props1.currentExtent.width, props2.currentExtent.width);
+        ASSERT_EQ(props1.currentExtent.height, props2.currentExtent.height);
+        ASSERT_EQ(props1.minImageExtent.width, props2.minImageExtent.width);
+        ASSERT_EQ(props1.minImageExtent.height, props2.minImageExtent.height);
+        ASSERT_EQ(props1.maxImageExtent.width, props2.maxImageExtent.width);
+        ASSERT_EQ(props1.maxImageExtent.height, props2.maxImageExtent.height);
+        ASSERT_EQ(props1.maxImageArrayLayers, props2.maxImageArrayLayers);
+        ASSERT_EQ(props1.supportedTransforms, props2.supportedTransforms);
+        ASSERT_EQ(props1.currentTransform, props2.currentTransform);
+        ASSERT_EQ(props1.supportedCompositeAlpha, props2.supportedCompositeAlpha);
+        ASSERT_EQ(props1.supportedUsageFlags, props2.supportedUsageFlags);
+    } else {
+        ASSERT_EQ(0, props2.minImageCount);
+        ASSERT_EQ(0, props2.maxImageCount);
+        ASSERT_EQ(0, props2.currentExtent.width);
+        ASSERT_EQ(0, props2.currentExtent.height);
+        ASSERT_EQ(0, props2.minImageExtent.width);
+        ASSERT_EQ(0, props2.minImageExtent.height);
+        ASSERT_EQ(0, props2.maxImageExtent.width);
+        ASSERT_EQ(0, props2.maxImageExtent.height);
+        ASSERT_EQ(0, props2.maxImageArrayLayers);
+        ASSERT_EQ(0, props2.supportedTransforms);
+        ASSERT_EQ(0, props2.currentTransform);
+        ASSERT_EQ(0, props2.supportedCompositeAlpha);
+        ASSERT_EQ(0, props2.supportedUsageFlags);
+    }
+}
+
+// Test vkGetPhysicalDeviceSurfaceCapabilities2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
+    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext, third_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomSurfaceCapsData(env.get_test_icd(0).physical_devices.back().surface_capabilities);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions(
+        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceSurfaceCapabilities = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilities, nullptr);
+    auto CreateHeadlessSurfaceEXT = reinterpret_cast<PFN_vkCreateHeadlessSurfaceEXT>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT"));
+    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
+    auto DestroySurfaceKHR =
+        reinterpret_cast<PFN_vkDestroySurfaceKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR"));
+    ASSERT_NE(DestroySurfaceKHR, nullptr);
+    auto GetPhysicalDeviceSurfaceCapabilities2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilities2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkSurfaceKHR surface;
+    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
+    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
+
+    VkSurfaceCapabilitiesKHR props{};
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilities(physical_device, surface, &props));
+
+    VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
+    VkSurfaceCapabilities2KHR props2{VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR};
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilities2(physical_device, &info, &props2));
+    CompareSurfaceCapsData(props, props2.surfaceCapabilities);
+
+    DestroySurfaceKHR(instance.inst, surface, nullptr);
+}
+
+// Test vkGetPhysicalDeviceSurfaceCapabilities2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
+    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extensions({first_ext, third_ext});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension(second_ext);
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_SURFACE_EXTENSION_NAME, 0});
+            cur_dev.extensions.push_back({VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomSurfaceCapsData(cur_dev.surface_capabilities);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions(
+        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceSurfaceCapabilities = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilities, nullptr);
+    auto CreateHeadlessSurfaceEXT = reinterpret_cast<PFN_vkCreateHeadlessSurfaceEXT>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT"));
+    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
+    auto DestroySurfaceKHR =
+        reinterpret_cast<PFN_vkDestroySurfaceKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR"));
+    ASSERT_NE(DestroySurfaceKHR, nullptr);
+    auto GetPhysicalDeviceSurfaceCapabilities2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilities2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    VkSurfaceKHR surface;
+    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
+    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkSurfaceCapabilitiesKHR props{};
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilities(physical_devices[dev], surface, &props));
+
+        VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
+        VkSurfaceCapabilities2KHR props2{VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR};
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilities2(physical_devices[dev], &info, &props2));
+        CompareSurfaceCapsData(props, props2.surfaceCapabilities);
+    }
+
+    DestroySurfaceKHR(instance.inst, surface, nullptr);
+}
+
+// Test vkGetPhysicalDeviceSurfaceFormats2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceSurfaceFormats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormats2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceSurfaceFormats2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceSurfaceFormats2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceSurfaceFormats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormats2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceSurfaceFormats2, nullptr);
+}
+
+// Fill in random but valid data into the surface formats data struct for the current physical device
+static void FillInRandomSurfaceFormatsData(std::vector<VkSurfaceFormatKHR>& props) {
+    props.resize((rand() % 5) + 1);
+    for (uint32_t i = 0; i < props.size(); ++i) {
+        props[i].format = static_cast<VkFormat>((rand() % 0xFFF) + 1);
+        props[i].colorSpace = static_cast<VkColorSpaceKHR>((rand() % 0xFFF) + 1);
+    }
+}
+
+// Compare the surface formats data structs
+static void CompareSurfaceFormatsData(const std::vector<VkSurfaceFormatKHR>& props1, const std::vector<VkSurfaceFormat2KHR>& props2,
+                                      bool supported = true) {
+    ASSERT_EQ(props1.size(), props2.size());
+    for (uint32_t i = 0; i < props1.size(); ++i) {
+        if (supported) {
+            ASSERT_EQ(props1[i].format, props2[i].surfaceFormat.format);
+            ASSERT_EQ(props1[i].colorSpace, props2[i].surfaceFormat.colorSpace);
+        } else {
+            ASSERT_EQ(0, props2[i].surfaceFormat.format);
+            ASSERT_EQ(0, props2[i].surfaceFormat.colorSpace);
+        }
+    }
+}
+
+// Test vkGetPhysicalDeviceSurfaceFormats2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
+    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext, third_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomSurfaceFormatsData(env.get_test_icd(0).physical_devices.back().surface_formats);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions(
+        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceSurfaceFormats = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceFormats, nullptr);
+    auto CreateHeadlessSurfaceEXT = reinterpret_cast<PFN_vkCreateHeadlessSurfaceEXT>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT"));
+    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
+    auto DestroySurfaceKHR =
+        reinterpret_cast<PFN_vkDestroySurfaceKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR"));
+    ASSERT_NE(DestroySurfaceKHR, nullptr);
+    auto GetPhysicalDeviceSurfaceFormats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormats2KHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceFormats2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkSurfaceKHR surface;
+    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
+    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
+
+    std::vector<VkSurfaceFormatKHR> props{};
+    uint32_t count_1 = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats(physical_device, surface, &count_1, nullptr));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().surface_formats.size(), count_1);
+    props.resize(count_1);
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats(physical_device, surface, &count_1, props.data()));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().surface_formats.size(), count_1);
+
+    VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
+    std::vector<VkSurfaceFormat2KHR> props2{};
+    uint32_t count_2 = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2(physical_device, &info, &count_2, nullptr));
+    ASSERT_EQ(count_1, count_2);
+    props2.resize(count_2, VkSurfaceFormat2KHR{VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR});
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2(physical_device, &info, &count_2, props2.data()));
+    CompareSurfaceFormatsData(props, props2);
+
+    DestroySurfaceKHR(instance.inst, surface, nullptr);
+}
+
+// Test vkGetPhysicalDeviceSurfaceFormats2 where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
+    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extensions({first_ext, third_ext});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension(second_ext);
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_SURFACE_EXTENSION_NAME, 0});
+            cur_dev.extensions.push_back({VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomSurfaceFormatsData(cur_dev.surface_formats);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions(
+        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceSurfaceFormats = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceFormats, nullptr);
+    auto CreateHeadlessSurfaceEXT = reinterpret_cast<PFN_vkCreateHeadlessSurfaceEXT>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT"));
+    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
+    auto DestroySurfaceKHR =
+        reinterpret_cast<PFN_vkDestroySurfaceKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR"));
+    ASSERT_NE(DestroySurfaceKHR, nullptr);
+    auto GetPhysicalDeviceSurfaceFormats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormats2KHR"));
+    ASSERT_NE(GetPhysicalDeviceSurfaceFormats2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    VkSurfaceKHR surface;
+    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
+    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        std::vector<VkSurfaceFormatKHR> props{};
+        uint32_t count_1 = 0;
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats(physical_devices[dev], surface, &count_1, nullptr));
+        ASSERT_NE(0, count_1);
+        props.resize(count_1);
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats(physical_devices[dev], surface, &count_1, props.data()));
+        ASSERT_NE(0, count_1);
+
+        VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
+        std::vector<VkSurfaceFormat2KHR> props2{};
+        uint32_t count_2 = 0;
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2(physical_devices[dev], &info, &count_2, nullptr));
+        ASSERT_EQ(count_1, count_2);
+        props2.resize(count_2, VkSurfaceFormat2KHR{VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR});
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2(physical_devices[dev], &info, &count_2, props2.data()));
+        ASSERT_EQ(count_1, count_2);
+        CompareSurfaceFormatsData(props, props2);
+    }
+
+    DestroySurfaceKHR(instance.inst, surface, nullptr);
+}
+
+//
+// VK_KHR_display
+//
+
+// Test vkGetPhysicalDeviceDisplayPropertiesKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPropsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayProperties, nullptr);
+}
+
+// Test vkGetPhysicalDeviceDisplayPropertiesKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceDisplayProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayProperties, nullptr);
+}
+
+// Fill in random but valid data into the display property data struct for the current physical device
+static void FillInRandomDisplayPropData(std::vector<VkDisplayPropertiesKHR>& props) {
+    props.resize((rand() % 5) + 1);
+    for (uint32_t i = 0; i < props.size(); ++i) {
+        props[i].display = (VkDisplayKHR)((rand() % 0xFFFFFFF) + 1);
+        props[i].physicalDimensions.width = static_cast<uint32_t>((rand() % 0xFFF) + 1);
+        props[i].physicalDimensions.height = static_cast<uint32_t>((rand() % 0xFFF) + 1);
+        props[i].physicalResolution.width = static_cast<uint32_t>((rand() % 0xFFF) + 1);
+        props[i].physicalResolution.height = static_cast<uint32_t>((rand() % 0xFFF) + 1);
+        props[i].supportedTransforms = static_cast<VkSurfaceTransformFlagsKHR>((rand() % 0xFFE) + 1);
+        props[i].planeReorderPossible = rand() % 2 > 0 ? VK_TRUE : VK_FALSE;
+        props[i].persistentContent = rand() % 2 > 0 ? VK_TRUE : VK_FALSE;
+    }
+}
+
+// Compare the display property data structs
+static void CompareDisplayPropData(const std::vector<VkDisplayPropertiesKHR>& props1,
+                                   const std::vector<VkDisplayPropertiesKHR>& props2) {
+    ASSERT_EQ(props1.size(), props2.size());
+    for (uint32_t i = 0; i < props1.size(); ++i) {
+        ASSERT_EQ(props1[i].display, props2[i].display);
+        ASSERT_EQ(props1[i].physicalDimensions.width, props2[i].physicalDimensions.width);
+        ASSERT_EQ(props1[i].physicalDimensions.height, props2[i].physicalDimensions.height);
+        ASSERT_EQ(props1[i].physicalResolution.width, props2[i].physicalResolution.width);
+        ASSERT_EQ(props1[i].physicalResolution.height, props2[i].physicalResolution.height);
+        ASSERT_EQ(props1[i].supportedTransforms, props2[i].supportedTransforms);
+        ASSERT_EQ(props1[i].planeReorderPossible, props2[i].planeReorderPossible);
+        ASSERT_EQ(props1[i].persistentContent, props2[i].persistentContent);
+    }
+}
+
+// Test vGetPhysicalDeviceDisplayPropertiesKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPropsKHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomDisplayPropData(env.get_test_icd(0).physical_devices.back().display_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkDisplayPropertiesKHR> props{};
+    uint32_t prop_count = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_device, &prop_count, nullptr));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_properties.size(), prop_count);
+    props.resize(prop_count);
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_device, &prop_count, props.data()));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_properties.size(), prop_count);
+
+    CompareDisplayPropData(props, env.get_test_icd(0).physical_devices.back().display_properties);
+}
+
+// Test vkGetPhysicalDeviceDisplayPropertiesKHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPropsKHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomDisplayPropData(cur_dev.display_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayProperties, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    std::vector<VkDisplayPropertiesKHR> props{};
+                    uint32_t prop_count = 0;
+                    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_devices[dev], &prop_count, nullptr));
+                    if (icd == 1) {
+                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
+                        // loader.
+                        ASSERT_EQ(0, prop_count);
+                    } else {
+                        ASSERT_EQ(cur_dev.display_properties.size(), prop_count);
+                        props.resize(prop_count);
+                        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_devices[dev], &prop_count, props.data()));
+                        ASSERT_EQ(cur_dev.display_properties.size(), prop_count);
+
+                        CompareDisplayPropData(props, cur_dev.display_properties);
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+// Test vkGetPhysicalDeviceDisplayPlanePropertiesKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayPlaneProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayPlaneProperties, nullptr);
+}
+
+// Test vkGetPhysicalDeviceDisplayPlanePropertiesKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceDisplayPlaneProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayPlaneProperties, nullptr);
+}
+
+// Fill in random but valid data into the display plane property data struct for the current physical device
+static void FillInRandomDisplayPlanePropData(std::vector<VkDisplayPlanePropertiesKHR>& props) {
+    props.resize((rand() % 5) + 1);
+    for (uint32_t i = 0; i < props.size(); ++i) {
+        props[i].currentDisplay = (VkDisplayKHR)((rand() % 0xFFFFFFF) + 1);
+        props[i].currentStackIndex = static_cast<uint32_t>((rand() % 0xFFF) + (rand() % 0xFFF) + 1);
+    }
+}
+
+// Compare the display plane property data structs
+static void CompareDisplayPlanePropData(const std::vector<VkDisplayPlanePropertiesKHR>& props1,
+                                        const std::vector<VkDisplayPlanePropertiesKHR>& props2) {
+    ASSERT_EQ(props1.size(), props2.size());
+    for (uint32_t i = 0; i < props1.size(); ++i) {
+        ASSERT_EQ(props1[i].currentDisplay, props2[i].currentDisplay);
+        ASSERT_EQ(props1[i].currentStackIndex, props2[i].currentStackIndex);
+    }
+}
+
+// Test vGetPhysicalDeviceDisplayPlanePropertiesKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomDisplayPlanePropData(env.get_test_icd(0).physical_devices.back().display_plane_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayPlaneProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkDisplayPlanePropertiesKHR> props{};
+    uint32_t prop_count = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties(physical_device, &prop_count, nullptr));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_plane_properties.size(), prop_count);
+    props.resize(prop_count);
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties(physical_device, &prop_count, props.data()));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_plane_properties.size(), prop_count);
+
+    CompareDisplayPlanePropData(props, env.get_test_icd(0).physical_devices.back().display_plane_properties);
+}
+
+// Test vkGetPhysicalDeviceDisplayPlanePropertiesKHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomDisplayPlanePropData(cur_dev.display_plane_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayPlaneProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    std::vector<VkDisplayPlanePropertiesKHR> props{};
+                    uint32_t prop_count = 0;
+                    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties(physical_devices[dev], &prop_count, nullptr));
+                    if (icd == 1) {
+                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
+                        // loader.
+                        ASSERT_EQ(0, prop_count);
+                    } else {
+                        ASSERT_EQ(cur_dev.display_plane_properties.size(), prop_count);
+                        props.resize(prop_count);
+                        ASSERT_EQ(VK_SUCCESS,
+                                  GetPhysicalDeviceDisplayPlaneProperties(physical_devices[dev], &prop_count, props.data()));
+                        ASSERT_EQ(cur_dev.display_plane_properties.size(), prop_count);
+
+                        CompareDisplayPlanePropData(props, cur_dev.display_plane_properties);
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+// Test vkGetDisplayPlaneSupportedDisplaysKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneSupportedDisplays = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR"));
+    ASSERT_EQ(GetDisplayPlaneSupportedDisplays, nullptr);
+}
+
+// Test vkGetDisplayPlaneSupportedDisplaysKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetDisplayPlaneSupportedDisplays = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR"));
+    ASSERT_EQ(GetDisplayPlaneSupportedDisplays, nullptr);
+}
+
+// Fill in random but valid data into the display plane property data struct for the current physical device
+static void GenerateRandomDisplays(std::vector<VkDisplayKHR>& disps) {
+    disps.resize((rand() % 5) + 1);
+    for (uint32_t i = 0; i < disps.size(); ++i) {
+        disps[i] = (VkDisplayKHR)((rand() % 0xFFFFFFF) + 1);
+    }
+}
+
+// Compare the display plane property data structs
+static void CompareDisplays(const std::vector<VkDisplayKHR>& disps1, const std::vector<VkDisplayKHR>& disps2) {
+    ASSERT_EQ(disps1.size(), disps2.size());
+    for (uint32_t i = 0; i < disps1.size(); ++i) {
+        ASSERT_EQ(disps1[i], disps2[i]);
+    }
+}
+
+// Test vGetDisplayPlaneSupportedDisplaysKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    GenerateRandomDisplays(env.get_test_icd(0).physical_devices.back().displays);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneSupportedDisplays = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR"));
+    ASSERT_NE(GetDisplayPlaneSupportedDisplays, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkDisplayKHR> disps{};
+    uint32_t disp_count = 0;
+    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneSupportedDisplays(physical_device, 0, &disp_count, nullptr));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().displays.size(), disp_count);
+    disps.resize(disp_count);
+    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneSupportedDisplays(physical_device, 0, &disp_count, disps.data()));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().displays.size(), disp_count);
+
+    CompareDisplays(disps, env.get_test_icd(0).physical_devices.back().displays);
+}
+
+// Test vkGetDisplayPlaneSupportedDisplaysKHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplays(cur_dev.displays);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneSupportedDisplays = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR"));
+    ASSERT_NE(GetDisplayPlaneSupportedDisplays, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    std::vector<VkDisplayKHR> disps{};
+                    uint32_t disp_count = 0;
+                    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneSupportedDisplays(physical_devices[dev], 0, &disp_count, nullptr));
+                    if (icd == 1) {
+                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
+                        // loader.
+                        ASSERT_EQ(0, disp_count);
+                    } else {
+                        ASSERT_EQ(cur_dev.displays.size(), disp_count);
+                        disps.resize(disp_count);
+                        ASSERT_EQ(VK_SUCCESS,
+                                  GetDisplayPlaneSupportedDisplays(physical_devices[dev], 0, &disp_count, disps.data()));
+                        ASSERT_EQ(cur_dev.displays.size(), disp_count);
+
+                        CompareDisplays(disps, cur_dev.displays);
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+// Test vkGetDisplayModePropertiesKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, GetDispModePropsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetDisplayModeProperties = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
+    ASSERT_EQ(GetDisplayModeProperties, nullptr);
+}
+
+// Test vkGetDisplayModePropertiesKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, GetDispModePropsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetDisplayModeProperties = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
+    ASSERT_EQ(GetDisplayModeProperties, nullptr);
+}
+
+// Fill in random but valid data into the display mode properties data struct for the current physical device
+static void GenerateRandomDisplayModeProps(std::vector<VkDisplayModePropertiesKHR>& disps) {
+    disps.resize((rand() % 5) + 1);
+    for (uint32_t i = 0; i < disps.size(); ++i) {
+        disps[i].displayMode = (VkDisplayModeKHR)((rand() % 0xFFFFFFF) + 1);
+        disps[i].parameters.visibleRegion.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+        disps[i].parameters.visibleRegion.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+        disps[i].parameters.refreshRate = 1 << (rand() % 8);
+    }
+}
+
+// Compare the display mode properties data structs
+static void CompareDisplayModeProps(const std::vector<VkDisplayModePropertiesKHR>& disps1,
+                                    const std::vector<VkDisplayModePropertiesKHR>& disps2) {
+    ASSERT_EQ(disps1.size(), disps2.size());
+    for (uint32_t i = 0; i < disps1.size(); ++i) {
+        ASSERT_EQ(disps1[i].displayMode, disps2[i].displayMode);
+        ASSERT_EQ(disps1[i].parameters.visibleRegion.width, disps2[i].parameters.visibleRegion.width);
+        ASSERT_EQ(disps1[i].parameters.visibleRegion.height, disps2[i].parameters.visibleRegion.height);
+        ASSERT_EQ(disps1[i].parameters.refreshRate, disps2[i].parameters.refreshRate);
+    }
+}
+
+// Test vGetDisplayModePropertiesKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, GetDispModePropsKHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    GenerateRandomDisplayModeProps(env.get_test_icd(0).physical_devices.back().display_mode_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDisplayModeProperties = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
+    ASSERT_NE(GetDisplayModeProperties, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkDisplayModePropertiesKHR> props{};
+    uint32_t props_count = 0;
+    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties(physical_device, VK_NULL_HANDLE, &props_count, nullptr));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_mode_properties.size(), props_count);
+    props.resize(props_count);
+    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties(physical_device, VK_NULL_HANDLE, &props_count, props.data()));
+    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_mode_properties.size(), props_count);
+
+    CompareDisplayModeProps(props, env.get_test_icd(0).physical_devices.back().display_mode_properties);
+}
+
+// Test vkGetDisplayModePropertiesKHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, GetDispModePropsKHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplayModeProps(cur_dev.display_mode_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetDisplayModeProperties = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
+    ASSERT_NE(GetDisplayModeProperties, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    uint32_t props_count = 0;
+                    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties(physical_devices[dev], VK_NULL_HANDLE, &props_count, nullptr));
+                    if (icd == 1) {
+                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
+                        // loader.
+                        ASSERT_EQ(0, props_count);
+                    } else {
+                        std::vector<VkDisplayModePropertiesKHR> props{};
+                        ASSERT_EQ(cur_dev.display_mode_properties.size(), props_count);
+                        props.resize(props_count);
+                        ASSERT_EQ(VK_SUCCESS,
+                                  GetDisplayModeProperties(physical_devices[dev], VK_NULL_HANDLE, &props_count, props.data()));
+                        ASSERT_EQ(cur_dev.display_mode_properties.size(), props_count);
+
+                        CompareDisplayModeProps(props, cur_dev.display_mode_properties);
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+// Test vkCreateDisplayModeKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, GetDispModesKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto CreateDisplayMode =
+        reinterpret_cast<PFN_vkCreateDisplayModeKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkCreateDisplayModeKHR"));
+    ASSERT_EQ(CreateDisplayMode, nullptr);
+}
+
+// Test vkCreateDisplayModeKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, GetDispModesKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto CreateDisplayMode =
+        reinterpret_cast<PFN_vkCreateDisplayModeKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkCreateDisplayModeKHR"));
+    ASSERT_EQ(CreateDisplayMode, nullptr);
+}
+
+// Fill in random but valid data into the display modes for the current physical device
+static void GenerateRandomDisplayMode(VkDisplayModeKHR& mode) { mode = (VkDisplayModeKHR)((rand() % 0xFFFFFFF) + 1); }
+
+// Compare the display modes
+static void CompareDisplayModes(const VkDisplayModeKHR& disps1, VkDisplayModeKHR& disps2) { ASSERT_EQ(disps1, disps2); }
+
+// Test vkCreateDisplayModeKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, GetDispModesKHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    GenerateRandomDisplayMode(env.get_test_icd(0).physical_devices.back().display_mode);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto CreateDisplayMode =
+        reinterpret_cast<PFN_vkCreateDisplayModeKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkCreateDisplayModeKHR"));
+    ASSERT_NE(CreateDisplayMode, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkDisplayModeKHR mode{};
+    VkDisplayModeCreateInfoKHR create_info{VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR};
+    ASSERT_EQ(VK_SUCCESS, CreateDisplayMode(physical_device, VK_NULL_HANDLE, &create_info, nullptr, &mode));
+    CompareDisplayModes(mode, env.get_test_icd(0).physical_devices.back().display_mode);
+}
+
+// Test vkCreateDisplayModeKHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, GetDispModesKHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplayMode(cur_dev.display_mode);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto CreateDisplayMode =
+        reinterpret_cast<PFN_vkCreateDisplayModeKHR>(instance.functions->vkGetInstanceProcAddr(instance, "vkCreateDisplayModeKHR"));
+    ASSERT_NE(CreateDisplayMode, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    VkDisplayModeKHR mode{};
+                    VkDisplayModeCreateInfoKHR create_info{VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR};
+                    if (icd == 1) {
+                        // Unsupported ICD should return initialization failed (instead of crash)
+                        ASSERT_EQ(VK_ERROR_INITIALIZATION_FAILED,
+                                  CreateDisplayMode(physical_devices[dev], VK_NULL_HANDLE, &create_info, nullptr, &mode));
+                    } else {
+                        ASSERT_EQ(VK_SUCCESS,
+                                  CreateDisplayMode(physical_devices[dev], VK_NULL_HANDLE, &create_info, nullptr, &mode));
+                        CompareDisplayModes(mode, cur_dev.display_mode);
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+// Test vkGetDisplayPlaneCapabilitiesKHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCapsKHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_EQ(GetDisplayPlaneCapabilities, nullptr);
+}
+
+// Test vkGetDisplayPlaneCapabilitiesKHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCapsKHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_EQ(GetDisplayPlaneCapabilities, nullptr);
+}
+
+// Fill in random but valid data into the display plane caps for the current physical device
+static void GenerateRandomDisplayPlaneCaps(VkDisplayPlaneCapabilitiesKHR& caps) {
+    caps.supportedAlpha = static_cast<VkDisplayPlaneAlphaFlagsKHR>((rand() % 0xFFFFFFF) + 1);
+    caps.minSrcPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.minSrcPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxSrcPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxSrcPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.minSrcExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.minSrcExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxSrcExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxSrcExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.minDstPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.minDstPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxDstPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxDstPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.minDstExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.minDstExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxDstExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+    caps.maxDstExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
+}
+
+// Compare the display plane caps
+static void CompareDisplayPlaneCaps(const VkDisplayPlaneCapabilitiesKHR& caps1, VkDisplayPlaneCapabilitiesKHR& caps2,
+                                    bool supported = true) {
+    if (supported) {
+        ASSERT_EQ(caps1.supportedAlpha, caps2.supportedAlpha);
+        ASSERT_EQ(caps1.minSrcPosition.x, caps2.minSrcPosition.x);
+        ASSERT_EQ(caps1.minSrcPosition.y, caps2.minSrcPosition.y);
+        ASSERT_EQ(caps1.maxSrcPosition.x, caps2.maxSrcPosition.x);
+        ASSERT_EQ(caps1.maxSrcPosition.y, caps2.maxSrcPosition.y);
+        ASSERT_EQ(caps1.minSrcExtent.width, caps2.minSrcExtent.width);
+        ASSERT_EQ(caps1.minSrcExtent.height, caps2.minSrcExtent.height);
+        ASSERT_EQ(caps1.maxSrcExtent.width, caps2.maxSrcExtent.width);
+        ASSERT_EQ(caps1.maxSrcExtent.height, caps2.maxSrcExtent.height);
+        ASSERT_EQ(caps1.minDstPosition.x, caps2.minDstPosition.x);
+        ASSERT_EQ(caps1.minDstPosition.y, caps2.minDstPosition.y);
+        ASSERT_EQ(caps1.maxDstPosition.x, caps2.maxDstPosition.x);
+        ASSERT_EQ(caps1.maxDstPosition.y, caps2.maxDstPosition.y);
+        ASSERT_EQ(caps1.minDstExtent.width, caps2.minDstExtent.width);
+        ASSERT_EQ(caps1.minDstExtent.height, caps2.minDstExtent.height);
+        ASSERT_EQ(caps1.maxDstExtent.width, caps2.maxDstExtent.width);
+        ASSERT_EQ(caps1.maxDstExtent.height, caps2.maxDstExtent.height);
+    } else {
+        ASSERT_EQ(caps1.supportedAlpha, 0);
+        ASSERT_EQ(caps1.minSrcPosition.x, 0);
+        ASSERT_EQ(caps1.minSrcPosition.y, 0);
+        ASSERT_EQ(caps1.maxSrcPosition.x, 0);
+        ASSERT_EQ(caps1.maxSrcPosition.y, 0);
+        ASSERT_EQ(caps1.minSrcExtent.width, 0);
+        ASSERT_EQ(caps1.minSrcExtent.height, 0);
+        ASSERT_EQ(caps1.maxSrcExtent.width, 0);
+        ASSERT_EQ(caps1.maxSrcExtent.height, 0);
+        ASSERT_EQ(caps1.minDstPosition.x, 0);
+        ASSERT_EQ(caps1.minDstPosition.y, 0);
+        ASSERT_EQ(caps1.maxDstPosition.x, 0);
+        ASSERT_EQ(caps1.maxDstPosition.y, 0);
+        ASSERT_EQ(caps1.minDstExtent.width, 0);
+        ASSERT_EQ(caps1.minDstExtent.height, 0);
+        ASSERT_EQ(caps1.maxDstExtent.width, 0);
+        ASSERT_EQ(caps1.maxDstExtent.height, 0);
+    }
+}
+
+// Test vkGetDisplayPlaneCapabilitiesKHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCapsKHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    env.get_test_icd(0).physical_devices.push_back({});
+    GenerateRandomDisplayPlaneCaps(env.get_test_icd(0).physical_devices.back().display_plane_capabilities);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_NE(GetDisplayPlaneCapabilities, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkDisplayPlaneCapabilitiesKHR caps{};
+    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities(physical_device, 0, 0, &caps));
+    CompareDisplayPlaneCaps(caps, env.get_test_icd(0).physical_devices.back().display_plane_capabilities);
+}
+
+// Test vkGetDisplayPlaneCapabilitiesKHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCapsKHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplayPlaneCaps(cur_dev.display_plane_capabilities);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_NE(GetDisplayPlaneCapabilities, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    VkDisplayPlaneCapabilitiesKHR caps{};
+                    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities(physical_devices[dev], 0, 0, &caps));
+                    CompareDisplayPlaneCaps(caps, cur_dev.display_plane_capabilities, icd != 1);
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+//
+// VK_KHR_get_display_properties2
+//
+
+// Test vkGetPhysicalDeviceDisplayProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayProperties2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayProperties2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceDisplayProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispProps2KHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceDisplayProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayProperties2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayProperties2, nullptr);
+}
+
+// Compare the display property data structs
+static void CompareDisplayPropData(const std::vector<VkDisplayPropertiesKHR>& props1,
+                                   const std::vector<VkDisplayProperties2KHR>& props2) {
+    ASSERT_EQ(props1.size(), props2.size());
+    for (uint32_t i = 0; i < props1.size(); ++i) {
+        ASSERT_EQ(props1[i].display, props2[i].displayProperties.display);
+        ASSERT_EQ(props1[i].physicalDimensions.width, props2[i].displayProperties.physicalDimensions.width);
+        ASSERT_EQ(props1[i].physicalDimensions.height, props2[i].displayProperties.physicalDimensions.height);
+        ASSERT_EQ(props1[i].physicalResolution.width, props2[i].displayProperties.physicalResolution.width);
+        ASSERT_EQ(props1[i].physicalResolution.height, props2[i].displayProperties.physicalResolution.height);
+        ASSERT_EQ(props1[i].supportedTransforms, props2[i].displayProperties.supportedTransforms);
+        ASSERT_EQ(props1[i].planeReorderPossible, props2[i].displayProperties.planeReorderPossible);
+        ASSERT_EQ(props1[i].persistentContent, props2[i].displayProperties.persistentContent);
+    }
+}
+
+// Test vGetPhysicalDeviceDisplayProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomDisplayPropData(env.get_test_icd(0).physical_devices.back().display_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayProperties, nullptr);
+    auto GetPhysicalDeviceDisplayProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayProperties2KHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayProperties2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkDisplayPropertiesKHR> props{};
+    uint32_t prop_count = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_device, &prop_count, nullptr));
+    ASSERT_NE(0, prop_count);
+    props.resize(prop_count);
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_device, &prop_count, props.data()));
+
+    std::vector<VkDisplayProperties2KHR> props2{};
+    uint32_t prop_count_2 = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2(physical_device, &prop_count_2, nullptr));
+    ASSERT_EQ(prop_count, prop_count_2);
+    props2.resize(prop_count_2, {VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR});
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2(physical_device, &prop_count_2, props2.data()));
+    ASSERT_EQ(prop_count, prop_count_2);
+
+    CompareDisplayPropData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceDisplayProperties2KHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevDispProps2KHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomDisplayPropData(cur_dev.display_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayProperties, nullptr);
+    auto GetPhysicalDeviceDisplayProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayProperties2KHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayProperties2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        std::vector<VkDisplayPropertiesKHR> props{};
+        uint32_t prop_count = 0;
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_devices[dev], &prop_count, nullptr));
+        ASSERT_NE(0, prop_count);
+        props.resize(prop_count);
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties(physical_devices[dev], &prop_count, props.data()));
+
+        std::vector<VkDisplayProperties2KHR> props2{};
+        uint32_t prop_count_2 = 0;
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2(physical_devices[dev], &prop_count_2, nullptr));
+        ASSERT_EQ(prop_count, prop_count_2);
+        props2.resize(prop_count_2, {VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR});
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2(physical_devices[dev], &prop_count_2, props2.data()));
+        ASSERT_EQ(prop_count, prop_count_2);
+
+        CompareDisplayPropData(props, props2);
+    }
+}
+
+// Test vkGetPhysicalDeviceDisplayPlaneProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayPlaneProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayPlaneProperties2, nullptr);
+}
+
+// Test vkGetPhysicalDeviceDisplayPlaneProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetPhysicalDeviceDisplayPlaneProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"));
+    ASSERT_EQ(GetPhysicalDeviceDisplayPlaneProperties2, nullptr);
+}
+
+// Compare the display plane property data structs
+static void CompareDisplayPlanePropData(const std::vector<VkDisplayPlanePropertiesKHR>& props1,
+                                        const std::vector<VkDisplayPlaneProperties2KHR>& props2) {
+    ASSERT_EQ(props1.size(), props2.size());
+    for (uint32_t i = 0; i < props1.size(); ++i) {
+        ASSERT_EQ(props1[i].currentDisplay, props2[i].displayPlaneProperties.currentDisplay);
+        ASSERT_EQ(props1[i].currentStackIndex, props2[i].displayPlaneProperties.currentStackIndex);
+    }
+}
+
+// Test vGetPhysicalDeviceDisplayPlaneProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomDisplayPlanePropData(env.get_test_icd(0).physical_devices.back().display_plane_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayPlaneProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties, nullptr);
+    auto GetPhysicalDeviceDisplayPlaneProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkDisplayPlanePropertiesKHR> props{};
+    uint32_t prop_count = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties(physical_device, &prop_count, nullptr));
+    ASSERT_NE(0, prop_count);
+    props.resize(prop_count);
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties(physical_device, &prop_count, props.data()));
+
+    std::vector<VkDisplayPlaneProperties2KHR> props2{};
+    uint32_t prop_count2 = 0;
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2(physical_device, &prop_count2, nullptr));
+    ASSERT_EQ(prop_count, prop_count2);
+    props2.resize(prop_count2, {VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR});
+    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2(physical_device, &prop_count2, props2.data()));
+
+    CompareDisplayPlanePropData(props, props2);
+}
+
+// Test vkGetPhysicalDeviceDisplayPlaneProperties2KHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            FillInRandomDisplayPlanePropData(cur_dev.display_plane_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetPhysicalDeviceDisplayPlaneProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties, nullptr);
+    auto GetPhysicalDeviceDisplayPlaneProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"));
+    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        std::vector<VkDisplayPlanePropertiesKHR> props{};
+        uint32_t prop_count = 0;
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties(physical_devices[dev], &prop_count, nullptr));
+        ASSERT_NE(0, prop_count);
+        props.resize(prop_count);
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties(physical_devices[dev], &prop_count, props.data()));
+
+        std::vector<VkDisplayPlaneProperties2KHR> props2{};
+        uint32_t prop_count2 = 0;
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2(physical_devices[dev], &prop_count2, nullptr));
+        ASSERT_EQ(prop_count, prop_count2);
+        props2.resize(prop_count2, {VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR});
+        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2(physical_devices[dev], &prop_count2, props2.data()));
+
+        CompareDisplayPlanePropData(props, props2);
+    }
+}
+
+// Test vkGetDisplayModeProperties2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, GetDispModeProps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetDisplayModeProperties2 = reinterpret_cast<PFN_vkGetDisplayModeProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModeProperties2KHR"));
+    ASSERT_EQ(GetDisplayModeProperties2, nullptr);
+}
+
+// Test vkGetDisplayModeProperties2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, GetDispModeProps2KHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetDisplayModeProperties2 = reinterpret_cast<PFN_vkGetDisplayModeProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModeProperties2KHR"));
+    ASSERT_EQ(GetDisplayModeProperties2, nullptr);
+}
+
+// Compare the display mode properties data structs
+static void CompareDisplayModeProps(const std::vector<VkDisplayModePropertiesKHR>& disps1,
+                                    const std::vector<VkDisplayModeProperties2KHR>& disps2) {
+    ASSERT_EQ(disps1.size(), disps2.size());
+    for (uint32_t i = 0; i < disps1.size(); ++i) {
+        ASSERT_EQ(disps1[i].displayMode, disps2[i].displayModeProperties.displayMode);
+        ASSERT_EQ(disps1[i].parameters.visibleRegion.width, disps2[i].displayModeProperties.parameters.visibleRegion.width);
+        ASSERT_EQ(disps1[i].parameters.visibleRegion.height, disps2[i].displayModeProperties.parameters.visibleRegion.height);
+        ASSERT_EQ(disps1[i].parameters.refreshRate, disps2[i].displayModeProperties.parameters.refreshRate);
+    }
+}
+
+// Test vGetDisplayModeProperties2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, GetDispModeProps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    GenerateRandomDisplayModeProps(env.get_test_icd(0).physical_devices.back().display_mode_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDisplayModeProperties = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
+    ASSERT_NE(GetDisplayModeProperties, nullptr);
+    auto GetDisplayModeProperties2 = reinterpret_cast<PFN_vkGetDisplayModeProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModeProperties2KHR"));
+    ASSERT_NE(GetDisplayModeProperties2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    std::vector<VkDisplayModePropertiesKHR> props{};
+    uint32_t props_count1 = 0;
+    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties(physical_device, VK_NULL_HANDLE, &props_count1, nullptr));
+    ASSERT_NE(0, props_count1);
+    props.resize(props_count1);
+    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties(physical_device, VK_NULL_HANDLE, &props_count1, props.data()));
+
+    std::vector<VkDisplayModeProperties2KHR> props2{};
+    uint32_t props_count2 = 0;
+    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2(physical_device, VK_NULL_HANDLE, &props_count2, nullptr));
+    ASSERT_EQ(props_count1, props_count2);
+    props2.resize(props_count2, {VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR});
+    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2(physical_device, VK_NULL_HANDLE, &props_count2, props2.data()));
+
+    CompareDisplayModeProps(props, props2);
+}
+
+// Test vkGetDisplayModeProperties2KHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, GetDispModeProps2KHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplayModeProps(cur_dev.display_mode_properties);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDisplayModeProperties = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
+    ASSERT_NE(GetDisplayModeProperties, nullptr);
+    auto GetDisplayModeProperties2 = reinterpret_cast<PFN_vkGetDisplayModeProperties2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayModeProperties2KHR"));
+    ASSERT_NE(GetDisplayModeProperties2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        std::vector<VkDisplayModePropertiesKHR> props{};
+        uint32_t props_count1 = 0;
+        ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties(physical_devices[dev], VK_NULL_HANDLE, &props_count1, nullptr));
+        ASSERT_NE(0, props_count1);
+        props.resize(props_count1);
+        ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties(physical_devices[dev], VK_NULL_HANDLE, &props_count1, props.data()));
+
+        std::vector<VkDisplayModeProperties2KHR> props2{};
+        uint32_t props_count2 = 0;
+        ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2(physical_devices[dev], VK_NULL_HANDLE, &props_count2, nullptr));
+        ASSERT_EQ(props_count1, props_count2);
+        props2.resize(props_count2, {VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR});
+        ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2(physical_devices[dev], VK_NULL_HANDLE, &props_count2, props2.data()));
+
+        CompareDisplayModeProps(props, props2);
+    }
+}
+
+// Test vkGetDisplayPlaneCapabilities2KHR where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_EQ(GetDisplayPlaneCapabilities, nullptr);
+}
+
+// Test vkGetDisplayPlaneCapabilities2KHR where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_EQ(GetDisplayPlaneCapabilities, nullptr);
+}
+
+// Compare the display plane caps
+static void CompareDisplayPlaneCaps(const VkDisplayPlaneCapabilitiesKHR& caps1, VkDisplayPlaneCapabilities2KHR& caps2) {
+    ASSERT_EQ(caps1.supportedAlpha, caps2.capabilities.supportedAlpha);
+    ASSERT_EQ(caps1.minSrcPosition.x, caps2.capabilities.minSrcPosition.x);
+    ASSERT_EQ(caps1.minSrcPosition.y, caps2.capabilities.minSrcPosition.y);
+    ASSERT_EQ(caps1.maxSrcPosition.x, caps2.capabilities.maxSrcPosition.x);
+    ASSERT_EQ(caps1.maxSrcPosition.y, caps2.capabilities.maxSrcPosition.y);
+    ASSERT_EQ(caps1.minSrcExtent.width, caps2.capabilities.minSrcExtent.width);
+    ASSERT_EQ(caps1.minSrcExtent.height, caps2.capabilities.minSrcExtent.height);
+    ASSERT_EQ(caps1.maxSrcExtent.width, caps2.capabilities.maxSrcExtent.width);
+    ASSERT_EQ(caps1.maxSrcExtent.height, caps2.capabilities.maxSrcExtent.height);
+    ASSERT_EQ(caps1.minDstPosition.x, caps2.capabilities.minDstPosition.x);
+    ASSERT_EQ(caps1.minDstPosition.y, caps2.capabilities.minDstPosition.y);
+    ASSERT_EQ(caps1.maxDstPosition.x, caps2.capabilities.maxDstPosition.x);
+    ASSERT_EQ(caps1.maxDstPosition.y, caps2.capabilities.maxDstPosition.y);
+    ASSERT_EQ(caps1.minDstExtent.width, caps2.capabilities.minDstExtent.width);
+    ASSERT_EQ(caps1.minDstExtent.height, caps2.capabilities.minDstExtent.height);
+    ASSERT_EQ(caps1.maxDstExtent.width, caps2.capabilities.maxDstExtent.width);
+    ASSERT_EQ(caps1.maxDstExtent.height, caps2.capabilities.maxDstExtent.height);
+}
+
+// Test vkGetDisplayPlaneCapabilities2KHR where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
+    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    FillInRandomDisplayPropData(env.get_test_icd(0).physical_devices.back().display_properties);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_NE(GetDisplayPlaneCapabilities, nullptr);
+    auto GetDisplayPlaneCapabilities2 = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilities2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilities2KHR"));
+    ASSERT_NE(GetDisplayPlaneCapabilities2, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkDisplayPlaneCapabilitiesKHR caps{};
+    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities(physical_device, 0, 0, &caps));
+    VkDisplayPlaneCapabilities2KHR caps2{};
+    VkDisplayPlaneInfo2KHR info{VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR};
+    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities2(physical_device, &info, &caps2));
+    CompareDisplayPlaneCaps(caps, caps2);
+}
+
+// Test vkGetDisplayPlaneCapabilities2KHR where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplayPlaneCaps(cur_dev.display_plane_capabilities);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDisplayPlaneCapabilities = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
+    ASSERT_NE(GetDisplayPlaneCapabilities, nullptr);
+    auto GetDisplayPlaneCapabilities2 = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilities2KHR>(
+        instance.functions->vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilities2KHR"));
+    ASSERT_NE(GetDisplayPlaneCapabilities2, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkDisplayPlaneCapabilitiesKHR caps{};
+        ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities(physical_devices[dev], 0, 0, &caps));
+        VkDisplayPlaneCapabilities2KHR caps2{};
+        VkDisplayPlaneInfo2KHR info{VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR};
+        ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities2(physical_devices[dev], &info, &caps2));
+        CompareDisplayPlaneCaps(caps, caps2);
+    }
+}
+
+//
+// VK_EXT_acquire_drm_display
+//
+
+// Test vkAcquireDrmDisplayEXT where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, AcquireDrmDisplayEXTNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto AcquireDrmDisplay =
+        reinterpret_cast<PFN_vkAcquireDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkAcquireDrmDisplayEXT"));
+    ASSERT_EQ(AcquireDrmDisplay, nullptr);
+}
+
+// Test vkAcquireDrmDisplayEXT where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, AcquireDrmDisplayEXTNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto AcquireDrmDisplay =
+        reinterpret_cast<PFN_vkAcquireDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkAcquireDrmDisplayEXT"));
+    ASSERT_EQ(AcquireDrmDisplay, nullptr);
+}
+
+// Test vkAcquireDrmDisplayEXT where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, AcquireDrmDisplayEXTInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
+    Extension second_ext{VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    GenerateRandomDisplays(env.get_test_icd(0).physical_devices.back().displays);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto AcquireDrmDisplay =
+        reinterpret_cast<PFN_vkAcquireDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkAcquireDrmDisplayEXT"));
+    ASSERT_NE(AcquireDrmDisplay, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkDisplayKHR display = VK_NULL_HANDLE;
+    ASSERT_EQ(VK_SUCCESS, AcquireDrmDisplay(physical_device, 0, display));
+}
+
+// Test vkAcquireDrmDisplayEXT where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, AcquireDrmDisplayEXTMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplays(cur_dev.displays);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto AcquireDrmDisplay =
+        reinterpret_cast<PFN_vkAcquireDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkAcquireDrmDisplayEXT"));
+    ASSERT_NE(AcquireDrmDisplay, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    VkDisplayKHR display = VK_NULL_HANDLE;
+                    if (icd == 1) {
+                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
+                        // loader.
+                        ASSERT_EQ(VK_ERROR_INITIALIZATION_FAILED, AcquireDrmDisplay(physical_devices[dev], 0, display));
+                    } else {
+                        ASSERT_EQ(VK_SUCCESS, AcquireDrmDisplay(physical_devices[dev], 0, display));
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
+
+// Test vkGetDrmDisplayEXT where nothing supports it.
+TEST_F(LoaderInstPhysDevExts, GetDrmDisplayEXTNoSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.CheckCreate();
+
+    auto GetDrmDisplay =
+        reinterpret_cast<PFN_vkGetDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkGetDrmDisplayEXT"));
+    ASSERT_EQ(GetDrmDisplay, nullptr);
+}
+
+// Test vkGetDrmDisplayEXT where instance supports it, but nothing else.
+TEST_F(LoaderInstPhysDevExts, GetDrmDisplayEXTNoICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    env.get_test_icd(0).physical_devices.push_back({});
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extension(VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME);
+    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
+
+    auto GetDrmDisplay =
+        reinterpret_cast<PFN_vkGetDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkGetDrmDisplayEXT"));
+    ASSERT_EQ(GetDrmDisplay, nullptr);
+}
+
+// Test vkGetDrmDisplayEXT where instance and ICD supports it, but device does not support it.
+TEST_F(LoaderInstPhysDevExts, GetDrmDisplayEXTInstanceAndICDSupport) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
+    Extension second_ext{VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME};
+    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
+    env.get_test_icd(0).physical_devices.push_back({});
+    GenerateRandomDisplays(env.get_test_icd(0).physical_devices.back().displays);
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDrmDisplay =
+        reinterpret_cast<PFN_vkGetDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkGetDrmDisplayEXT"));
+    ASSERT_NE(GetDrmDisplay, nullptr);
+
+    uint32_t driver_count = 1;
+    VkPhysicalDevice physical_device;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+    ASSERT_EQ(driver_count, 1);
+
+    VkDisplayKHR display = VK_NULL_HANDLE;
+    ASSERT_EQ(VK_SUCCESS, GetDrmDisplay(physical_device, 0, 0, &display));
+    ASSERT_EQ(display, env.get_test_icd(0).physical_devices.back().displays[0]);
+}
+
+// Test vkGetDrmDisplayEXT where instance supports it with some ICDs that both support
+// and don't support it:
+//    ICD 0 supports
+//        Physical device 0 does not
+//        Physical device 1 does
+//        Physical device 2 does not
+//    ICD 1 doesn't support
+//        Physical device 3 does not
+//    ICD 2 supports
+//        Physical device 4 does not
+//        Physical device 5 does not
+//    ICD 3 supports
+//        Physical device 6 does
+TEST_F(LoaderInstPhysDevExts, GetDrmDisplayEXTMixed) {
+    FrameworkEnvironment env{};
+    const uint32_t max_icd_count = 4;
+    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
+    const uint32_t max_phys_devs = 7;
+
+    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+        auto& cur_icd = env.get_test_icd(icd);
+        cur_icd.icd_api_version = VK_API_VERSION_1_0;
+        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
+
+        // ICD 1 should not have 1.1
+        if (icd != 1) {
+            cur_icd.icd_api_version = VK_API_VERSION_1_1;
+            cur_icd.add_instance_extension({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
+        }
+
+        uint32_t rand_vendor_id;
+        uint32_t rand_driver_vers;
+        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
+
+        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
+            uint32_t device_version = VK_API_VERSION_1_0;
+            cur_icd.physical_devices.push_back({});
+            auto& cur_dev = cur_icd.physical_devices.back();
+            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
+
+            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
+            if ((icd == 0 && dev == 1) || icd == 3) {
+                cur_dev.extensions.push_back({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME, 0});
+                device_version = VK_API_VERSION_1_1;
+            }
+
+            // Still set physical device properties (so we can determine if device is correct API version)
+            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
+            GenerateRandomDisplays(cur_dev.displays);
+        }
+    }
+
+    InstWrapper instance(env.vulkan_functions);
+    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
+    instance.CheckCreate();
+
+    auto GetDrmDisplay =
+        reinterpret_cast<PFN_vkGetDrmDisplayEXT>(instance.functions->vkGetInstanceProcAddr(instance, "vkGetDrmDisplayEXT"));
+    ASSERT_NE(GetDrmDisplay, nullptr);
+
+    uint32_t device_count = max_phys_devs;
+    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
+    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
+    ASSERT_EQ(device_count, max_phys_devs);
+
+    for (uint32_t dev = 0; dev < device_count; ++dev) {
+        VkPhysicalDeviceProperties pd_props{};
+        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
+
+        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
+            auto& cur_icd = env.get_test_icd(icd);
+            bool found = false;
+            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
+                auto& cur_dev = cur_icd.physical_devices[pd];
+                // Find the ICD device matching the physical device we're looking at info for so we can compare the
+                // physical devices info with the returned info.
+                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
+                    cur_dev.properties.deviceType == pd_props.deviceType &&
+                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
+                    cur_dev.properties.vendorID == pd_props.vendorID) {
+                    VkDisplayKHR display = VK_NULL_HANDLE;
+                    if (icd == 1) {
+                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
+                        // loader.
+                        ASSERT_EQ(VK_ERROR_INITIALIZATION_FAILED, GetDrmDisplay(physical_devices[dev], 0, 0, &display));
+                    } else {
+                        ASSERT_EQ(VK_SUCCESS, GetDrmDisplay(physical_devices[dev], 0, 0, &display));
+                        ASSERT_EQ(display, cur_dev.displays[0]);
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                break;
+            }
+        }
+    }
+}
\ No newline at end of file
index e872bbec630529f33c9853325652f1fb2d096a4e..e04e4503ce0c16772815a56e314910407598c9de 100644 (file)
@@ -446,7 +446,7 @@ TEST_F(EnumeratePhysicalDevices, TwoCallIncomplete) {
 TEST_F(EnumeratePhysicalDevices, ZeroPhysicalDevicesAfterCreateInstance) {
     auto& driver = env->get_test_icd().set_min_icd_interface_version(5);
     InstWrapper inst{env->vulkan_functions};
-    inst.create_info.set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0));
+    inst.create_info.set_api_version(VK_API_VERSION_1_1);
     inst.CheckCreate();
     driver.physical_devices.clear();
 
@@ -609,7 +609,7 @@ TEST_F(EnumeratePhysicalDeviceGroups, OneCall) {
     // Core function
     {
         InstWrapper inst{env->vulkan_functions};
-        inst.create_info.set_api_version(1, 1, 0);
+        inst.create_info.set_api_version(VK_API_VERSION_1_1);
         inst.CheckCreate();
 
         auto physical_devices = std::vector<VkPhysicalDevice>(physical_device_count);
@@ -667,7 +667,7 @@ TEST_F(EnumeratePhysicalDeviceGroups, TwoCall) {
     // Core function
     {
         InstWrapper inst{env->vulkan_functions};
-        inst.create_info.set_api_version(1, 1, 0);
+        inst.create_info.set_api_version(VK_API_VERSION_1_1);
         inst.CheckCreate();
 
         auto physical_devices = std::vector<VkPhysicalDevice>(physical_device_count);
@@ -730,7 +730,7 @@ TEST_F(EnumeratePhysicalDeviceGroups, TwoCallIncomplete) {
     // Core function
     {
         InstWrapper inst{env->vulkan_functions};
-        inst.create_info.set_api_version(1, 1, 0);
+        inst.create_info.set_api_version(VK_API_VERSION_1_1);
         inst.CheckCreate();
 
         uint32_t group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
@@ -920,4 +920,4 @@ TEST_F(CreateInstance, InstanceNullExtensionPtr) {
     info.enabledExtensionCount = 1;
 
     ASSERT_EQ(env->vulkan_functions.vkCreateInstance(&info, VK_NULL_HANDLE, &inst), VK_ERROR_EXTENSION_NOT_PRESENT);
-}
\ No newline at end of file
+}