1/*
2 * Copyright (c) 2021-2022 The Khronos Group Inc.
3 * Copyright (c) 2021-2022 Valve Corporation
4 * Copyright (c) 2021-2022 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and/or associated documentation files (the "Materials"), to
8 * deal in the Materials without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Materials, and to permit persons to whom the Materials are
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice(s) and this permission notice shall be included in
14 * all copies or substantial portions of the Materials.
15 *
16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 *
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23 * USE OR OTHER DEALINGS IN THE MATERIALS.
24 *
25 * Author: Charles Giessen <charles@lunarg.com>
26 * Author: Mark Young <marky@lunarg.com>
27 */
28
29#include "test_environment.h"
30
31// These tests are all instance extension tests that touch physical devices.  This was
32// before the idea that physical device extensions were more appropriately found in the
33// list of device extensions.  Because of that, all these tests need to support devices
34// that don't support the extension and have a fallback path in the loader that needs
35// validation.
36
37// Fill in random but valid data into the device properties struct for the current physical device
38void FillInRandomICDInfo(uint32_t& vendor_id, uint32_t& driver_vers) {
39    vendor_id = VK_MAKE_API_VERSION(0, rand() % 64, rand() % 255, rand() % 255);
40    driver_vers = VK_MAKE_API_VERSION(0, rand() % 64, rand() % 255, rand() % 255);
41}
42
43// Fill in random but valid data into the device properties struct for the current physical device
44void FillInRandomDeviceProps(VkPhysicalDeviceProperties& props, uint32_t api_vers, uint32_t vendor, uint32_t driver_vers) {
45    props.apiVersion = api_vers;
46    props.driverVersion = driver_vers;
47    props.vendorID = vendor;
48    props.deviceID = (static_cast<uint32_t>(rand()) >> 4) + (static_cast<uint32_t>(rand()) << 2);
49    props.deviceType = static_cast<VkPhysicalDeviceType>(rand() % 5);
50    for (uint8_t idx = 0; idx < VK_UUID_SIZE; ++idx) {
51        props.pipelineCacheUUID[idx] = static_cast<uint8_t>(rand() % 255);
52    }
53}
54
55//
56// VK_KHR_get_physical_device_properties2
57//
58
59// Test vkGetPhysicalDeviceProperties2KHR where nothing supports it.
60TEST(LoaderInstPhysDevExts, PhysDevProps2KHRNoSupport) {
61    FrameworkEnvironment env{};
62    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
63    env.get_test_icd(0).physical_devices.push_back({});
64
65    InstWrapper instance(env.vulkan_functions);
66    instance.CheckCreate();
67
68    PFN_vkGetPhysicalDeviceProperties2KHR GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2KHR");
69    ASSERT_EQ(GetPhysDevProps2, nullptr);
70}
71
72// Test vkGetPhysicalDeviceProperties2KHR where instance supports it, but nothing else.
73TEST(LoaderInstPhysDevExts, PhysDevProps2KHRNoICDSupport) {
74    FrameworkEnvironment env{};
75    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
76    env.get_test_icd(0).physical_devices.push_back({});
77
78    InstWrapper instance(env.vulkan_functions);
79    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
80    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
81
82    PFN_vkGetPhysicalDeviceProperties2KHR GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2KHR");
83    ASSERT_EQ(GetPhysDevProps2, nullptr);
84}
85
86// Test vkGetPhysicalDeviceProperties2KHR where instance and ICD supports it, but device does not support it.
87TEST(LoaderInstPhysDevExts, PhysDevProps2KHRInstanceAndICDSupport) {
88    FrameworkEnvironment env{};
89    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
90    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
91    env.get_test_icd(0).physical_devices.push_back({});
92    FillInRandomDeviceProps(env.get_test_icd(0).physical_devices.back().properties, VK_API_VERSION_1_0, 5, 123);
93
94    InstWrapper instance(env.vulkan_functions);
95    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
96    instance.CheckCreate();
97
98    PFN_vkGetPhysicalDeviceProperties2KHR GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2KHR");
99    ASSERT_NE(GetPhysDevProps2, nullptr);
100
101    uint32_t driver_count = 1;
102    VkPhysicalDevice physical_device;
103    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
104    ASSERT_EQ(driver_count, 1U);
105
106    VkPhysicalDeviceProperties props{};
107    instance->vkGetPhysicalDeviceProperties(physical_device, &props);
108    VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
109    GetPhysDevProps2(physical_device, &props2);
110
111    // Both properties should match
112    ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
113    ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
114    ASSERT_EQ(props.vendorID, props2.properties.vendorID);
115    ASSERT_EQ(props.deviceID, props2.properties.deviceID);
116    ASSERT_EQ(props.deviceType, props2.properties.deviceType);
117    ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
118}
119
120// Test vkGetPhysicalDeviceProperties2 where instance supports, an ICD, and a device under that ICD
121// also support, so everything should work and return properly.
122// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
123TEST(LoaderInstPhysDevExts, PhysDevProps2Simple) {
124    FrameworkEnvironment env{};
125    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_API_VERSION_1_1));
126    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
127    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
128    env.get_test_icd(0).physical_devices.push_back({});
129    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
130    FillInRandomDeviceProps(env.get_test_icd(0).physical_devices.back().properties, VK_API_VERSION_1_1, 5, 123);
131    {
132        InstWrapper instance(env.vulkan_functions);
133        instance.create_info.set_api_version(VK_API_VERSION_1_1);
134        instance.CheckCreate();
135
136        PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2");
137        ASSERT_NE(GetPhysDevProps2, nullptr);
138
139        uint32_t driver_count = 1;
140        VkPhysicalDevice physical_device;
141        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
142        ASSERT_EQ(driver_count, 1U);
143
144        VkPhysicalDeviceProperties props{};
145        instance->vkGetPhysicalDeviceProperties(physical_device, &props);
146        VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
147        GetPhysDevProps2(physical_device, &props2);
148
149        // Both properties should match
150        ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
151        ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
152        ASSERT_EQ(props.vendorID, props2.properties.vendorID);
153        ASSERT_EQ(props.deviceID, props2.properties.deviceID);
154        ASSERT_EQ(props.deviceType, props2.properties.deviceType);
155        ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
156    }
157
158    {  // Do the same logic but have the application forget to use 1.1 and doesn't enable the extension - should emulate the call
159        InstWrapper instance(env.vulkan_functions);
160        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
161        instance.CheckCreate();
162        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
163        CreateDebugUtilsMessenger(log);
164
165        PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2");
166        ASSERT_NE(GetPhysDevProps2, nullptr);
167
168        uint32_t driver_count = 1;
169        VkPhysicalDevice physical_device;
170        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
171        ASSERT_EQ(driver_count, 1U);
172
173        VkPhysicalDeviceProperties props{};
174        instance->vkGetPhysicalDeviceProperties(physical_device, &props);
175        VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
176        GetPhysDevProps2(physical_device, &props2);
177
178        // Both properties should match
179        ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
180        ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
181        ASSERT_EQ(props.vendorID, props2.properties.vendorID);
182        ASSERT_EQ(props.deviceID, props2.properties.deviceID);
183        ASSERT_EQ(props.deviceType, props2.properties.deviceType);
184        ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
185        ASSERT_TRUE(log.find("Emulating call in ICD"));
186    }
187    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
188                                                         .set_name("modify_api_version_layer")
189                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
190                                                         .set_disable_environment("DisableEnvVar")),
191                           "modify_api_version_layer.json");
192    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
193    {  // Now do the same as above but with a layer that updates the version to 1.1
194        InstWrapper instance(env.vulkan_functions);
195        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
196        instance.CheckCreate();
197        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
198        CreateDebugUtilsMessenger(log);
199
200        PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2");
201        ASSERT_NE(GetPhysDevProps2, nullptr);
202
203        uint32_t driver_count = 1;
204        VkPhysicalDevice physical_device;
205        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
206        ASSERT_EQ(driver_count, 1U);
207
208        VkPhysicalDeviceProperties props{};
209        instance->vkGetPhysicalDeviceProperties(physical_device, &props);
210        VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
211        GetPhysDevProps2(physical_device, &props2);
212
213        // Both properties should match
214        ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
215        ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
216        ASSERT_EQ(props.vendorID, props2.properties.vendorID);
217        ASSERT_EQ(props.deviceID, props2.properties.deviceID);
218        ASSERT_EQ(props.deviceType, props2.properties.deviceType);
219        ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
220        ASSERT_FALSE(log.find("Emulating call in ICD"));
221    }
222}
223
224// Test vkGetPhysicalDeviceProperties2 and vkGetPhysicalDeviceProperties2KHR where ICD is 1.0 and supports
225// extension but the instance supports 1.1 and the extension
226TEST(LoaderInstPhysDevExts, PhysDevProps2KHRInstanceSupports11) {
227    FrameworkEnvironment env{};
228    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_API_VERSION_1_0));
229    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
230    env.get_test_icd(0).physical_devices.push_back({});
231    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
232    FillInRandomDeviceProps(env.get_test_icd(0).physical_devices.back().properties, VK_API_VERSION_1_0, 5, 123);
233
234    InstWrapper instance(env.vulkan_functions);
235    instance.create_info.set_api_version(VK_API_VERSION_1_1);
236    instance.create_info.add_extensions(
237        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
238    instance.CheckCreate();
239    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
240    CreateDebugUtilsMessenger(log);
241
242    PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2");
243    ASSERT_NE(GetPhysDevProps2, nullptr);
244
245    PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2KHR = instance.load("vkGetPhysicalDeviceProperties2KHR");
246    ASSERT_NE(GetPhysDevProps2KHR, nullptr);
247
248    uint32_t driver_count = 1;
249    VkPhysicalDevice physical_device;
250    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
251    ASSERT_EQ(driver_count, 1U);
252
253    VkPhysicalDeviceProperties props{};
254    instance->vkGetPhysicalDeviceProperties(physical_device, &props);
255    VkPhysicalDeviceProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
256    GetPhysDevProps2(physical_device, &props2);
257
258    // Both VkPhysicalDeviceProperties2 properties should match
259    ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
260    ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
261    ASSERT_EQ(props.vendorID, props2.properties.vendorID);
262    ASSERT_EQ(props.deviceID, props2.properties.deviceID);
263    ASSERT_EQ(props.deviceType, props2.properties.deviceType);
264    ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
265
266    VkPhysicalDeviceProperties2KHR props2KHR{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
267    GetPhysDevProps2(physical_device, &props2KHR);
268
269    // Both VkPhysicalDeviceProperties2KHR properties should match
270    ASSERT_EQ(props.apiVersion, props2KHR.properties.apiVersion);
271    ASSERT_EQ(props.driverVersion, props2KHR.properties.driverVersion);
272    ASSERT_EQ(props.vendorID, props2KHR.properties.vendorID);
273    ASSERT_EQ(props.deviceID, props2KHR.properties.deviceID);
274    ASSERT_EQ(props.deviceType, props2KHR.properties.deviceType);
275    ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2KHR.properties.pipelineCacheUUID, VK_UUID_SIZE));
276
277    ASSERT_FALSE(log.find("Emulating call in ICD"));
278}
279
280// Test vkGetPhysicalDeviceProperties2 where instance supports it with some ICDs that both support
281// and don't support it:
282//    ICD 0 supports
283//        Physical device 0 does not
284//        Physical device 1 does
285//        Physical device 2 does not
286//    ICD 1 doesn't support
287//        Physical device 3 does not
288//    ICD 2 supports
289//        Physical device 4 does not
290//        Physical device 5 does not
291//    ICD 3 supports
292//        Physical device 6 does
293TEST(LoaderInstPhysDevExts, PhysDevProps2Mixed) {
294    FrameworkEnvironment env{};
295    const uint32_t max_icd_count = 4;
296    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
297    const uint32_t max_phys_devs = 7;
298
299    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
300        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
301        auto& cur_icd = env.get_test_icd(icd);
302
303        // ICD 1 should not have 1.1
304        if (icd != 1) {
305            cur_icd.icd_api_version = VK_API_VERSION_1_1;
306            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
307        }
308
309        uint32_t rand_vendor_id;
310        uint32_t rand_driver_vers;
311        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
312
313        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
314            uint32_t device_version = VK_API_VERSION_1_0;
315            cur_icd.physical_devices.push_back({});
316            auto& cur_dev = cur_icd.physical_devices.back();
317
318            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
319            if ((icd == 0 && dev == 1) || icd == 3) {
320                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
321                device_version = VK_API_VERSION_1_1;
322            }
323            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
324        }
325    }
326
327    InstWrapper instance(env.vulkan_functions);
328    instance.create_info.set_api_version(VK_API_VERSION_1_1);
329    instance.CheckCreate();
330
331    PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = instance.load("vkGetPhysicalDeviceProperties2");
332    ASSERT_NE(GetPhysDevProps2, nullptr);
333
334    uint32_t device_count = max_phys_devs;
335    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
336    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
337    ASSERT_EQ(device_count, max_phys_devs);
338
339    for (uint32_t dev = 0; dev < device_count; ++dev) {
340        VkPhysicalDeviceProperties props{};
341        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &props);
342        VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
343        GetPhysDevProps2(physical_devices[dev], &props2);
344
345        // Both properties should match
346        ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
347        ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
348        ASSERT_EQ(props.vendorID, props2.properties.vendorID);
349        ASSERT_EQ(props.deviceID, props2.properties.deviceID);
350        ASSERT_EQ(props.deviceType, props2.properties.deviceType);
351        ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
352    }
353}
354
355// Fill in random but valid data into the features struct for the current physical device
356void FillInRandomFeatures(VkPhysicalDeviceFeatures& feats) {
357    feats.robustBufferAccess = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
358    feats.fullDrawIndexUint32 = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
359    feats.imageCubeArray = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
360    feats.independentBlend = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
361    feats.geometryShader = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
362    feats.tessellationShader = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
363    feats.sampleRateShading = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
364    feats.dualSrcBlend = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
365    feats.logicOp = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
366    feats.multiDrawIndirect = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
367    feats.drawIndirectFirstInstance = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
368    feats.depthClamp = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
369    feats.depthBiasClamp = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
370    feats.fillModeNonSolid = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
371    feats.depthBounds = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
372    feats.wideLines = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
373    feats.largePoints = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
374    feats.alphaToOne = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
375    feats.multiViewport = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
376    feats.samplerAnisotropy = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
377    feats.textureCompressionETC2 = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
378    feats.textureCompressionASTC_LDR = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
379    feats.textureCompressionBC = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
380    feats.occlusionQueryPrecise = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
381    feats.pipelineStatisticsQuery = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
382    feats.vertexPipelineStoresAndAtomics = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
383    feats.fragmentStoresAndAtomics = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
384    feats.shaderTessellationAndGeometryPointSize = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
385    feats.shaderImageGatherExtended = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
386    feats.shaderStorageImageExtendedFormats = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
387    feats.shaderStorageImageMultisample = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
388    feats.shaderStorageImageReadWithoutFormat = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
389    feats.shaderStorageImageWriteWithoutFormat = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
390    feats.shaderUniformBufferArrayDynamicIndexing = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
391    feats.shaderSampledImageArrayDynamicIndexing = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
392    feats.shaderStorageBufferArrayDynamicIndexing = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
393    feats.shaderStorageImageArrayDynamicIndexing = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
394    feats.shaderClipDistance = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
395    feats.shaderCullDistance = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
396    feats.shaderFloat64 = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
397    feats.shaderInt64 = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
398    feats.shaderInt16 = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
399    feats.shaderResourceResidency = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
400    feats.shaderResourceMinLod = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
401    feats.sparseBinding = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
402    feats.sparseResidencyBuffer = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
403    feats.sparseResidencyImage2D = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
404    feats.sparseResidencyImage3D = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
405    feats.sparseResidency2Samples = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
406    feats.sparseResidency4Samples = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
407    feats.sparseResidency8Samples = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
408    feats.sparseResidency16Samples = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
409    feats.sparseResidencyAliased = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
410    feats.variableMultisampleRate = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
411    feats.inheritedQueries = (rand() % 2) == 0 ? VK_FALSE : VK_TRUE;
412}
413
414// Compare the contents of the feature structs
415bool CompareFeatures(const VkPhysicalDeviceFeatures& feats1, const VkPhysicalDeviceFeatures2& feats2) {
416    return feats1.robustBufferAccess == feats2.features.robustBufferAccess &&
417           feats1.fullDrawIndexUint32 == feats2.features.fullDrawIndexUint32 &&
418           feats1.imageCubeArray == feats2.features.imageCubeArray && feats1.independentBlend == feats2.features.independentBlend &&
419           feats1.geometryShader == feats2.features.geometryShader &&
420           feats1.tessellationShader == feats2.features.tessellationShader &&
421           feats1.sampleRateShading == feats2.features.sampleRateShading && feats1.dualSrcBlend == feats2.features.dualSrcBlend &&
422           feats1.logicOp == feats2.features.logicOp && feats1.multiDrawIndirect == feats2.features.multiDrawIndirect &&
423           feats1.drawIndirectFirstInstance == feats2.features.drawIndirectFirstInstance &&
424           feats1.depthClamp == feats2.features.depthClamp && feats1.depthBiasClamp == feats2.features.depthBiasClamp &&
425           feats1.fillModeNonSolid == feats2.features.fillModeNonSolid && feats1.depthBounds == feats2.features.depthBounds &&
426           feats1.wideLines == feats2.features.wideLines && feats1.largePoints == feats2.features.largePoints &&
427           feats1.alphaToOne == feats2.features.alphaToOne && feats1.multiViewport == feats2.features.multiViewport &&
428           feats1.samplerAnisotropy == feats2.features.samplerAnisotropy &&
429           feats1.textureCompressionETC2 == feats2.features.textureCompressionETC2 &&
430           feats1.textureCompressionASTC_LDR == feats2.features.textureCompressionASTC_LDR &&
431           feats1.textureCompressionBC == feats2.features.textureCompressionBC &&
432           feats1.occlusionQueryPrecise == feats2.features.occlusionQueryPrecise &&
433           feats1.pipelineStatisticsQuery == feats2.features.pipelineStatisticsQuery &&
434           feats1.vertexPipelineStoresAndAtomics == feats2.features.vertexPipelineStoresAndAtomics &&
435           feats1.fragmentStoresAndAtomics == feats2.features.fragmentStoresAndAtomics &&
436           feats1.shaderTessellationAndGeometryPointSize == feats2.features.shaderTessellationAndGeometryPointSize &&
437           feats1.shaderImageGatherExtended == feats2.features.shaderImageGatherExtended &&
438           feats1.shaderStorageImageExtendedFormats == feats2.features.shaderStorageImageExtendedFormats &&
439           feats1.shaderStorageImageMultisample == feats2.features.shaderStorageImageMultisample &&
440           feats1.shaderStorageImageReadWithoutFormat == feats2.features.shaderStorageImageReadWithoutFormat &&
441           feats1.shaderStorageImageWriteWithoutFormat == feats2.features.shaderStorageImageWriteWithoutFormat &&
442           feats1.shaderUniformBufferArrayDynamicIndexing == feats2.features.shaderUniformBufferArrayDynamicIndexing &&
443           feats1.shaderSampledImageArrayDynamicIndexing == feats2.features.shaderSampledImageArrayDynamicIndexing &&
444           feats1.shaderStorageBufferArrayDynamicIndexing == feats2.features.shaderStorageBufferArrayDynamicIndexing &&
445           feats1.shaderStorageImageArrayDynamicIndexing == feats2.features.shaderStorageImageArrayDynamicIndexing &&
446           feats1.shaderClipDistance == feats2.features.shaderClipDistance &&
447           feats1.shaderCullDistance == feats2.features.shaderCullDistance &&
448           feats1.shaderFloat64 == feats2.features.shaderFloat64 && feats1.shaderInt64 == feats2.features.shaderInt64 &&
449           feats1.shaderInt16 == feats2.features.shaderInt16 &&
450           feats1.shaderResourceResidency == feats2.features.shaderResourceResidency &&
451           feats1.shaderResourceMinLod == feats2.features.shaderResourceMinLod &&
452           feats1.sparseBinding == feats2.features.sparseBinding &&
453           feats1.sparseResidencyBuffer == feats2.features.sparseResidencyBuffer &&
454           feats1.sparseResidencyImage2D == feats2.features.sparseResidencyImage2D &&
455           feats1.sparseResidencyImage3D == feats2.features.sparseResidencyImage3D &&
456           feats1.sparseResidency2Samples == feats2.features.sparseResidency2Samples &&
457           feats1.sparseResidency4Samples == feats2.features.sparseResidency4Samples &&
458           feats1.sparseResidency8Samples == feats2.features.sparseResidency8Samples &&
459           feats1.sparseResidency16Samples == feats2.features.sparseResidency16Samples &&
460           feats1.sparseResidencyAliased == feats2.features.sparseResidencyAliased &&
461           feats1.variableMultisampleRate == feats2.features.variableMultisampleRate &&
462           feats1.inheritedQueries == feats2.features.inheritedQueries;
463}
464
465// Test vkGetPhysicalDeviceFeatures2KHR where nothing supports it.
466TEST(LoaderInstPhysDevExts, PhysDevFeats2KHRNoSupport) {
467    FrameworkEnvironment env{};
468    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
469    env.get_test_icd(0).physical_devices.push_back({});
470
471    InstWrapper instance(env.vulkan_functions);
472    instance.CheckCreate();
473
474    PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysDevFeats2KHR = instance.load("vkGetPhysicalDeviceFeatures2KHR");
475    ASSERT_EQ(GetPhysDevFeats2KHR, nullptr);
476}
477
478// Test vkGetPhysicalDeviceFeatures2KHR where instance supports it, but nothing else.
479TEST(LoaderInstPhysDevExts, PhysDevFeatsKHRNoICDSupport) {
480    FrameworkEnvironment env{};
481    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
482    env.get_test_icd(0).physical_devices.push_back({});
483
484    InstWrapper instance(env.vulkan_functions);
485    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
486    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
487
488    PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysDevFeats2KHR = instance.load("vkGetPhysicalDeviceFeatures2KHR");
489    ASSERT_EQ(GetPhysDevFeats2KHR, nullptr);
490}
491
492// Test vkGetPhysicalDeviceFeatures2KHR where instance and ICD supports it, but device does not support it.
493TEST(LoaderInstPhysDevExts, PhysDevFeats2KHRInstanceAndICDSupport) {
494    FrameworkEnvironment env{};
495    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
496    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
497    env.get_test_icd(0).physical_devices.push_back({});
498    FillInRandomFeatures(env.get_test_icd(0).physical_devices.back().features);
499
500    InstWrapper instance(env.vulkan_functions);
501    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
502    instance.CheckCreate();
503
504    PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysDevFeats2KHR = instance.load("vkGetPhysicalDeviceFeatures2KHR");
505    ASSERT_NE(GetPhysDevFeats2KHR, nullptr);
506
507    uint32_t driver_count = 1;
508    VkPhysicalDevice physical_device;
509    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
510    ASSERT_EQ(driver_count, 1U);
511
512    VkPhysicalDeviceFeatures feats{};
513    instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
514    VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR};
515    GetPhysDevFeats2KHR(physical_device, &feats2);
516    ASSERT_TRUE(CompareFeatures(feats, feats2));
517}
518
519// Test vkGetPhysicalDeviceFeatures2 where instance supports, an ICD, and a device under that ICD
520// also support, so everything should work and return properly.
521// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
522TEST(LoaderInstPhysDevExts, PhysDevFeats2Simple) {
523    FrameworkEnvironment env{};
524    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_API_VERSION_1_1));
525    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
526    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
527    env.get_test_icd(0).physical_devices.push_back({});
528    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
529    env.get_test_icd(0).physical_devices.back().set_api_version(VK_API_VERSION_1_1);
530    FillInRandomFeatures(env.get_test_icd(0).physical_devices.back().features);
531    {
532        InstWrapper instance(env.vulkan_functions);
533        instance.create_info.set_api_version(VK_API_VERSION_1_1);
534        instance.CheckCreate();
535
536        PFN_vkGetPhysicalDeviceFeatures2 GetPhysDevFeats2 = instance.load("vkGetPhysicalDeviceFeatures2");
537        ASSERT_NE(GetPhysDevFeats2, nullptr);
538
539        uint32_t driver_count = 1;
540        VkPhysicalDevice physical_device;
541        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
542        ASSERT_EQ(driver_count, 1U);
543
544        VkPhysicalDeviceFeatures feats{};
545        instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
546        VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
547        GetPhysDevFeats2(physical_device, &feats2);
548        ASSERT_TRUE(CompareFeatures(feats, feats2));
549    }
550    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
551        InstWrapper instance(env.vulkan_functions);
552        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
553        instance.CheckCreate();
554        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
555        CreateDebugUtilsMessenger(log);
556
557        PFN_vkGetPhysicalDeviceFeatures2 GetPhysDevFeats2 = instance.load("vkGetPhysicalDeviceFeatures2");
558        ASSERT_NE(GetPhysDevFeats2, nullptr);
559
560        uint32_t driver_count = 1;
561        VkPhysicalDevice physical_device;
562        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
563        ASSERT_EQ(driver_count, 1U);
564
565        VkPhysicalDeviceFeatures feats{};
566        instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
567        VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
568        GetPhysDevFeats2(physical_device, &feats2);
569        ASSERT_TRUE(CompareFeatures(feats, feats2));
570
571        ASSERT_TRUE(log.find("Emulating call in ICD"));
572    }
573    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
574                                                         .set_name("modify_api_version_layer")
575                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
576                                                         .set_disable_environment("DisableEnvVar")),
577                           "modify_api_version_layer.json");
578    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
579    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
580        InstWrapper instance(env.vulkan_functions);
581        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
582        instance.CheckCreate();
583        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
584        CreateDebugUtilsMessenger(log);
585
586        PFN_vkGetPhysicalDeviceFeatures2 GetPhysDevFeats2 = instance.load("vkGetPhysicalDeviceFeatures2");
587        ASSERT_NE(GetPhysDevFeats2, nullptr);
588
589        uint32_t driver_count = 1;
590        VkPhysicalDevice physical_device;
591        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
592        ASSERT_EQ(driver_count, 1U);
593
594        VkPhysicalDeviceFeatures feats{};
595        instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
596        VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
597        GetPhysDevFeats2(physical_device, &feats2);
598        ASSERT_TRUE(CompareFeatures(feats, feats2));
599
600        ASSERT_FALSE(log.find("Emulating call in ICD"));
601    }
602}
603
604// Test vkGetPhysicalDeviceFeatures2 and vkGetPhysicalDeviceFeatures2KHR where ICD is 1.0 and supports
605// extension but the instance supports 1.1 and the extension
606TEST(LoaderInstPhysDevExts, PhysDevFeats2KHRInstanceSupports11) {
607    FrameworkEnvironment env{};
608    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_API_VERSION_1_0));
609    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
610    env.get_test_icd(0).physical_devices.push_back({});
611    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
612    FillInRandomFeatures(env.get_test_icd(0).physical_devices.back().features);
613
614    InstWrapper instance(env.vulkan_functions);
615    instance.create_info.set_api_version(VK_API_VERSION_1_1);
616    instance.create_info.add_extensions(
617        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
618    instance.CheckCreate();
619    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
620    CreateDebugUtilsMessenger(log);
621
622    PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysDevFeats2KHR = instance.load("vkGetPhysicalDeviceFeatures2KHR");
623    ASSERT_NE(GetPhysDevFeats2KHR, nullptr);
624
625    PFN_vkGetPhysicalDeviceFeatures2 GetPhysDevFeats2 = instance.load("vkGetPhysicalDeviceFeatures2");
626    ASSERT_NE(GetPhysDevFeats2, nullptr);
627
628    uint32_t driver_count = 1;
629    VkPhysicalDevice physical_device;
630    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
631    ASSERT_EQ(driver_count, 1U);
632
633    VkPhysicalDeviceFeatures feats{};
634    instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
635
636    VkPhysicalDeviceFeatures2KHR feats2KHR{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR};
637    GetPhysDevFeats2KHR(physical_device, &feats2KHR);
638    ASSERT_TRUE(CompareFeatures(feats, feats2KHR));
639
640    VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
641    GetPhysDevFeats2(physical_device, &feats2);
642    ASSERT_TRUE(CompareFeatures(feats, feats2));
643
644    ASSERT_FALSE(log.find("Emulating call in ICD"));
645}
646
647// Test vkGetPhysicalDeviceFeatures2 where instance supports it with some ICDs that both support
648// and don't support it:
649//    ICD 0 supports
650//        Physical device 0 does not
651//        Physical device 1 does
652//        Physical device 2 does not
653//    ICD 1 doesn't support
654//        Physical device 3 does not
655//    ICD 2 supports
656//        Physical device 4 does not
657//        Physical device 5 does not
658//    ICD 3 supports
659//        Physical device 6 does
660TEST(LoaderInstPhysDevExts, PhysDevFeatsMixed) {
661    FrameworkEnvironment env{};
662    const uint32_t max_icd_count = 4;
663    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
664    const uint32_t max_phys_devs = 7;
665
666    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
667        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
668        auto& cur_icd = env.get_test_icd(icd);
669
670        // ICD 1 should not have 1.1
671        if (icd != 1) {
672            cur_icd.icd_api_version = VK_API_VERSION_1_1;
673            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
674        }
675
676        uint32_t rand_vendor_id;
677        uint32_t rand_driver_vers;
678        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
679
680        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
681            uint32_t device_version = VK_API_VERSION_1_0;
682            cur_icd.physical_devices.push_back({});
683            auto& cur_dev = cur_icd.physical_devices.back();
684
685            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
686            if ((icd == 0 && dev == 1) || icd == 3) {
687                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
688                device_version = VK_API_VERSION_1_1;
689            }
690
691            // Still set physical device properties (so we can determine if device is correct API version)
692            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
693            FillInRandomFeatures(cur_dev.features);
694        }
695    }
696
697    InstWrapper instance(env.vulkan_functions);
698    instance.create_info.set_api_version(VK_API_VERSION_1_1);
699    instance.CheckCreate();
700
701    PFN_vkGetPhysicalDeviceFeatures2 GetPhysDevFeats2 = instance.load("vkGetPhysicalDeviceFeatures2");
702    ASSERT_NE(GetPhysDevFeats2, nullptr);
703
704    uint32_t device_count = max_phys_devs;
705    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
706    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
707    ASSERT_EQ(device_count, max_phys_devs);
708
709    for (uint32_t dev = 0; dev < device_count; ++dev) {
710        VkPhysicalDeviceFeatures feats{};
711        instance->vkGetPhysicalDeviceFeatures(physical_devices[dev], &feats);
712        VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
713        GetPhysDevFeats2(physical_devices[dev], &feats2);
714        ASSERT_TRUE(CompareFeatures(feats, feats2));
715    }
716}
717
718// Fill in random but valid data into the format properties struct for the current physical device
719void FillInRandomFormatProperties(std::vector<VkFormatProperties>& props) {
720    props.resize(5);
721    for (uint8_t form = 0; form < 5; ++form) {
722        props[form].bufferFeatures = static_cast<VkFormatFeatureFlags>(rand());
723        props[form].linearTilingFeatures = static_cast<VkFormatFeatureFlags>(rand());
724        props[form].optimalTilingFeatures = static_cast<VkFormatFeatureFlags>(rand());
725    }
726}
727
728// Test vkGetPhysicalDeviceFormatProperties2KHR where nothing supports it.
729TEST(LoaderInstPhysDevExts, PhysDevFormatProps2KHRNoSupport) {
730    FrameworkEnvironment env{};
731    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
732    env.get_test_icd(0).physical_devices.push_back({});
733
734    InstWrapper instance(env.vulkan_functions);
735    instance.CheckCreate();
736
737    PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysDevFormatProps2KHR =
738        instance.load("vkGetPhysicalDeviceFormatProperties2KHR");
739    ASSERT_EQ(GetPhysDevFormatProps2KHR, nullptr);
740}
741
742// Test vkGetPhysicalDeviceFormatProperties2KHR where instance supports it, but nothing else.
743TEST(LoaderInstPhysDevExts, PhysDevFormatPropsKHRNoICDSupport) {
744    FrameworkEnvironment env{};
745    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
746    env.get_test_icd(0).physical_devices.push_back({});
747
748    InstWrapper instance(env.vulkan_functions);
749    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
750    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
751
752    PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysDevFormatProps2KHR =
753        instance.load("vkGetPhysicalDeviceFormatProperties2KHR");
754    ASSERT_EQ(GetPhysDevFormatProps2KHR, nullptr);
755}
756
757// Test vkGetPhysicalDeviceFormatProperties2KHR where instance and ICD supports it, but device does not support it.
758TEST(LoaderInstPhysDevExts, PhysDevFormatProps2KHRInstanceAndICDSupport) {
759    FrameworkEnvironment env{};
760    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
761    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
762    env.get_test_icd(0).physical_devices.push_back({});
763    FillInRandomFormatProperties(env.get_test_icd(0).physical_devices.back().format_properties);
764
765    InstWrapper instance(env.vulkan_functions);
766    instance.create_info.add_extensions(
767        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
768    instance.CheckCreate();
769    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
770    CreateDebugUtilsMessenger(log);
771
772    PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysDevFormatProps2KHR =
773        instance.load("vkGetPhysicalDeviceFormatProperties2KHR");
774    ASSERT_NE(GetPhysDevFormatProps2KHR, nullptr);
775
776    uint32_t driver_count = 1;
777    VkPhysicalDevice physical_device;
778    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
779    ASSERT_EQ(driver_count, 1U);
780
781    VkFormatProperties props{};
782    instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
783    VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
784    GetPhysDevFormatProps2KHR(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
785
786    ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
787    ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
788    ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
789}
790
791// Test vkGetPhysicalDeviceFormatProperties2 where instance supports, an ICD, and a device under that ICD
792// also support, so everything should work and return properly.
793// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
794TEST(LoaderInstPhysDevExts, PhysDevFormatProps2Simple) {
795    FrameworkEnvironment env{};
796    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_API_VERSION_1_1));
797    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
798    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
799    env.get_test_icd(0).physical_devices.push_back({});
800    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
801    env.get_test_icd(0).physical_devices.back().set_api_version(VK_API_VERSION_1_1);
802    FillInRandomFormatProperties(env.get_test_icd(0).physical_devices.back().format_properties);
803    {
804        InstWrapper instance(env.vulkan_functions);
805        instance.create_info.set_api_version(VK_API_VERSION_1_1);
806        instance.CheckCreate();
807
808        PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysDevFormatProps2 = instance.load("vkGetPhysicalDeviceFormatProperties2");
809        ASSERT_NE(GetPhysDevFormatProps2, nullptr);
810
811        uint32_t driver_count = 1;
812        VkPhysicalDevice physical_device;
813        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
814        ASSERT_EQ(driver_count, 1U);
815
816        VkFormatProperties props{};
817        instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
818        VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
819        GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
820
821        ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
822        ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
823        ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
824    }
825    {  // Do the same logic but have the application forget to enable 1.1 and doesn't enable the extension
826        InstWrapper instance(env.vulkan_functions);
827        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
828        instance.CheckCreate();
829        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
830        CreateDebugUtilsMessenger(log);
831
832        PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysDevFormatProps2 = instance.load("vkGetPhysicalDeviceFormatProperties2");
833        ASSERT_NE(GetPhysDevFormatProps2, nullptr);
834
835        uint32_t driver_count = 1;
836        VkPhysicalDevice physical_device;
837        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
838        ASSERT_EQ(driver_count, 1U);
839
840        VkFormatProperties props{};
841        instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
842        VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
843        GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
844
845        ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
846        ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
847        ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
848        ASSERT_TRUE(log.find("Emulating call in ICD"));
849    }
850    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
851                                                         .set_name("modify_api_version_layer")
852                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
853                                                         .set_disable_environment("DisableEnvVar")),
854                           "modify_api_version_layer.json");
855    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
856    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
857        InstWrapper instance(env.vulkan_functions);
858        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
859        instance.CheckCreate();
860        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
861        CreateDebugUtilsMessenger(log);
862
863        PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysDevFormatProps2 = instance.load("vkGetPhysicalDeviceFormatProperties2");
864        ASSERT_NE(GetPhysDevFormatProps2, nullptr);
865
866        uint32_t driver_count = 1;
867        VkPhysicalDevice physical_device;
868        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
869        ASSERT_EQ(driver_count, 1U);
870
871        VkFormatProperties props{};
872        instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
873        VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
874        GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
875
876        ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
877        ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
878        ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
879        ASSERT_FALSE(log.find("Emulating call in ICD"));
880    }
881}
882// Test vkGetPhysicalDeviceFormatProperties2 and vkGetPhysicalDeviceFormatProperties2KHR where ICD is 1.0 and supports
883// extension but the instance supports 1.1 and the extension
884TEST(LoaderInstPhysDevExts, PhysDevFormatProps2KHRInstanceSupports11) {
885    FrameworkEnvironment env{};
886    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
887    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
888    env.get_test_icd(0).physical_devices.push_back({});
889    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
890    FillInRandomFormatProperties(env.get_test_icd(0).physical_devices.back().format_properties);
891
892    InstWrapper instance(env.vulkan_functions);
893    instance.create_info.set_api_version(VK_API_VERSION_1_1);
894    instance.create_info.add_extensions(
895        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
896    instance.CheckCreate();
897    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
898    CreateDebugUtilsMessenger(log);
899
900    PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysDevFormatProps2 = instance.load("vkGetPhysicalDeviceFormatProperties2");
901    ASSERT_NE(GetPhysDevFormatProps2, nullptr);
902
903    PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysDevFormatProps2KHR =
904        instance.load("vkGetPhysicalDeviceFormatProperties2KHR");
905    ASSERT_NE(GetPhysDevFormatProps2KHR, nullptr);
906
907    uint32_t driver_count = 1;
908    VkPhysicalDevice physical_device;
909    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
910    ASSERT_EQ(driver_count, 1U);
911
912    VkFormatProperties props{};
913    instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
914    VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
915    GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
916
917    ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
918    ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
919    ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
920
921    VkFormatProperties2KHR props2KHR{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
922    GetPhysDevFormatProps2KHR(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2KHR);
923
924    ASSERT_EQ(props.bufferFeatures, props2KHR.formatProperties.bufferFeatures);
925    ASSERT_EQ(props.linearTilingFeatures, props2KHR.formatProperties.linearTilingFeatures);
926    ASSERT_EQ(props.optimalTilingFeatures, props2KHR.formatProperties.optimalTilingFeatures);
927
928    ASSERT_FALSE(log.find("Emulating call in ICD"));
929}
930
931// Test vkGetPhysicalDeviceFormatProperties2 where instance supports it with some ICDs that both support
932// and don't support it:
933//    ICD 0 supports
934//        Physical device 0 does not
935//        Physical device 1 does
936//        Physical device 2 does not
937//    ICD 1 doesn't support
938//        Physical device 3 does not
939//    ICD 2 supports
940//        Physical device 4 does not
941//        Physical device 5 does not
942//    ICD 3 supports
943//        Physical device 6 does
944TEST(LoaderInstPhysDevExts, PhysDevFormatPropsMixed) {
945    FrameworkEnvironment env{};
946    const uint32_t max_icd_count = 4;
947    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
948    const uint32_t max_phys_devs = 7;
949
950    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
951        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
952        auto& cur_icd = env.get_test_icd(icd);
953
954        // ICD 1 should not have 1.1
955        if (icd != 1) {
956            cur_icd.icd_api_version = VK_API_VERSION_1_1;
957            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
958        }
959
960        uint32_t rand_vendor_id;
961        uint32_t rand_driver_vers;
962        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
963
964        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
965            uint32_t device_version = VK_API_VERSION_1_0;
966            cur_icd.physical_devices.push_back({});
967            auto& cur_dev = cur_icd.physical_devices.back();
968
969            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
970            if ((icd == 0 && dev == 1) || icd == 3) {
971                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
972                device_version = VK_API_VERSION_1_1;
973            }
974
975            // Still set physical device properties (so we can determine if device is correct API version)
976            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
977            FillInRandomFormatProperties(cur_dev.format_properties);
978        }
979    }
980
981    InstWrapper instance(env.vulkan_functions);
982    instance.create_info.set_api_version(VK_API_VERSION_1_1);
983    instance.CheckCreate();
984
985    PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysDevFormatProps2 = instance.load("vkGetPhysicalDeviceFormatProperties2");
986    ASSERT_NE(GetPhysDevFormatProps2, nullptr);
987
988    uint32_t device_count = max_phys_devs;
989    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
990    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
991    ASSERT_EQ(device_count, max_phys_devs);
992
993    for (uint32_t dev = 0; dev < device_count; ++dev) {
994        VkFormat format = static_cast<VkFormat>((dev + 1) % 5);
995        VkFormatProperties props{};
996        instance->vkGetPhysicalDeviceFormatProperties(physical_devices[dev], format, &props);
997        VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
998        GetPhysDevFormatProps2(physical_devices[dev], format, &props2);
999
1000        ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
1001        ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
1002        ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
1003    }
1004}
1005
1006// Fill in random but valid data into the image format data struct for the current physical device
1007void FillInRandomImageFormatData(VkImageFormatProperties& props) {
1008    props.maxExtent = {static_cast<uint32_t>(rand() % 512), static_cast<uint32_t>(rand() % 512),
1009                       static_cast<uint32_t>(rand() % 512)};
1010    props.maxMipLevels = static_cast<uint32_t>(1 << (rand() % 16));
1011    props.maxArrayLayers = static_cast<uint32_t>(1 << (rand() % 16));
1012    props.sampleCounts = static_cast<VkSampleCountFlags>(1 << (rand() % 7));
1013    props.maxResourceSize = static_cast<uint64_t>(rand());
1014}
1015
1016// Test vkGetPhysicalDeviceImageFormatProperties2KHR where nothing supports it.
1017TEST(LoaderInstPhysDevExts, PhysDevImageFormatProps2KHRNoSupport) {
1018    FrameworkEnvironment env{};
1019    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1020    env.get_test_icd(0).physical_devices.push_back({});
1021
1022    InstWrapper instance(env.vulkan_functions);
1023    instance.CheckCreate();
1024
1025    PFN_vkGetPhysicalDeviceImageFormatProperties2KHR GetPhysDevImageFormatProps2 =
1026        instance.load("vkGetPhysicalDeviceImageFormatProperties2KHR");
1027    ASSERT_EQ(GetPhysDevImageFormatProps2, nullptr);
1028}
1029
1030// Test vkGetPhysicalDeviceImageFormatProperties2KHR where instance supports it, but nothing else.
1031TEST(LoaderInstPhysDevExts, PhysDevImageFormatPropsKHRNoICDSupport) {
1032    FrameworkEnvironment env{};
1033    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1034    env.get_test_icd(0).physical_devices.push_back({});
1035
1036    InstWrapper instance(env.vulkan_functions);
1037    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1038    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
1039
1040    PFN_vkGetPhysicalDeviceImageFormatProperties2KHR GetPhysDevImageFormatProps2KHR =
1041        instance.load("vkGetPhysicalDeviceImageFormatProperties2KHR");
1042    ASSERT_EQ(GetPhysDevImageFormatProps2KHR, nullptr);
1043}
1044
1045// Test vkGetPhysicalDeviceImageFormatProperties2KHR where instance and ICD supports it, but device does not support it.
1046TEST(LoaderInstPhysDevExts, PhysDevImageFormatProps2KHRInstanceAndICDSupport) {
1047    FrameworkEnvironment env{};
1048    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1049    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1050    env.get_test_icd(0).physical_devices.push_back({});
1051    FillInRandomImageFormatData(env.get_test_icd(0).physical_devices.back().image_format_properties);
1052
1053    InstWrapper instance(env.vulkan_functions);
1054    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1055    instance.CheckCreate();
1056
1057    PFN_vkGetPhysicalDeviceImageFormatProperties2KHR GetPhysDevImageFormatProps2KHR =
1058        instance.load("vkGetPhysicalDeviceImageFormatProperties2KHR");
1059    ASSERT_NE(GetPhysDevImageFormatProps2KHR, nullptr);
1060
1061    uint32_t driver_count = 1;
1062    VkPhysicalDevice physical_device;
1063    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1064    ASSERT_EQ(driver_count, 1U);
1065
1066    VkImageFormatProperties props{};
1067    ASSERT_EQ(VK_SUCCESS,
1068              instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
1069                                                                 VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
1070
1071    VkPhysicalDeviceImageFormatInfo2 info2{
1072        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
1073        nullptr,                                                // pNext
1074        VK_FORMAT_R4G4_UNORM_PACK8,                             // format
1075        VK_IMAGE_TYPE_2D,                                       // type
1076        VK_IMAGE_TILING_OPTIMAL,                                // tiling
1077        0,                                                      // usage
1078        0,                                                      // flags
1079    };
1080    VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
1081    ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2KHR(physical_device, &info2, &props2));
1082
1083    ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
1084    ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
1085    ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
1086    ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
1087    ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
1088    ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
1089    ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
1090}
1091
1092// Test vkGetPhysicalDeviceImageFormatProperties2 where instance supports, an ICD, and a device under that ICD
1093// also support, so everything should work and return properly.
1094// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
1095TEST(LoaderInstPhysDevExts, PhysDevImageFormatProps2Simple) {
1096    FrameworkEnvironment env{};
1097    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1098    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
1099    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1100    env.get_test_icd(0).physical_devices.push_back({});
1101    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1102    FillInRandomImageFormatData(env.get_test_icd(0).physical_devices.back().image_format_properties);
1103    {
1104        InstWrapper instance(env.vulkan_functions);
1105        instance.create_info.set_api_version(VK_API_VERSION_1_1);
1106        instance.CheckCreate();
1107
1108        PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysDevImageFormatProps2 =
1109            instance.load("vkGetPhysicalDeviceImageFormatProperties2");
1110        ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
1111
1112        uint32_t driver_count = 1;
1113        VkPhysicalDevice physical_device;
1114        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1115        ASSERT_EQ(driver_count, 1U);
1116
1117        VkImageFormatProperties props{};
1118        ASSERT_EQ(VK_SUCCESS,
1119                  instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
1120                                                                     VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
1121
1122        VkPhysicalDeviceImageFormatInfo2 info2{
1123            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
1124            nullptr,                                                // pNext
1125            VK_FORMAT_R4G4_UNORM_PACK8,                             // format
1126            VK_IMAGE_TYPE_2D,                                       // type
1127            VK_IMAGE_TILING_OPTIMAL,                                // tiling
1128            0,                                                      // usage
1129            0,                                                      // flags
1130        };
1131
1132        VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
1133        ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
1134
1135        ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
1136        ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
1137        ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
1138        ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
1139        ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
1140        ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
1141        ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
1142    }
1143    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
1144        InstWrapper instance(env.vulkan_functions);
1145        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
1146        instance.CheckCreate();
1147        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1148        CreateDebugUtilsMessenger(log);
1149
1150        PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysDevImageFormatProps2 =
1151            instance.load("vkGetPhysicalDeviceImageFormatProperties2");
1152        ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
1153
1154        uint32_t driver_count = 1;
1155        VkPhysicalDevice physical_device;
1156        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1157        ASSERT_EQ(driver_count, 1U);
1158
1159        VkImageFormatProperties props{};
1160        ASSERT_EQ(VK_SUCCESS,
1161                  instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
1162                                                                     VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
1163
1164        VkPhysicalDeviceImageFormatInfo2 info2{
1165            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
1166            nullptr,                                                // pNext
1167            VK_FORMAT_R4G4_UNORM_PACK8,                             // format
1168            VK_IMAGE_TYPE_2D,                                       // type
1169            VK_IMAGE_TILING_OPTIMAL,                                // tiling
1170            0,                                                      // usage
1171            0,                                                      // flags
1172        };
1173
1174        VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
1175        ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
1176
1177        ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
1178        ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
1179        ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
1180        ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
1181        ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
1182        ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
1183        ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
1184        ASSERT_TRUE(log.find("Emulating call in ICD"));
1185    }
1186    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1187                                                         .set_name("modify_api_version_layer")
1188                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1189                                                         .set_disable_environment("DisableEnvVar")),
1190                           "modify_api_version_layer.json");
1191    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
1192    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
1193        InstWrapper instance(env.vulkan_functions);
1194        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
1195        instance.CheckCreate();
1196        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1197        CreateDebugUtilsMessenger(log);
1198
1199        PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysDevImageFormatProps2 =
1200            instance.load("vkGetPhysicalDeviceImageFormatProperties2");
1201        ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
1202
1203        uint32_t driver_count = 1;
1204        VkPhysicalDevice physical_device;
1205        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1206        ASSERT_EQ(driver_count, 1U);
1207
1208        VkImageFormatProperties props{};
1209        ASSERT_EQ(VK_SUCCESS,
1210                  instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
1211                                                                     VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
1212
1213        VkPhysicalDeviceImageFormatInfo2 info2{
1214            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
1215            nullptr,                                                // pNext
1216            VK_FORMAT_R4G4_UNORM_PACK8,                             // format
1217            VK_IMAGE_TYPE_2D,                                       // type
1218            VK_IMAGE_TILING_OPTIMAL,                                // tiling
1219            0,                                                      // usage
1220            0,                                                      // flags
1221        };
1222
1223        VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
1224        ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
1225
1226        ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
1227        ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
1228        ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
1229        ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
1230        ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
1231        ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
1232        ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
1233        ASSERT_FALSE(log.find("Emulating call in ICD"));
1234    }
1235}
1236
1237// Test vkGetPhysicalDeviceImageFormatProperties2 and vkGetPhysicalDeviceImageFormatProperties2KHR where instance supports, an ICD,
1238// and a device under that ICD also support, so everything should work and return properly.
1239TEST(LoaderInstPhysDevExts, PhysDevImageFormatProps2KHRInstanceSupports11) {
1240    FrameworkEnvironment env{};
1241    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1242    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1243    env.get_test_icd(0).physical_devices.push_back({});
1244    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1245    FillInRandomImageFormatData(env.get_test_icd(0).physical_devices.back().image_format_properties);
1246
1247    InstWrapper instance(env.vulkan_functions);
1248    instance.create_info.set_api_version(VK_API_VERSION_1_1);
1249    instance.create_info.add_extensions(
1250        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
1251    instance.CheckCreate();
1252    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1253    CreateDebugUtilsMessenger(log);
1254
1255    PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysDevImageFormatProps2 =
1256        instance.load("vkGetPhysicalDeviceImageFormatProperties2");
1257    ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
1258
1259    PFN_vkGetPhysicalDeviceImageFormatProperties2KHR GetPhysDevImageFormatProps2KHR =
1260        instance.load("vkGetPhysicalDeviceImageFormatProperties2KHR");
1261    ASSERT_NE(GetPhysDevImageFormatProps2KHR, nullptr);
1262
1263    uint32_t driver_count = 1;
1264    VkPhysicalDevice physical_device;
1265    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1266    ASSERT_EQ(driver_count, 1U);
1267
1268    VkImageFormatProperties props{};
1269    ASSERT_EQ(VK_SUCCESS,
1270              instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
1271                                                                 VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
1272
1273    VkPhysicalDeviceImageFormatInfo2 info2{
1274        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
1275        nullptr,                                                // pNext
1276        VK_FORMAT_R4G4_UNORM_PACK8,                             // format
1277        VK_IMAGE_TYPE_2D,                                       // type
1278        VK_IMAGE_TILING_OPTIMAL,                                // tiling
1279        0,                                                      // usage
1280        0,                                                      // flags
1281    };
1282
1283    VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
1284    ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
1285
1286    ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
1287    ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
1288    ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
1289    ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
1290    ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
1291    ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
1292    ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
1293
1294    VkImageFormatProperties2KHR props2KHR{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR};
1295    ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2KHR(physical_device, &info2, &props2KHR));
1296
1297    ASSERT_EQ(props.maxExtent.width, props2KHR.imageFormatProperties.maxExtent.width);
1298    ASSERT_EQ(props.maxExtent.height, props2KHR.imageFormatProperties.maxExtent.height);
1299    ASSERT_EQ(props.maxExtent.depth, props2KHR.imageFormatProperties.maxExtent.depth);
1300    ASSERT_EQ(props.maxMipLevels, props2KHR.imageFormatProperties.maxMipLevels);
1301    ASSERT_EQ(props.maxArrayLayers, props2KHR.imageFormatProperties.maxArrayLayers);
1302    ASSERT_EQ(props.sampleCounts, props2KHR.imageFormatProperties.sampleCounts);
1303    ASSERT_EQ(props.maxResourceSize, props2KHR.imageFormatProperties.maxResourceSize);
1304
1305    ASSERT_FALSE(log.find("Emulating call in ICD"));
1306}
1307
1308// Test vkGetPhysicalDeviceImageFormatProperties2 where instance supports it with some ICDs that both support
1309// and don't support it:
1310//    ICD 0 supports
1311//        Physical device 0 does not
1312//        Physical device 1 does
1313//        Physical device 2 does not
1314//    ICD 1 doesn't support
1315//        Physical device 3 does not
1316//    ICD 2 supports
1317//        Physical device 4 does not
1318//        Physical device 5 does not
1319//    ICD 3 supports
1320//        Physical device 6 does
1321TEST(LoaderInstPhysDevExts, PhysDevImageFormatPropsMixed) {
1322    FrameworkEnvironment env{};
1323    const uint32_t max_icd_count = 4;
1324    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
1325    const uint32_t max_phys_devs = 7;
1326
1327    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
1328        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
1329        auto& cur_icd = env.get_test_icd(icd);
1330
1331        // ICD 1 should not have 1.1
1332        if (icd != 1) {
1333            cur_icd.icd_api_version = VK_API_VERSION_1_1;
1334            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1335        }
1336
1337        uint32_t rand_vendor_id;
1338        uint32_t rand_driver_vers;
1339        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
1340
1341        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
1342            uint32_t device_version = VK_API_VERSION_1_0;
1343            cur_icd.physical_devices.push_back({});
1344            auto& cur_dev = cur_icd.physical_devices.back();
1345
1346            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
1347            if ((icd == 0 && dev == 1) || icd == 3) {
1348                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1349                device_version = VK_API_VERSION_1_1;
1350            }
1351
1352            // Still set physical device properties (so we can determine if device is correct API version)
1353            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
1354            FillInRandomImageFormatData(cur_dev.image_format_properties);
1355        }
1356    }
1357
1358    InstWrapper instance(env.vulkan_functions);
1359    instance.create_info.set_api_version(VK_API_VERSION_1_1);
1360    instance.CheckCreate();
1361
1362    PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysDevImageFormatProps2 =
1363        instance.load("vkGetPhysicalDeviceImageFormatProperties2");
1364    ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
1365
1366    uint32_t device_count = max_phys_devs;
1367    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
1368    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
1369    ASSERT_EQ(device_count, max_phys_devs);
1370
1371    for (uint32_t dev = 0; dev < device_count; ++dev) {
1372        VkImageFormatProperties props{};
1373        ASSERT_EQ(VK_SUCCESS,
1374                  instance->vkGetPhysicalDeviceImageFormatProperties(physical_devices[dev], VK_FORMAT_R4G4_UNORM_PACK8,
1375                                                                     VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
1376
1377        VkPhysicalDeviceImageFormatInfo2 info2{
1378            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,  // sType
1379            nullptr,                                                // pNext
1380            VK_FORMAT_R4G4_UNORM_PACK8,                             // format
1381            VK_IMAGE_TYPE_2D,                                       // type
1382            VK_IMAGE_TILING_OPTIMAL,                                // tiling
1383            0,                                                      // usage
1384            0,                                                      // flags
1385        };
1386        VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
1387        ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_devices[dev], &info2, &props2));
1388
1389        ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
1390        ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
1391        ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
1392        ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
1393        ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
1394        ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
1395        ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
1396    }
1397}
1398
1399// Test vkGetPhysicalDeviceMemoryProperties2KHR where nothing supports it.
1400TEST(LoaderInstPhysDevExts, PhysDevMemoryProps2KHRNoSupport) {
1401    FrameworkEnvironment env{};
1402    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1403    env.get_test_icd(0).physical_devices.push_back({});
1404
1405    InstWrapper instance(env.vulkan_functions);
1406    instance.CheckCreate();
1407
1408    PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysDevMemoryProps2KHR =
1409        instance.load("vkGetPhysicalDeviceMemoryProperties2KHR");
1410    ASSERT_EQ(GetPhysDevMemoryProps2KHR, nullptr);
1411}
1412
1413// Test vkGetPhysicalDeviceMemoryProperties2KHR where instance supports it, but nothing else.
1414TEST(LoaderInstPhysDevExts, PhysDevMemoryPropsKHRNoICDSupport) {
1415    FrameworkEnvironment env{};
1416    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1417    env.get_test_icd(0).physical_devices.push_back({});
1418
1419    InstWrapper instance(env.vulkan_functions);
1420    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1421    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
1422
1423    PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysDevMemoryProps2KHR =
1424        instance.load("vkGetPhysicalDeviceMemoryProperties2KHR");
1425    ASSERT_EQ(GetPhysDevMemoryProps2KHR, nullptr);
1426}
1427
1428// Fill in random but valid data into the memory data struct for the current physical device
1429void FillInRandomMemoryData(VkPhysicalDeviceMemoryProperties& props) {
1430    props.memoryTypeCount = (rand() % 7) + 1;
1431    props.memoryHeapCount = (rand() % 7) + 1;
1432    for (uint32_t i = 0; i < props.memoryHeapCount; ++i) {
1433        props.memoryHeaps[i].size = (rand() % 728) + (rand() % 728) + 1;
1434        props.memoryHeaps[i].flags = (rand() % 2) + 1;
1435    }
1436    for (uint32_t i = 0; i < props.memoryTypeCount; ++i) {
1437        props.memoryTypes[i].propertyFlags = static_cast<VkMemoryPropertyFlags>((rand() % 2) + 1);
1438        props.memoryTypes[i].heapIndex = rand() % props.memoryHeapCount;
1439    }
1440}
1441
1442// Compare the memory structs
1443bool CompareMemoryData(const VkPhysicalDeviceMemoryProperties& props1, const VkPhysicalDeviceMemoryProperties2& props2) {
1444    bool equal = true;
1445    equal = equal && props1.memoryTypeCount == props2.memoryProperties.memoryTypeCount;
1446    equal = equal && props1.memoryHeapCount == props2.memoryProperties.memoryHeapCount;
1447    for (uint32_t i = 0; i < props1.memoryHeapCount; ++i) {
1448        equal = equal && props1.memoryHeaps[i].size == props2.memoryProperties.memoryHeaps[i].size;
1449        equal = equal && props1.memoryHeaps[i].flags == props2.memoryProperties.memoryHeaps[i].flags;
1450    }
1451    for (uint32_t i = 0; i < props1.memoryTypeCount; ++i) {
1452        equal = equal && props1.memoryTypes[i].propertyFlags == props2.memoryProperties.memoryTypes[i].propertyFlags;
1453        equal = equal && props1.memoryTypes[i].heapIndex == props2.memoryProperties.memoryTypes[i].heapIndex;
1454    }
1455    return equal;
1456}
1457
1458// Test vkGetPhysicalDeviceMemoryProperties2KHR where instance and ICD supports it, but device does not support it.
1459TEST(LoaderInstPhysDevExts, PhysDevMemoryProps2KHRInstanceAndICDSupport) {
1460    FrameworkEnvironment env{};
1461    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1462    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1463    env.get_test_icd(0).physical_devices.push_back({});
1464    FillInRandomMemoryData(env.get_test_icd(0).physical_devices.back().memory_properties);
1465
1466    InstWrapper instance(env.vulkan_functions);
1467    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1468    instance.CheckCreate();
1469
1470    PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysDevMemoryProps2KHR =
1471        instance.load("vkGetPhysicalDeviceMemoryProperties2KHR");
1472    ASSERT_NE(GetPhysDevMemoryProps2KHR, nullptr);
1473
1474    uint32_t driver_count = 1;
1475    VkPhysicalDevice physical_device;
1476    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1477    ASSERT_EQ(driver_count, 1U);
1478
1479    VkPhysicalDeviceMemoryProperties props{};
1480    instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
1481
1482    VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
1483    GetPhysDevMemoryProps2KHR(physical_device, &props2);
1484    ASSERT_TRUE(CompareMemoryData(props, props2));
1485}
1486
1487// Test vkGetPhysicalDeviceMemoryProperties2 where instance supports, an ICD, and a device under that ICD
1488// also support, so everything should work and return properly.
1489// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
1490TEST(LoaderInstPhysDevExts, PhysDevMemoryProps2Simple) {
1491    FrameworkEnvironment env{};
1492    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1493    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
1494    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1495    env.get_test_icd(0).physical_devices.push_back({});
1496    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1497    FillInRandomMemoryData(env.get_test_icd(0).physical_devices.back().memory_properties);
1498    {
1499        InstWrapper instance(env.vulkan_functions);
1500        instance.create_info.set_api_version(VK_API_VERSION_1_1);
1501        instance.CheckCreate();
1502
1503        PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysDevMemoryProps2 = instance.load("vkGetPhysicalDeviceMemoryProperties2");
1504        ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
1505
1506        uint32_t driver_count = 1;
1507        VkPhysicalDevice physical_device;
1508        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1509        ASSERT_EQ(driver_count, 1U);
1510
1511        VkPhysicalDeviceMemoryProperties props{};
1512        instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
1513
1514        VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
1515        GetPhysDevMemoryProps2(physical_device, &props2);
1516        ASSERT_TRUE(CompareMemoryData(props, props2));
1517    }
1518    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
1519        InstWrapper instance(env.vulkan_functions);
1520        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
1521        instance.CheckCreate();
1522        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1523        CreateDebugUtilsMessenger(log);
1524
1525        PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysDevMemoryProps2 = instance.load("vkGetPhysicalDeviceMemoryProperties2");
1526        ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
1527
1528        uint32_t driver_count = 1;
1529        VkPhysicalDevice physical_device;
1530        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1531        ASSERT_EQ(driver_count, 1U);
1532
1533        VkPhysicalDeviceMemoryProperties props{};
1534        instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
1535
1536        VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
1537        GetPhysDevMemoryProps2(physical_device, &props2);
1538        ASSERT_TRUE(CompareMemoryData(props, props2));
1539        ASSERT_TRUE(log.find("Emulating call in ICD"));
1540    }
1541    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1542                                                         .set_name("modify_api_version_layer")
1543                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1544                                                         .set_disable_environment("DisableEnvVar")),
1545                           "modify_api_version_layer.json");
1546    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
1547    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
1548        InstWrapper instance(env.vulkan_functions);
1549        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
1550        instance.CheckCreate();
1551        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1552        CreateDebugUtilsMessenger(log);
1553
1554        PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysDevMemoryProps2 = instance.load("vkGetPhysicalDeviceMemoryProperties2");
1555        ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
1556
1557        uint32_t driver_count = 1;
1558        VkPhysicalDevice physical_device;
1559        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1560        ASSERT_EQ(driver_count, 1U);
1561
1562        VkPhysicalDeviceMemoryProperties props{};
1563        instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
1564
1565        VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
1566        GetPhysDevMemoryProps2(physical_device, &props2);
1567        ASSERT_TRUE(CompareMemoryData(props, props2));
1568        ASSERT_FALSE(log.find("Emulating call in ICD"));
1569    }
1570}
1571
1572// Test vkGetPhysicalDeviceMemoryProperties2 and vkGetPhysicalDeviceMemoryProperties2KHR where ICD is 1.0 and supports
1573// extension but the instance supports 1.1 and the extension
1574TEST(LoaderInstPhysDevExts, PhysDevMemoryProps2KHRInstanceSupports11) {
1575    FrameworkEnvironment env{};
1576    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1577    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1578    env.get_test_icd(0).physical_devices.push_back({});
1579    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1580    FillInRandomMemoryData(env.get_test_icd(0).physical_devices.back().memory_properties);
1581
1582    InstWrapper instance(env.vulkan_functions);
1583    instance.create_info.set_api_version(VK_API_VERSION_1_1);
1584    instance.create_info.add_extensions(
1585        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
1586    instance.CheckCreate();
1587    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1588    CreateDebugUtilsMessenger(log);
1589
1590    PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysDevMemoryProps2 = instance.load("vkGetPhysicalDeviceMemoryProperties2");
1591    ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
1592
1593    PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysDevMemoryProps2KHR =
1594        instance.load("vkGetPhysicalDeviceMemoryProperties2KHR");
1595    ASSERT_NE(GetPhysDevMemoryProps2KHR, nullptr);
1596
1597    uint32_t driver_count = 1;
1598    VkPhysicalDevice physical_device;
1599    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1600    ASSERT_EQ(driver_count, 1U);
1601
1602    VkPhysicalDeviceMemoryProperties props{};
1603    instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
1604
1605    VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
1606    GetPhysDevMemoryProps2(physical_device, &props2);
1607    ASSERT_TRUE(CompareMemoryData(props, props2));
1608
1609    VkPhysicalDeviceMemoryProperties2KHR props2KHR{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR};
1610    GetPhysDevMemoryProps2KHR(physical_device, &props2KHR);
1611    ASSERT_TRUE(CompareMemoryData(props, props2KHR));
1612
1613    ASSERT_FALSE(log.find("Emulating call in ICD"));
1614}
1615// Test vkGetPhysicalDeviceMemoryProperties2 where instance supports it with some ICDs that both support
1616// and don't support it:
1617//    ICD 0 supports
1618//        Physical device 0 does not
1619//        Physical device 1 does
1620//        Physical device 2 does not
1621//    ICD 1 doesn't support
1622//        Physical device 3 does not
1623//    ICD 2 supports
1624//        Physical device 4 does not
1625//        Physical device 5 does not
1626//    ICD 3 supports
1627//        Physical device 6 does
1628TEST(LoaderInstPhysDevExts, PhysDevMemoryPropsMixed) {
1629    FrameworkEnvironment env{};
1630    const uint32_t max_icd_count = 4;
1631    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
1632    const uint32_t max_phys_devs = 7;
1633
1634    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
1635        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
1636        auto& cur_icd = env.get_test_icd(icd);
1637
1638        // ICD 1 should not have 1.1
1639        if (icd != 1) {
1640            cur_icd.icd_api_version = VK_API_VERSION_1_1;
1641            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1642        }
1643
1644        uint32_t rand_vendor_id;
1645        uint32_t rand_driver_vers;
1646        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
1647
1648        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
1649            uint32_t device_version = VK_API_VERSION_1_0;
1650            cur_icd.physical_devices.push_back({});
1651            auto& cur_dev = cur_icd.physical_devices.back();
1652
1653            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
1654            if ((icd == 0 && dev == 1) || icd == 3) {
1655                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1656                device_version = VK_API_VERSION_1_1;
1657            }
1658
1659            // Still set physical device properties (so we can determine if device is correct API version)
1660            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
1661            FillInRandomMemoryData(cur_dev.memory_properties);
1662        }
1663    }
1664
1665    InstWrapper instance(env.vulkan_functions);
1666    instance.create_info.set_api_version(VK_API_VERSION_1_1);
1667    instance.CheckCreate();
1668
1669    PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysDevMemoryProps2 = instance.load("vkGetPhysicalDeviceMemoryProperties2");
1670    ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
1671
1672    uint32_t device_count = max_phys_devs;
1673    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
1674    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
1675    ASSERT_EQ(device_count, max_phys_devs);
1676
1677    for (uint32_t dev = 0; dev < device_count; ++dev) {
1678        VkPhysicalDeviceMemoryProperties props{};
1679        instance->vkGetPhysicalDeviceMemoryProperties(physical_devices[dev], &props);
1680
1681        VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
1682        GetPhysDevMemoryProps2(physical_devices[dev], &props2);
1683        ASSERT_TRUE(CompareMemoryData(props, props2));
1684    }
1685}
1686
1687// Test vkGetPhysicalDeviceQueueFamilyProperties2KHR where nothing supports it.
1688TEST(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2KHRNoSupport) {
1689    FrameworkEnvironment env{};
1690    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1691    env.get_test_icd(0).physical_devices.push_back({});
1692
1693    InstWrapper instance(env.vulkan_functions);
1694    instance.CheckCreate();
1695
1696    PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR GetPhysDevQueueFamilyProps2KHR =
1697        instance.load("vkGetPhysicalDeviceQueueFamilyProperties2KHR");
1698    ASSERT_EQ(GetPhysDevQueueFamilyProps2KHR, nullptr);
1699}
1700
1701// Test vkGetPhysicalDeviceQueueFamilyProperties2KHR where instance supports it, but nothing else.
1702TEST(LoaderInstPhysDevExts, PhysDevQueueFamilyPropsKHRNoICDSupport) {
1703    FrameworkEnvironment env{};
1704    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1705    env.get_test_icd(0).physical_devices.push_back({});
1706
1707    InstWrapper instance(env.vulkan_functions);
1708    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1709    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
1710
1711    PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR GetPhysDevQueueFamilyProps2KHR =
1712        instance.load("vkGetPhysicalDeviceQueueFamilyProperties2KHR");
1713    ASSERT_EQ(GetPhysDevQueueFamilyProps2KHR, nullptr);
1714}
1715
1716// Fill in random but valid data into the queue family data struct for the current physical device
1717uint32_t FillInRandomQueueFamilyData(std::vector<MockQueueFamilyProperties>& props) {
1718    props.resize((rand() % 4) + 1);
1719    for (uint32_t i = 0; i < props.size(); ++i) {
1720        props[i].properties.queueFlags = (rand() % 30) + 1;
1721        props[i].properties.queueCount = (rand() % 7) + 1;
1722        props[i].properties.timestampValidBits = (rand() % 30) + 7;
1723        props[i].properties.minImageTransferGranularity.width = (rand() % 30) + 1;
1724        props[i].properties.minImageTransferGranularity.height = (rand() % 30) + 1;
1725        props[i].properties.minImageTransferGranularity.depth = (rand() % 30) + 1;
1726        props[i].support_present = rand() % 2 == 0;
1727    }
1728    return static_cast<uint32_t>(props.size());
1729}
1730
1731// Compare the queue family structs
1732bool CompareQueueFamilyData(const std::vector<VkQueueFamilyProperties>& props1,
1733                            const std::vector<VkQueueFamilyProperties2>& props2) {
1734    if (props1.size() != props2.size()) return false;
1735    bool equal = true;
1736    for (uint32_t i = 0; i < props1.size(); ++i) {
1737        equal = equal && props1[i].queueFlags == props2[i].queueFamilyProperties.queueFlags;
1738        equal = equal && props1[i].queueCount == props2[i].queueFamilyProperties.queueCount;
1739        equal = equal && props1[i].timestampValidBits == props2[i].queueFamilyProperties.timestampValidBits;
1740        equal = equal &&
1741                props1[i].minImageTransferGranularity.width == props2[i].queueFamilyProperties.minImageTransferGranularity.width;
1742        equal = equal &&
1743                props1[i].minImageTransferGranularity.height == props2[i].queueFamilyProperties.minImageTransferGranularity.height;
1744        equal = equal &&
1745                props1[i].minImageTransferGranularity.depth == props2[i].queueFamilyProperties.minImageTransferGranularity.depth;
1746    }
1747    return equal;
1748}
1749
1750// Test vkGetPhysicalDeviceQueueFamilyProperties2KHR where instance and ICD supports it, but device does not support it.
1751TEST(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2KHRInstanceAndICDSupport) {
1752    FrameworkEnvironment env{};
1753    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1754    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1755    env.get_test_icd(0).physical_devices.push_back({});
1756    uint32_t num_fam = FillInRandomQueueFamilyData(env.get_test_icd(0).physical_devices.back().queue_family_properties);
1757
1758    InstWrapper instance(env.vulkan_functions);
1759    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1760    instance.CheckCreate();
1761
1762    PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR GetPhysDevQueueFamilyProps2KHR =
1763        instance.load("vkGetPhysicalDeviceQueueFamilyProperties2KHR");
1764    ASSERT_NE(GetPhysDevQueueFamilyProps2KHR, nullptr);
1765
1766    uint32_t driver_count = 1;
1767    VkPhysicalDevice physical_device;
1768    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1769    ASSERT_EQ(driver_count, 1U);
1770
1771    uint32_t ret_fam_1 = 0;
1772    std::vector<VkQueueFamilyProperties> props{};
1773    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
1774    ASSERT_EQ(num_fam, ret_fam_1);
1775    props.resize(ret_fam_1);
1776
1777    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
1778
1779    std::vector<VkQueueFamilyProperties2> props2{};
1780    uint32_t ret_fam_2 = 0;
1781    GetPhysDevQueueFamilyProps2KHR(physical_device, &ret_fam_2, nullptr);
1782    ASSERT_EQ(ret_fam_1, ret_fam_2);
1783    props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
1784    GetPhysDevQueueFamilyProps2KHR(physical_device, &ret_fam_2, props2.data());
1785    ASSERT_TRUE(CompareQueueFamilyData(props, props2));
1786}
1787
1788// Test vkGetPhysicalDeviceQueueFamilyProperties2 where instance supports, an ICD, and a device under that ICD
1789// also support, so everything should work and return properly.
1790// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
1791TEST(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2Simple) {
1792    FrameworkEnvironment env{};
1793    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1794    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
1795    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1796    env.get_test_icd(0).physical_devices.push_back({});
1797    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1798    uint32_t num_fam = FillInRandomQueueFamilyData(env.get_test_icd(0).physical_devices.back().queue_family_properties);
1799    {
1800        InstWrapper instance(env.vulkan_functions);
1801        instance.create_info.set_api_version(VK_API_VERSION_1_1);
1802        instance.CheckCreate();
1803
1804        PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysDevQueueFamilyProps2 =
1805            instance.load("vkGetPhysicalDeviceQueueFamilyProperties2");
1806        ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
1807
1808        uint32_t driver_count = 1;
1809        VkPhysicalDevice physical_device;
1810        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1811        ASSERT_EQ(driver_count, 1U);
1812
1813        uint32_t ret_fam_1 = 0;
1814        std::vector<VkQueueFamilyProperties> props{};
1815        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
1816        ASSERT_EQ(num_fam, ret_fam_1);
1817        props.resize(ret_fam_1);
1818
1819        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
1820
1821        std::vector<VkQueueFamilyProperties2> props2{};
1822        uint32_t ret_fam_2 = 0;
1823        GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
1824        ASSERT_EQ(ret_fam_1, ret_fam_2);
1825        props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
1826        GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
1827        ASSERT_TRUE(CompareQueueFamilyData(props, props2));
1828    }
1829    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
1830        InstWrapper instance(env.vulkan_functions);
1831        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
1832        instance.CheckCreate();
1833        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1834        CreateDebugUtilsMessenger(log);
1835
1836        PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysDevQueueFamilyProps2 =
1837            instance.load("vkGetPhysicalDeviceQueueFamilyProperties2");
1838        ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
1839
1840        uint32_t driver_count = 1;
1841        VkPhysicalDevice physical_device;
1842        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1843        ASSERT_EQ(driver_count, 1U);
1844
1845        uint32_t ret_fam_1 = 0;
1846        std::vector<VkQueueFamilyProperties> props{};
1847        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
1848        ASSERT_EQ(num_fam, ret_fam_1);
1849        props.resize(ret_fam_1);
1850
1851        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
1852
1853        std::vector<VkQueueFamilyProperties2> props2{};
1854        uint32_t ret_fam_2 = 0;
1855        GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
1856        ASSERT_EQ(ret_fam_1, ret_fam_2);
1857        props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
1858        GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
1859        ASSERT_TRUE(CompareQueueFamilyData(props, props2));
1860        ASSERT_TRUE(log.find("Emulating call in ICD"));
1861    }
1862    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1863                                                         .set_name("modify_api_version_layer")
1864                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1865                                                         .set_disable_environment("DisableEnvVar")),
1866                           "modify_api_version_layer.json");
1867    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
1868    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
1869        InstWrapper instance(env.vulkan_functions);
1870        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
1871        instance.CheckCreate();
1872        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1873        CreateDebugUtilsMessenger(log);
1874
1875        PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysDevQueueFamilyProps2 =
1876            instance.load("vkGetPhysicalDeviceQueueFamilyProperties2");
1877        ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
1878
1879        uint32_t driver_count = 1;
1880        VkPhysicalDevice physical_device;
1881        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1882        ASSERT_EQ(driver_count, 1U);
1883
1884        uint32_t ret_fam_1 = 0;
1885        std::vector<VkQueueFamilyProperties> props{};
1886        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
1887        ASSERT_EQ(num_fam, ret_fam_1);
1888        props.resize(ret_fam_1);
1889
1890        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
1891
1892        std::vector<VkQueueFamilyProperties2> props2{};
1893        uint32_t ret_fam_2 = 0;
1894        GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
1895        ASSERT_EQ(ret_fam_1, ret_fam_2);
1896        props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
1897        GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
1898        ASSERT_TRUE(CompareQueueFamilyData(props, props2));
1899        ASSERT_FALSE(log.find("Emulating call in ICD"));
1900    }
1901}
1902
1903// Test vkGetPhysicalDeviceQueueFamilyProperties2 and vkGetPhysicalDeviceQueueFamilyProperties2KHR where ICD is 1.0 and supports
1904// extension but the instance supports 1.1 and the extension
1905TEST(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2KHRInstanceSupports11) {
1906    FrameworkEnvironment env{};
1907    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
1908    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1909    env.get_test_icd(0).physical_devices.push_back({});
1910    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
1911    uint32_t num_fam = FillInRandomQueueFamilyData(env.get_test_icd(0).physical_devices.back().queue_family_properties);
1912
1913    InstWrapper instance(env.vulkan_functions);
1914    instance.create_info.set_api_version(VK_API_VERSION_1_1);
1915    instance.create_info.add_extensions(
1916        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
1917    instance.CheckCreate();
1918    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
1919    CreateDebugUtilsMessenger(log);
1920
1921    PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysDevQueueFamilyProps2 =
1922        instance.load("vkGetPhysicalDeviceQueueFamilyProperties2");
1923    ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
1924
1925    PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR GetPhysDevQueueFamilyProps2KHR =
1926        instance.load("vkGetPhysicalDeviceQueueFamilyProperties2KHR");
1927    ASSERT_NE(GetPhysDevQueueFamilyProps2KHR, nullptr);
1928
1929    uint32_t driver_count = 1;
1930    VkPhysicalDevice physical_device;
1931    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
1932    ASSERT_EQ(driver_count, 1U);
1933
1934    uint32_t ret_fam_1 = 0;
1935    std::vector<VkQueueFamilyProperties> props{};
1936    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
1937    ASSERT_EQ(num_fam, ret_fam_1);
1938    props.resize(ret_fam_1);
1939
1940    instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
1941
1942    std::vector<VkQueueFamilyProperties2> props2{};
1943    uint32_t ret_fam_2 = 0;
1944    GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
1945    ASSERT_EQ(ret_fam_1, ret_fam_2);
1946    props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
1947    GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
1948    ASSERT_TRUE(CompareQueueFamilyData(props, props2));
1949
1950    std::vector<VkQueueFamilyProperties2KHR> props2KHR{};
1951    uint32_t ret_fam_2_khr = 0;
1952    GetPhysDevQueueFamilyProps2KHR(physical_device, &ret_fam_2_khr, nullptr);
1953    ASSERT_EQ(ret_fam_1, ret_fam_2_khr);
1954    props2KHR.resize(ret_fam_2_khr, VkQueueFamilyProperties2KHR{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR});
1955    GetPhysDevQueueFamilyProps2KHR(physical_device, &ret_fam_2_khr, props2KHR.data());
1956    ASSERT_TRUE(CompareQueueFamilyData(props, props2KHR));
1957
1958    ASSERT_FALSE(log.find("Emulating call in ICD"));
1959}
1960
1961// Test vkGetPhysicalDeviceQueueFamilyProperties2 where instance supports it with some ICDs that both support
1962// and don't support it:
1963//    ICD 0 supports
1964//        Physical device 0 does not
1965//        Physical device 1 does
1966//        Physical device 2 does not
1967//    ICD 1 doesn't support
1968//        Physical device 3 does not
1969//    ICD 2 supports
1970//        Physical device 4 does not
1971//        Physical device 5 does not
1972//    ICD 3 supports
1973//        Physical device 6 does
1974TEST(LoaderInstPhysDevExts, PhysDevQueueFamilyPropsMixed) {
1975    FrameworkEnvironment env{};
1976    const uint32_t max_icd_count = 4;
1977    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
1978    const uint32_t max_phys_devs = 7;
1979
1980    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
1981        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
1982        auto& cur_icd = env.get_test_icd(icd);
1983
1984        // ICD 1 should not have 1.1
1985        if (icd != 1) {
1986            cur_icd.icd_api_version = VK_API_VERSION_1_1;
1987            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
1988        }
1989
1990        uint32_t rand_vendor_id;
1991        uint32_t rand_driver_vers;
1992        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
1993
1994        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
1995            uint32_t device_version = VK_API_VERSION_1_0;
1996            cur_icd.physical_devices.push_back({});
1997            auto& cur_dev = cur_icd.physical_devices.back();
1998
1999            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
2000            if ((icd == 0 && dev == 1) || icd == 3) {
2001                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
2002                device_version = VK_API_VERSION_1_1;
2003            }
2004
2005            // Still set physical device properties (so we can determine if device is correct API version)
2006            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
2007            FillInRandomQueueFamilyData(cur_dev.queue_family_properties);
2008        }
2009    }
2010
2011    InstWrapper instance(env.vulkan_functions);
2012    instance.create_info.set_api_version(VK_API_VERSION_1_1);
2013    instance.CheckCreate();
2014
2015    PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysDevQueueFamilyProps2 =
2016        instance.load("vkGetPhysicalDeviceQueueFamilyProperties2");
2017    ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
2018
2019    uint32_t device_count = max_phys_devs;
2020    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
2021    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
2022    ASSERT_EQ(device_count, max_phys_devs);
2023
2024    for (uint32_t dev = 0; dev < device_count; ++dev) {
2025        uint32_t ret_fam_1 = 0;
2026        std::vector<VkQueueFamilyProperties> props{};
2027        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[dev], &ret_fam_1, nullptr);
2028        props.resize(ret_fam_1);
2029        instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[dev], &ret_fam_1, props.data());
2030
2031        std::vector<VkQueueFamilyProperties2> props2{};
2032        uint32_t ret_fam_2 = 0;
2033        GetPhysDevQueueFamilyProps2(physical_devices[dev], &ret_fam_2, nullptr);
2034        ASSERT_EQ(ret_fam_1, ret_fam_2);
2035        props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
2036        GetPhysDevQueueFamilyProps2(physical_devices[dev], &ret_fam_2, props2.data());
2037        ASSERT_TRUE(CompareQueueFamilyData(props, props2));
2038    }
2039}
2040
2041// Test vkGetPhysicalDeviceSparseImageFormatProperties2KHR where nothing supports it.
2042TEST(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2KHRNoSupport) {
2043    FrameworkEnvironment env{};
2044    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2045    env.get_test_icd(0).physical_devices.push_back({});
2046
2047    InstWrapper instance(env.vulkan_functions);
2048    instance.CheckCreate();
2049
2050    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR GetPhysDevSparseImageFormatProps2KHR =
2051        instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
2052    ASSERT_EQ(GetPhysDevSparseImageFormatProps2KHR, nullptr);
2053}
2054
2055// Test vkGetPhysicalDeviceSparseImageFormatProperties2KHR where instance supports it, but nothing else.
2056TEST(LoaderInstPhysDevExts, PhysDevSparseImageFormatPropsKHRNoICDSupport) {
2057    FrameworkEnvironment env{};
2058    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2059    env.get_test_icd(0).physical_devices.push_back({});
2060
2061    InstWrapper instance(env.vulkan_functions);
2062    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
2063    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
2064
2065    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR GetPhysDevSparseImageFormatProps2KHR =
2066        instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
2067    ASSERT_EQ(GetPhysDevSparseImageFormatProps2KHR, nullptr);
2068}
2069
2070// Fill in random but valid data into the sparse image format data struct for the current physical device
2071void FillInRandomSparseImageFormatData(std::vector<VkSparseImageFormatProperties>& props) {
2072    props.resize((rand() % 4) + 1);
2073    for (uint32_t i = 0; i < props.size(); ++i) {
2074        props[i].aspectMask = static_cast<VkImageAspectFlags>((rand() % 0x7FE) + 1);
2075        props[i].imageGranularity = {static_cast<uint32_t>(rand() % 512), static_cast<uint32_t>(rand() % 512),
2076                                     static_cast<uint32_t>(rand() % 512)};
2077        props[i].flags = static_cast<VkSparseImageFormatFlags>((rand() % 6) + 1);
2078    }
2079}
2080
2081// Compare the sparse image format structs
2082bool CompareSparseImageFormatData(const std::vector<VkSparseImageFormatProperties>& props1,
2083                                  const std::vector<VkSparseImageFormatProperties2>& props2) {
2084    if (props1.size() != props2.size()) return false;
2085    bool equal = true;
2086    for (uint32_t i = 0; i < props1.size(); ++i) {
2087        equal = equal && props1[i].aspectMask == props2[i].properties.aspectMask;
2088        equal = equal && props1[i].imageGranularity.width == props2[i].properties.imageGranularity.width;
2089        equal = equal && props1[i].imageGranularity.height == props2[i].properties.imageGranularity.height;
2090        equal = equal && props1[i].imageGranularity.depth == props2[i].properties.imageGranularity.depth;
2091        equal = equal && props1[i].flags == props2[i].properties.flags;
2092    }
2093    return equal;
2094}
2095
2096// Test vkGetPhysicalDeviceSparseImageFormatProperties2KHR where instance and ICD supports it, but device does not support it.
2097TEST(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2KHRInstanceAndICDSupport) {
2098    FrameworkEnvironment env{};
2099    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2100    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
2101    env.get_test_icd(0).physical_devices.push_back({});
2102    FillInRandomSparseImageFormatData(env.get_test_icd(0).physical_devices.back().sparse_image_format_properties);
2103
2104    InstWrapper instance(env.vulkan_functions);
2105    instance.create_info.add_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
2106    instance.CheckCreate();
2107
2108    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR GetPhysDevSparseImageFormatProps2KHR =
2109        instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
2110    ASSERT_NE(GetPhysDevSparseImageFormatProps2KHR, nullptr);
2111
2112    uint32_t driver_count = 1;
2113    VkPhysicalDevice physical_device;
2114    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2115    ASSERT_EQ(driver_count, 1U);
2116
2117    std::vector<VkSparseImageFormatProperties> props{};
2118    uint32_t sparse_count_1 = 0;
2119    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2120                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2121                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
2122    ASSERT_NE(sparse_count_1, 0U);
2123    props.resize(sparse_count_1);
2124    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2125                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2126                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
2127    ASSERT_NE(sparse_count_1, 0U);
2128
2129    VkPhysicalDeviceSparseImageFormatInfo2 info2{
2130        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
2131        nullptr,                                                       // pNext
2132        VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
2133        VK_IMAGE_TYPE_2D,                                              // type
2134        VK_SAMPLE_COUNT_4_BIT,                                         // samples
2135        VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
2136        VK_IMAGE_TILING_OPTIMAL,                                       // tiling
2137    };
2138    std::vector<VkSparseImageFormatProperties2> props2{};
2139    uint32_t sparse_count_2 = 0;
2140    GetPhysDevSparseImageFormatProps2KHR(physical_device, &info2, &sparse_count_2, nullptr);
2141    ASSERT_EQ(sparse_count_1, sparse_count_2);
2142    props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
2143    GetPhysDevSparseImageFormatProps2KHR(physical_device, &info2, &sparse_count_2, props2.data());
2144    ASSERT_EQ(sparse_count_1, sparse_count_2);
2145    ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
2146}
2147
2148// Test vkGetPhysicalDeviceSparseImageFormatProperties2 where instance supports, an ICD, and a device under that ICD
2149// also support, so everything should work and return properly.
2150// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
2151TEST(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2Simple) {
2152    FrameworkEnvironment env{};
2153    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2154    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
2155    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
2156    env.get_test_icd(0).physical_devices.push_back({});
2157    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
2158    FillInRandomSparseImageFormatData(env.get_test_icd(0).physical_devices.back().sparse_image_format_properties);
2159    {
2160        InstWrapper instance(env.vulkan_functions);
2161        instance.create_info.set_api_version(VK_API_VERSION_1_1);
2162        instance.CheckCreate();
2163
2164        PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysDevSparseImageFormatProps2 =
2165            instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2");
2166        ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
2167
2168        uint32_t driver_count = 1;
2169        VkPhysicalDevice physical_device;
2170        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2171        ASSERT_EQ(driver_count, 1U);
2172
2173        std::vector<VkSparseImageFormatProperties> props{};
2174        uint32_t sparse_count_1 = 0;
2175        instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2176                                                                 VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2177                                                                 VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
2178        ASSERT_NE(sparse_count_1, 0U);
2179        props.resize(sparse_count_1);
2180        instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2181                                                                 VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2182                                                                 VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
2183        ASSERT_NE(sparse_count_1, 0U);
2184
2185        VkPhysicalDeviceSparseImageFormatInfo2 info2{
2186            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
2187            nullptr,                                                       // pNext
2188            VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
2189            VK_IMAGE_TYPE_2D,                                              // type
2190            VK_SAMPLE_COUNT_4_BIT,                                         // samples
2191            VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
2192            VK_IMAGE_TILING_OPTIMAL,                                       // tiling
2193        };
2194        std::vector<VkSparseImageFormatProperties2> props2{};
2195        uint32_t sparse_count_2 = 0;
2196        GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
2197        ASSERT_EQ(sparse_count_1, sparse_count_2);
2198        props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
2199        GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
2200        ASSERT_EQ(sparse_count_1, sparse_count_2);
2201        ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
2202    }
2203    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
2204        InstWrapper instance(env.vulkan_functions);
2205        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
2206        instance.CheckCreate();
2207        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
2208        CreateDebugUtilsMessenger(log);
2209
2210        PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysDevSparseImageFormatProps2 =
2211            instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2");
2212        ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
2213
2214        uint32_t driver_count = 1;
2215        VkPhysicalDevice physical_device;
2216        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2217        ASSERT_EQ(driver_count, 1U);
2218
2219        std::vector<VkSparseImageFormatProperties> props{};
2220        uint32_t sparse_count_1 = 0;
2221        instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2222                                                                 VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2223                                                                 VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
2224        ASSERT_NE(sparse_count_1, 0U);
2225        props.resize(sparse_count_1);
2226        instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2227                                                                 VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2228                                                                 VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
2229        ASSERT_NE(sparse_count_1, 0U);
2230
2231        VkPhysicalDeviceSparseImageFormatInfo2 info2{
2232            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
2233            nullptr,                                                       // pNext
2234            VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
2235            VK_IMAGE_TYPE_2D,                                              // type
2236            VK_SAMPLE_COUNT_4_BIT,                                         // samples
2237            VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
2238            VK_IMAGE_TILING_OPTIMAL,                                       // tiling
2239        };
2240        std::vector<VkSparseImageFormatProperties2> props2{};
2241        uint32_t sparse_count_2 = 0;
2242        GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
2243        ASSERT_EQ(sparse_count_1, sparse_count_2);
2244        props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
2245        GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
2246        ASSERT_EQ(sparse_count_1, sparse_count_2);
2247        ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
2248        ASSERT_TRUE(log.find("Emulating call in ICD"));
2249    }
2250    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
2251                                                         .set_name("modify_api_version_layer")
2252                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
2253                                                         .set_disable_environment("DisableEnvVar")),
2254                           "modify_api_version_layer.json");
2255    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
2256    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
2257        InstWrapper instance(env.vulkan_functions);
2258        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
2259        instance.CheckCreate();
2260        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
2261        CreateDebugUtilsMessenger(log);
2262
2263        PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysDevSparseImageFormatProps2 =
2264            instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2");
2265        ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
2266
2267        uint32_t driver_count = 1;
2268        VkPhysicalDevice physical_device;
2269        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2270        ASSERT_EQ(driver_count, 1U);
2271
2272        std::vector<VkSparseImageFormatProperties> props{};
2273        uint32_t sparse_count_1 = 0;
2274        instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2275                                                                 VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2276                                                                 VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
2277        ASSERT_NE(sparse_count_1, 0U);
2278        props.resize(sparse_count_1);
2279        instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2280                                                                 VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2281                                                                 VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
2282        ASSERT_NE(sparse_count_1, 0U);
2283
2284        VkPhysicalDeviceSparseImageFormatInfo2 info2{
2285            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
2286            nullptr,                                                       // pNext
2287            VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
2288            VK_IMAGE_TYPE_2D,                                              // type
2289            VK_SAMPLE_COUNT_4_BIT,                                         // samples
2290            VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
2291            VK_IMAGE_TILING_OPTIMAL,                                       // tiling
2292        };
2293        std::vector<VkSparseImageFormatProperties2> props2{};
2294        uint32_t sparse_count_2 = 0;
2295        GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
2296        ASSERT_EQ(sparse_count_1, sparse_count_2);
2297        props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
2298        GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
2299        ASSERT_EQ(sparse_count_1, sparse_count_2);
2300        ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
2301        ASSERT_FALSE(log.find("Emulating call in ICD"));
2302    }
2303}
2304
2305// Test vkGetPhysicalDeviceSparseImageFormatProperties2 and vkGetPhysicalDeviceSparseImageFormatProperties2KHR where ICD is 1.0 and
2306// supports extension but the instance supports 1.1 and the extension
2307TEST(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2KHRInstanceSupports11) {
2308    FrameworkEnvironment env{};
2309    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2310    env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
2311    env.get_test_icd(0).physical_devices.push_back({});
2312    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
2313    FillInRandomSparseImageFormatData(env.get_test_icd(0).physical_devices.back().sparse_image_format_properties);
2314
2315    InstWrapper instance(env.vulkan_functions);
2316    instance.create_info.set_api_version(VK_API_VERSION_1_1);
2317    instance.create_info.add_extensions(
2318        {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
2319    instance.CheckCreate();
2320    DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
2321    CreateDebugUtilsMessenger(log);
2322
2323    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysDevSparseImageFormatProps2 =
2324        instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2");
2325    ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
2326
2327    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR GetPhysDevSparseImageFormatProps2KHR =
2328        instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
2329    ASSERT_NE(GetPhysDevSparseImageFormatProps2KHR, nullptr);
2330
2331    uint32_t driver_count = 1;
2332    VkPhysicalDevice physical_device;
2333    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2334    ASSERT_EQ(driver_count, 1U);
2335
2336    std::vector<VkSparseImageFormatProperties> props{};
2337    uint32_t sparse_count_1 = 0;
2338    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2339                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2340                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
2341    ASSERT_NE(sparse_count_1, 0U);
2342    props.resize(sparse_count_1);
2343    instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
2344                                                             VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2345                                                             VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
2346    ASSERT_NE(sparse_count_1, 0U);
2347
2348    VkPhysicalDeviceSparseImageFormatInfo2 info2{
2349        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
2350        nullptr,                                                       // pNext
2351        VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
2352        VK_IMAGE_TYPE_2D,                                              // type
2353        VK_SAMPLE_COUNT_4_BIT,                                         // samples
2354        VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
2355        VK_IMAGE_TILING_OPTIMAL,                                       // tiling
2356    };
2357    std::vector<VkSparseImageFormatProperties2> props2{};
2358    uint32_t sparse_count_2 = 0;
2359    GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
2360    ASSERT_EQ(sparse_count_1, sparse_count_2);
2361    props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
2362    GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
2363    ASSERT_EQ(sparse_count_1, sparse_count_2);
2364    ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
2365
2366    std::vector<VkSparseImageFormatProperties2KHR> props2KHR{};
2367    uint32_t sparse_count_2_khr = 0;
2368    GetPhysDevSparseImageFormatProps2KHR(physical_device, &info2, &sparse_count_2_khr, nullptr);
2369    ASSERT_EQ(sparse_count_1, sparse_count_2_khr);
2370    props2KHR.resize(sparse_count_2, VkSparseImageFormatProperties2KHR{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR});
2371    GetPhysDevSparseImageFormatProps2KHR(physical_device, &info2, &sparse_count_2_khr, props2KHR.data());
2372    ASSERT_EQ(sparse_count_1, sparse_count_2_khr);
2373    ASSERT_TRUE(CompareSparseImageFormatData(props, props2KHR));
2374
2375    ASSERT_FALSE(log.find("Emulating call in ICD"));
2376}
2377
2378// Test vkGetPhysicalDeviceSparseImageFormatProperties2 where instance supports it with some ICDs that both support
2379// and don't support it:
2380//    ICD 0 supports
2381//        Physical device 0 does not
2382//        Physical device 1 does
2383//        Physical device 2 does not
2384//    ICD 1 doesn't support
2385//        Physical device 3 does not
2386//    ICD 2 supports
2387//        Physical device 4 does not
2388//        Physical device 5 does not
2389//    ICD 3 supports
2390//        Physical device 6 does
2391TEST(LoaderInstPhysDevExts, PhysDevSparseImageFormatPropsMixed) {
2392    FrameworkEnvironment env{};
2393    const uint32_t max_icd_count = 4;
2394    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
2395    const uint32_t max_phys_devs = 7;
2396
2397    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
2398        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
2399        auto& cur_icd = env.get_test_icd(icd);
2400
2401        // ICD 1 should not have 1.1
2402        if (icd != 1) {
2403            cur_icd.icd_api_version = VK_API_VERSION_1_1;
2404            cur_icd.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
2405        }
2406
2407        uint32_t rand_vendor_id;
2408        uint32_t rand_driver_vers;
2409        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
2410
2411        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
2412            uint32_t device_version = VK_API_VERSION_1_0;
2413            cur_icd.physical_devices.push_back({});
2414            auto& cur_dev = cur_icd.physical_devices.back();
2415
2416            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
2417            if ((icd == 0 && dev == 1) || icd == 3) {
2418                cur_dev.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
2419                device_version = VK_API_VERSION_1_1;
2420            }
2421
2422            // Still set physical device properties (so we can determine if device is correct API version)
2423            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
2424            FillInRandomSparseImageFormatData(cur_dev.sparse_image_format_properties);
2425        }
2426    }
2427
2428    InstWrapper instance(env.vulkan_functions);
2429    instance.create_info.set_api_version(VK_API_VERSION_1_1);
2430    instance.CheckCreate();
2431
2432    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysDevSparseImageFormatProps2 =
2433        instance.load("vkGetPhysicalDeviceSparseImageFormatProperties2");
2434    ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
2435
2436    uint32_t device_count = max_phys_devs;
2437    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
2438    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
2439    ASSERT_EQ(device_count, max_phys_devs);
2440
2441    for (uint32_t dev = 0; dev < device_count; ++dev) {
2442        std::vector<VkSparseImageFormatProperties> props{};
2443        uint32_t sparse_count_1 = 0;
2444        instance->vkGetPhysicalDeviceSparseImageFormatProperties(
2445            physical_devices[dev], VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D, VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2446            VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
2447        ASSERT_NE(sparse_count_1, 0U);
2448        props.resize(sparse_count_1);
2449        instance->vkGetPhysicalDeviceSparseImageFormatProperties(
2450            physical_devices[dev], VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D, VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
2451            VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
2452        ASSERT_NE(sparse_count_1, 0U);
2453
2454        VkPhysicalDeviceSparseImageFormatInfo2 info2{
2455            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,  // sType
2456            nullptr,                                                       // pNext
2457            VK_FORMAT_R4G4_UNORM_PACK8,                                    // format
2458            VK_IMAGE_TYPE_2D,                                              // type
2459            VK_SAMPLE_COUNT_4_BIT,                                         // samples
2460            VK_IMAGE_USAGE_STORAGE_BIT,                                    // usage
2461            VK_IMAGE_TILING_OPTIMAL,                                       // tiling
2462        };
2463        std::vector<VkSparseImageFormatProperties2> props2{};
2464        uint32_t sparse_count_2 = 0;
2465        GetPhysDevSparseImageFormatProps2(physical_devices[dev], &info2, &sparse_count_2, nullptr);
2466        ASSERT_EQ(sparse_count_1, sparse_count_2);
2467        props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
2468        GetPhysDevSparseImageFormatProps2(physical_devices[dev], &info2, &sparse_count_2, props2.data());
2469        ASSERT_EQ(sparse_count_1, sparse_count_2);
2470        ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
2471    }
2472}
2473
2474//
2475// VK_KHR_external_memory_capabilities
2476//
2477
2478// Test vkGetPhysicalDeviceExternalBufferPropertiesKHR where nothing supports it.
2479TEST(LoaderInstPhysDevExts, PhysDevExtBufPropsKHRNoSupport) {
2480    FrameworkEnvironment env{};
2481    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2482    env.get_test_icd(0).physical_devices.push_back({});
2483
2484    InstWrapper instance(env.vulkan_functions);
2485    instance.CheckCreate();
2486
2487    PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR GetPhysicalDeviceExternalBufferPropertiesKHR =
2488        instance.load("vkGetPhysicalDeviceExternalBufferPropertiesKHR");
2489    ASSERT_EQ(GetPhysicalDeviceExternalBufferPropertiesKHR, nullptr);
2490}
2491
2492// Test vkGetPhysicalDeviceExternalBufferPropertiesKHR where instance supports it, but nothing else.
2493TEST(LoaderInstPhysDevExts, PhysDevExtBufPropsKHRNoICDSupport) {
2494    FrameworkEnvironment env{};
2495    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2496    env.get_test_icd(0).physical_devices.push_back({});
2497
2498    InstWrapper instance(env.vulkan_functions);
2499    instance.create_info.add_extension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
2500    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
2501
2502    PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR GetPhysicalDeviceExternalBufferPropertiesKHR =
2503        instance.load("vkGetPhysicalDeviceExternalBufferPropertiesKHR");
2504    ASSERT_EQ(GetPhysicalDeviceExternalBufferPropertiesKHR, nullptr);
2505}
2506
2507// Fill in random but valid data into the external memorydata struct for the current physical device
2508void FillInRandomExtMemoryData(VkExternalMemoryProperties& props) {
2509    props.externalMemoryFeatures = static_cast<VkExternalMemoryFeatureFlags>((rand() % 6) + 1);
2510    props.exportFromImportedHandleTypes = static_cast<VkExternalMemoryHandleTypeFlags>((rand() % 0x1FFE) + 1);
2511    props.compatibleHandleTypes = static_cast<VkExternalMemoryHandleTypeFlags>((rand() % 0x1FFE) + 1);
2512}
2513
2514// Compare the external memory data structs
2515bool CompareExtMemoryData(const VkExternalMemoryProperties& props1, const VkExternalMemoryProperties& props2,
2516                          bool supported = true) {
2517    bool equal = true;
2518    if (supported) {
2519        equal = equal && props1.externalMemoryFeatures == props2.externalMemoryFeatures;
2520        equal = equal && props1.exportFromImportedHandleTypes == props2.exportFromImportedHandleTypes;
2521        equal = equal && props1.compatibleHandleTypes == props2.compatibleHandleTypes;
2522    } else {
2523        equal = equal && 0 == props2.externalMemoryFeatures;
2524        equal = equal && 0 == props2.exportFromImportedHandleTypes;
2525        equal = equal && 0 == props2.compatibleHandleTypes;
2526    }
2527    return equal;
2528}
2529
2530// Test vkGetPhysicalDeviceExternalBufferPropertiesKHR where instance and ICD supports it, but device does not support it.
2531TEST(LoaderInstPhysDevExts, PhysDevExtBufProps2KHRInstanceAndICDSupport) {
2532    FrameworkEnvironment env{};
2533    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2534    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME});
2535    env.get_test_icd(0).physical_devices.push_back({});
2536    FillInRandomExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties);
2537
2538    InstWrapper instance(env.vulkan_functions);
2539    instance.create_info.add_extension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
2540    instance.CheckCreate();
2541
2542    PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR GetPhysicalDeviceExternalBufferPropertiesKHR =
2543        instance.load("vkGetPhysicalDeviceExternalBufferPropertiesKHR");
2544    ASSERT_NE(GetPhysicalDeviceExternalBufferPropertiesKHR, nullptr);
2545
2546    uint32_t driver_count = 1;
2547    VkPhysicalDevice physical_device;
2548    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2549    ASSERT_EQ(driver_count, 1U);
2550
2551    VkPhysicalDeviceExternalBufferInfoKHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR};
2552    VkExternalBufferPropertiesKHR props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR};
2553    GetPhysicalDeviceExternalBufferPropertiesKHR(physical_device, &info, &props);
2554    ASSERT_TRUE(CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties,
2555                                     props.externalMemoryProperties));
2556}
2557
2558// Test vkGetPhysicalDeviceExternalBufferProperties where instance supports, an ICD, and a device under that ICD
2559// also support, so everything should work and return properly.
2560// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
2561TEST(LoaderInstPhysDevExts, PhysDevExtBufProps2Simple) {
2562    FrameworkEnvironment env{};
2563    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2564    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
2565    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME});
2566    env.get_test_icd(0).physical_devices.push_back({});
2567    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 0});
2568    FillInRandomExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties);
2569    {
2570        InstWrapper instance(env.vulkan_functions);
2571        instance.create_info.set_api_version(VK_API_VERSION_1_1);
2572        instance.CheckCreate();
2573
2574        PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties =
2575            instance.load("vkGetPhysicalDeviceExternalBufferProperties");
2576        ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
2577
2578        uint32_t driver_count = 1;
2579        VkPhysicalDevice physical_device;
2580        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2581        ASSERT_EQ(driver_count, 1U);
2582
2583        VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
2584        VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
2585        GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
2586        ASSERT_TRUE(CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties,
2587                                         props.externalMemoryProperties));
2588    }
2589    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
2590        InstWrapper instance(env.vulkan_functions);
2591        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
2592        instance.CheckCreate();
2593        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
2594        CreateDebugUtilsMessenger(log);
2595
2596        PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties =
2597            instance.load("vkGetPhysicalDeviceExternalBufferProperties");
2598        ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
2599
2600        uint32_t driver_count = 1;
2601        VkPhysicalDevice physical_device;
2602        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2603        ASSERT_EQ(driver_count, 1U);
2604
2605        VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
2606        VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
2607        GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
2608        // Compare against 'zeroed' out VkExternalMemoryProperties
2609        ASSERT_TRUE(CompareExtMemoryData(VkExternalMemoryProperties{}, props.externalMemoryProperties));
2610        ASSERT_TRUE(log.find("Emulating call in ICD"));
2611    }
2612    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
2613                                                         .set_name("modify_api_version_layer")
2614                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
2615                                                         .set_disable_environment("DisableEnvVar")),
2616                           "modify_api_version_layer.json");
2617    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
2618    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
2619        InstWrapper instance(env.vulkan_functions);
2620        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
2621        instance.CheckCreate();
2622        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
2623        CreateDebugUtilsMessenger(log);
2624
2625        PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties =
2626            instance.load("vkGetPhysicalDeviceExternalBufferProperties");
2627        ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
2628
2629        uint32_t driver_count = 1;
2630        VkPhysicalDevice physical_device;
2631        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2632        ASSERT_EQ(driver_count, 1U);
2633
2634        VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
2635        VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
2636        GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
2637        ASSERT_TRUE(CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties,
2638                                         props.externalMemoryProperties));
2639        ASSERT_FALSE(log.find("Emulating call in ICD"));
2640    }
2641}
2642
2643// Test vkGetPhysicalDeviceExternalBufferProperties where instance supports it with some ICDs that both support
2644// and don't support it:
2645//    ICD 0 supports
2646//        Physical device 0 does not
2647//        Physical device 1 does
2648//        Physical device 2 does not
2649//    ICD 1 doesn't support
2650//        Physical device 3 does not
2651//    ICD 2 supports
2652//        Physical device 4 does not
2653//        Physical device 5 does not
2654//    ICD 3 supports
2655//        Physical device 6 does
2656TEST(LoaderInstPhysDevExts, PhysDevExtBufPropsMixed) {
2657    FrameworkEnvironment env{};
2658    const uint32_t max_icd_count = 4;
2659    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
2660    const uint32_t max_phys_devs = 7;
2661
2662    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
2663        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
2664        auto& cur_icd = env.get_test_icd(icd);
2665
2666        // ICD 1 should not have 1.1
2667        if (icd != 1) {
2668            cur_icd.icd_api_version = VK_API_VERSION_1_1;
2669            cur_icd.add_instance_extension({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME});
2670        }
2671
2672        uint32_t rand_vendor_id;
2673        uint32_t rand_driver_vers;
2674        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
2675
2676        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
2677            uint32_t device_version = VK_API_VERSION_1_0;
2678            cur_icd.physical_devices.push_back({});
2679            auto& cur_dev = cur_icd.physical_devices.back();
2680
2681            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
2682            if ((icd == 0 && dev == 1) || icd == 3) {
2683                cur_dev.extensions.push_back({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 0});
2684                device_version = VK_API_VERSION_1_1;
2685            }
2686
2687            // Still set physical device properties (so we can determine if device is correct API version)
2688            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
2689            FillInRandomExtMemoryData(cur_dev.external_memory_properties);
2690        }
2691    }
2692
2693    InstWrapper instance(env.vulkan_functions);
2694    instance.create_info.set_api_version(VK_API_VERSION_1_1);
2695    instance.CheckCreate();
2696
2697    PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties =
2698        instance.load("vkGetPhysicalDeviceExternalBufferProperties");
2699    ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
2700
2701    uint32_t device_count = max_phys_devs;
2702    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
2703    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
2704    ASSERT_EQ(device_count, max_phys_devs);
2705
2706    for (uint32_t dev = 0; dev < device_count; ++dev) {
2707        VkPhysicalDeviceProperties pd_props{};
2708        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
2709
2710        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
2711            auto& cur_icd = env.get_test_icd(icd);
2712            bool found = false;
2713            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
2714                auto& cur_dev = cur_icd.physical_devices[pd];
2715                // Find the ICD device matching the physical device we're looking at info for so we can compare the
2716                // physical devices info with the returned info.
2717                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
2718                    cur_dev.properties.deviceType == pd_props.deviceType &&
2719                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
2720                    cur_dev.properties.vendorID == pd_props.vendorID) {
2721                    VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
2722                    VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
2723                    GetPhysicalDeviceExternalBufferProperties(physical_devices[dev], &info, &props);
2724                    // No driver support for extension or 1.1 for ICD 1, all others support
2725                    ASSERT_TRUE(CompareExtMemoryData(cur_dev.external_memory_properties, props.externalMemoryProperties, icd != 1));
2726                    found = true;
2727                    break;
2728                }
2729            }
2730            if (found) {
2731                break;
2732            }
2733        }
2734    }
2735}
2736
2737//
2738// VK_KHR_external_semaphore_capabilities
2739//
2740
2741// Test vkGetPhysicalDeviceExternalSemaphorePropertiesKHR where nothing supports it.
2742TEST(LoaderInstPhysDevExts, PhysDevExtSemPropsKHRNoSupport) {
2743    FrameworkEnvironment env{};
2744    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2745    env.get_test_icd(0).physical_devices.push_back({});
2746
2747    InstWrapper instance(env.vulkan_functions);
2748    instance.CheckCreate();
2749
2750    PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR GetPhysicalDeviceExternalSemaphorePropertiesKHR =
2751        instance.load("vkGetPhysicalDeviceExternalSemaphorePropertiesKHR");
2752    ASSERT_EQ(GetPhysicalDeviceExternalSemaphorePropertiesKHR, nullptr);
2753}
2754
2755// Test vkGetPhysicalDeviceExternalSemaphorePropertiesKHR where instance supports it, but nothing else.
2756TEST(LoaderInstPhysDevExts, PhysDevExtSemPropsKHRNoICDSupport) {
2757    FrameworkEnvironment env{};
2758    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2759    env.get_test_icd(0).physical_devices.push_back({});
2760
2761    InstWrapper instance(env.vulkan_functions);
2762    instance.create_info.add_extension(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME);
2763    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
2764
2765    PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR GetPhysicalDeviceExternalSemaphorePropertiesKHR =
2766        instance.load("vkGetPhysicalDeviceExternalSemaphorePropertiesKHR");
2767    ASSERT_EQ(GetPhysicalDeviceExternalSemaphorePropertiesKHR, nullptr);
2768}
2769
2770// Fill in random but valid data into the external semaphore data struct for the current physical device
2771void FillInRandomExtSemData(VkExternalSemaphoreProperties& props) {
2772    props.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES;
2773    props.pNext = nullptr;
2774    props.exportFromImportedHandleTypes = static_cast<VkExternalSemaphoreHandleTypeFlags>((rand() % 0xFFF) + 1);
2775    props.compatibleHandleTypes = static_cast<VkExternalSemaphoreHandleTypeFlags>((rand() % 0xFFF) + 1);
2776    props.externalSemaphoreFeatures = static_cast<VkExternalSemaphoreFeatureFlags>((rand() % 0xFFF) + 1);
2777}
2778
2779// Compare the external semaphore data structs
2780bool CompareExtSemaphoreData(const VkExternalSemaphoreProperties& props1, const VkExternalSemaphoreProperties& props2,
2781                             bool supported = true) {
2782    bool equal = true;
2783    if (supported) {
2784        equal = equal && props1.externalSemaphoreFeatures == props2.externalSemaphoreFeatures;
2785        equal = equal && props1.exportFromImportedHandleTypes == props2.exportFromImportedHandleTypes;
2786        equal = equal && props1.compatibleHandleTypes == props2.compatibleHandleTypes;
2787    } else {
2788        equal = equal && 0 == props2.externalSemaphoreFeatures;
2789        equal = equal && 0 == props2.exportFromImportedHandleTypes;
2790        equal = equal && 0 == props2.compatibleHandleTypes;
2791    }
2792    return equal;
2793}
2794
2795// Test vkGetPhysicalDeviceExternalSemaphorePropertiesKHR where instance and ICD supports it, but device does not support it.
2796TEST(LoaderInstPhysDevExts, PhysDevExtSemProps2KHRInstanceAndICDSupport) {
2797    FrameworkEnvironment env{};
2798    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2799    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME});
2800    env.get_test_icd(0).physical_devices.push_back({});
2801    FillInRandomExtSemData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties);
2802
2803    InstWrapper instance(env.vulkan_functions);
2804    instance.create_info.add_extension(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME);
2805    instance.CheckCreate();
2806
2807    PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR GetPhysicalDeviceExternalSemaphorePropertiesKHR =
2808        instance.load("vkGetPhysicalDeviceExternalSemaphorePropertiesKHR");
2809    ASSERT_NE(GetPhysicalDeviceExternalSemaphorePropertiesKHR, nullptr);
2810
2811    uint32_t driver_count = 1;
2812    VkPhysicalDevice physical_device;
2813    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2814    ASSERT_EQ(driver_count, 1U);
2815
2816    VkPhysicalDeviceExternalSemaphoreInfoKHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR};
2817    VkExternalSemaphorePropertiesKHR props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR};
2818    GetPhysicalDeviceExternalSemaphorePropertiesKHR(physical_device, &info, &props);
2819    ASSERT_TRUE(CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props));
2820}
2821
2822// Test vkGetPhysicalDeviceExternalSemaphoreProperties where instance supports, an ICD, and a device under that ICD
2823// also support, so everything should work and return properly.
2824// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
2825TEST(LoaderInstPhysDevExts, PhysDevExtSemProps2Simple) {
2826    FrameworkEnvironment env{};
2827    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
2828    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
2829    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME});
2830    env.get_test_icd(0).physical_devices.push_back({});
2831    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, 0});
2832    FillInRandomExtSemData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties);
2833    {
2834        InstWrapper instance(env.vulkan_functions);
2835        instance.create_info.set_api_version(VK_API_VERSION_1_1);
2836        instance.CheckCreate();
2837
2838        PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties =
2839            instance.load("vkGetPhysicalDeviceExternalSemaphoreProperties");
2840        ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
2841
2842        uint32_t driver_count = 1;
2843        VkPhysicalDevice physical_device;
2844        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2845        ASSERT_EQ(driver_count, 1U);
2846
2847        VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
2848        VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
2849        GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
2850        ASSERT_TRUE(CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props));
2851    }
2852    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
2853        InstWrapper instance(env.vulkan_functions);
2854        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
2855        instance.CheckCreate();
2856        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
2857        CreateDebugUtilsMessenger(log);
2858        PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties =
2859            instance.load("vkGetPhysicalDeviceExternalSemaphoreProperties");
2860        ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
2861
2862        uint32_t driver_count = 1;
2863        VkPhysicalDevice physical_device;
2864        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2865        ASSERT_EQ(driver_count, 1U);
2866
2867        VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
2868        VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
2869        GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
2870        // Compare against 'zeroed' out VkExternalSemaphoreProperties
2871        ASSERT_TRUE(CompareExtSemaphoreData(VkExternalSemaphoreProperties{}, props));
2872        ASSERT_TRUE(log.find("Emulating call in ICD"));
2873    }
2874    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
2875                                                         .set_name("modify_api_version_layer")
2876                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
2877                                                         .set_disable_environment("DisableEnvVar")),
2878                           "modify_api_version_layer.json");
2879    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
2880    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
2881        InstWrapper instance(env.vulkan_functions);
2882        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
2883        instance.CheckCreate();
2884        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
2885        CreateDebugUtilsMessenger(log);
2886        PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties =
2887            instance.load("vkGetPhysicalDeviceExternalSemaphoreProperties");
2888        ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
2889
2890        uint32_t driver_count = 1;
2891        VkPhysicalDevice physical_device;
2892        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
2893        ASSERT_EQ(driver_count, 1U);
2894
2895        VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
2896        VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
2897        GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
2898        ASSERT_TRUE(CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props));
2899        ASSERT_FALSE(log.find("Emulating call in ICD"));
2900    }
2901}
2902
2903// Test vkGetPhysicalDeviceExternalSemaphoreProperties where instance supports it with some ICDs that both support
2904// and don't support it:
2905//    ICD 0 supports
2906//        Physical device 0 does not
2907//        Physical device 1 does
2908//        Physical device 2 does not
2909//    ICD 1 doesn't support
2910//        Physical device 3 does not
2911//    ICD 2 supports
2912//        Physical device 4 does not
2913//        Physical device 5 does not
2914//    ICD 3 supports
2915//        Physical device 6 does
2916TEST(LoaderInstPhysDevExts, PhysDevExtSemPropsMixed) {
2917    FrameworkEnvironment env{};
2918    const uint32_t max_icd_count = 4;
2919    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
2920    const uint32_t max_phys_devs = 7;
2921
2922    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
2923        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
2924        auto& cur_icd = env.get_test_icd(icd);
2925
2926        // ICD 1 should not have 1.1
2927        if (icd != 1) {
2928            cur_icd.icd_api_version = VK_API_VERSION_1_1;
2929            cur_icd.add_instance_extension({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME});
2930        }
2931
2932        uint32_t rand_vendor_id;
2933        uint32_t rand_driver_vers;
2934        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
2935
2936        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
2937            uint32_t device_version = VK_API_VERSION_1_0;
2938            cur_icd.physical_devices.push_back({});
2939            auto& cur_dev = cur_icd.physical_devices.back();
2940
2941            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
2942            if ((icd == 0 && dev == 1) || icd == 3) {
2943                cur_dev.extensions.push_back({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, 0});
2944                device_version = VK_API_VERSION_1_1;
2945            }
2946
2947            // Still set physical device properties (so we can determine if device is correct API version)
2948            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
2949            FillInRandomExtSemData(cur_dev.external_semaphore_properties);
2950        }
2951    }
2952
2953    InstWrapper instance(env.vulkan_functions);
2954    instance.create_info.set_api_version(VK_API_VERSION_1_1);
2955    instance.CheckCreate();
2956
2957    PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties =
2958        instance.load("vkGetPhysicalDeviceExternalSemaphoreProperties");
2959    ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
2960
2961    uint32_t device_count = max_phys_devs;
2962    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
2963    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
2964    ASSERT_EQ(device_count, max_phys_devs);
2965
2966    for (uint32_t dev = 0; dev < device_count; ++dev) {
2967        VkPhysicalDeviceProperties pd_props{};
2968        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
2969
2970        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
2971            auto& cur_icd = env.get_test_icd(icd);
2972            bool found = false;
2973            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
2974                auto& cur_dev = cur_icd.physical_devices[pd];
2975                // Find the ICD device matching the physical device we're looking at info for so we can compare the
2976                // physical devices info with the returned info.
2977                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
2978                    cur_dev.properties.deviceType == pd_props.deviceType &&
2979                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
2980                    cur_dev.properties.vendorID == pd_props.vendorID) {
2981                    VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
2982                    VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
2983                    GetPhysicalDeviceExternalSemaphoreProperties(physical_devices[dev], &info, &props);
2984                    // No driver support for extension or 1.1 for ICD 1, all others support
2985                    ASSERT_TRUE(CompareExtSemaphoreData(cur_dev.external_semaphore_properties, props, icd != 1));
2986                    found = true;
2987                    break;
2988                }
2989            }
2990            if (found) {
2991                break;
2992            }
2993        }
2994    }
2995}
2996
2997//
2998// VK_KHR_external_fence_capabilities
2999//
3000
3001// Test vkGetPhysicalDeviceExternalFencePropertiesKHR where nothing supports it.
3002TEST(LoaderInstPhysDevExts, PhysDevExtFencePropsKHRNoSupport) {
3003    FrameworkEnvironment env{};
3004    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3005    env.get_test_icd(0).physical_devices.push_back({});
3006
3007    InstWrapper instance(env.vulkan_functions);
3008    instance.CheckCreate();
3009
3010    PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR GetPhysicalDeviceExternalFencePropertiesKHR =
3011        instance.load("vkGetPhysicalDeviceExternalFencePropertiesKHR");
3012    ASSERT_EQ(GetPhysicalDeviceExternalFencePropertiesKHR, nullptr);
3013}
3014
3015// Test vkGetPhysicalDeviceExternalFencePropertiesKHR where instance supports it, but nothing else.
3016TEST(LoaderInstPhysDevExts, PhysDevExtFencePropsKHRNoICDSupport) {
3017    FrameworkEnvironment env{};
3018    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3019    env.get_test_icd(0).physical_devices.push_back({});
3020
3021    InstWrapper instance(env.vulkan_functions);
3022    instance.create_info.add_extension(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME);
3023    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
3024
3025    PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR GetPhysicalDeviceExternalFencePropertiesKHR =
3026        instance.load("vkGetPhysicalDeviceExternalFencePropertiesKHR");
3027    ASSERT_EQ(GetPhysicalDeviceExternalFencePropertiesKHR, nullptr);
3028}
3029
3030// Fill in random but valid data into the external fence data struct for the current physical device
3031void FillInRandomExtFenceData(VkExternalFenceProperties& props) {
3032    props.sType = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES;
3033    props.pNext = nullptr;
3034    props.exportFromImportedHandleTypes = static_cast<VkExternalFenceHandleTypeFlags>((rand() % 0xFFF) + 1);
3035    props.compatibleHandleTypes = static_cast<VkExternalFenceHandleTypeFlags>((rand() % 0xFFF) + 1);
3036    props.externalFenceFeatures = static_cast<VkExternalFenceFeatureFlags>((rand() % 0xFFF) + 1);
3037}
3038
3039// Compare the external fence data structs
3040bool CompareExtFenceData(const VkExternalFenceProperties& props1, const VkExternalFenceProperties& props2, bool supported = true) {
3041    bool equal = true;
3042    if (supported) {
3043        equal = equal && props1.externalFenceFeatures == props2.externalFenceFeatures;
3044        equal = equal && props1.exportFromImportedHandleTypes == props2.exportFromImportedHandleTypes;
3045        equal = equal && props1.compatibleHandleTypes == props2.compatibleHandleTypes;
3046    } else {
3047        equal = equal && 0 == props2.externalFenceFeatures;
3048        equal = equal && 0 == props2.exportFromImportedHandleTypes;
3049        equal = equal && 0 == props2.compatibleHandleTypes;
3050    }
3051    return equal;
3052}
3053
3054// Test vkGetPhysicalDeviceExternalFencePropertiesKHR where instance and ICD supports it, but device does not support it.
3055TEST(LoaderInstPhysDevExts, PhysDevExtFenceProps2KHRInstanceAndICDSupport) {
3056    FrameworkEnvironment env{};
3057    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3058    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
3059    env.get_test_icd(0).physical_devices.push_back({});
3060    FillInRandomExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties);
3061
3062    InstWrapper instance(env.vulkan_functions);
3063    instance.create_info.add_extension(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME);
3064    instance.CheckCreate();
3065
3066    PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR GetPhysicalDeviceExternalFencePropertiesKHR =
3067        instance.load("vkGetPhysicalDeviceExternalFencePropertiesKHR");
3068    ASSERT_NE(GetPhysicalDeviceExternalFencePropertiesKHR, nullptr);
3069
3070    uint32_t driver_count = 1;
3071    VkPhysicalDevice physical_device;
3072    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3073    ASSERT_EQ(driver_count, 1U);
3074
3075    VkPhysicalDeviceExternalFenceInfoKHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR};
3076    VkExternalFencePropertiesKHR props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR};
3077    GetPhysicalDeviceExternalFencePropertiesKHR(physical_device, &info, &props);
3078    ASSERT_TRUE(CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props));
3079}
3080
3081// Test vkGetPhysicalDeviceExternalFenceProperties where instance supports, an ICD, and a device under that ICD
3082// also support, so everything should work and return properly.
3083// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
3084TEST(LoaderInstPhysDevExts, PhysDevExtFenceProps2Simple) {
3085    FrameworkEnvironment env{};
3086    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3087    env.get_test_icd(0).icd_api_version = VK_API_VERSION_1_1;
3088    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
3089    env.get_test_icd(0).physical_devices.push_back({});
3090    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, 0});
3091    FillInRandomExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties);
3092    {
3093        InstWrapper instance(env.vulkan_functions);
3094        instance.create_info.set_api_version(VK_API_VERSION_1_1);
3095        instance.CheckCreate();
3096
3097        PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties =
3098            instance.load("vkGetPhysicalDeviceExternalFenceProperties");
3099        ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
3100
3101        uint32_t driver_count = 1;
3102        VkPhysicalDevice physical_device;
3103        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3104        ASSERT_EQ(driver_count, 1U);
3105
3106        VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
3107        VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
3108        GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
3109        ASSERT_TRUE(CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props));
3110    }
3111    {  // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
3112        InstWrapper instance(env.vulkan_functions);
3113        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
3114        instance.CheckCreate();
3115        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
3116        CreateDebugUtilsMessenger(log);
3117
3118        PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties =
3119            instance.load("vkGetPhysicalDeviceExternalFenceProperties");
3120        ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
3121
3122        uint32_t driver_count = 1;
3123        VkPhysicalDevice physical_device;
3124        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3125        ASSERT_EQ(driver_count, 1U);
3126
3127        VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
3128        VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
3129        GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
3130        // Compare against 'zeroed' out VkExternalFenceProperties
3131        ASSERT_TRUE(CompareExtFenceData(VkExternalFenceProperties{}, props));
3132        ASSERT_TRUE(log.find("Emulating call in ICD"));
3133    }
3134    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
3135                                                         .set_name("modify_api_version_layer")
3136                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
3137                                                         .set_disable_environment("DisableEnvVar")),
3138                           "modify_api_version_layer.json");
3139    env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
3140    {  // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
3141        InstWrapper instance(env.vulkan_functions);
3142        instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
3143        instance.CheckCreate();
3144        DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
3145        CreateDebugUtilsMessenger(log);
3146        PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties =
3147            instance.load("vkGetPhysicalDeviceExternalFenceProperties");
3148        ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
3149
3150        uint32_t driver_count = 1;
3151        VkPhysicalDevice physical_device;
3152        ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3153        ASSERT_EQ(driver_count, 1U);
3154
3155        VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
3156        VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
3157        GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
3158        ASSERT_TRUE(CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props));
3159        ASSERT_FALSE(log.find("Emulating call in ICD"));
3160    }
3161}
3162// Test vkGetPhysicalDeviceExternalFenceProperties where instance supports it with some ICDs that both support
3163// and don't support it:
3164//    ICD 0 supports
3165//        Physical device 0 does not
3166//        Physical device 1 does
3167//        Physical device 2 does not
3168//    ICD 1 doesn't support
3169//        Physical device 3 does not
3170//    ICD 2 supports
3171//        Physical device 4 does not
3172//        Physical device 5 does not
3173//    ICD 3 supports
3174//        Physical device 6 does
3175TEST(LoaderInstPhysDevExts, PhysDevExtFencePropsMixed) {
3176    FrameworkEnvironment env{};
3177    const uint32_t max_icd_count = 4;
3178    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
3179    const uint32_t max_phys_devs = 7;
3180
3181    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
3182        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
3183        auto& cur_icd = env.get_test_icd(icd);
3184
3185        // ICD 1 should not have 1.1
3186        if (icd != 1) {
3187            cur_icd.icd_api_version = VK_API_VERSION_1_1;
3188            cur_icd.add_instance_extension({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
3189        }
3190
3191        uint32_t rand_vendor_id;
3192        uint32_t rand_driver_vers;
3193        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
3194
3195        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
3196            uint32_t device_version = VK_API_VERSION_1_0;
3197            cur_icd.physical_devices.push_back({});
3198            auto& cur_dev = cur_icd.physical_devices.back();
3199
3200            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
3201            if ((icd == 0 && dev == 1) || icd == 3) {
3202                cur_dev.extensions.push_back({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, 0});
3203                device_version = VK_API_VERSION_1_1;
3204            }
3205
3206            // Still set physical device properties (so we can determine if device is correct API version)
3207            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
3208            FillInRandomExtFenceData(cur_dev.external_fence_properties);
3209        }
3210    }
3211
3212    InstWrapper instance(env.vulkan_functions);
3213    instance.create_info.set_api_version(VK_API_VERSION_1_1);
3214    instance.CheckCreate();
3215
3216    PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties =
3217        instance.load("vkGetPhysicalDeviceExternalFenceProperties");
3218    ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
3219
3220    uint32_t device_count = max_phys_devs;
3221    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
3222    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
3223    ASSERT_EQ(device_count, max_phys_devs);
3224
3225    for (uint32_t dev = 0; dev < device_count; ++dev) {
3226        VkPhysicalDeviceProperties pd_props{};
3227        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
3228
3229        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
3230            auto& cur_icd = env.get_test_icd(icd);
3231            bool found = false;
3232            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
3233                auto& cur_dev = cur_icd.physical_devices[pd];
3234                // Find the ICD device matching the physical device we're looking at info for so we can compare the
3235                // physical devices info with the returned info.
3236                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
3237                    cur_dev.properties.deviceType == pd_props.deviceType &&
3238                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
3239                    cur_dev.properties.vendorID == pd_props.vendorID) {
3240                    VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
3241                    VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
3242                    GetPhysicalDeviceExternalFenceProperties(physical_devices[dev], &info, &props);
3243                    // No driver support for extension or 1.1 for ICD 1, all others support
3244                    ASSERT_TRUE(CompareExtFenceData(cur_dev.external_fence_properties, props, icd != 1));
3245                    found = true;
3246                    break;
3247                }
3248            }
3249            if (found) {
3250                break;
3251            }
3252        }
3253    }
3254}
3255
3256//
3257// VK_KHR_get_surface_capabilities2
3258//
3259
3260// Test vkGetPhysicalDeviceSurfaceCapabilities2KHR where nothing supports it.
3261TEST(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRNoSupport) {
3262    FrameworkEnvironment env{};
3263    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3264    env.get_test_icd(0).physical_devices.push_back({});
3265
3266    InstWrapper instance(env.vulkan_functions);
3267    instance.CheckCreate();
3268
3269    PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR GetPhysicalDeviceSurfaceCapabilities2KHR =
3270        instance.load("vkGetPhysicalDeviceSurfaceCapabilities2KHR");
3271    ASSERT_EQ(GetPhysicalDeviceSurfaceCapabilities2KHR, nullptr);
3272}
3273
3274// Test vkGetPhysicalDeviceSurfaceCapabilities2KHR where instance supports it, but nothing else.
3275TEST(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRNoICDSupport) {
3276    FrameworkEnvironment env{};
3277    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3278    env.get_test_icd(0).physical_devices.push_back({});
3279
3280    InstWrapper instance(env.vulkan_functions);
3281    instance.create_info.add_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
3282    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
3283
3284    PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR GetPhysicalDeviceSurfaceCapabilities2KHR =
3285        instance.load("vkGetPhysicalDeviceSurfaceCapabilities2KHR");
3286    ASSERT_EQ(GetPhysicalDeviceSurfaceCapabilities2KHR, nullptr);
3287}
3288
3289// Fill in random but valid data into the surface capability data struct for the current physical device
3290void FillInRandomSurfaceCapsData(VkSurfaceCapabilitiesKHR& props) {
3291    props.minImageCount = (rand() % 0xFFF) + 1;
3292    props.maxImageCount = (rand() % 0xFFF) + 1;
3293    props.currentExtent.width = (rand() % 0xFFF) + 1;
3294    props.currentExtent.height = (rand() % 0xFFF) + 1;
3295    props.minImageExtent.width = (rand() % 0xFFF) + 1;
3296    props.minImageExtent.height = (rand() % 0xFFF) + 1;
3297    props.maxImageExtent.width = (rand() % 0xFFF) + 1;
3298    props.maxImageExtent.height = (rand() % 0xFFF) + 1;
3299    props.maxImageArrayLayers = (rand() % 0xFFF) + 1;
3300    props.supportedTransforms = static_cast<VkSurfaceTransformFlagsKHR>((rand() % 0xFFF) + 1);
3301    props.currentTransform = static_cast<VkSurfaceTransformFlagBitsKHR>((rand() % 0xFFF) + 1);
3302    props.supportedCompositeAlpha = static_cast<VkCompositeAlphaFlagsKHR>((rand() % 0xFFF) + 1);
3303    props.supportedUsageFlags = static_cast<VkImageUsageFlags>((rand() % 0xFFF) + 1);
3304}
3305
3306// Compare the surface capability data structs
3307bool CompareSurfaceCapsData(const VkSurfaceCapabilitiesKHR& props1, const VkSurfaceCapabilitiesKHR& props2, bool supported = true) {
3308    bool equal = true;
3309    if (supported) {
3310        equal = equal && props1.minImageCount == props2.minImageCount;
3311        equal = equal && props1.maxImageCount == props2.maxImageCount;
3312        equal = equal && props1.currentExtent.width == props2.currentExtent.width;
3313        equal = equal && props1.currentExtent.height == props2.currentExtent.height;
3314        equal = equal && props1.minImageExtent.width == props2.minImageExtent.width;
3315        equal = equal && props1.minImageExtent.height == props2.minImageExtent.height;
3316        equal = equal && props1.maxImageExtent.width == props2.maxImageExtent.width;
3317        equal = equal && props1.maxImageExtent.height == props2.maxImageExtent.height;
3318        equal = equal && props1.maxImageArrayLayers == props2.maxImageArrayLayers;
3319        equal = equal && props1.supportedTransforms == props2.supportedTransforms;
3320        equal = equal && props1.currentTransform == props2.currentTransform;
3321        equal = equal && props1.supportedCompositeAlpha == props2.supportedCompositeAlpha;
3322        equal = equal && props1.supportedUsageFlags == props2.supportedUsageFlags;
3323    } else {
3324        equal = equal && 0 == props2.minImageCount;
3325        equal = equal && 0 == props2.maxImageCount;
3326        equal = equal && 0 == props2.currentExtent.width;
3327        equal = equal && 0 == props2.currentExtent.height;
3328        equal = equal && 0 == props2.minImageExtent.width;
3329        equal = equal && 0 == props2.minImageExtent.height;
3330        equal = equal && 0 == props2.maxImageExtent.width;
3331        equal = equal && 0 == props2.maxImageExtent.height;
3332        equal = equal && 0 == props2.maxImageArrayLayers;
3333        equal = equal && 0 == props2.supportedTransforms;
3334        equal = equal && 0 == props2.currentTransform;
3335        equal = equal && 0 == props2.supportedCompositeAlpha;
3336        equal = equal && 0 == props2.supportedUsageFlags;
3337    }
3338    return equal;
3339}
3340
3341// Test vkGetPhysicalDeviceSurfaceCapabilities2KHR where instance and ICD supports it, but device does not support it.
3342TEST(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRInstanceAndICDSupport) {
3343    FrameworkEnvironment env{};
3344    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3345    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
3346    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
3347    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
3348    auto& cur_icd = env.get_test_icd(0);
3349    cur_icd.add_instance_extensions({first_ext, second_ext, third_ext});
3350    cur_icd.physical_devices.push_back({});
3351    cur_icd.min_icd_interface_version = 3;
3352    cur_icd.enable_icd_wsi = true;
3353    FillInRandomSurfaceCapsData(env.get_test_icd(0).physical_devices.back().surface_capabilities);
3354
3355    InstWrapper instance(env.vulkan_functions);
3356    instance.create_info.add_extensions(
3357        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
3358    instance.CheckCreate();
3359
3360    PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR =
3361        instance.load("vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
3362    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilitiesKHR, nullptr);
3363    PFN_vkCreateHeadlessSurfaceEXT CreateHeadlessSurfaceEXT = instance.load("vkCreateHeadlessSurfaceEXT");
3364    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
3365    PFN_vkDestroySurfaceKHR DestroySurfaceKHR = instance.load("vkDestroySurfaceKHR");
3366    ASSERT_NE(DestroySurfaceKHR, nullptr);
3367    PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR GetPhysicalDeviceSurfaceCapabilities2KHR =
3368        instance.load("vkGetPhysicalDeviceSurfaceCapabilities2KHR");
3369    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilities2KHR, nullptr);
3370
3371    uint32_t driver_count = 1;
3372    VkPhysicalDevice physical_device;
3373    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3374    ASSERT_EQ(driver_count, 1U);
3375
3376    VkSurfaceKHR surface;
3377    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
3378    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
3379
3380    VkSurfaceCapabilitiesKHR props{};
3381    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &props));
3382
3383    VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
3384    VkSurfaceCapabilities2KHR props2{VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR};
3385    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilities2KHR(physical_device, &info, &props2));
3386    ASSERT_TRUE(CompareSurfaceCapsData(props, props2.surfaceCapabilities));
3387
3388    DestroySurfaceKHR(instance.inst, surface, nullptr);
3389}
3390
3391// Test vkGetPhysicalDeviceSurfaceCapabilities2 where instance supports it with some ICDs that both support
3392// and don't support it:
3393//    ICD 0 supports
3394//        Physical device 0 does not
3395//        Physical device 1 does
3396//        Physical device 2 does not
3397//    ICD 1 doesn't support
3398//        Physical device 3 does not
3399//    ICD 2 supports
3400//        Physical device 4 does not
3401//        Physical device 5 does not
3402//    ICD 3 supports
3403//        Physical device 6 does
3404TEST(LoaderInstPhysDevExts, PhysDevSurfaceCaps2KHRMixed) {
3405    FrameworkEnvironment env{};
3406    const uint32_t max_icd_count = 4;
3407    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
3408    const uint32_t max_phys_devs = 7;
3409    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
3410    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
3411    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
3412
3413    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
3414        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
3415        auto& cur_icd = env.get_test_icd(icd);
3416        cur_icd.icd_api_version = VK_API_VERSION_1_0;
3417        cur_icd.min_icd_interface_version = 3;
3418        cur_icd.enable_icd_wsi = true;
3419        cur_icd.add_instance_extensions({first_ext, third_ext});
3420
3421        // ICD 1 should not have 1.1
3422        if (icd != 1) {
3423            cur_icd.icd_api_version = VK_API_VERSION_1_1;
3424            cur_icd.add_instance_extension(second_ext);
3425        }
3426
3427        uint32_t rand_vendor_id;
3428        uint32_t rand_driver_vers;
3429        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
3430
3431        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
3432            uint32_t device_version = VK_API_VERSION_1_0;
3433            cur_icd.physical_devices.push_back({});
3434            auto& cur_dev = cur_icd.physical_devices.back();
3435            cur_dev.extensions.push_back({VK_KHR_SURFACE_EXTENSION_NAME, 0});
3436            cur_dev.extensions.push_back({VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, 0});
3437
3438            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
3439            if ((icd == 0 && dev == 1) || icd == 3) {
3440                cur_dev.extensions.push_back({VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, 0});
3441                device_version = VK_API_VERSION_1_1;
3442            }
3443
3444            // Still set physical device properties (so we can determine if device is correct API version)
3445            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
3446            FillInRandomSurfaceCapsData(cur_dev.surface_capabilities);
3447        }
3448    }
3449
3450    InstWrapper instance(env.vulkan_functions);
3451    instance.create_info.add_extensions(
3452        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
3453    instance.CheckCreate();
3454
3455    PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR =
3456        instance.load("vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
3457    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilitiesKHR, nullptr);
3458    PFN_vkCreateHeadlessSurfaceEXT CreateHeadlessSurfaceEXT = instance.load("vkCreateHeadlessSurfaceEXT");
3459    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
3460    PFN_vkDestroySurfaceKHR DestroySurfaceKHR = instance.load("vkDestroySurfaceKHR");
3461    ASSERT_NE(DestroySurfaceKHR, nullptr);
3462    PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR GetPhysicalDeviceSurfaceCapabilities2KHR =
3463        instance.load("vkGetPhysicalDeviceSurfaceCapabilities2KHR");
3464    ASSERT_NE(GetPhysicalDeviceSurfaceCapabilities2KHR, nullptr);
3465
3466    uint32_t device_count = max_phys_devs;
3467    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
3468    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
3469    ASSERT_EQ(device_count, max_phys_devs);
3470
3471    VkSurfaceKHR surface;
3472    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
3473    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
3474
3475    for (uint32_t dev = 0; dev < device_count; ++dev) {
3476        VkSurfaceCapabilitiesKHR props{};
3477        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices[dev], surface, &props));
3478
3479        VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
3480        VkSurfaceCapabilities2KHR props2{VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR};
3481        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceCapabilities2KHR(physical_devices[dev], &info, &props2));
3482        ASSERT_TRUE(CompareSurfaceCapsData(props, props2.surfaceCapabilities));
3483    }
3484
3485    DestroySurfaceKHR(instance.inst, surface, nullptr);
3486}
3487
3488// Test vkGetPhysicalDeviceSurfaceFormats2KHR where nothing supports it.
3489TEST(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRNoSupport) {
3490    FrameworkEnvironment env{};
3491    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3492    env.get_test_icd(0).physical_devices.push_back({});
3493
3494    InstWrapper instance(env.vulkan_functions);
3495    instance.CheckCreate();
3496
3497    PFN_vkGetPhysicalDeviceSurfaceFormats2KHR GetPhysicalDeviceSurfaceFormats2KHR =
3498        instance.load("vkGetPhysicalDeviceSurfaceFormats2KHR");
3499    ASSERT_EQ(GetPhysicalDeviceSurfaceFormats2KHR, nullptr);
3500}
3501
3502// Test vkGetPhysicalDeviceSurfaceFormats2KHR where instance supports it, but nothing else.
3503TEST(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRNoICDSupport) {
3504    FrameworkEnvironment env{};
3505    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3506    env.get_test_icd(0).physical_devices.push_back({});
3507
3508    InstWrapper instance(env.vulkan_functions);
3509    instance.create_info.add_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
3510    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
3511
3512    PFN_vkGetPhysicalDeviceSurfaceFormats2KHR GetPhysicalDeviceSurfaceFormats2KHR =
3513        instance.load("vkGetPhysicalDeviceSurfaceFormats2KHR");
3514    ASSERT_EQ(GetPhysicalDeviceSurfaceFormats2KHR, nullptr);
3515}
3516
3517// Fill in random but valid data into the surface formats data struct for the current physical device
3518void FillInRandomSurfaceFormatsData(std::vector<VkSurfaceFormatKHR>& props) {
3519    props.resize((rand() % 5) + 1);
3520    for (uint32_t i = 0; i < props.size(); ++i) {
3521        props[i].format = static_cast<VkFormat>((rand() % 0xFFF) + 1);
3522        props[i].colorSpace = static_cast<VkColorSpaceKHR>((rand() % 0xFFF) + 1);
3523    }
3524}
3525
3526// Compare the surface formats data structs
3527bool CompareSurfaceFormatsData(const std::vector<VkSurfaceFormatKHR>& props1, const std::vector<VkSurfaceFormat2KHR>& props2,
3528                               bool supported = true) {
3529    if (props1.size() != props2.size()) return false;
3530    bool equal = true;
3531    for (uint32_t i = 0; i < props1.size(); ++i) {
3532        if (supported) {
3533            equal = equal && props1[i].format == props2[i].surfaceFormat.format;
3534            equal = equal && props1[i].colorSpace == props2[i].surfaceFormat.colorSpace;
3535        } else {
3536            equal = equal && 0 == props2[i].surfaceFormat.format;
3537            equal = equal && 0 == props2[i].surfaceFormat.colorSpace;
3538        }
3539    }
3540    return equal;
3541}
3542
3543// Test vkGetPhysicalDeviceSurfaceFormats2KHR where instance and ICD supports it, but device does not support it.
3544TEST(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRInstanceAndICDSupport) {
3545    FrameworkEnvironment env{};
3546    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3547    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
3548    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
3549    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
3550    auto& cur_icd = env.get_test_icd(0);
3551    cur_icd.add_instance_extensions({first_ext, second_ext, third_ext});
3552    cur_icd.physical_devices.push_back({});
3553    cur_icd.min_icd_interface_version = 3;
3554    cur_icd.enable_icd_wsi = true;
3555    FillInRandomSurfaceFormatsData(env.get_test_icd(0).physical_devices.back().surface_formats);
3556
3557    InstWrapper instance(env.vulkan_functions);
3558    instance.create_info.add_extensions(
3559        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
3560    instance.CheckCreate();
3561
3562    PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR =
3563        instance.load("vkGetPhysicalDeviceSurfaceFormatsKHR");
3564    ASSERT_NE(GetPhysicalDeviceSurfaceFormatsKHR, nullptr);
3565    PFN_vkCreateHeadlessSurfaceEXT CreateHeadlessSurfaceEXT = instance.load("vkCreateHeadlessSurfaceEXT");
3566    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
3567    PFN_vkDestroySurfaceKHR DestroySurfaceKHR = instance.load("vkDestroySurfaceKHR");
3568    ASSERT_NE(DestroySurfaceKHR, nullptr);
3569    PFN_vkGetPhysicalDeviceSurfaceFormats2KHR GetPhysicalDeviceSurfaceFormats2KHR =
3570        instance.load("vkGetPhysicalDeviceSurfaceFormats2KHR");
3571    ASSERT_NE(GetPhysicalDeviceSurfaceFormats2KHR, nullptr);
3572
3573    uint32_t driver_count = 1;
3574    VkPhysicalDevice physical_device;
3575    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3576    ASSERT_EQ(driver_count, 1U);
3577
3578    VkSurfaceKHR surface;
3579    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
3580    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
3581
3582    std::vector<VkSurfaceFormatKHR> props{};
3583    uint32_t count_1 = 0;
3584    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &count_1, nullptr));
3585    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().surface_formats.size(), count_1);
3586    props.resize(count_1);
3587    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &count_1, props.data()));
3588    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().surface_formats.size(), count_1);
3589
3590    VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
3591    std::vector<VkSurfaceFormat2KHR> props2{};
3592    uint32_t count_2 = 0;
3593    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2KHR(physical_device, &info, &count_2, nullptr));
3594    ASSERT_EQ(count_1, count_2);
3595    props2.resize(count_2, VkSurfaceFormat2KHR{VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR});
3596    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2KHR(physical_device, &info, &count_2, props2.data()));
3597    ASSERT_TRUE(CompareSurfaceFormatsData(props, props2));
3598
3599    DestroySurfaceKHR(instance.inst, surface, nullptr);
3600}
3601
3602// Test vkGetPhysicalDeviceSurfaceFormats2 where instance supports it with some ICDs that both support
3603// and don't support it:
3604//    ICD 0 supports
3605//        Physical device 0 does not
3606//        Physical device 1 does
3607//        Physical device 2 does not
3608//    ICD 1 doesn't support
3609//        Physical device 3 does not
3610//    ICD 2 supports
3611//        Physical device 4 does not
3612//        Physical device 5 does not
3613//    ICD 3 supports
3614//        Physical device 6 does
3615TEST(LoaderInstPhysDevExts, PhysDevSurfaceFormats2KHRMixed) {
3616    FrameworkEnvironment env{};
3617    const uint32_t max_icd_count = 4;
3618    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
3619    const uint32_t max_phys_devs = 7;
3620    Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
3621    Extension second_ext{VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME};
3622    Extension third_ext{VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME};
3623
3624    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
3625        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
3626        auto& cur_icd = env.get_test_icd(icd);
3627        cur_icd.icd_api_version = VK_API_VERSION_1_0;
3628        cur_icd.enable_icd_wsi = true;
3629        cur_icd.min_icd_interface_version = 3;
3630        cur_icd.add_instance_extensions({first_ext, third_ext});
3631
3632        // ICD 1 should not have 1.1
3633        if (icd != 1) {
3634            cur_icd.icd_api_version = VK_API_VERSION_1_1;
3635            cur_icd.add_instance_extension(second_ext);
3636        }
3637
3638        uint32_t rand_vendor_id;
3639        uint32_t rand_driver_vers;
3640        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
3641
3642        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
3643            uint32_t device_version = VK_API_VERSION_1_0;
3644            cur_icd.physical_devices.push_back({});
3645            auto& cur_dev = cur_icd.physical_devices.back();
3646            cur_dev.extensions.push_back({VK_KHR_SURFACE_EXTENSION_NAME, 0});
3647            cur_dev.extensions.push_back({VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, 0});
3648
3649            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
3650            if ((icd == 0 && dev == 1) || icd == 3) {
3651                cur_dev.extensions.push_back({VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, 0});
3652                device_version = VK_API_VERSION_1_1;
3653            }
3654
3655            // Still set physical device properties (so we can determine if device is correct API version)
3656            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
3657            FillInRandomSurfaceFormatsData(cur_dev.surface_formats);
3658        }
3659    }
3660
3661    InstWrapper instance(env.vulkan_functions);
3662    instance.create_info.add_extensions(
3663        {VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME});
3664    instance.CheckCreate();
3665
3666    PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR =
3667        instance.load("vkGetPhysicalDeviceSurfaceFormatsKHR");
3668    ASSERT_NE(GetPhysicalDeviceSurfaceFormatsKHR, nullptr);
3669    PFN_vkCreateHeadlessSurfaceEXT CreateHeadlessSurfaceEXT = instance.load("vkCreateHeadlessSurfaceEXT");
3670    ASSERT_NE(CreateHeadlessSurfaceEXT, nullptr);
3671    PFN_vkDestroySurfaceKHR DestroySurfaceKHR = instance.load("vkDestroySurfaceKHR");
3672    ASSERT_NE(DestroySurfaceKHR, nullptr);
3673    PFN_vkGetPhysicalDeviceSurfaceFormats2KHR GetPhysicalDeviceSurfaceFormats2KHR =
3674        instance.load("vkGetPhysicalDeviceSurfaceFormats2KHR");
3675    ASSERT_NE(GetPhysicalDeviceSurfaceFormats2KHR, nullptr);
3676
3677    uint32_t device_count = max_phys_devs;
3678    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
3679    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
3680    ASSERT_EQ(device_count, max_phys_devs);
3681
3682    VkSurfaceKHR surface;
3683    VkHeadlessSurfaceCreateInfoEXT create_info{VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
3684    ASSERT_EQ(VK_SUCCESS, CreateHeadlessSurfaceEXT(instance.inst, &create_info, nullptr, &surface));
3685
3686    for (uint32_t dev = 0; dev < device_count; ++dev) {
3687        std::vector<VkSurfaceFormatKHR> props{};
3688        uint32_t count_1 = 0;
3689        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormatsKHR(physical_devices[dev], surface, &count_1, nullptr));
3690        ASSERT_NE(0U, count_1);
3691        props.resize(count_1);
3692        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormatsKHR(physical_devices[dev], surface, &count_1, props.data()));
3693        ASSERT_NE(0U, count_1);
3694
3695        VkPhysicalDeviceSurfaceInfo2KHR info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
3696        std::vector<VkSurfaceFormat2KHR> props2{};
3697        uint32_t count_2 = 0;
3698        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2KHR(physical_devices[dev], &info, &count_2, nullptr));
3699        ASSERT_EQ(count_1, count_2);
3700        props2.resize(count_2, VkSurfaceFormat2KHR{VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR});
3701        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceSurfaceFormats2KHR(physical_devices[dev], &info, &count_2, props2.data()));
3702        ASSERT_EQ(count_1, count_2);
3703        ASSERT_TRUE(CompareSurfaceFormatsData(props, props2));
3704    }
3705
3706    DestroySurfaceKHR(instance.inst, surface, nullptr);
3707}
3708
3709//
3710// VK_KHR_display
3711//
3712
3713// Test vkGetPhysicalDeviceDisplayPropertiesKHR where nothing supports it.
3714TEST(LoaderInstPhysDevExts, PhysDevDispPropsKHRNoSupport) {
3715    FrameworkEnvironment env{};
3716    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3717    env.get_test_icd(0).physical_devices.push_back({});
3718
3719    InstWrapper instance(env.vulkan_functions);
3720    instance.CheckCreate();
3721
3722    PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR =
3723        instance.load("vkGetPhysicalDeviceDisplayPropertiesKHR");
3724    ASSERT_EQ(GetPhysicalDeviceDisplayPropertiesKHR, nullptr);
3725}
3726
3727// Test vkGetPhysicalDeviceDisplayPropertiesKHR where instance supports it, but nothing else.
3728TEST(LoaderInstPhysDevExts, PhysDevDispPropsKHRNoICDSupport) {
3729    FrameworkEnvironment env{};
3730    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3731    env.get_test_icd(0).physical_devices.push_back({});
3732
3733    InstWrapper instance(env.vulkan_functions);
3734    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
3735    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
3736
3737    PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR =
3738        instance.load("vkGetPhysicalDeviceDisplayPropertiesKHR");
3739    ASSERT_EQ(GetPhysicalDeviceDisplayPropertiesKHR, nullptr);
3740}
3741
3742VkDisplayKHR CreateRandomDisplay() { return (VkDisplayKHR)(((rand() % 0xFFFFFFFBull) << 12) * (rand() % 0xFFFFFFFull) + 1); }
3743
3744VkDisplayModeKHR CreateRandomDisplayMode() {
3745    return (VkDisplayModeKHR)(((rand() % 0xFFFFFFFBull) << 12) * (rand() % 0xFFFFFFFull) + 1);
3746}
3747
3748// Fill in random but valid data into the display property data struct for the current physical device
3749void FillInRandomDisplayPropData(std::vector<VkDisplayPropertiesKHR>& props) {
3750    props.resize((rand() % 5) + 1);
3751    for (uint32_t i = 0; i < props.size(); ++i) {
3752        props[i].display = CreateRandomDisplay();
3753        props[i].physicalDimensions.width = static_cast<uint32_t>((rand() % 0xFFF) + 1);
3754        props[i].physicalDimensions.height = static_cast<uint32_t>((rand() % 0xFFF) + 1);
3755        props[i].physicalResolution.width = static_cast<uint32_t>((rand() % 0xFFF) + 1);
3756        props[i].physicalResolution.height = static_cast<uint32_t>((rand() % 0xFFF) + 1);
3757        props[i].supportedTransforms = static_cast<VkSurfaceTransformFlagsKHR>((rand() % 0xFFE) + 1);
3758        props[i].planeReorderPossible = rand() % 2 > 0 ? VK_TRUE : VK_FALSE;
3759        props[i].persistentContent = rand() % 2 > 0 ? VK_TRUE : VK_FALSE;
3760    }
3761}
3762
3763// Compare the display property data structs
3764bool CompareDisplayPropData(const std::vector<VkDisplayPropertiesKHR>& props1, const std::vector<VkDisplayPropertiesKHR>& props2) {
3765    if (props1.size() != props2.size()) return false;
3766    bool equal = true;
3767    for (uint32_t i = 0; i < props1.size(); ++i) {
3768        equal = equal && props1[i].display == props2[i].display;
3769        equal = equal && props1[i].physicalDimensions.width == props2[i].physicalDimensions.width;
3770        equal = equal && props1[i].physicalDimensions.height == props2[i].physicalDimensions.height;
3771        equal = equal && props1[i].physicalResolution.width == props2[i].physicalResolution.width;
3772        equal = equal && props1[i].physicalResolution.height == props2[i].physicalResolution.height;
3773        equal = equal && props1[i].supportedTransforms == props2[i].supportedTransforms;
3774        equal = equal && props1[i].planeReorderPossible == props2[i].planeReorderPossible;
3775        equal = equal && props1[i].persistentContent == props2[i].persistentContent;
3776    }
3777    return equal;
3778}
3779
3780// Test vGetPhysicalDeviceDisplayPropertiesKHR where instance and ICD supports it, but device does not support it.
3781TEST(LoaderInstPhysDevExts, PhysDevDispPropsKHRInstanceAndICDSupport) {
3782    FrameworkEnvironment env{};
3783    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3784    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
3785    env.get_test_icd(0).physical_devices.push_back({});
3786    FillInRandomDisplayPropData(env.get_test_icd(0).physical_devices.back().display_properties);
3787
3788    InstWrapper instance(env.vulkan_functions);
3789    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
3790    instance.CheckCreate();
3791
3792    PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR =
3793        instance.load("vkGetPhysicalDeviceDisplayPropertiesKHR");
3794    ASSERT_NE(GetPhysicalDeviceDisplayPropertiesKHR, nullptr);
3795
3796    uint32_t driver_count = 1;
3797    VkPhysicalDevice physical_device;
3798    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3799    ASSERT_EQ(driver_count, 1U);
3800
3801    std::vector<VkDisplayPropertiesKHR> props{};
3802    uint32_t prop_count = 0;
3803    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPropertiesKHR(physical_device, &prop_count, nullptr));
3804    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_properties.size(), prop_count);
3805    props.resize(prop_count);
3806    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPropertiesKHR(physical_device, &prop_count, props.data()));
3807    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_properties.size(), prop_count);
3808
3809    ASSERT_TRUE(CompareDisplayPropData(props, env.get_test_icd(0).physical_devices.back().display_properties));
3810}
3811
3812// Test vkGetPhysicalDeviceDisplayPropertiesKHR where instance supports it with some ICDs that both support
3813// and don't support it:
3814//    ICD 0 supports
3815//        Physical device 0 does not
3816//        Physical device 1 does
3817//        Physical device 2 does not
3818//    ICD 1 doesn't support
3819//        Physical device 3 does not
3820//    ICD 2 supports
3821//        Physical device 4 does not
3822//        Physical device 5 does not
3823//    ICD 3 supports
3824//        Physical device 6 does
3825TEST(LoaderInstPhysDevExts, PhysDevDispPropsKHRMixed) {
3826    FrameworkEnvironment env{};
3827    const uint32_t max_icd_count = 4;
3828    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
3829    const uint32_t max_phys_devs = 7;
3830
3831    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
3832        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
3833        auto& cur_icd = env.get_test_icd(icd);
3834        cur_icd.icd_api_version = VK_API_VERSION_1_0;
3835
3836        // ICD 1 should not have 1.1
3837        if (icd != 1) {
3838            cur_icd.icd_api_version = VK_API_VERSION_1_1;
3839            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
3840        }
3841
3842        uint32_t rand_vendor_id;
3843        uint32_t rand_driver_vers;
3844        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
3845
3846        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
3847            uint32_t device_version = VK_API_VERSION_1_0;
3848            cur_icd.physical_devices.push_back({});
3849            auto& cur_dev = cur_icd.physical_devices.back();
3850
3851            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
3852            if ((icd == 0 && dev == 1) || icd == 3) {
3853                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
3854                device_version = VK_API_VERSION_1_1;
3855            }
3856
3857            // Still set physical device properties (so we can determine if device is correct API version)
3858            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
3859            FillInRandomDisplayPropData(cur_dev.display_properties);
3860        }
3861    }
3862
3863    InstWrapper instance(env.vulkan_functions);
3864    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
3865    instance.CheckCreate();
3866
3867    PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR =
3868        instance.load("vkGetPhysicalDeviceDisplayPropertiesKHR");
3869    ASSERT_NE(GetPhysicalDeviceDisplayPropertiesKHR, nullptr);
3870
3871    uint32_t device_count = max_phys_devs;
3872    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
3873    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
3874    ASSERT_EQ(device_count, max_phys_devs);
3875
3876    for (uint32_t dev = 0; dev < device_count; ++dev) {
3877        VkPhysicalDeviceProperties pd_props{};
3878        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
3879
3880        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
3881            auto& cur_icd = env.get_test_icd(icd);
3882            bool found = false;
3883            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
3884                auto& cur_dev = cur_icd.physical_devices[pd];
3885                // Find the ICD device matching the physical device we're looking at info for so we can compare the
3886                // physical devices info with the returned info.
3887                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
3888                    cur_dev.properties.deviceType == pd_props.deviceType &&
3889                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
3890                    cur_dev.properties.vendorID == pd_props.vendorID) {
3891                    std::vector<VkDisplayPropertiesKHR> props{};
3892                    uint32_t prop_count = 0;
3893                    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPropertiesKHR(physical_devices[dev], &prop_count, nullptr));
3894                    if (icd == 1) {
3895                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
3896                        // loader.
3897                        ASSERT_EQ(0U, prop_count);
3898                    } else {
3899                        ASSERT_EQ(cur_dev.display_properties.size(), prop_count);
3900                        props.resize(prop_count);
3901                        ASSERT_EQ(VK_SUCCESS,
3902                                  GetPhysicalDeviceDisplayPropertiesKHR(physical_devices[dev], &prop_count, props.data()));
3903                        ASSERT_EQ(cur_dev.display_properties.size(), prop_count);
3904
3905                        ASSERT_TRUE(CompareDisplayPropData(props, cur_dev.display_properties));
3906                    }
3907                    found = true;
3908                    break;
3909                }
3910            }
3911            if (found) {
3912                break;
3913            }
3914        }
3915    }
3916}
3917
3918// Test vkGetPhysicalDeviceDisplayPlanePropertiesKHR where nothing supports it.
3919TEST(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRNoSupport) {
3920    FrameworkEnvironment env{};
3921    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3922    env.get_test_icd(0).physical_devices.push_back({});
3923
3924    InstWrapper instance(env.vulkan_functions);
3925    instance.CheckCreate();
3926
3927    PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR =
3928        instance.load("vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
3929    ASSERT_EQ(GetPhysicalDeviceDisplayPlanePropertiesKHR, nullptr);
3930}
3931
3932// Test vkGetPhysicalDeviceDisplayPlanePropertiesKHR where instance supports it, but nothing else.
3933TEST(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRNoICDSupport) {
3934    FrameworkEnvironment env{};
3935    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3936    env.get_test_icd(0).physical_devices.push_back({});
3937
3938    InstWrapper instance(env.vulkan_functions);
3939    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
3940    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
3941
3942    PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR =
3943        instance.load("vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
3944    ASSERT_EQ(GetPhysicalDeviceDisplayPlanePropertiesKHR, nullptr);
3945}
3946
3947// Fill in random but valid data into the display plane property data struct for the current physical device
3948void FillInRandomDisplayPlanePropData(std::vector<VkDisplayPlanePropertiesKHR>& props) {
3949    props.resize((rand() % 5) + 1);
3950    for (uint32_t i = 0; i < props.size(); ++i) {
3951        props[i].currentDisplay = CreateRandomDisplay();
3952        props[i].currentStackIndex = static_cast<uint32_t>((rand() % 0xFFF) + (rand() % 0xFFF) + 1);
3953    }
3954}
3955
3956// Compare the display plane property data structs
3957bool CompareDisplayPlanePropData(const std::vector<VkDisplayPlanePropertiesKHR>& props1,
3958                                 const std::vector<VkDisplayPlanePropertiesKHR>& props2) {
3959    if (props1.size() != props2.size()) return false;
3960    bool equal = true;
3961    for (uint32_t i = 0; i < props1.size(); ++i) {
3962        equal = equal && props1[i].currentDisplay == props2[i].currentDisplay;
3963        equal = equal && props1[i].currentStackIndex == props2[i].currentStackIndex;
3964    }
3965    return equal;
3966}
3967
3968// Test vGetPhysicalDeviceDisplayPlanePropertiesKHR where instance and ICD supports it, but device does not support it.
3969TEST(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRInstanceAndICDSupport) {
3970    FrameworkEnvironment env{};
3971    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
3972    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
3973    env.get_test_icd(0).physical_devices.push_back({});
3974    FillInRandomDisplayPlanePropData(env.get_test_icd(0).physical_devices.back().display_plane_properties);
3975
3976    InstWrapper instance(env.vulkan_functions);
3977    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
3978    instance.CheckCreate();
3979
3980    PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR =
3981        instance.load("vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
3982    ASSERT_NE(GetPhysicalDeviceDisplayPlanePropertiesKHR, nullptr);
3983
3984    uint32_t driver_count = 1;
3985    VkPhysicalDevice physical_device;
3986    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
3987    ASSERT_EQ(driver_count, 1U);
3988
3989    std::vector<VkDisplayPlanePropertiesKHR> props{};
3990    uint32_t prop_count = 0;
3991    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &prop_count, nullptr));
3992    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_plane_properties.size(), prop_count);
3993    props.resize(prop_count);
3994    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &prop_count, props.data()));
3995    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_plane_properties.size(), prop_count);
3996
3997    ASSERT_TRUE(CompareDisplayPlanePropData(props, env.get_test_icd(0).physical_devices.back().display_plane_properties));
3998}
3999
4000// Test vkGetPhysicalDeviceDisplayPlanePropertiesKHR where instance supports it with some ICDs that both support
4001// and don't support it:
4002//    ICD 0 supports
4003//        Physical device 0 does not
4004//        Physical device 1 does
4005//        Physical device 2 does not
4006//    ICD 1 doesn't support
4007//        Physical device 3 does not
4008//    ICD 2 supports
4009//        Physical device 4 does not
4010//        Physical device 5 does not
4011//    ICD 3 supports
4012//        Physical device 6 does
4013TEST(LoaderInstPhysDevExts, PhysDevDispPlanePropsKHRMixed) {
4014    FrameworkEnvironment env{};
4015    const uint32_t max_icd_count = 4;
4016    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
4017    const uint32_t max_phys_devs = 7;
4018
4019    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4020        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
4021        auto& cur_icd = env.get_test_icd(icd);
4022        cur_icd.icd_api_version = VK_API_VERSION_1_0;
4023
4024        // ICD 1 should not have 1.1
4025        if (icd != 1) {
4026            cur_icd.icd_api_version = VK_API_VERSION_1_1;
4027            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4028        }
4029
4030        uint32_t rand_vendor_id;
4031        uint32_t rand_driver_vers;
4032        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
4033
4034        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
4035            uint32_t device_version = VK_API_VERSION_1_0;
4036            cur_icd.physical_devices.push_back({});
4037            auto& cur_dev = cur_icd.physical_devices.back();
4038
4039            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
4040            if ((icd == 0 && dev == 1) || icd == 3) {
4041                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
4042                device_version = VK_API_VERSION_1_1;
4043            }
4044
4045            // Still set physical device properties (so we can determine if device is correct API version)
4046            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
4047            FillInRandomDisplayPlanePropData(cur_dev.display_plane_properties);
4048        }
4049    }
4050
4051    InstWrapper instance(env.vulkan_functions);
4052    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4053    instance.CheckCreate();
4054
4055    PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR =
4056        instance.load("vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
4057    ASSERT_NE(GetPhysicalDeviceDisplayPlanePropertiesKHR, nullptr);
4058
4059    uint32_t device_count = max_phys_devs;
4060    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
4061    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
4062    ASSERT_EQ(device_count, max_phys_devs);
4063
4064    for (uint32_t dev = 0; dev < device_count; ++dev) {
4065        VkPhysicalDeviceProperties pd_props{};
4066        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
4067
4068        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4069            auto& cur_icd = env.get_test_icd(icd);
4070            bool found = false;
4071            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
4072                auto& cur_dev = cur_icd.physical_devices[pd];
4073                // Find the ICD device matching the physical device we're looking at info for so we can compare the
4074                // physical devices info with the returned info.
4075                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
4076                    cur_dev.properties.deviceType == pd_props.deviceType &&
4077                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
4078                    cur_dev.properties.vendorID == pd_props.vendorID) {
4079                    std::vector<VkDisplayPlanePropertiesKHR> props{};
4080                    uint32_t prop_count = 0;
4081                    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_devices[dev], &prop_count, nullptr));
4082                    if (icd == 1) {
4083                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
4084                        // loader.
4085                        ASSERT_EQ(0U, prop_count);
4086                    } else {
4087                        ASSERT_EQ(cur_dev.display_plane_properties.size(), prop_count);
4088                        props.resize(prop_count);
4089                        ASSERT_EQ(VK_SUCCESS,
4090                                  GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_devices[dev], &prop_count, props.data()));
4091                        ASSERT_EQ(cur_dev.display_plane_properties.size(), prop_count);
4092
4093                        ASSERT_TRUE(CompareDisplayPlanePropData(props, cur_dev.display_plane_properties));
4094                    }
4095                    found = true;
4096                    break;
4097                }
4098            }
4099            if (found) {
4100                break;
4101            }
4102        }
4103    }
4104}
4105
4106// Test vkGetDisplayPlaneSupportedDisplaysKHR where nothing supports it.
4107TEST(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRNoSupport) {
4108    FrameworkEnvironment env{};
4109    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4110    env.get_test_icd(0).physical_devices.push_back({});
4111
4112    InstWrapper instance(env.vulkan_functions);
4113    instance.CheckCreate();
4114
4115    PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR =
4116        instance.load("vkGetDisplayPlaneSupportedDisplaysKHR");
4117    ASSERT_EQ(GetDisplayPlaneSupportedDisplaysKHR, nullptr);
4118}
4119
4120// Test vkGetDisplayPlaneSupportedDisplaysKHR where instance supports it, but nothing else.
4121TEST(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRNoICDSupport) {
4122    FrameworkEnvironment env{};
4123    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4124    env.get_test_icd(0).physical_devices.push_back({});
4125
4126    InstWrapper instance(env.vulkan_functions);
4127    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4128    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
4129
4130    PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR =
4131        instance.load("vkGetDisplayPlaneSupportedDisplaysKHR");
4132    ASSERT_EQ(GetDisplayPlaneSupportedDisplaysKHR, nullptr);
4133}
4134
4135// Fill in random but valid data into the display plane property data struct for the current physical device
4136void GenerateRandomDisplays(std::vector<VkDisplayKHR>& disps) {
4137    disps.resize((rand() % 5) + 1);
4138    for (uint32_t i = 0; i < disps.size(); ++i) {
4139        disps[i] = CreateRandomDisplay();
4140    }
4141}
4142
4143// Compare the display plane property data structs
4144bool CompareDisplays(const std::vector<VkDisplayKHR>& disps1, const std::vector<VkDisplayKHR>& disps2) {
4145    if (disps1.size() != disps2.size()) return false;
4146    bool equal = true;
4147    for (uint32_t i = 0; i < disps1.size(); ++i) {
4148        equal = equal && disps1[i] == disps2[i];
4149    }
4150    return equal;
4151}
4152
4153// Test vGetDisplayPlaneSupportedDisplaysKHR where instance and ICD supports it, but device does not support it.
4154TEST(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRInstanceAndICDSupport) {
4155    FrameworkEnvironment env{};
4156    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4157    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4158    env.get_test_icd(0).physical_devices.push_back({});
4159    GenerateRandomDisplays(env.get_test_icd(0).physical_devices.back().displays);
4160
4161    InstWrapper instance(env.vulkan_functions);
4162    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4163    instance.CheckCreate();
4164
4165    PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR =
4166        instance.load("vkGetDisplayPlaneSupportedDisplaysKHR");
4167    ASSERT_NE(GetDisplayPlaneSupportedDisplaysKHR, nullptr);
4168
4169    uint32_t driver_count = 1;
4170    VkPhysicalDevice physical_device;
4171    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
4172    ASSERT_EQ(driver_count, 1U);
4173
4174    std::vector<VkDisplayKHR> disps{};
4175    uint32_t disp_count = 0;
4176    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneSupportedDisplaysKHR(physical_device, 0, &disp_count, nullptr));
4177    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().displays.size(), disp_count);
4178    disps.resize(disp_count);
4179    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneSupportedDisplaysKHR(physical_device, 0, &disp_count, disps.data()));
4180    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().displays.size(), disp_count);
4181
4182    ASSERT_TRUE(CompareDisplays(disps, env.get_test_icd(0).physical_devices.back().displays));
4183}
4184
4185// Test vkGetDisplayPlaneSupportedDisplaysKHR where instance supports it with some ICDs that both support
4186// and don't support it:
4187//    ICD 0 supports
4188//        Physical device 0 does not
4189//        Physical device 1 does
4190//        Physical device 2 does not
4191//    ICD 1 doesn't support
4192//        Physical device 3 does not
4193//    ICD 2 supports
4194//        Physical device 4 does not
4195//        Physical device 5 does not
4196//    ICD 3 supports
4197//        Physical device 6 does
4198TEST(LoaderInstPhysDevExts, GetDispPlaneSupDispsKHRMixed) {
4199    FrameworkEnvironment env{};
4200    const uint32_t max_icd_count = 4;
4201    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
4202    const uint32_t max_phys_devs = 7;
4203
4204    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4205        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
4206        auto& cur_icd = env.get_test_icd(icd);
4207        cur_icd.icd_api_version = VK_API_VERSION_1_0;
4208
4209        // ICD 1 should not have 1.1
4210        if (icd != 1) {
4211            cur_icd.icd_api_version = VK_API_VERSION_1_1;
4212            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4213        }
4214
4215        uint32_t rand_vendor_id;
4216        uint32_t rand_driver_vers;
4217        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
4218
4219        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
4220            uint32_t device_version = VK_API_VERSION_1_0;
4221            cur_icd.physical_devices.push_back({});
4222            auto& cur_dev = cur_icd.physical_devices.back();
4223
4224            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
4225            if ((icd == 0 && dev == 1) || icd == 3) {
4226                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
4227                device_version = VK_API_VERSION_1_1;
4228            }
4229
4230            // Still set physical device properties (so we can determine if device is correct API version)
4231            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
4232            GenerateRandomDisplays(cur_dev.displays);
4233        }
4234    }
4235
4236    InstWrapper instance(env.vulkan_functions);
4237    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4238    instance.CheckCreate();
4239
4240    PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR =
4241        instance.load("vkGetDisplayPlaneSupportedDisplaysKHR");
4242    ASSERT_NE(GetDisplayPlaneSupportedDisplaysKHR, nullptr);
4243
4244    uint32_t device_count = max_phys_devs;
4245    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
4246    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
4247    ASSERT_EQ(device_count, max_phys_devs);
4248
4249    for (uint32_t dev = 0; dev < device_count; ++dev) {
4250        VkPhysicalDeviceProperties pd_props{};
4251        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
4252
4253        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4254            auto& cur_icd = env.get_test_icd(icd);
4255            bool found = false;
4256            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
4257                auto& cur_dev = cur_icd.physical_devices[pd];
4258                // Find the ICD device matching the physical device we're looking at info for so we can compare the
4259                // physical devices info with the returned info.
4260                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
4261                    cur_dev.properties.deviceType == pd_props.deviceType &&
4262                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
4263                    cur_dev.properties.vendorID == pd_props.vendorID) {
4264                    std::vector<VkDisplayKHR> disps{};
4265                    uint32_t disp_count = 0;
4266                    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneSupportedDisplaysKHR(physical_devices[dev], 0, &disp_count, nullptr));
4267                    if (icd == 1) {
4268                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
4269                        // loader.
4270                        ASSERT_EQ(0U, disp_count);
4271                    } else {
4272                        ASSERT_EQ(cur_dev.displays.size(), disp_count);
4273                        disps.resize(disp_count);
4274                        ASSERT_EQ(VK_SUCCESS,
4275                                  GetDisplayPlaneSupportedDisplaysKHR(physical_devices[dev], 0, &disp_count, disps.data()));
4276                        ASSERT_EQ(cur_dev.displays.size(), disp_count);
4277
4278                        ASSERT_TRUE(CompareDisplays(disps, cur_dev.displays));
4279                    }
4280                    found = true;
4281                    break;
4282                }
4283            }
4284            if (found) {
4285                break;
4286            }
4287        }
4288    }
4289}
4290
4291// Test vkGetDisplayModePropertiesKHR where nothing supports it.
4292TEST(LoaderInstPhysDevExts, GetDispModePropsKHRNoSupport) {
4293    FrameworkEnvironment env{};
4294    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4295    env.get_test_icd(0).physical_devices.push_back({});
4296
4297    InstWrapper instance(env.vulkan_functions);
4298    instance.CheckCreate();
4299
4300    PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR = instance.load("vkGetDisplayModePropertiesKHR");
4301    ASSERT_EQ(GetDisplayModePropertiesKHR, nullptr);
4302}
4303
4304// Test vkGetDisplayModePropertiesKHR where instance supports it, but nothing else.
4305TEST(LoaderInstPhysDevExts, GetDispModePropsKHRNoICDSupport) {
4306    FrameworkEnvironment env{};
4307    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4308    env.get_test_icd(0).physical_devices.push_back({});
4309
4310    InstWrapper instance(env.vulkan_functions);
4311    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4312    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
4313
4314    PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR = instance.load("vkGetDisplayModePropertiesKHR");
4315    ASSERT_EQ(GetDisplayModePropertiesKHR, nullptr);
4316}
4317
4318// Fill in random but valid data into the display mode properties data struct for the current physical device
4319void GenerateRandomDisplayModeProps(std::vector<VkDisplayModePropertiesKHR>& disps) {
4320    disps.resize((rand() % 5) + 1);
4321    for (uint32_t i = 0; i < disps.size(); ++i) {
4322        disps[i].displayMode = CreateRandomDisplayMode();
4323        disps[i].parameters.visibleRegion.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4324        disps[i].parameters.visibleRegion.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4325        disps[i].parameters.refreshRate = 1 << (rand() % 8);
4326    }
4327}
4328
4329// Compare the display mode properties data structs
4330bool CompareDisplayModeProps(const std::vector<VkDisplayModePropertiesKHR>& disps1,
4331                             const std::vector<VkDisplayModePropertiesKHR>& disps2) {
4332    if (disps1.size() != disps2.size()) return false;
4333    bool equal = true;
4334    for (uint32_t i = 0; i < disps1.size(); ++i) {
4335        equal = equal && disps1[i].displayMode == disps2[i].displayMode;
4336        equal = equal && disps1[i].parameters.visibleRegion.width == disps2[i].parameters.visibleRegion.width;
4337        equal = equal && disps1[i].parameters.visibleRegion.height == disps2[i].parameters.visibleRegion.height;
4338        equal = equal && disps1[i].parameters.refreshRate == disps2[i].parameters.refreshRate;
4339    }
4340    return equal;
4341}
4342
4343// Test vGetDisplayModePropertiesKHR where instance and ICD supports it, but device does not support it.
4344TEST(LoaderInstPhysDevExts, GetDispModePropsKHRInstanceAndICDSupport) {
4345    FrameworkEnvironment env{};
4346    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4347    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4348    env.get_test_icd(0).physical_devices.push_back({});
4349    GenerateRandomDisplayModeProps(env.get_test_icd(0).physical_devices.back().display_mode_properties);
4350
4351    InstWrapper instance(env.vulkan_functions);
4352    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4353    instance.CheckCreate();
4354
4355    PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR = instance.load("vkGetDisplayModePropertiesKHR");
4356    ASSERT_NE(GetDisplayModePropertiesKHR, nullptr);
4357
4358    uint32_t driver_count = 1;
4359    VkPhysicalDevice physical_device;
4360    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
4361    ASSERT_EQ(driver_count, 1U);
4362
4363    std::vector<VkDisplayModePropertiesKHR> props{};
4364    uint32_t props_count = 0;
4365    ASSERT_EQ(VK_SUCCESS, GetDisplayModePropertiesKHR(physical_device, VK_NULL_HANDLE, &props_count, nullptr));
4366    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_mode_properties.size(), props_count);
4367    props.resize(props_count);
4368    ASSERT_EQ(VK_SUCCESS, GetDisplayModePropertiesKHR(physical_device, VK_NULL_HANDLE, &props_count, props.data()));
4369    ASSERT_EQ(env.get_test_icd(0).physical_devices.back().display_mode_properties.size(), props_count);
4370
4371    ASSERT_TRUE(CompareDisplayModeProps(props, env.get_test_icd(0).physical_devices.back().display_mode_properties));
4372}
4373
4374// Test vkGetDisplayModePropertiesKHR where instance supports it with some ICDs that both support
4375// and don't support it:
4376//    ICD 0 supports
4377//        Physical device 0 does not
4378//        Physical device 1 does
4379//        Physical device 2 does not
4380//    ICD 1 doesn't support
4381//        Physical device 3 does not
4382//    ICD 2 supports
4383//        Physical device 4 does not
4384//        Physical device 5 does not
4385//    ICD 3 supports
4386//        Physical device 6 does
4387TEST(LoaderInstPhysDevExts, GetDispModePropsKHRMixed) {
4388    FrameworkEnvironment env{};
4389    const uint32_t max_icd_count = 4;
4390    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
4391    const uint32_t max_phys_devs = 7;
4392
4393    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4394        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
4395        auto& cur_icd = env.get_test_icd(icd);
4396        cur_icd.icd_api_version = VK_API_VERSION_1_0;
4397
4398        // ICD 1 should not have 1.1
4399        if (icd != 1) {
4400            cur_icd.icd_api_version = VK_API_VERSION_1_1;
4401            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4402        }
4403
4404        uint32_t rand_vendor_id;
4405        uint32_t rand_driver_vers;
4406        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
4407
4408        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
4409            uint32_t device_version = VK_API_VERSION_1_0;
4410            cur_icd.physical_devices.push_back({});
4411            auto& cur_dev = cur_icd.physical_devices.back();
4412
4413            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
4414            if ((icd == 0 && dev == 1) || icd == 3) {
4415                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
4416                device_version = VK_API_VERSION_1_1;
4417            }
4418
4419            // Still set physical device properties (so we can determine if device is correct API version)
4420            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
4421            GenerateRandomDisplayModeProps(cur_dev.display_mode_properties);
4422        }
4423    }
4424
4425    InstWrapper instance(env.vulkan_functions);
4426    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4427    instance.CheckCreate();
4428
4429    PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR = instance.load("vkGetDisplayModePropertiesKHR");
4430    ASSERT_NE(GetDisplayModePropertiesKHR, nullptr);
4431
4432    uint32_t device_count = max_phys_devs;
4433    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
4434    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
4435    ASSERT_EQ(device_count, max_phys_devs);
4436
4437    for (uint32_t dev = 0; dev < device_count; ++dev) {
4438        VkPhysicalDeviceProperties pd_props{};
4439        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
4440
4441        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4442            auto& cur_icd = env.get_test_icd(icd);
4443            bool found = false;
4444            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
4445                auto& cur_dev = cur_icd.physical_devices[pd];
4446                // Find the ICD device matching the physical device we're looking at info for so we can compare the
4447                // physical devices info with the returned info.
4448                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
4449                    cur_dev.properties.deviceType == pd_props.deviceType &&
4450                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
4451                    cur_dev.properties.vendorID == pd_props.vendorID) {
4452                    uint32_t props_count = 0;
4453                    ASSERT_EQ(VK_SUCCESS,
4454                              GetDisplayModePropertiesKHR(physical_devices[dev], VK_NULL_HANDLE, &props_count, nullptr));
4455                    if (icd == 1) {
4456                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
4457                        // loader.
4458                        ASSERT_EQ(0U, props_count);
4459                    } else {
4460                        std::vector<VkDisplayModePropertiesKHR> props{};
4461                        ASSERT_EQ(cur_dev.display_mode_properties.size(), props_count);
4462                        props.resize(props_count);
4463                        ASSERT_EQ(VK_SUCCESS,
4464                                  GetDisplayModePropertiesKHR(physical_devices[dev], VK_NULL_HANDLE, &props_count, props.data()));
4465                        ASSERT_EQ(cur_dev.display_mode_properties.size(), props_count);
4466
4467                        ASSERT_TRUE(CompareDisplayModeProps(props, cur_dev.display_mode_properties));
4468                    }
4469                    found = true;
4470                    break;
4471                }
4472            }
4473            if (found) {
4474                break;
4475            }
4476        }
4477    }
4478}
4479
4480// Test vkCreateDisplayModeKHR where nothing supports it.
4481TEST(LoaderInstPhysDevExts, GetDispModesKHRNoSupport) {
4482    FrameworkEnvironment env{};
4483    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4484    env.get_test_icd(0).physical_devices.push_back({});
4485
4486    InstWrapper instance(env.vulkan_functions);
4487    instance.CheckCreate();
4488
4489    PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR = instance.load("vkCreateDisplayModeKHR");
4490    ASSERT_EQ(CreateDisplayModeKHR, nullptr);
4491}
4492
4493// Test vkCreateDisplayModeKHR where instance supports it, but nothing else.
4494TEST(LoaderInstPhysDevExts, GetDispModesKHRNoICDSupport) {
4495    FrameworkEnvironment env{};
4496    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4497    env.get_test_icd(0).physical_devices.push_back({});
4498
4499    InstWrapper instance(env.vulkan_functions);
4500    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4501    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
4502
4503    PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR = instance.load("vkCreateDisplayModeKHR");
4504    ASSERT_EQ(CreateDisplayModeKHR, nullptr);
4505}
4506
4507// Compare the display modes
4508bool CompareDisplayModes(const VkDisplayModeKHR& disps1, VkDisplayModeKHR& disps2) { return disps1 == disps2; }
4509
4510// Test vkCreateDisplayModeKHR where instance and ICD supports it, but device does not support it.
4511TEST(LoaderInstPhysDevExts, GetDispModesKHRInstanceAndICDSupport) {
4512    FrameworkEnvironment env{};
4513    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4514    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4515    env.get_test_icd(0).physical_devices.push_back({});
4516    env.get_test_icd(0).physical_devices.back().display_mode = CreateRandomDisplayMode();
4517
4518    InstWrapper instance(env.vulkan_functions);
4519    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4520    instance.CheckCreate();
4521
4522    PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR = instance.load("vkCreateDisplayModeKHR");
4523    ASSERT_NE(CreateDisplayModeKHR, nullptr);
4524
4525    uint32_t driver_count = 1;
4526    VkPhysicalDevice physical_device;
4527    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
4528    ASSERT_EQ(driver_count, 1U);
4529
4530    VkDisplayModeKHR mode{};
4531    VkDisplayModeCreateInfoKHR create_info{VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR};
4532    ASSERT_EQ(VK_SUCCESS, CreateDisplayModeKHR(physical_device, VK_NULL_HANDLE, &create_info, nullptr, &mode));
4533    ASSERT_TRUE(CompareDisplayModes(mode, env.get_test_icd(0).physical_devices.back().display_mode));
4534}
4535
4536// Test vkCreateDisplayModeKHR where instance supports it with some ICDs that both support
4537// and don't support it:
4538//    ICD 0 supports
4539//        Physical device 0 does not
4540//        Physical device 1 does
4541//        Physical device 2 does not
4542//    ICD 1 doesn't support
4543//        Physical device 3 does not
4544//    ICD 2 supports
4545//        Physical device 4 does not
4546//        Physical device 5 does not
4547//    ICD 3 supports
4548//        Physical device 6 does
4549TEST(LoaderInstPhysDevExts, GetDispModesKHRMixed) {
4550    FrameworkEnvironment env{};
4551    const uint32_t max_icd_count = 4;
4552    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
4553    const uint32_t max_phys_devs = 7;
4554
4555    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4556        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
4557        auto& cur_icd = env.get_test_icd(icd);
4558        cur_icd.icd_api_version = VK_API_VERSION_1_0;
4559
4560        // ICD 1 should not have 1.1
4561        if (icd != 1) {
4562            cur_icd.icd_api_version = VK_API_VERSION_1_1;
4563            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4564        }
4565
4566        uint32_t rand_vendor_id;
4567        uint32_t rand_driver_vers;
4568        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
4569
4570        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
4571            uint32_t device_version = VK_API_VERSION_1_0;
4572            cur_icd.physical_devices.push_back({});
4573            auto& cur_dev = cur_icd.physical_devices.back();
4574
4575            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
4576            if ((icd == 0 && dev == 1) || icd == 3) {
4577                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
4578                device_version = VK_API_VERSION_1_1;
4579            }
4580
4581            // Still set physical device properties (so we can determine if device is correct API version)
4582            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
4583            cur_dev.display_mode = CreateRandomDisplayMode();
4584        }
4585    }
4586
4587    InstWrapper instance(env.vulkan_functions);
4588    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4589    instance.CheckCreate();
4590
4591    PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR = instance.load("vkCreateDisplayModeKHR");
4592    ASSERT_NE(CreateDisplayModeKHR, nullptr);
4593
4594    uint32_t device_count = max_phys_devs;
4595    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
4596    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
4597    ASSERT_EQ(device_count, max_phys_devs);
4598
4599    for (uint32_t dev = 0; dev < device_count; ++dev) {
4600        VkPhysicalDeviceProperties pd_props{};
4601        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
4602
4603        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4604            auto& cur_icd = env.get_test_icd(icd);
4605            bool found = false;
4606            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
4607                auto& cur_dev = cur_icd.physical_devices[pd];
4608                // Find the ICD device matching the physical device we're looking at info for so we can compare the
4609                // physical devices info with the returned info.
4610                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
4611                    cur_dev.properties.deviceType == pd_props.deviceType &&
4612                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
4613                    cur_dev.properties.vendorID == pd_props.vendorID) {
4614                    VkDisplayModeKHR mode{};
4615                    VkDisplayModeCreateInfoKHR create_info{VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR};
4616                    if (icd == 1) {
4617                        // Unsupported ICD should return initialization failed (instead of crash)
4618                        ASSERT_EQ(VK_ERROR_INITIALIZATION_FAILED,
4619                                  CreateDisplayModeKHR(physical_devices[dev], VK_NULL_HANDLE, &create_info, nullptr, &mode));
4620                    } else {
4621                        ASSERT_EQ(VK_SUCCESS,
4622                                  CreateDisplayModeKHR(physical_devices[dev], VK_NULL_HANDLE, &create_info, nullptr, &mode));
4623                        ASSERT_TRUE(CompareDisplayModes(mode, cur_dev.display_mode));
4624                    }
4625                    found = true;
4626                    break;
4627                }
4628            }
4629            if (found) {
4630                break;
4631            }
4632        }
4633    }
4634}
4635
4636// Test vkGetDisplayPlaneCapabilitiesKHR where nothing supports it.
4637TEST(LoaderInstPhysDevExts, GetDispPlaneCapsKHRNoSupport) {
4638    FrameworkEnvironment env{};
4639    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4640    env.get_test_icd(0).physical_devices.push_back({});
4641
4642    InstWrapper instance(env.vulkan_functions);
4643    instance.CheckCreate();
4644
4645    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
4646    ASSERT_EQ(GetDisplayPlaneCapabilitiesKHR, nullptr);
4647}
4648
4649// Test vkGetDisplayPlaneCapabilitiesKHR where instance supports it, but nothing else.
4650TEST(LoaderInstPhysDevExts, GetDispPlaneCapsKHRNoICDSupport) {
4651    FrameworkEnvironment env{};
4652    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4653    env.get_test_icd(0).physical_devices.push_back({});
4654
4655    InstWrapper instance(env.vulkan_functions);
4656    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4657    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
4658
4659    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
4660    ASSERT_EQ(GetDisplayPlaneCapabilitiesKHR, nullptr);
4661}
4662
4663// Fill in random but valid data into the display plane caps for the current physical device
4664void GenerateRandomDisplayPlaneCaps(VkDisplayPlaneCapabilitiesKHR& caps) {
4665    caps.supportedAlpha = static_cast<VkDisplayPlaneAlphaFlagsKHR>((rand() % 0xFFFFFFF) + 1);
4666    caps.minSrcPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4667    caps.minSrcPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4668    caps.maxSrcPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4669    caps.maxSrcPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4670    caps.minSrcExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4671    caps.minSrcExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4672    caps.maxSrcExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4673    caps.maxSrcExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4674    caps.minDstPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4675    caps.minDstPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4676    caps.maxDstPosition.x = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4677    caps.maxDstPosition.y = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4678    caps.minDstExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4679    caps.minDstExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4680    caps.maxDstExtent.width = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4681    caps.maxDstExtent.height = static_cast<uint32_t>((rand() % 0xFFFFFFF) + 1);
4682}
4683
4684// Compare the display plane caps
4685bool CompareDisplayPlaneCaps(const VkDisplayPlaneCapabilitiesKHR& caps1, VkDisplayPlaneCapabilitiesKHR& caps2,
4686                             bool supported = true) {
4687    bool equal = true;
4688    if (supported) {
4689        equal = equal && caps1.supportedAlpha == caps2.supportedAlpha;
4690        equal = equal && caps1.minSrcPosition.x == caps2.minSrcPosition.x;
4691        equal = equal && caps1.minSrcPosition.y == caps2.minSrcPosition.y;
4692        equal = equal && caps1.maxSrcPosition.x == caps2.maxSrcPosition.x;
4693        equal = equal && caps1.maxSrcPosition.y == caps2.maxSrcPosition.y;
4694        equal = equal && caps1.minSrcExtent.width == caps2.minSrcExtent.width;
4695        equal = equal && caps1.minSrcExtent.height == caps2.minSrcExtent.height;
4696        equal = equal && caps1.maxSrcExtent.width == caps2.maxSrcExtent.width;
4697        equal = equal && caps1.maxSrcExtent.height == caps2.maxSrcExtent.height;
4698        equal = equal && caps1.minDstPosition.x == caps2.minDstPosition.x;
4699        equal = equal && caps1.minDstPosition.y == caps2.minDstPosition.y;
4700        equal = equal && caps1.maxDstPosition.x == caps2.maxDstPosition.x;
4701        equal = equal && caps1.maxDstPosition.y == caps2.maxDstPosition.y;
4702        equal = equal && caps1.minDstExtent.width == caps2.minDstExtent.width;
4703        equal = equal && caps1.minDstExtent.height == caps2.minDstExtent.height;
4704        equal = equal && caps1.maxDstExtent.width == caps2.maxDstExtent.width;
4705        equal = equal && caps1.maxDstExtent.height == caps2.maxDstExtent.height;
4706    } else {
4707        equal = equal && caps1.supportedAlpha == 0;
4708        equal = equal && caps1.minSrcPosition.x == 0;
4709        equal = equal && caps1.minSrcPosition.y == 0;
4710        equal = equal && caps1.maxSrcPosition.x == 0;
4711        equal = equal && caps1.maxSrcPosition.y == 0;
4712        equal = equal && caps1.minSrcExtent.width == 0;
4713        equal = equal && caps1.minSrcExtent.height == 0;
4714        equal = equal && caps1.maxSrcExtent.width == 0;
4715        equal = equal && caps1.maxSrcExtent.height == 0;
4716        equal = equal && caps1.minDstPosition.x == 0;
4717        equal = equal && caps1.minDstPosition.y == 0;
4718        equal = equal && caps1.maxDstPosition.x == 0;
4719        equal = equal && caps1.maxDstPosition.y == 0;
4720        equal = equal && caps1.minDstExtent.width == 0;
4721        equal = equal && caps1.minDstExtent.height == 0;
4722        equal = equal && caps1.maxDstExtent.width == 0;
4723        equal = equal && caps1.maxDstExtent.height == 0;
4724    }
4725    return equal;
4726}
4727
4728// Test vkGetDisplayPlaneCapabilitiesKHR where instance and ICD supports it, but device does not support it.
4729TEST(LoaderInstPhysDevExts, GetDispPlaneCapsKHRInstanceAndICDSupport) {
4730    FrameworkEnvironment env{};
4731    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4732    env.get_test_icd(0).add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4733    env.get_test_icd(0).physical_devices.push_back({});
4734    GenerateRandomDisplayPlaneCaps(env.get_test_icd(0).physical_devices.back().display_plane_capabilities);
4735
4736    InstWrapper instance(env.vulkan_functions);
4737    instance.create_info.add_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4738    instance.CheckCreate();
4739
4740    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
4741    ASSERT_NE(GetDisplayPlaneCapabilitiesKHR, nullptr);
4742
4743    uint32_t driver_count = 1;
4744    VkPhysicalDevice physical_device;
4745    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
4746    ASSERT_EQ(driver_count, 1U);
4747
4748    VkDisplayPlaneCapabilitiesKHR caps{};
4749    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilitiesKHR(physical_device, 0, 0, &caps));
4750    ASSERT_TRUE(CompareDisplayPlaneCaps(caps, env.get_test_icd(0).physical_devices.back().display_plane_capabilities));
4751}
4752
4753// Test vkGetDisplayPlaneCapabilitiesKHR where instance supports it with some ICDs that both support
4754// and don't support it:
4755//    ICD 0 supports
4756//        Physical device 0 does not
4757//        Physical device 1 does
4758//        Physical device 2 does not
4759//    ICD 1 doesn't support
4760//        Physical device 3 does not
4761//    ICD 2 supports
4762//        Physical device 4 does not
4763//        Physical device 5 does not
4764//    ICD 3 supports
4765//        Physical device 6 does
4766TEST(LoaderInstPhysDevExts, GetDispPlaneCapsKHRMixed) {
4767    FrameworkEnvironment env{};
4768    const uint32_t max_icd_count = 4;
4769    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
4770    const uint32_t max_phys_devs = 7;
4771
4772    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4773        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
4774        auto& cur_icd = env.get_test_icd(icd);
4775        cur_icd.icd_api_version = VK_API_VERSION_1_0;
4776
4777        // ICD 1 should not have 1.1
4778        if (icd != 1) {
4779            cur_icd.icd_api_version = VK_API_VERSION_1_1;
4780            cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4781        }
4782
4783        uint32_t rand_vendor_id;
4784        uint32_t rand_driver_vers;
4785        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
4786
4787        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
4788            uint32_t device_version = VK_API_VERSION_1_0;
4789            cur_icd.physical_devices.push_back({});
4790            auto& cur_dev = cur_icd.physical_devices.back();
4791
4792            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
4793            if ((icd == 0 && dev == 1) || icd == 3) {
4794                cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
4795                device_version = VK_API_VERSION_1_1;
4796            }
4797
4798            // Still set physical device properties (so we can determine if device is correct API version)
4799            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
4800            GenerateRandomDisplayPlaneCaps(cur_dev.display_plane_capabilities);
4801        }
4802    }
4803
4804    InstWrapper instance(env.vulkan_functions);
4805    instance.create_info.add_extension(VK_KHR_DISPLAY_EXTENSION_NAME);
4806    instance.CheckCreate();
4807
4808    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
4809    ASSERT_NE(GetDisplayPlaneCapabilitiesKHR, nullptr);
4810
4811    uint32_t device_count = max_phys_devs;
4812    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
4813    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
4814    ASSERT_EQ(device_count, max_phys_devs);
4815
4816    for (uint32_t dev = 0; dev < device_count; ++dev) {
4817        VkPhysicalDeviceProperties pd_props{};
4818        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
4819
4820        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4821            auto& cur_icd = env.get_test_icd(icd);
4822            bool found = false;
4823            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
4824                auto& cur_dev = cur_icd.physical_devices[pd];
4825                // Find the ICD device matching the physical device we're looking at info for so we can compare the
4826                // physical devices info with the returned info.
4827                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
4828                    cur_dev.properties.deviceType == pd_props.deviceType &&
4829                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
4830                    cur_dev.properties.vendorID == pd_props.vendorID) {
4831                    VkDisplayPlaneCapabilitiesKHR caps{};
4832                    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilitiesKHR(physical_devices[dev], 0, 0, &caps));
4833                    ASSERT_TRUE(CompareDisplayPlaneCaps(caps, cur_dev.display_plane_capabilities, icd != 1));
4834                    found = true;
4835                    break;
4836                }
4837            }
4838            if (found) {
4839                break;
4840            }
4841        }
4842    }
4843}
4844
4845//
4846// VK_KHR_get_display_properties2
4847//
4848
4849// Test vkGetPhysicalDeviceDisplayProperties2KHR where nothing supports it.
4850TEST(LoaderInstPhysDevExts, PhysDevDispProps2KHRNoSupport) {
4851    FrameworkEnvironment env{};
4852    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4853    env.get_test_icd(0).physical_devices.push_back({});
4854
4855    InstWrapper instance(env.vulkan_functions);
4856    instance.CheckCreate();
4857
4858    PFN_vkGetPhysicalDeviceDisplayProperties2KHR GetPhysicalDeviceDisplayProperties2KHR =
4859        instance.load("vkGetPhysicalDeviceDisplayProperties2KHR");
4860    ASSERT_EQ(GetPhysicalDeviceDisplayProperties2KHR, nullptr);
4861}
4862
4863// Test vkGetPhysicalDeviceDisplayProperties2KHR where instance supports it, but nothing else.
4864TEST(LoaderInstPhysDevExts, PhysDevDispProps2KHRNoICDSupport) {
4865    FrameworkEnvironment env{};
4866    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4867    env.get_test_icd(0).physical_devices.push_back({});
4868
4869    InstWrapper instance(env.vulkan_functions);
4870    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
4871    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
4872
4873    PFN_vkGetPhysicalDeviceDisplayProperties2KHR GetPhysicalDeviceDisplayProperties2KHR =
4874        instance.load("vkGetPhysicalDeviceDisplayProperties2KHR");
4875    ASSERT_EQ(GetPhysicalDeviceDisplayProperties2KHR, nullptr);
4876}
4877
4878// Compare the display property data structs
4879bool CompareDisplayPropData(const std::vector<VkDisplayPropertiesKHR>& props1, const std::vector<VkDisplayProperties2KHR>& props2) {
4880    if (props1.size() != props2.size()) return false;
4881    bool equal = true;
4882    for (uint32_t i = 0; i < props1.size(); ++i) {
4883        equal = equal && props1[i].display == props2[i].displayProperties.display;
4884        equal = equal && props1[i].physicalDimensions.width == props2[i].displayProperties.physicalDimensions.width;
4885        equal = equal && props1[i].physicalDimensions.height == props2[i].displayProperties.physicalDimensions.height;
4886        equal = equal && props1[i].physicalResolution.width == props2[i].displayProperties.physicalResolution.width;
4887        equal = equal && props1[i].physicalResolution.height == props2[i].displayProperties.physicalResolution.height;
4888        equal = equal && props1[i].supportedTransforms == props2[i].displayProperties.supportedTransforms;
4889        equal = equal && props1[i].planeReorderPossible == props2[i].displayProperties.planeReorderPossible;
4890        equal = equal && props1[i].persistentContent == props2[i].displayProperties.persistentContent;
4891    }
4892    return equal;
4893}
4894
4895// Test vGetPhysicalDeviceDisplayProperties2KHR where instance and ICD supports it, but device does not support it.
4896TEST(LoaderInstPhysDevExts, PhysDevDispProps2KHRInstanceAndICDSupport) {
4897    FrameworkEnvironment env{};
4898    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
4899    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
4900    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
4901    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
4902    env.get_test_icd(0).physical_devices.push_back({});
4903    FillInRandomDisplayPropData(env.get_test_icd(0).physical_devices.back().display_properties);
4904
4905    InstWrapper instance(env.vulkan_functions);
4906    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
4907    instance.CheckCreate();
4908
4909    PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR =
4910        instance.load("vkGetPhysicalDeviceDisplayPropertiesKHR");
4911    ASSERT_NE(GetPhysicalDeviceDisplayPropertiesKHR, nullptr);
4912    PFN_vkGetPhysicalDeviceDisplayProperties2KHR GetPhysicalDeviceDisplayProperties2KHR =
4913        instance.load("vkGetPhysicalDeviceDisplayProperties2KHR");
4914    ASSERT_NE(GetPhysicalDeviceDisplayProperties2KHR, nullptr);
4915
4916    uint32_t driver_count = 1;
4917    VkPhysicalDevice physical_device;
4918    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
4919    ASSERT_EQ(driver_count, 1U);
4920
4921    std::vector<VkDisplayPropertiesKHR> props{};
4922    uint32_t prop_count = 0;
4923    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPropertiesKHR(physical_device, &prop_count, nullptr));
4924    ASSERT_NE(0U, prop_count);
4925    props.resize(prop_count);
4926    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPropertiesKHR(physical_device, &prop_count, props.data()));
4927
4928    std::vector<VkDisplayProperties2KHR> props2{};
4929    uint32_t prop_count_2 = 0;
4930    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2KHR(physical_device, &prop_count_2, nullptr));
4931    ASSERT_EQ(prop_count, prop_count_2);
4932    props2.resize(prop_count_2, {VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR});
4933    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2KHR(physical_device, &prop_count_2, props2.data()));
4934    ASSERT_EQ(prop_count, prop_count_2);
4935
4936    ASSERT_TRUE(CompareDisplayPropData(props, props2));
4937}
4938
4939// Test vkGetPhysicalDeviceDisplayProperties2KHR where instance supports it with some ICDs that both support
4940// and don't support it:
4941//    ICD 0 supports
4942//        Physical device 0 does not
4943//        Physical device 1 does
4944//        Physical device 2 does not
4945//    ICD 1 doesn't support
4946//        Physical device 3 does not
4947//    ICD 2 supports
4948//        Physical device 4 does not
4949//        Physical device 5 does not
4950//    ICD 3 supports
4951//        Physical device 6 does
4952TEST(LoaderInstPhysDevExts, PhysDevDispProps2KHRMixed) {
4953    FrameworkEnvironment env{};
4954    const uint32_t max_icd_count = 4;
4955    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
4956    const uint32_t max_phys_devs = 7;
4957
4958    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
4959        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
4960        auto& cur_icd = env.get_test_icd(icd);
4961        cur_icd.icd_api_version = VK_API_VERSION_1_0;
4962        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
4963
4964        // ICD 1 should not have 1.1
4965        if (icd != 1) {
4966            cur_icd.icd_api_version = VK_API_VERSION_1_1;
4967            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
4968        }
4969
4970        uint32_t rand_vendor_id;
4971        uint32_t rand_driver_vers;
4972        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
4973
4974        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
4975            uint32_t device_version = VK_API_VERSION_1_0;
4976            cur_icd.physical_devices.push_back({});
4977            auto& cur_dev = cur_icd.physical_devices.back();
4978            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
4979
4980            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
4981            if ((icd == 0 && dev == 1) || icd == 3) {
4982                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
4983                device_version = VK_API_VERSION_1_1;
4984            }
4985
4986            // Still set physical device properties (so we can determine if device is correct API version)
4987            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
4988            FillInRandomDisplayPropData(cur_dev.display_properties);
4989        }
4990    }
4991
4992    InstWrapper instance(env.vulkan_functions);
4993    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
4994    instance.CheckCreate();
4995
4996    PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR =
4997        instance.load("vkGetPhysicalDeviceDisplayPropertiesKHR");
4998    ASSERT_NE(GetPhysicalDeviceDisplayPropertiesKHR, nullptr);
4999    PFN_vkGetPhysicalDeviceDisplayProperties2KHR GetPhysicalDeviceDisplayProperties2KHR =
5000        instance.load("vkGetPhysicalDeviceDisplayProperties2KHR");
5001    ASSERT_NE(GetPhysicalDeviceDisplayProperties2KHR, nullptr);
5002
5003    uint32_t device_count = max_phys_devs;
5004    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
5005    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
5006    ASSERT_EQ(device_count, max_phys_devs);
5007
5008    for (uint32_t dev = 0; dev < device_count; ++dev) {
5009        std::vector<VkDisplayPropertiesKHR> props{};
5010        uint32_t prop_count = 0;
5011        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPropertiesKHR(physical_devices[dev], &prop_count, nullptr));
5012        ASSERT_NE(0U, prop_count);
5013        props.resize(prop_count);
5014        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPropertiesKHR(physical_devices[dev], &prop_count, props.data()));
5015
5016        std::vector<VkDisplayProperties2KHR> props2{};
5017        uint32_t prop_count_2 = 0;
5018        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2KHR(physical_devices[dev], &prop_count_2, nullptr));
5019        ASSERT_EQ(prop_count, prop_count_2);
5020        props2.resize(prop_count_2, {VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR});
5021        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayProperties2KHR(physical_devices[dev], &prop_count_2, props2.data()));
5022        ASSERT_EQ(prop_count, prop_count_2);
5023
5024        ASSERT_TRUE(CompareDisplayPropData(props, props2));
5025    }
5026}
5027
5028// Test vkGetPhysicalDeviceDisplayPlaneProperties2KHR where nothing supports it.
5029TEST(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRNoSupport) {
5030    FrameworkEnvironment env{};
5031    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5032    env.get_test_icd(0).physical_devices.push_back({});
5033
5034    InstWrapper instance(env.vulkan_functions);
5035    instance.CheckCreate();
5036
5037    PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR GetPhysicalDeviceDisplayPlaneProperties2KHR =
5038        instance.load("vkGetPhysicalDeviceDisplayPlaneProperties2KHR");
5039    ASSERT_EQ(GetPhysicalDeviceDisplayPlaneProperties2KHR, nullptr);
5040}
5041
5042// Test vkGetPhysicalDeviceDisplayPlaneProperties2KHR where instance supports it, but nothing else.
5043TEST(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRNoICDSupport) {
5044    FrameworkEnvironment env{};
5045    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5046    env.get_test_icd(0).physical_devices.push_back({});
5047
5048    InstWrapper instance(env.vulkan_functions);
5049    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
5050    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
5051
5052    PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR GetPhysicalDeviceDisplayPlaneProperties2KHR =
5053        instance.load("vkGetPhysicalDeviceDisplayPlaneProperties2KHR");
5054    ASSERT_EQ(GetPhysicalDeviceDisplayPlaneProperties2KHR, nullptr);
5055}
5056
5057// Compare the display plane property data structs
5058bool CompareDisplayPlanePropData(const std::vector<VkDisplayPlanePropertiesKHR>& props1,
5059                                 const std::vector<VkDisplayPlaneProperties2KHR>& props2) {
5060    if (props1.size() != props2.size()) return false;
5061    bool equal = true;
5062    for (uint32_t i = 0; i < props1.size(); ++i) {
5063        equal = equal && props1[i].currentDisplay == props2[i].displayPlaneProperties.currentDisplay;
5064        equal = equal && props1[i].currentStackIndex == props2[i].displayPlaneProperties.currentStackIndex;
5065    }
5066    return equal;
5067}
5068
5069// Test vGetPhysicalDeviceDisplayPlaneProperties2KHR where instance and ICD supports it, but device does not support it.
5070TEST(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRInstanceAndICDSupport) {
5071    FrameworkEnvironment env{};
5072    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5073    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
5074    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
5075    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
5076    env.get_test_icd(0).physical_devices.push_back({});
5077    FillInRandomDisplayPlanePropData(env.get_test_icd(0).physical_devices.back().display_plane_properties);
5078
5079    InstWrapper instance(env.vulkan_functions);
5080    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5081    instance.CheckCreate();
5082
5083    PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR =
5084        instance.load("vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
5085    ASSERT_NE(GetPhysicalDeviceDisplayPlanePropertiesKHR, nullptr);
5086    PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR GetPhysicalDeviceDisplayPlaneProperties2KHR =
5087        instance.load("vkGetPhysicalDeviceDisplayPlaneProperties2KHR");
5088    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties2KHR, nullptr);
5089
5090    uint32_t driver_count = 1;
5091    VkPhysicalDevice physical_device;
5092    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
5093    ASSERT_EQ(driver_count, 1U);
5094
5095    std::vector<VkDisplayPlanePropertiesKHR> props{};
5096    uint32_t prop_count = 0;
5097    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &prop_count, nullptr));
5098    ASSERT_NE(0U, prop_count);
5099    props.resize(prop_count);
5100    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &prop_count, props.data()));
5101
5102    std::vector<VkDisplayPlaneProperties2KHR> props2{};
5103    uint32_t prop_count2 = 0;
5104    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2KHR(physical_device, &prop_count2, nullptr));
5105    ASSERT_EQ(prop_count, prop_count2);
5106    props2.resize(prop_count2, {VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR});
5107    ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2KHR(physical_device, &prop_count2, props2.data()));
5108
5109    ASSERT_TRUE(CompareDisplayPlanePropData(props, props2));
5110}
5111
5112// Test vkGetPhysicalDeviceDisplayPlaneProperties2KHR where instance supports it with some ICDs that both support
5113// and don't support it:
5114//    ICD 0 supports
5115//        Physical device 0 does not
5116//        Physical device 1 does
5117//        Physical device 2 does not
5118//    ICD 1 doesn't support
5119//        Physical device 3 does not
5120//    ICD 2 supports
5121//        Physical device 4 does not
5122//        Physical device 5 does not
5123//    ICD 3 supports
5124//        Physical device 6 does
5125TEST(LoaderInstPhysDevExts, PhysDevDispPlaneProps2KHRMixed) {
5126    FrameworkEnvironment env{};
5127    const uint32_t max_icd_count = 4;
5128    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
5129    const uint32_t max_phys_devs = 7;
5130
5131    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
5132        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
5133        auto& cur_icd = env.get_test_icd(icd);
5134        cur_icd.icd_api_version = VK_API_VERSION_1_0;
5135        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
5136
5137        // ICD 1 should not have 1.1
5138        if (icd != 1) {
5139            cur_icd.icd_api_version = VK_API_VERSION_1_1;
5140            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5141        }
5142
5143        uint32_t rand_vendor_id;
5144        uint32_t rand_driver_vers;
5145        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
5146
5147        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
5148            uint32_t device_version = VK_API_VERSION_1_0;
5149            cur_icd.physical_devices.push_back({});
5150            auto& cur_dev = cur_icd.physical_devices.back();
5151            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
5152
5153            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
5154            if ((icd == 0 && dev == 1) || icd == 3) {
5155                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
5156                device_version = VK_API_VERSION_1_1;
5157            }
5158
5159            // Still set physical device properties (so we can determine if device is correct API version)
5160            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
5161            FillInRandomDisplayPlanePropData(cur_dev.display_plane_properties);
5162        }
5163    }
5164
5165    InstWrapper instance(env.vulkan_functions);
5166    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5167    instance.CheckCreate();
5168
5169    PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR =
5170        instance.load("vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
5171    ASSERT_NE(GetPhysicalDeviceDisplayPlanePropertiesKHR, nullptr);
5172    PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR GetPhysicalDeviceDisplayPlaneProperties2KHR =
5173        instance.load("vkGetPhysicalDeviceDisplayPlaneProperties2KHR");
5174    ASSERT_NE(GetPhysicalDeviceDisplayPlaneProperties2KHR, nullptr);
5175
5176    uint32_t device_count = max_phys_devs;
5177    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
5178    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
5179    ASSERT_EQ(device_count, max_phys_devs);
5180
5181    for (uint32_t dev = 0; dev < device_count; ++dev) {
5182        std::vector<VkDisplayPlanePropertiesKHR> props{};
5183        uint32_t prop_count = 0;
5184        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_devices[dev], &prop_count, nullptr));
5185        ASSERT_NE(0U, prop_count);
5186        props.resize(prop_count);
5187        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlanePropertiesKHR(physical_devices[dev], &prop_count, props.data()));
5188
5189        std::vector<VkDisplayPlaneProperties2KHR> props2{};
5190        uint32_t prop_count2 = 0;
5191        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2KHR(physical_devices[dev], &prop_count2, nullptr));
5192        ASSERT_EQ(prop_count, prop_count2);
5193        props2.resize(prop_count2, {VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR});
5194        ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceDisplayPlaneProperties2KHR(physical_devices[dev], &prop_count2, props2.data()));
5195
5196        ASSERT_TRUE(CompareDisplayPlanePropData(props, props2));
5197    }
5198}
5199
5200// Test vkGetDisplayModeProperties2KHR where nothing supports it.
5201TEST(LoaderInstPhysDevExts, GetDispModeProps2KHRNoSupport) {
5202    FrameworkEnvironment env{};
5203    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5204    env.get_test_icd(0).physical_devices.push_back({});
5205
5206    InstWrapper instance(env.vulkan_functions);
5207    instance.CheckCreate();
5208
5209    PFN_vkGetDisplayModeProperties2KHR GetDisplayModeProperties2KHR = instance.load("vkGetDisplayModeProperties2KHR");
5210    ASSERT_EQ(GetDisplayModeProperties2KHR, nullptr);
5211}
5212
5213// Test vkGetDisplayModeProperties2KHR where instance supports it, but nothing else.
5214TEST(LoaderInstPhysDevExts, GetDispModeProps2KHRNoICDSupport) {
5215    FrameworkEnvironment env{};
5216    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5217    env.get_test_icd(0).physical_devices.push_back({});
5218
5219    InstWrapper instance(env.vulkan_functions);
5220    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
5221    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
5222
5223    PFN_vkGetDisplayModeProperties2KHR GetDisplayModeProperties2KHR = instance.load("vkGetDisplayModeProperties2KHR");
5224    ASSERT_EQ(GetDisplayModeProperties2KHR, nullptr);
5225}
5226
5227// Compare the display mode properties data structs
5228bool CompareDisplayModeProps(const std::vector<VkDisplayModePropertiesKHR>& disps1,
5229                             const std::vector<VkDisplayModeProperties2KHR>& disps2) {
5230    if (disps1.size() != disps2.size()) return false;
5231
5232    bool equal = true;
5233    for (uint32_t i = 0; i < disps1.size(); ++i) {
5234        equal = equal && disps1[i].displayMode == disps2[i].displayModeProperties.displayMode;
5235        equal = equal && disps1[i].parameters.visibleRegion.width == disps2[i].displayModeProperties.parameters.visibleRegion.width;
5236        equal =
5237            equal && disps1[i].parameters.visibleRegion.height == disps2[i].displayModeProperties.parameters.visibleRegion.height;
5238        equal = equal && disps1[i].parameters.refreshRate == disps2[i].displayModeProperties.parameters.refreshRate;
5239    }
5240    return equal;
5241}
5242
5243// Test vGetDisplayModeProperties2KHR where instance and ICD supports it, but device does not support it.
5244TEST(LoaderInstPhysDevExts, GetDispModeProps2KHRInstanceAndICDSupport) {
5245    FrameworkEnvironment env{};
5246    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5247    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
5248    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
5249    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
5250    env.get_test_icd(0).physical_devices.push_back({});
5251    GenerateRandomDisplayModeProps(env.get_test_icd(0).physical_devices.back().display_mode_properties);
5252
5253    InstWrapper instance(env.vulkan_functions);
5254    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5255    instance.CheckCreate();
5256
5257    PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR = instance.load("vkGetDisplayModePropertiesKHR");
5258    ASSERT_NE(GetDisplayModePropertiesKHR, nullptr);
5259    PFN_vkGetDisplayModeProperties2KHR GetDisplayModeProperties2KHR = instance.load("vkGetDisplayModeProperties2KHR");
5260    ASSERT_NE(GetDisplayModeProperties2KHR, nullptr);
5261
5262    uint32_t driver_count = 1;
5263    VkPhysicalDevice physical_device;
5264    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
5265    ASSERT_EQ(driver_count, 1U);
5266
5267    std::vector<VkDisplayModePropertiesKHR> props{};
5268    uint32_t props_count1 = 0;
5269    ASSERT_EQ(VK_SUCCESS, GetDisplayModePropertiesKHR(physical_device, VK_NULL_HANDLE, &props_count1, nullptr));
5270    ASSERT_NE(0U, props_count1);
5271    props.resize(props_count1);
5272    ASSERT_EQ(VK_SUCCESS, GetDisplayModePropertiesKHR(physical_device, VK_NULL_HANDLE, &props_count1, props.data()));
5273
5274    std::vector<VkDisplayModeProperties2KHR> props2{};
5275    uint32_t props_count2 = 0;
5276    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2KHR(physical_device, VK_NULL_HANDLE, &props_count2, nullptr));
5277    ASSERT_EQ(props_count1, props_count2);
5278    props2.resize(props_count2, {VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR});
5279    ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2KHR(physical_device, VK_NULL_HANDLE, &props_count2, props2.data()));
5280
5281    ASSERT_TRUE(CompareDisplayModeProps(props, props2));
5282}
5283
5284// Test vkGetDisplayModeProperties2KHR where instance supports it with some ICDs that both support
5285// and don't support it:
5286//    ICD 0 supports
5287//        Physical device 0 does not
5288//        Physical device 1 does
5289//        Physical device 2 does not
5290//    ICD 1 doesn't support
5291//        Physical device 3 does not
5292//    ICD 2 supports
5293//        Physical device 4 does not
5294//        Physical device 5 does not
5295//    ICD 3 supports
5296//        Physical device 6 does
5297TEST(LoaderInstPhysDevExts, GetDispModeProps2KHRMixed) {
5298    FrameworkEnvironment env{};
5299    const uint32_t max_icd_count = 4;
5300    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
5301    const uint32_t max_phys_devs = 7;
5302
5303    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
5304        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
5305        auto& cur_icd = env.get_test_icd(icd);
5306        cur_icd.icd_api_version = VK_API_VERSION_1_0;
5307        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
5308
5309        // ICD 1 should not have 1.1
5310        if (icd != 1) {
5311            cur_icd.icd_api_version = VK_API_VERSION_1_1;
5312            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5313        }
5314
5315        uint32_t rand_vendor_id;
5316        uint32_t rand_driver_vers;
5317        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
5318
5319        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
5320            uint32_t device_version = VK_API_VERSION_1_0;
5321            cur_icd.physical_devices.push_back({});
5322            auto& cur_dev = cur_icd.physical_devices.back();
5323            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
5324
5325            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
5326            if ((icd == 0 && dev == 1) || icd == 3) {
5327                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
5328                device_version = VK_API_VERSION_1_1;
5329            }
5330
5331            // Still set physical device properties (so we can determine if device is correct API version)
5332            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
5333            GenerateRandomDisplayModeProps(cur_dev.display_mode_properties);
5334        }
5335    }
5336
5337    InstWrapper instance(env.vulkan_functions);
5338    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5339    instance.CheckCreate();
5340
5341    PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR = instance.load("vkGetDisplayModePropertiesKHR");
5342    ASSERT_NE(GetDisplayModePropertiesKHR, nullptr);
5343    PFN_vkGetDisplayModeProperties2KHR GetDisplayModeProperties2KHR = instance.load("vkGetDisplayModeProperties2KHR");
5344    ASSERT_NE(GetDisplayModeProperties2KHR, nullptr);
5345
5346    uint32_t device_count = max_phys_devs;
5347    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
5348    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
5349    ASSERT_EQ(device_count, max_phys_devs);
5350
5351    for (uint32_t dev = 0; dev < device_count; ++dev) {
5352        std::vector<VkDisplayModePropertiesKHR> props{};
5353        uint32_t props_count1 = 0;
5354        ASSERT_EQ(VK_SUCCESS, GetDisplayModePropertiesKHR(physical_devices[dev], VK_NULL_HANDLE, &props_count1, nullptr));
5355        ASSERT_NE(0U, props_count1);
5356        props.resize(props_count1);
5357        ASSERT_EQ(VK_SUCCESS, GetDisplayModePropertiesKHR(physical_devices[dev], VK_NULL_HANDLE, &props_count1, props.data()));
5358
5359        std::vector<VkDisplayModeProperties2KHR> props2{};
5360        uint32_t props_count2 = 0;
5361        ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2KHR(physical_devices[dev], VK_NULL_HANDLE, &props_count2, nullptr));
5362        ASSERT_EQ(props_count1, props_count2);
5363        props2.resize(props_count2, {VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR});
5364        ASSERT_EQ(VK_SUCCESS, GetDisplayModeProperties2KHR(physical_devices[dev], VK_NULL_HANDLE, &props_count2, props2.data()));
5365
5366        ASSERT_TRUE(CompareDisplayModeProps(props, props2));
5367    }
5368}
5369
5370// Test vkGetDisplayPlaneCapabilities2KHR where nothing supports it.
5371TEST(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRNoSupport) {
5372    FrameworkEnvironment env{};
5373    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5374    env.get_test_icd(0).physical_devices.push_back({});
5375
5376    InstWrapper instance(env.vulkan_functions);
5377    instance.CheckCreate();
5378
5379    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
5380    ASSERT_EQ(GetDisplayPlaneCapabilitiesKHR, nullptr);
5381}
5382
5383// Test vkGetDisplayPlaneCapabilities2KHR where instance supports it, but nothing else.
5384TEST(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRNoICDSupport) {
5385    FrameworkEnvironment env{};
5386    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5387    env.get_test_icd(0).physical_devices.push_back({});
5388
5389    InstWrapper instance(env.vulkan_functions);
5390    instance.create_info.add_extension(VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME);
5391    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
5392
5393    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
5394    ASSERT_EQ(GetDisplayPlaneCapabilitiesKHR, nullptr);
5395}
5396
5397// Compare the display plane caps
5398bool CompareDisplayPlaneCaps(const VkDisplayPlaneCapabilitiesKHR& caps1, VkDisplayPlaneCapabilities2KHR& caps2) {
5399    bool equal = true;
5400    equal = equal && caps1.supportedAlpha == caps2.capabilities.supportedAlpha;
5401    equal = equal && caps1.minSrcPosition.x == caps2.capabilities.minSrcPosition.x;
5402    equal = equal && caps1.minSrcPosition.y == caps2.capabilities.minSrcPosition.y;
5403    equal = equal && caps1.maxSrcPosition.x == caps2.capabilities.maxSrcPosition.x;
5404    equal = equal && caps1.maxSrcPosition.y == caps2.capabilities.maxSrcPosition.y;
5405    equal = equal && caps1.minSrcExtent.width == caps2.capabilities.minSrcExtent.width;
5406    equal = equal && caps1.minSrcExtent.height == caps2.capabilities.minSrcExtent.height;
5407    equal = equal && caps1.maxSrcExtent.width == caps2.capabilities.maxSrcExtent.width;
5408    equal = equal && caps1.maxSrcExtent.height == caps2.capabilities.maxSrcExtent.height;
5409    equal = equal && caps1.minDstPosition.x == caps2.capabilities.minDstPosition.x;
5410    equal = equal && caps1.minDstPosition.y == caps2.capabilities.minDstPosition.y;
5411    equal = equal && caps1.maxDstPosition.x == caps2.capabilities.maxDstPosition.x;
5412    equal = equal && caps1.maxDstPosition.y == caps2.capabilities.maxDstPosition.y;
5413    equal = equal && caps1.minDstExtent.width == caps2.capabilities.minDstExtent.width;
5414    equal = equal && caps1.minDstExtent.height == caps2.capabilities.minDstExtent.height;
5415    equal = equal && caps1.maxDstExtent.width == caps2.capabilities.maxDstExtent.width;
5416    equal = equal && caps1.maxDstExtent.height == caps2.capabilities.maxDstExtent.height;
5417    return equal;
5418}
5419
5420// Test vkGetDisplayPlaneCapabilities2KHR where instance and ICD supports it, but device does not support it.
5421TEST(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRInstanceAndICDSupport) {
5422    FrameworkEnvironment env{};
5423    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5424    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
5425    Extension second_ext{VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME};
5426    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
5427    env.get_test_icd(0).physical_devices.push_back({});
5428    FillInRandomDisplayPropData(env.get_test_icd(0).physical_devices.back().display_properties);
5429
5430    InstWrapper instance(env.vulkan_functions);
5431    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5432    instance.CheckCreate();
5433
5434    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
5435    ASSERT_NE(GetDisplayPlaneCapabilitiesKHR, nullptr);
5436    PFN_vkGetDisplayPlaneCapabilities2KHR GetDisplayPlaneCapabilities2KHR = instance.load("vkGetDisplayPlaneCapabilities2KHR");
5437    ASSERT_NE(GetDisplayPlaneCapabilities2KHR, nullptr);
5438
5439    uint32_t driver_count = 1;
5440    VkPhysicalDevice physical_device;
5441    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
5442    ASSERT_EQ(driver_count, 1U);
5443
5444    VkDisplayPlaneCapabilitiesKHR caps{};
5445    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilitiesKHR(physical_device, 0, 0, &caps));
5446    VkDisplayPlaneCapabilities2KHR caps2{};
5447    VkDisplayPlaneInfo2KHR info{VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR};
5448    ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities2KHR(physical_device, &info, &caps2));
5449    ASSERT_TRUE(CompareDisplayPlaneCaps(caps, caps2));
5450}
5451
5452// Test vkGetDisplayPlaneCapabilities2KHR where instance supports it with some ICDs that both support
5453// and don't support it:
5454//    ICD 0 supports
5455//        Physical device 0 does not
5456//        Physical device 1 does
5457//        Physical device 2 does not
5458//    ICD 1 doesn't support
5459//        Physical device 3 does not
5460//    ICD 2 supports
5461//        Physical device 4 does not
5462//        Physical device 5 does not
5463//    ICD 3 supports
5464//        Physical device 6 does
5465TEST(LoaderInstPhysDevExts, GetDispPlaneCaps2KHRMixed) {
5466    FrameworkEnvironment env{};
5467    const uint32_t max_icd_count = 4;
5468    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
5469    const uint32_t max_phys_devs = 7;
5470
5471    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
5472        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
5473        auto& cur_icd = env.get_test_icd(icd);
5474        cur_icd.icd_api_version = VK_API_VERSION_1_0;
5475        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
5476
5477        // ICD 1 should not have 1.1
5478        if (icd != 1) {
5479            cur_icd.icd_api_version = VK_API_VERSION_1_1;
5480            cur_icd.add_instance_extension({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5481        }
5482
5483        uint32_t rand_vendor_id;
5484        uint32_t rand_driver_vers;
5485        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
5486
5487        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
5488            uint32_t device_version = VK_API_VERSION_1_0;
5489            cur_icd.physical_devices.push_back({});
5490            auto& cur_dev = cur_icd.physical_devices.back();
5491            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
5492
5493            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
5494            if ((icd == 0 && dev == 1) || icd == 3) {
5495                cur_dev.extensions.push_back({VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME, 0});
5496                device_version = VK_API_VERSION_1_1;
5497            }
5498
5499            // Still set physical device properties (so we can determine if device is correct API version)
5500            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
5501            GenerateRandomDisplayPlaneCaps(cur_dev.display_plane_capabilities);
5502        }
5503    }
5504
5505    InstWrapper instance(env.vulkan_functions);
5506    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME});
5507    instance.CheckCreate();
5508
5509    PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR = instance.load("vkGetDisplayPlaneCapabilitiesKHR");
5510    ASSERT_NE(GetDisplayPlaneCapabilitiesKHR, nullptr);
5511    PFN_vkGetDisplayPlaneCapabilities2KHR GetDisplayPlaneCapabilities2KHR = instance.load("vkGetDisplayPlaneCapabilities2KHR");
5512    ASSERT_NE(GetDisplayPlaneCapabilities2KHR, nullptr);
5513
5514    uint32_t device_count = max_phys_devs;
5515    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
5516    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
5517    ASSERT_EQ(device_count, max_phys_devs);
5518
5519    for (uint32_t dev = 0; dev < device_count; ++dev) {
5520        VkDisplayPlaneCapabilitiesKHR caps{};
5521        ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilitiesKHR(physical_devices[dev], 0, 0, &caps));
5522        VkDisplayPlaneCapabilities2KHR caps2{};
5523        VkDisplayPlaneInfo2KHR info{VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR};
5524        ASSERT_EQ(VK_SUCCESS, GetDisplayPlaneCapabilities2KHR(physical_devices[dev], &info, &caps2));
5525        CompareDisplayPlaneCaps(caps, caps2);
5526    }
5527}
5528
5529//
5530// VK_EXT_acquire_drm_display
5531//
5532
5533// Test vkAcquireDrmDisplayEXT where nothing supports it.
5534TEST(LoaderInstPhysDevExts, AcquireDrmDisplayEXTNoSupport) {
5535    FrameworkEnvironment env{};
5536    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5537    env.get_test_icd(0).physical_devices.push_back({});
5538
5539    InstWrapper instance(env.vulkan_functions);
5540    instance.CheckCreate();
5541
5542    PFN_vkAcquireDrmDisplayEXT AcquireDrmDisplayEXT = instance.load("vkAcquireDrmDisplayEXT");
5543    ASSERT_EQ(AcquireDrmDisplayEXT, nullptr);
5544}
5545
5546// Test vkAcquireDrmDisplayEXT where instance supports it, but nothing else.
5547TEST(LoaderInstPhysDevExts, AcquireDrmDisplayEXTNoICDSupport) {
5548    FrameworkEnvironment env{};
5549    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5550    env.get_test_icd(0).physical_devices.push_back({});
5551
5552    InstWrapper instance(env.vulkan_functions);
5553    instance.create_info.add_extension(VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME);
5554    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
5555
5556    PFN_vkAcquireDrmDisplayEXT AcquireDrmDisplayEXT = instance.load("vkAcquireDrmDisplayEXT");
5557    ASSERT_EQ(AcquireDrmDisplayEXT, nullptr);
5558}
5559
5560// Test vkAcquireDrmDisplayEXT where instance and ICD supports it, but device does not support it.
5561TEST(LoaderInstPhysDevExts, AcquireDrmDisplayEXTInstanceAndICDSupport) {
5562    FrameworkEnvironment env{};
5563    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5564    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
5565    Extension second_ext{VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME};
5566    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
5567    env.get_test_icd(0).physical_devices.push_back({});
5568    GenerateRandomDisplays(env.get_test_icd(0).physical_devices.back().displays);
5569
5570    InstWrapper instance(env.vulkan_functions);
5571    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
5572    instance.CheckCreate();
5573
5574    PFN_vkAcquireDrmDisplayEXT AcquireDrmDisplayEXT = instance.load("vkAcquireDrmDisplayEXT");
5575    ASSERT_NE(AcquireDrmDisplayEXT, nullptr);
5576
5577    uint32_t driver_count = 1;
5578    VkPhysicalDevice physical_device;
5579    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
5580    ASSERT_EQ(driver_count, 1U);
5581
5582    VkDisplayKHR display = VK_NULL_HANDLE;
5583    ASSERT_EQ(VK_SUCCESS, AcquireDrmDisplayEXT(physical_device, 0, display));
5584}
5585
5586// Test vkAcquireDrmDisplayEXT where instance supports it with some ICDs that both support
5587// and don't support it:
5588//    ICD 0 supports
5589//        Physical device 0 does not
5590//        Physical device 1 does
5591//        Physical device 2 does not
5592//    ICD 1 doesn't support
5593//        Physical device 3 does not
5594//    ICD 2 supports
5595//        Physical device 4 does not
5596//        Physical device 5 does not
5597//    ICD 3 supports
5598//        Physical device 6 does
5599TEST(LoaderInstPhysDevExts, AcquireDrmDisplayEXTMixed) {
5600    FrameworkEnvironment env{};
5601    const uint32_t max_icd_count = 4;
5602    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
5603    const uint32_t max_phys_devs = 7;
5604
5605    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
5606        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
5607        auto& cur_icd = env.get_test_icd(icd);
5608        cur_icd.icd_api_version = VK_API_VERSION_1_0;
5609        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
5610
5611        // ICD 1 should not have 1.1
5612        if (icd != 1) {
5613            cur_icd.icd_api_version = VK_API_VERSION_1_1;
5614            cur_icd.add_instance_extension({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
5615        }
5616
5617        uint32_t rand_vendor_id;
5618        uint32_t rand_driver_vers;
5619        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
5620
5621        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
5622            uint32_t device_version = VK_API_VERSION_1_0;
5623            cur_icd.physical_devices.push_back({});
5624            auto& cur_dev = cur_icd.physical_devices.back();
5625            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
5626
5627            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
5628            if ((icd == 0 && dev == 1) || icd == 3) {
5629                cur_dev.extensions.push_back({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME, 0});
5630                device_version = VK_API_VERSION_1_1;
5631            }
5632
5633            // Still set physical device properties (so we can determine if device is correct API version)
5634            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
5635            GenerateRandomDisplays(cur_dev.displays);
5636        }
5637    }
5638
5639    InstWrapper instance(env.vulkan_functions);
5640    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
5641    instance.CheckCreate();
5642
5643    PFN_vkAcquireDrmDisplayEXT AcquireDrmDisplayEXT = instance.load("vkAcquireDrmDisplayEXT");
5644    ASSERT_NE(AcquireDrmDisplayEXT, nullptr);
5645
5646    uint32_t device_count = max_phys_devs;
5647    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
5648    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
5649    ASSERT_EQ(device_count, max_phys_devs);
5650
5651    for (uint32_t dev = 0; dev < device_count; ++dev) {
5652        VkPhysicalDeviceProperties pd_props{};
5653        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
5654
5655        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
5656            auto& cur_icd = env.get_test_icd(icd);
5657            bool found = false;
5658            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
5659                auto& cur_dev = cur_icd.physical_devices[pd];
5660                // Find the ICD device matching the physical device we're looking at info for so we can compare the
5661                // physical devices info with the returned info.
5662                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
5663                    cur_dev.properties.deviceType == pd_props.deviceType &&
5664                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
5665                    cur_dev.properties.vendorID == pd_props.vendorID) {
5666                    VkDisplayKHR display = VK_NULL_HANDLE;
5667                    if (icd == 1) {
5668                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
5669                        // loader.
5670                        ASSERT_EQ(VK_ERROR_EXTENSION_NOT_PRESENT, AcquireDrmDisplayEXT(physical_devices[dev], 0, display));
5671                    } else {
5672                        ASSERT_EQ(VK_SUCCESS, AcquireDrmDisplayEXT(physical_devices[dev], 0, display));
5673                    }
5674                    found = true;
5675                    break;
5676                }
5677            }
5678            if (found) {
5679                break;
5680            }
5681        }
5682    }
5683}
5684
5685// Test vkGetDrmDisplayEXT where nothing supports it.
5686TEST(LoaderInstPhysDevExts, GetDrmDisplayEXTNoSupport) {
5687    FrameworkEnvironment env{};
5688    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5689    env.get_test_icd(0).physical_devices.push_back({});
5690
5691    InstWrapper instance(env.vulkan_functions);
5692    instance.CheckCreate();
5693
5694    PFN_vkGetDrmDisplayEXT GetDrmDisplayEXT = instance.load("vkGetDrmDisplayEXT");
5695    ASSERT_EQ(GetDrmDisplayEXT, nullptr);
5696}
5697
5698// Test vkGetDrmDisplayEXT where instance supports it, but nothing else.
5699TEST(LoaderInstPhysDevExts, GetDrmDisplayEXTNoICDSupport) {
5700    FrameworkEnvironment env{};
5701    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5702    env.get_test_icd(0).physical_devices.push_back({});
5703
5704    InstWrapper instance(env.vulkan_functions);
5705    instance.create_info.add_extension(VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME);
5706    instance.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
5707
5708    PFN_vkGetDrmDisplayEXT GetDrmDisplayEXT = instance.load("vkGetDrmDisplayEXT");
5709    ASSERT_EQ(GetDrmDisplayEXT, nullptr);
5710}
5711
5712// Test vkGetDrmDisplayEXT where instance and ICD supports it, but device does not support it.
5713TEST(LoaderInstPhysDevExts, GetDrmDisplayEXTInstanceAndICDSupport) {
5714    FrameworkEnvironment env{};
5715    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
5716    Extension first_ext{VK_KHR_DISPLAY_EXTENSION_NAME};
5717    Extension second_ext{VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME};
5718    env.get_test_icd(0).add_instance_extensions({first_ext, second_ext});
5719    env.get_test_icd(0).physical_devices.push_back({});
5720    GenerateRandomDisplays(env.get_test_icd(0).physical_devices.back().displays);
5721
5722    InstWrapper instance(env.vulkan_functions);
5723    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
5724    instance.CheckCreate();
5725
5726    PFN_vkGetDrmDisplayEXT GetDrmDisplayEXT = instance.load("vkGetDrmDisplayEXT");
5727    ASSERT_NE(GetDrmDisplayEXT, nullptr);
5728
5729    uint32_t driver_count = 1;
5730    VkPhysicalDevice physical_device;
5731    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
5732    ASSERT_EQ(driver_count, 1U);
5733
5734    VkDisplayKHR display = VK_NULL_HANDLE;
5735    ASSERT_EQ(VK_SUCCESS, GetDrmDisplayEXT(physical_device, 0, 0, &display));
5736    ASSERT_EQ(display, env.get_test_icd(0).physical_devices.back().displays[0]);
5737}
5738
5739// Test vkGetDrmDisplayEXT where instance supports it with some ICDs that both support
5740// and don't support it:
5741//    ICD 0 supports
5742//        Physical device 0 does not
5743//        Physical device 1 does
5744//        Physical device 2 does not
5745//    ICD 1 doesn't support
5746//        Physical device 3 does not
5747//    ICD 2 supports
5748//        Physical device 4 does not
5749//        Physical device 5 does not
5750//    ICD 3 supports
5751//        Physical device 6 does
5752TEST(LoaderInstPhysDevExts, GetDrmDisplayEXTMixed) {
5753    FrameworkEnvironment env{};
5754    const uint32_t max_icd_count = 4;
5755    const uint32_t dev_counts[max_icd_count] = {3, 1, 2, 1};
5756    const uint32_t max_phys_devs = 7;
5757
5758    for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
5759        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, icd != 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0));
5760        auto& cur_icd = env.get_test_icd(icd);
5761        cur_icd.icd_api_version = VK_API_VERSION_1_0;
5762        cur_icd.add_instance_extension({VK_KHR_DISPLAY_EXTENSION_NAME});
5763
5764        // ICD 1 should not have 1.1
5765        if (icd != 1) {
5766            cur_icd.icd_api_version = VK_API_VERSION_1_1;
5767            cur_icd.add_instance_extension({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
5768        }
5769
5770        uint32_t rand_vendor_id;
5771        uint32_t rand_driver_vers;
5772        FillInRandomICDInfo(rand_vendor_id, rand_driver_vers);
5773
5774        for (uint32_t dev = 0; dev < dev_counts[icd]; ++dev) {
5775            uint32_t device_version = VK_API_VERSION_1_0;
5776            cur_icd.physical_devices.push_back({});
5777            auto& cur_dev = cur_icd.physical_devices.back();
5778            cur_dev.extensions.push_back({VK_KHR_DISPLAY_EXTENSION_NAME, 0});
5779
5780            // 2nd device in ICD 0 and the one device in ICD 3 support the extension and 1.1
5781            if ((icd == 0 && dev == 1) || icd == 3) {
5782                cur_dev.extensions.push_back({VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME, 0});
5783                device_version = VK_API_VERSION_1_1;
5784            }
5785
5786            // Still set physical device properties (so we can determine if device is correct API version)
5787            FillInRandomDeviceProps(cur_dev.properties, device_version, rand_vendor_id, rand_driver_vers);
5788            GenerateRandomDisplays(cur_dev.displays);
5789        }
5790    }
5791
5792    InstWrapper instance(env.vulkan_functions);
5793    instance.create_info.add_extensions({VK_KHR_DISPLAY_EXTENSION_NAME, VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME});
5794    instance.CheckCreate();
5795
5796    PFN_vkGetDrmDisplayEXT GetDrmDisplayEXT = instance.load("vkGetDrmDisplayEXT");
5797    ASSERT_NE(GetDrmDisplayEXT, nullptr);
5798
5799    uint32_t device_count = max_phys_devs;
5800    std::array<VkPhysicalDevice, max_phys_devs> physical_devices;
5801    ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &device_count, physical_devices.data()));
5802    ASSERT_EQ(device_count, max_phys_devs);
5803
5804    for (uint32_t dev = 0; dev < device_count; ++dev) {
5805        VkPhysicalDeviceProperties pd_props{};
5806        instance->vkGetPhysicalDeviceProperties(physical_devices[dev], &pd_props);
5807
5808        for (uint32_t icd = 0; icd < max_icd_count; ++icd) {
5809            auto& cur_icd = env.get_test_icd(icd);
5810            bool found = false;
5811            for (uint32_t pd = 0; pd < dev_counts[icd]; ++pd) {
5812                auto& cur_dev = cur_icd.physical_devices[pd];
5813                // Find the ICD device matching the physical device we're looking at info for so we can compare the
5814                // physical devices info with the returned info.
5815                if (cur_dev.properties.apiVersion == pd_props.apiVersion && cur_dev.properties.deviceID == pd_props.deviceID &&
5816                    cur_dev.properties.deviceType == pd_props.deviceType &&
5817                    cur_dev.properties.driverVersion == pd_props.driverVersion &&
5818                    cur_dev.properties.vendorID == pd_props.vendorID) {
5819                    VkDisplayKHR display = VK_NULL_HANDLE;
5820                    if (icd == 1) {
5821                        // For this extension, if no support exists (like for ICD 1), the value of 0 should be returned by the
5822                        // loader.
5823                        ASSERT_EQ(VK_ERROR_EXTENSION_NOT_PRESENT, GetDrmDisplayEXT(physical_devices[dev], 0, 0, &display));
5824                    } else {
5825                        ASSERT_EQ(VK_SUCCESS, GetDrmDisplayEXT(physical_devices[dev], 0, 0, &display));
5826                        ASSERT_EQ(display, cur_dev.displays[0]);
5827                    }
5828                    found = true;
5829                    break;
5830                }
5831            }
5832            if (found) {
5833                break;
5834            }
5835        }
5836    }
5837}
5838
5839TEST(LoaderInstPhysDevExts, DifferentInstanceExtensions) {
5840    FrameworkEnvironment env{};
5841
5842    // Add 3 drivers each of which supports a different instance extension
5843    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_0));
5844    env.get_test_icd(0).add_instance_extension({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME});
5845    env.get_test_icd(0).physical_devices.push_back({"pd0"});
5846    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 0});
5847
5848    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_0));
5849    env.get_test_icd(1).add_instance_extension({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME});
5850    env.get_test_icd(1).physical_devices.push_back({"pd1"});
5851    env.get_test_icd(1).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, 0});
5852
5853    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_0));
5854    env.get_test_icd(2).add_instance_extension({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
5855    env.get_test_icd(2).physical_devices.push_back({"pd2"});
5856    env.get_test_icd(2).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, 0});
5857
5858    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
5859    InstWrapper inst{env.vulkan_functions};
5860    inst.create_info.add_extensions({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
5861                                     VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
5862                                     VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME});
5863    FillDebugUtilsCreateDetails(inst.create_info, log);
5864    inst.CheckCreate();
5865
5866    const uint32_t expected_device_count = 3;
5867    auto physical_devices = inst.GetPhysDevs(expected_device_count);
5868
5869    PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR GetPhysicalDeviceExternalBufferProperties =
5870        inst.load("vkGetPhysicalDeviceExternalBufferPropertiesKHR");
5871    PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR GetPhysicalDeviceExternalSemaphoreProperties =
5872        inst.load("vkGetPhysicalDeviceExternalSemaphorePropertiesKHR");
5873    PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR GetPhysicalDeviceExternalFenceProperties =
5874        inst.load("vkGetPhysicalDeviceExternalFencePropertiesKHR");
5875    ASSERT_NE(nullptr, GetPhysicalDeviceExternalBufferProperties);
5876    ASSERT_NE(nullptr, GetPhysicalDeviceExternalSemaphoreProperties);
5877    ASSERT_NE(nullptr, GetPhysicalDeviceExternalFenceProperties);
5878
5879    // The above are instance extensions, so shouldn't crash even if only one physical device supports each
5880    // extension.
5881    for (uint32_t dev = 0; dev < expected_device_count; ++dev) {
5882        VkPhysicalDeviceExternalBufferInfo ext_buf_info{};
5883        VkExternalBufferProperties ext_buf_props{};
5884        VkPhysicalDeviceExternalSemaphoreInfo ext_sem_info{};
5885        VkExternalSemaphoreProperties ext_sem_props{};
5886        VkPhysicalDeviceExternalFenceInfo ext_fence_info{};
5887        VkExternalFenceProperties ext_fence_props{};
5888        GetPhysicalDeviceExternalBufferProperties(physical_devices[dev], &ext_buf_info, &ext_buf_props);
5889        GetPhysicalDeviceExternalSemaphoreProperties(physical_devices[dev], &ext_sem_info, &ext_sem_props);
5890        GetPhysicalDeviceExternalFenceProperties(physical_devices[dev], &ext_fence_info, &ext_fence_props);
5891    }
5892}
5893
5894TEST(LoaderInstPhysDevExts, DifferentPhysicalDeviceExtensions) {
5895    FrameworkEnvironment env{};
5896
5897    // Add 3 drivers each of which supports a different physical device extension
5898    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_0));
5899    env.get_test_icd(0).physical_devices.push_back("pd0");
5900    env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME, 0});
5901
5902    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_0));
5903    env.get_test_icd(1).physical_devices.push_back("pd1");
5904    env.get_test_icd(1).physical_devices.back().extensions.push_back({VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME, 0});
5905
5906    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_0));
5907    env.get_test_icd(2).physical_devices.push_back("pd2");
5908    env.get_test_icd(2).physical_devices.back().extensions.push_back({VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, 0});
5909
5910    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
5911    InstWrapper inst{env.vulkan_functions};
5912    FillDebugUtilsCreateDetails(inst.create_info, log);
5913    inst.CheckCreate();
5914
5915    const uint32_t expected_device_count = 3;
5916    auto physical_devices = inst.GetPhysDevs(expected_device_count);
5917
5918    PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR
5919        EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR =
5920            inst.load("vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR");
5921    PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT GetPhysicalDeviceMultisamplePropertiesEXT =
5922        inst.load("vkGetPhysicalDeviceMultisamplePropertiesEXT");
5923    PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT GetPhysicalDeviceCalibrateableTimeDomainsEXT =
5924        inst.load("vkGetPhysicalDeviceCalibrateableTimeDomainsEXT");
5925    ASSERT_NE(nullptr, EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR);
5926    ASSERT_NE(nullptr, GetPhysicalDeviceMultisamplePropertiesEXT);
5927    ASSERT_NE(nullptr, GetPhysicalDeviceCalibrateableTimeDomainsEXT);
5928
5929    for (uint32_t dev = 0; dev < expected_device_count; ++dev) {
5930        uint32_t extension_count = 0;
5931        std::vector<VkExtensionProperties> device_extensions;
5932        bool supports_query = false;
5933        bool supports_samples = false;
5934        bool supports_timestamps = false;
5935        ASSERT_EQ(VK_SUCCESS,
5936                  inst->vkEnumerateDeviceExtensionProperties(physical_devices[dev], nullptr, &extension_count, nullptr));
5937        ASSERT_GT(extension_count, 0U);
5938        device_extensions.resize(extension_count);
5939        ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_devices[dev], nullptr, &extension_count,
5940                                                                         device_extensions.data()));
5941        for (uint32_t ext = 0; ext < extension_count; ++ext) {
5942            if (string_eq(VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME, &device_extensions[ext].extensionName[0])) {
5943                supports_query = true;
5944            }
5945            if (string_eq(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME, &device_extensions[ext].extensionName[0])) {
5946                supports_samples = true;
5947            }
5948            if (string_eq(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, &device_extensions[ext].extensionName[0])) {
5949                supports_timestamps = true;
5950            }
5951        }
5952
5953        // For physical device extensions, they should work for devices that support it and crash for those that don't.
5954        if (supports_query) {
5955            ASSERT_EQ(VK_SUCCESS, EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(physical_devices[dev], 0, nullptr,
5956                                                                                                nullptr, nullptr));
5957        } else {
5958            ASSERT_DEATH(
5959                EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(physical_devices[dev], 0, nullptr, nullptr, nullptr),
5960                "");
5961            ASSERT_FALSE(
5962                log.find("ICD associated with VkPhysicalDevice does not support "
5963                         "EnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR"));
5964        }
5965        if (supports_samples) {
5966            GetPhysicalDeviceMultisamplePropertiesEXT(physical_devices[dev], VK_SAMPLE_COUNT_2_BIT, nullptr);
5967        } else {
5968            ASSERT_DEATH(GetPhysicalDeviceMultisamplePropertiesEXT(physical_devices[dev], VK_SAMPLE_COUNT_2_BIT, nullptr), "");
5969            ASSERT_FALSE(
5970                log.find("ICD associated with VkPhysicalDevice does not support GetPhysicalDeviceMultisamplePropertiesEXT"));
5971        }
5972        if (supports_timestamps) {
5973            ASSERT_EQ(VK_SUCCESS, GetPhysicalDeviceCalibrateableTimeDomainsEXT(physical_devices[dev], nullptr, nullptr));
5974        } else {
5975            ASSERT_DEATH(GetPhysicalDeviceCalibrateableTimeDomainsEXT(physical_devices[dev], nullptr, nullptr), "");
5976            ASSERT_FALSE(
5977                log.find("ICD associated with VkPhysicalDevice does not support GetPhysicalDeviceCalibrateableTimeDomainsEXT"));
5978        }
5979    }
5980}
5981