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 */
27
28#include "test_environment.h"
29
30class WsiTests : public ::testing::Test {};
31
32#if defined(VK_USE_PLATFORM_WIN32_KHR)
33
34// When ICD doesn't support the extension, create instance should fail
35TEST(WsiTests, CreateSurfaceWin32NoICDSupport) {
36    FrameworkEnvironment env{};
37    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
38    auto& cur_icd = env.get_test_icd(0);
39    cur_icd.set_min_icd_interface_version(5);
40
41    InstWrapper inst{env.vulkan_functions};
42    inst.create_info.add_extensions({VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
43    inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
44
45    InstWrapper inst2{env.vulkan_functions};
46    inst2.CheckCreate();
47
48    ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateWin32SurfaceKHR"));
49}
50
51// When ICD doesn't support the surface creation, the loader should handle it
52TEST(WsiTests, CreateSurfaceWin32NoICDCreateSupport) {
53    FrameworkEnvironment env{};
54    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
55    auto& cur_icd = env.get_test_icd(0);
56    cur_icd.set_min_icd_interface_version(5);
57    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
58    cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
59    cur_icd.enable_icd_wsi = false;
60
61    InstWrapper inst{env.vulkan_functions};
62    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
63    inst.CheckCreate();
64
65    VkSurfaceKHR surface{VK_NULL_HANDLE};
66    VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR};
67    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(inst, &surf_create_info, nullptr, &surface));
68    ASSERT_TRUE(surface != VK_NULL_HANDLE);
69
70    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
71}
72
73// When ICD does support the surface creation, the loader should  delegat handle it to the ICD
74TEST(WsiTests, CreateSurfaceWin32ICDSupport) {
75    FrameworkEnvironment env{};
76    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
77    auto& cur_icd = env.get_test_icd(0);
78    cur_icd.set_min_icd_interface_version(5);
79    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
80    cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
81    cur_icd.enable_icd_wsi = true;
82
83    InstWrapper inst{env.vulkan_functions};
84    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
85    inst.CheckCreate();
86
87    VkSurfaceKHR surface{VK_NULL_HANDLE};
88    VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR};
89    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(inst, &surf_create_info, nullptr, &surface));
90    ASSERT_TRUE(surface != VK_NULL_HANDLE);
91
92    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
93}
94
95// Some drivers supporting vkCreateWin32SurfaceKHR, and at least one that doesn't
96TEST(WsiTests, CreateSurfaceWin32MixedICDSupport) {
97    FrameworkEnvironment env{};
98    for (uint32_t icd = 0; icd < 3; ++icd) {
99        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
100        Extension second_ext{VK_KHR_WIN32_SURFACE_EXTENSION_NAME};
101        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
102        auto& cur_icd = env.get_test_icd(icd);
103        cur_icd.icd_api_version = VK_API_VERSION_1_0;
104        cur_icd.add_instance_extensions({first_ext, second_ext});
105        if (icd < 2) {
106            // Only enable ICD for first two
107            cur_icd.enable_icd_wsi = true;
108        }
109    }
110
111    InstWrapper instance(env.vulkan_functions);
112    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
113    instance.CheckCreate();
114
115    VkSurfaceKHR surface{VK_NULL_HANDLE};
116    VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR};
117    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(instance.inst, &surf_create_info, nullptr, &surface));
118    ASSERT_TRUE(surface != VK_NULL_HANDLE);
119
120    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
121}
122
123TEST(WsiTests, GetPhysicalDeviceWin32PresentNoICDSupport) {
124    FrameworkEnvironment env{};
125    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
126    auto& cur_icd = env.get_test_icd(0);
127    cur_icd.set_min_icd_interface_version(5);
128    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
129    cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
130    cur_icd.physical_devices.emplace_back("physical_device_0");
131    cur_icd.enable_icd_wsi = false;
132
133    InstWrapper inst{env.vulkan_functions};
134    inst.create_info.add_extensions(
135        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
136    inst.CheckCreate();
137
138    uint32_t driver_count = 1;
139    VkPhysicalDevice physical_device;
140    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
141    ASSERT_EQ(driver_count, 1U);
142
143    DebugUtilsWrapper log{inst};
144    CreateDebugUtilsMessenger(log);
145    auto res = env.vulkan_functions.vkGetPhysicalDeviceWin32PresentationSupportKHR(physical_device, 0);
146    ASSERT_EQ(res, VK_FALSE);
147    ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceWin32PresentationSupportKHR!"));
148}
149
150TEST(WsiTests, GetPhysicalDeviceWin32PresentICDSupport) {
151    FrameworkEnvironment env{};
152    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
153    auto& cur_icd = env.get_test_icd(0);
154    cur_icd.set_min_icd_interface_version(5);
155    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
156    cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
157    cur_icd.physical_devices.emplace_back("physical_device_0");
158    cur_icd.enable_icd_wsi = true;
159
160    InstWrapper inst{env.vulkan_functions};
161    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
162    inst.CheckCreate();
163
164    uint32_t driver_count = 1;
165    VkPhysicalDevice physical_device;
166    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
167    ASSERT_EQ(driver_count, 1U);
168
169    ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceWin32PresentationSupportKHR(physical_device, 0));
170}
171
172TEST(WsiTests, Win32GetPhysicalDeviceSurfaceSupportKHR) {
173    FrameworkEnvironment env{};
174    const uint32_t max_device_count = 4;
175    for (uint32_t icd = 0; icd < max_device_count; ++icd) {
176        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
177        Extension second_ext{VK_KHR_WIN32_SURFACE_EXTENSION_NAME};
178        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
179        auto& cur_icd = env.get_test_icd(icd);
180        cur_icd.icd_api_version = VK_API_VERSION_1_0;
181        cur_icd.set_min_icd_interface_version(5);
182        cur_icd.add_instance_extensions({first_ext, second_ext});
183        std::string dev_name = "phys_dev_" + std::to_string(icd);
184        cur_icd.physical_devices.emplace_back(dev_name.c_str());
185        cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true});
186        cur_icd.enable_icd_wsi = true;
187    }
188
189    InstWrapper instance(env.vulkan_functions);
190    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
191    instance.CheckCreate();
192
193    VkSurfaceKHR surface{VK_NULL_HANDLE};
194    VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR};
195    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(instance.inst, &surf_create_info, nullptr, &surface));
196    ASSERT_TRUE(surface != VK_NULL_HANDLE);
197
198    uint32_t device_count = max_device_count;
199    std::array<VkPhysicalDevice, max_device_count> phys_devs;
200    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data()));
201    ASSERT_EQ(device_count, max_device_count);
202
203    for (uint32_t pd = 0; pd < max_device_count; ++pd) {
204        VkBool32 supported = VK_FALSE;
205        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported));
206    }
207
208    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
209}
210#endif
211
212#if defined(VK_USE_PLATFORM_XCB_KHR)
213// When ICD doesn't support the extension, create instance should fail
214TEST(WsiTests, CreateSurfaceXCBNoICDSupport) {
215    FrameworkEnvironment env{};
216    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
217    auto& cur_icd = env.get_test_icd(0);
218    cur_icd.set_min_icd_interface_version(5);
219    cur_icd.enable_icd_wsi = false;
220
221    InstWrapper inst{env.vulkan_functions};
222    inst.create_info.add_extensions({VK_KHR_XCB_SURFACE_EXTENSION_NAME});
223    inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
224
225    InstWrapper inst2{env.vulkan_functions};
226    inst2.CheckCreate();
227
228    ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateXcbSurfaceKHR"));
229}
230
231// When ICD doesn't support the surface creation, the loader should handle it
232TEST(WsiTests, CreateSurfaceXCBNoICDCreateSupport) {
233    FrameworkEnvironment env{};
234    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
235    auto& cur_icd = env.get_test_icd(0);
236    cur_icd.set_min_icd_interface_version(5);
237    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
238    cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME});
239    cur_icd.enable_icd_wsi = false;
240
241    InstWrapper inst{env.vulkan_functions};
242    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME});
243    inst.CheckCreate();
244
245    VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR};
246
247    VkSurfaceKHR surface{VK_NULL_HANDLE};
248    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(inst, &xcb_createInfo, nullptr, &surface));
249    ASSERT_TRUE(surface != VK_NULL_HANDLE);
250
251    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
252}
253
254// When ICD does support the surface creation, the loader should  delegat handle it to the ICD
255TEST(WsiTests, CreateSurfaceXCBICDSupport) {
256    FrameworkEnvironment env{};
257    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
258    auto& cur_icd = env.get_test_icd(0);
259    cur_icd.set_min_icd_interface_version(5);
260    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
261    cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME});
262    cur_icd.enable_icd_wsi = true;
263
264    InstWrapper inst{env.vulkan_functions};
265    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME});
266    inst.CheckCreate();
267
268    VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR};
269
270    VkSurfaceKHR surface{VK_NULL_HANDLE};
271    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(inst, &xcb_createInfo, nullptr, &surface));
272    ASSERT_TRUE(surface != VK_NULL_HANDLE);
273
274    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
275}
276
277// Some drivers supporting vkCreateXcbSurfaceKHR, and at least one that doesn't
278TEST(WsiTests, CreateSurfaceXCBMixedICDSupport) {
279    FrameworkEnvironment env{};
280    for (uint32_t icd = 0; icd < 3; ++icd) {
281        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
282        Extension second_ext{VK_KHR_XCB_SURFACE_EXTENSION_NAME};
283        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
284        auto& cur_icd = env.get_test_icd(icd);
285        cur_icd.icd_api_version = VK_API_VERSION_1_0;
286        cur_icd.add_instance_extensions({first_ext, second_ext});
287        if (icd < 2) {
288            // Only enable ICD for first two
289            cur_icd.enable_icd_wsi = true;
290        }
291    }
292
293    InstWrapper instance(env.vulkan_functions);
294    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME});
295    instance.CheckCreate();
296
297    VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR};
298
299    VkSurfaceKHR surface{VK_NULL_HANDLE};
300    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(instance.inst, &xcb_createInfo, nullptr, &surface));
301    ASSERT_TRUE(surface != VK_NULL_HANDLE);
302
303    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
304}
305
306TEST(WsiTests, GetPhysicalDeviceXcbPresentNoICDSupport) {
307    FrameworkEnvironment env{};
308    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
309    auto& cur_icd = env.get_test_icd(0);
310    cur_icd.set_min_icd_interface_version(5);
311    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
312    cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME});
313    cur_icd.physical_devices.emplace_back("physical_device_0");
314    cur_icd.enable_icd_wsi = false;
315
316    InstWrapper inst{env.vulkan_functions};
317    inst.create_info.add_extensions(
318        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
319    inst.CheckCreate();
320
321    uint32_t driver_count = 1;
322    VkPhysicalDevice physical_device;
323    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
324    ASSERT_EQ(driver_count, 1U);
325
326    DebugUtilsWrapper log{inst};
327    CreateDebugUtilsMessenger(log);
328    auto res = env.vulkan_functions.vkGetPhysicalDeviceXcbPresentationSupportKHR(physical_device, 0, nullptr, 0);
329    ASSERT_EQ(res, VK_FALSE);
330    ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceXcbPresentationSupportKHR!"));
331}
332
333TEST(WsiTests, GetPhysicalDeviceXcbPresentICDSupport) {
334    FrameworkEnvironment env{};
335    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
336    auto& cur_icd = env.get_test_icd(0);
337    cur_icd.set_min_icd_interface_version(5);
338    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
339    cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME});
340    cur_icd.physical_devices.emplace_back("physical_device_0");
341    cur_icd.enable_icd_wsi = true;
342
343    InstWrapper inst{env.vulkan_functions};
344    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME});
345    inst.CheckCreate();
346
347    uint32_t driver_count = 1;
348    VkPhysicalDevice physical_device;
349    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
350    ASSERT_EQ(driver_count, 1U);
351
352    ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceXcbPresentationSupportKHR(physical_device, 0, nullptr, 0));
353}
354
355TEST(WsiTests, XcbGetPhysicalDeviceSurfaceSupportKHR) {
356    FrameworkEnvironment env{};
357    const uint32_t max_device_count = 4;
358    for (uint32_t icd = 0; icd < max_device_count; ++icd) {
359        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
360        Extension second_ext{VK_KHR_XCB_SURFACE_EXTENSION_NAME};
361        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
362        auto& cur_icd = env.get_test_icd(icd);
363        cur_icd.icd_api_version = VK_API_VERSION_1_0;
364        cur_icd.set_min_icd_interface_version(5);
365        cur_icd.add_instance_extensions({first_ext, second_ext});
366        std::string dev_name = "phys_dev_" + std::to_string(icd);
367        cur_icd.physical_devices.emplace_back(dev_name.c_str());
368        cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true});
369        cur_icd.enable_icd_wsi = true;
370    }
371
372    InstWrapper instance(env.vulkan_functions);
373    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME});
374    instance.CheckCreate();
375
376    VkSurfaceKHR surface{VK_NULL_HANDLE};
377    VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR};
378    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(instance.inst, &xcb_createInfo, nullptr, &surface));
379    ASSERT_TRUE(surface != VK_NULL_HANDLE);
380
381    uint32_t device_count = max_device_count;
382    std::array<VkPhysicalDevice, max_device_count> phys_devs;
383    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data()));
384    ASSERT_EQ(device_count, max_device_count);
385
386    for (uint32_t pd = 0; pd < max_device_count; ++pd) {
387        VkBool32 supported = VK_FALSE;
388        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported));
389    }
390
391    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
392}
393#endif
394
395#if defined(VK_USE_PLATFORM_XLIB_KHR)
396// When ICD doesn't support the extension, create instance should fail
397TEST(WsiTests, CreateSurfaceXLIBNoICDSupport) {
398    FrameworkEnvironment env{};
399    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
400    auto& cur_icd = env.get_test_icd(0);
401    cur_icd.set_min_icd_interface_version(5);
402    cur_icd.enable_icd_wsi = false;
403
404    InstWrapper inst{env.vulkan_functions};
405    inst.create_info.add_extensions({VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
406    inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
407
408    InstWrapper inst2{env.vulkan_functions};
409    inst2.CheckCreate();
410
411    ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateXlibSurfaceKHR"));
412}
413
414// When ICD doesn't support the surface creation, the loader should handle it
415TEST(WsiTests, CreateSurfaceXLIBNoICDCreateSupport) {
416    FrameworkEnvironment env{};
417    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
418    auto& cur_icd = env.get_test_icd(0);
419    cur_icd.set_min_icd_interface_version(5);
420    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
421    cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
422    cur_icd.enable_icd_wsi = false;
423
424    InstWrapper inst{env.vulkan_functions};
425    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
426    inst.CheckCreate();
427
428    VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR};
429
430    VkSurfaceKHR surface;
431    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(inst, &createInfo, nullptr, &surface));
432    ASSERT_TRUE(surface != VK_NULL_HANDLE);
433
434    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
435}
436
437// When ICD does support the surface creation, the loader should  delegat handle it to the ICD
438TEST(WsiTests, CreateSurfaceXLIBICDSupport) {
439    FrameworkEnvironment env{};
440    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
441    auto& cur_icd = env.get_test_icd(0);
442    cur_icd.set_min_icd_interface_version(5);
443    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
444    cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
445    cur_icd.enable_icd_wsi = true;
446
447    InstWrapper inst{env.vulkan_functions};
448    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
449    inst.CheckCreate();
450
451    VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR};
452
453    VkSurfaceKHR surface;
454    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(inst, &createInfo, nullptr, &surface));
455    ASSERT_TRUE(surface != VK_NULL_HANDLE);
456
457    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
458}
459
460// Some drivers supporting vkCreateXlibSurfaceKHR, and at least one that doesn't
461TEST(WsiTests, CreateSurfaceXLIBMixedICDSupport) {
462    FrameworkEnvironment env{};
463    for (uint32_t icd = 0; icd < 3; ++icd) {
464        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
465        Extension second_ext{VK_KHR_XLIB_SURFACE_EXTENSION_NAME};
466        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
467        auto& cur_icd = env.get_test_icd(icd);
468        cur_icd.icd_api_version = VK_API_VERSION_1_0;
469        cur_icd.add_instance_extensions({first_ext, second_ext});
470        if (icd < 2) {
471            // Only enable ICD for first two
472            cur_icd.enable_icd_wsi = true;
473        }
474    }
475
476    InstWrapper instance(env.vulkan_functions);
477    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
478    instance.CheckCreate();
479
480    VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR};
481
482    VkSurfaceKHR surface;
483    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(instance.inst, &createInfo, nullptr, &surface));
484    ASSERT_TRUE(surface != VK_NULL_HANDLE);
485
486    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
487}
488
489TEST(WsiTests, GetPhysicalDeviceXlibPresentNoICDSupport) {
490    FrameworkEnvironment env{};
491    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
492    auto& cur_icd = env.get_test_icd(0);
493    cur_icd.set_min_icd_interface_version(5);
494    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
495    cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
496    cur_icd.physical_devices.emplace_back("physical_device_0");
497    cur_icd.enable_icd_wsi = false;
498
499    InstWrapper inst{env.vulkan_functions};
500    inst.create_info.add_extensions(
501        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
502    inst.CheckCreate();
503
504    uint32_t driver_count = 1;
505    VkPhysicalDevice physical_device;
506    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
507    ASSERT_EQ(driver_count, 1U);
508
509    DebugUtilsWrapper log{inst};
510    CreateDebugUtilsMessenger(log);
511    auto res = env.vulkan_functions.vkGetPhysicalDeviceXlibPresentationSupportKHR(physical_device, 0, nullptr, 0);
512    ASSERT_EQ(res, VK_FALSE);
513    ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceXlibPresentationSupportKHR!"));
514}
515
516TEST(WsiTests, GetPhysicalDeviceXlibPresentICDSupport) {
517    FrameworkEnvironment env{};
518    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
519    auto& cur_icd = env.get_test_icd(0);
520    cur_icd.set_min_icd_interface_version(5);
521    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
522    cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
523    cur_icd.physical_devices.emplace_back("physical_device_0");
524    cur_icd.enable_icd_wsi = true;
525
526    InstWrapper inst{env.vulkan_functions};
527    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
528    inst.CheckCreate();
529
530    uint32_t driver_count = 1;
531    VkPhysicalDevice physical_device;
532    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
533    ASSERT_EQ(driver_count, 1U);
534
535    ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceXlibPresentationSupportKHR(physical_device, 0, nullptr, 0));
536}
537
538TEST(WsiTests, XlibGetPhysicalDeviceSurfaceSupportKHR) {
539    FrameworkEnvironment env{};
540    const uint32_t max_device_count = 4;
541    for (uint32_t icd = 0; icd < max_device_count; ++icd) {
542        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
543        Extension second_ext{VK_KHR_XLIB_SURFACE_EXTENSION_NAME};
544        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
545        auto& cur_icd = env.get_test_icd(icd);
546        cur_icd.icd_api_version = VK_API_VERSION_1_0;
547        cur_icd.set_min_icd_interface_version(5);
548        cur_icd.add_instance_extensions({first_ext, second_ext});
549        std::string dev_name = "phys_dev_" + std::to_string(icd);
550        cur_icd.physical_devices.emplace_back(dev_name.c_str());
551        cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true});
552        cur_icd.enable_icd_wsi = true;
553    }
554
555    InstWrapper instance(env.vulkan_functions);
556    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
557    instance.CheckCreate();
558
559    VkSurfaceKHR surface{VK_NULL_HANDLE};
560    VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR};
561    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(instance.inst, &createInfo, nullptr, &surface));
562    ASSERT_TRUE(surface != VK_NULL_HANDLE);
563
564    uint32_t device_count = max_device_count;
565    std::array<VkPhysicalDevice, max_device_count> phys_devs;
566    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data()));
567    ASSERT_EQ(device_count, max_device_count);
568
569    for (uint32_t pd = 0; pd < max_device_count; ++pd) {
570        VkBool32 supported = VK_FALSE;
571        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported));
572    }
573
574    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
575}
576#endif
577
578#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
579// When ICD doesn't support the extension, create instance should fail
580TEST(WsiTests, CreateSurfaceWaylandNoICDSupport) {
581    FrameworkEnvironment env{};
582    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
583    auto& cur_icd = env.get_test_icd(0);
584    cur_icd.set_min_icd_interface_version(5);
585    cur_icd.enable_icd_wsi = false;
586
587    InstWrapper inst{env.vulkan_functions};
588    inst.create_info.add_extensions({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
589    inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
590
591    InstWrapper inst2{env.vulkan_functions};
592    inst2.CheckCreate();
593
594    ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateWaylandSurfaceKHR"));
595}
596
597// When ICD doesn't support the surface creation, the loader should handle it
598TEST(WsiTests, CreateSurfaceWaylandNoICDCreateSupport) {
599    FrameworkEnvironment env{};
600    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
601    auto& cur_icd = env.get_test_icd(0);
602    cur_icd.set_min_icd_interface_version(5);
603    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
604    cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
605    cur_icd.enable_icd_wsi = false;
606
607    InstWrapper inst{env.vulkan_functions};
608    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
609    inst.CheckCreate();
610
611    VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR};
612
613    VkSurfaceKHR surface;
614    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(inst, &createInfo, nullptr, &surface));
615    ASSERT_TRUE(surface != VK_NULL_HANDLE);
616
617    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
618}
619
620// When ICD does support the surface creation, the loader should  delegat handle it to the ICD
621TEST(WsiTests, CreateSurfaceWaylandICDSupport) {
622    FrameworkEnvironment env{};
623    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
624    auto& cur_icd = env.get_test_icd(0);
625    cur_icd.set_min_icd_interface_version(5);
626    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
627    cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
628    cur_icd.enable_icd_wsi = true;
629
630    InstWrapper inst{env.vulkan_functions};
631    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
632    inst.CheckCreate();
633
634    VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR};
635
636    VkSurfaceKHR surface;
637    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(inst, &createInfo, nullptr, &surface));
638    ASSERT_TRUE(surface != VK_NULL_HANDLE);
639
640    env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr);
641}
642
643// Some drivers supporting vkCreateWaylandSurfaceKHR, and at least one that doesn't
644TEST(WsiTests, CreateSurfaceWaylandMixedICDSupport) {
645    FrameworkEnvironment env{};
646    for (uint32_t icd = 0; icd < 3; ++icd) {
647        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
648        Extension second_ext{VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME};
649        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
650        auto& cur_icd = env.get_test_icd(icd);
651        cur_icd.icd_api_version = VK_API_VERSION_1_0;
652        cur_icd.add_instance_extensions({first_ext, second_ext});
653        if (icd < 2) {
654            // Only enable ICD for first two
655            cur_icd.enable_icd_wsi = true;
656        }
657    }
658
659    InstWrapper instance(env.vulkan_functions);
660    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
661    instance.CheckCreate();
662
663    VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR};
664
665    VkSurfaceKHR surface;
666    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(instance.inst, &createInfo, nullptr, &surface));
667    ASSERT_TRUE(surface != VK_NULL_HANDLE);
668
669    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
670}
671
672TEST(WsiTests, GetPhysicalDeviceWaylandPresentNoICDSupport) {
673    FrameworkEnvironment env{};
674    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
675    auto& cur_icd = env.get_test_icd(0);
676    cur_icd.set_min_icd_interface_version(5);
677    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
678    cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
679    cur_icd.physical_devices.emplace_back("physical_device_0");
680    cur_icd.enable_icd_wsi = false;
681
682    InstWrapper inst{env.vulkan_functions};
683    inst.create_info.add_extensions(
684        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
685    inst.CheckCreate();
686
687    uint32_t driver_count = 1;
688    VkPhysicalDevice physical_device;
689    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
690    ASSERT_EQ(driver_count, 1U);
691
692    DebugUtilsWrapper log{inst};
693    CreateDebugUtilsMessenger(log);
694    auto res = env.vulkan_functions.vkGetPhysicalDeviceWaylandPresentationSupportKHR(physical_device, 0, nullptr);
695    ASSERT_EQ(res, VK_FALSE);
696    ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceWaylandPresentationSupportKHR!"));
697}
698
699TEST(WsiTests, GetPhysicalDeviceWaylandPresentICDSupport) {
700    FrameworkEnvironment env{};
701    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
702    auto& cur_icd = env.get_test_icd(0);
703    cur_icd.set_min_icd_interface_version(5);
704    cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME});
705    cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
706    cur_icd.physical_devices.emplace_back("physical_device_0");
707    cur_icd.enable_icd_wsi = true;
708
709    InstWrapper inst{env.vulkan_functions};
710    inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
711    inst.CheckCreate();
712
713    uint32_t driver_count = 1;
714    VkPhysicalDevice physical_device;
715    ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
716    ASSERT_EQ(driver_count, 1U);
717
718    ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceWaylandPresentationSupportKHR(physical_device, 0, nullptr));
719}
720
721TEST(WsiTests, WaylandGetPhysicalDeviceSurfaceSupportKHR) {
722    FrameworkEnvironment env{};
723    const uint32_t max_device_count = 4;
724    for (uint32_t icd = 0; icd < max_device_count; ++icd) {
725        Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME};
726        Extension second_ext{VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME};
727        env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
728        auto& cur_icd = env.get_test_icd(icd);
729        cur_icd.icd_api_version = VK_API_VERSION_1_0;
730        cur_icd.set_min_icd_interface_version(5);
731        cur_icd.add_instance_extensions({first_ext, second_ext});
732        std::string dev_name = "phys_dev_" + std::to_string(icd);
733        cur_icd.physical_devices.emplace_back(dev_name.c_str());
734        cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true});
735        cur_icd.enable_icd_wsi = true;
736    }
737
738    InstWrapper instance(env.vulkan_functions);
739    instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
740    instance.CheckCreate();
741
742    VkSurfaceKHR surface{VK_NULL_HANDLE};
743    VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR};
744    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(instance.inst, &createInfo, nullptr, &surface));
745    ASSERT_TRUE(surface != VK_NULL_HANDLE);
746
747    uint32_t device_count = max_device_count;
748    std::array<VkPhysicalDevice, max_device_count> phys_devs;
749    ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data()));
750    ASSERT_EQ(device_count, max_device_count);
751
752    for (uint32_t pd = 0; pd < max_device_count; ++pd) {
753        VkBool32 supported = VK_FALSE;
754        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported));
755    }
756
757    env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
758}
759#endif
760
761TEST(WsiTests, ForgetEnableSurfaceExtensions) {
762    FrameworkEnvironment env{};
763    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
764        .setup_WSI()
765        .add_physical_device(PhysicalDevice{}.add_extension("VK_KHR_swapchain").finish());
766
767    InstWrapper inst{env.vulkan_functions};
768    inst.create_info.add_extension("VK_KHR_surface");
769    ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
770
771    VkSurfaceKHR surface{};
772    ASSERT_EQ(VK_ERROR_EXTENSION_NOT_PRESENT, create_surface(inst, surface));
773}
774
775TEST(WsiTests, SwapchainFunctional) {
776    FrameworkEnvironment env{};
777    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
778        .setup_WSI()
779        .add_physical_device(PhysicalDevice{}.add_extension("VK_KHR_swapchain").finish());
780
781    InstWrapper inst{env.vulkan_functions};
782    inst.create_info.setup_WSI();
783    inst.CheckCreate();
784    VkSurfaceKHR surface{};
785    ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface));
786    VkPhysicalDevice phys_dev = inst.GetPhysDev();
787
788    {  // Use GDPA to get functions
789        DeviceWrapper dev{inst};
790        dev.create_info.add_extension("VK_KHR_swapchain");
791
792        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
793
794        VkSwapchainKHR swapchain{};
795        VkSwapchainCreateInfoKHR swap_create_info{};
796        swap_create_info.surface = surface;
797        DeviceFunctions funcs{*inst.functions, dev};
798        ASSERT_EQ(VK_SUCCESS, funcs.vkCreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain));
799        uint32_t count = 0;
800        ASSERT_EQ(VK_SUCCESS, funcs.vkGetSwapchainImagesKHR(dev, swapchain, &count, nullptr));
801        ASSERT_GT(count, 0U);
802        std::array<VkImage, 16> images;
803        ASSERT_EQ(VK_SUCCESS, funcs.vkGetSwapchainImagesKHR(dev, swapchain, &count, images.data()));
804        funcs.vkDestroySwapchainKHR(dev, swapchain, nullptr);
805    }
806    {  // Use GIPA gotten functions
807        DeviceWrapper dev{inst};
808        dev.create_info.add_extension("VK_KHR_swapchain");
809
810        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
811
812        PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
813        PFN_vkGetSwapchainImagesKHR inst_GetSwapchainImagesKHR = inst.load("vkGetSwapchainImagesKHR");
814        PFN_vkDestroySwapchainKHR inst_DestroySwapchainKHR = inst.load("vkDestroySwapchainKHR");
815        ASSERT_TRUE(nullptr != inst_CreateSwapchainKHR);
816        ASSERT_TRUE(nullptr != inst_GetSwapchainImagesKHR);
817        ASSERT_TRUE(nullptr != inst_DestroySwapchainKHR);
818
819        VkSwapchainKHR swapchain{};
820        VkSwapchainCreateInfoKHR swap_create_info{};
821        swap_create_info.surface = surface;
822
823        ASSERT_EQ(VK_SUCCESS, inst_CreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain));
824        uint32_t count = 0;
825        ASSERT_EQ(VK_SUCCESS, inst_GetSwapchainImagesKHR(dev, swapchain, &count, nullptr));
826        ASSERT_GT(count, 0U);
827        std::array<VkImage, 16> images;
828        ASSERT_EQ(VK_SUCCESS, inst_GetSwapchainImagesKHR(dev, swapchain, &count, images.data()));
829        inst_DestroySwapchainKHR(dev, swapchain, nullptr);
830    }
831    {  // forget to enable the extension
832        DeviceWrapper dev{inst};
833        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
834
835        DeviceFunctions funcs{*inst.functions, dev};
836        ASSERT_EQ(funcs.vkCreateSwapchainKHR, nullptr);
837        ASSERT_EQ(funcs.vkGetSwapchainImagesKHR, nullptr);
838        ASSERT_EQ(funcs.vkDestroySwapchainKHR, nullptr);
839    }
840    {  // forget to set the surface
841        DeviceWrapper dev{inst};
842        dev.create_info.add_extension("VK_KHR_swapchain");
843
844        dev.CheckCreate(phys_dev);
845
846        VkSwapchainKHR swapchain{};
847        VkSwapchainCreateInfoKHR swap_create_info{};
848        DeviceFunctions funcs{*inst.functions, dev};
849        ASSERT_DEATH(funcs.vkCreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain), "");
850    }
851    env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr);
852}
853