/* * Copyright (c) 2021-2022 The Khronos Group Inc. * Copyright (c) 2021-2022 Valve Corporation * Copyright (c) 2021-2022 LunarG, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and/or associated documentation files (the "Materials"), to * deal in the Materials without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Materials, and to permit persons to whom the Materials are * furnished to do so, subject to the following conditions: * * The above copyright notice(s) and this permission notice shall be included in * all copies or substantial portions of the Materials. * * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE * USE OR OTHER DEALINGS IN THE MATERIALS. * * Author: Charles Giessen */ #include "test_environment.h" class WsiTests : public ::testing::Test {}; #if defined(VK_USE_PLATFORM_WIN32_KHR) // When ICD doesn't support the extension, create instance should fail TEST(WsiTests, CreateSurfaceWin32NoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT); InstWrapper inst2{env.vulkan_functions}; inst2.CheckCreate(); ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateWin32SurfaceKHR")); } // When ICD doesn't support the surface creation, the loader should handle it TEST(WsiTests, CreateSurfaceWin32NoICDCreateSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkSurfaceKHR surface{VK_NULL_HANDLE}; VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(inst, &surf_create_info, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // When ICD does support the surface creation, the loader should delegat handle it to the ICD TEST(WsiTests, CreateSurfaceWin32ICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkSurfaceKHR surface{VK_NULL_HANDLE}; VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(inst, &surf_create_info, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // Some drivers supporting vkCreateWin32SurfaceKHR, and at least one that doesn't TEST(WsiTests, CreateSurfaceWin32MixedICDSupport) { FrameworkEnvironment env{}; for (uint32_t icd = 0; icd < 3; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_WIN32_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.add_instance_extensions({first_ext, second_ext}); if (icd < 2) { // Only enable ICD for first two cur_icd.enable_icd_wsi = true; } } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkSurfaceKHR surface{VK_NULL_HANDLE}; VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(instance.inst, &surf_create_info, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } TEST(WsiTests, GetPhysicalDeviceWin32PresentNoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions( {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); DebugUtilsWrapper log{inst}; CreateDebugUtilsMessenger(log); auto res = env.vulkan_functions.vkGetPhysicalDeviceWin32PresentationSupportKHR(physical_device, 0); ASSERT_EQ(res, VK_FALSE); ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceWin32PresentationSupportKHR!")); } TEST(WsiTests, GetPhysicalDeviceWin32PresentICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceWin32PresentationSupportKHR(physical_device, 0)); } TEST(WsiTests, Win32GetPhysicalDeviceSurfaceSupportKHR) { FrameworkEnvironment env{}; const uint32_t max_device_count = 4; for (uint32_t icd = 0; icd < max_device_count; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_WIN32_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extensions({first_ext, second_ext}); std::string dev_name = "phys_dev_" + std::to_string(icd); cur_icd.physical_devices.emplace_back(dev_name.c_str()); cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true}); cur_icd.enable_icd_wsi = true; } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkSurfaceKHR surface{VK_NULL_HANDLE}; VkWin32SurfaceCreateInfoKHR surf_create_info{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWin32SurfaceKHR(instance.inst, &surf_create_info, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); uint32_t device_count = max_device_count; std::array phys_devs; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data())); ASSERT_EQ(device_count, max_device_count); for (uint32_t pd = 0; pd < max_device_count; ++pd) { VkBool32 supported = VK_FALSE; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported)); } env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } #endif #if defined(VK_USE_PLATFORM_XCB_KHR) // When ICD doesn't support the extension, create instance should fail TEST(WsiTests, CreateSurfaceXCBNoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_XCB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT); InstWrapper inst2{env.vulkan_functions}; inst2.CheckCreate(); ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateXcbSurfaceKHR")); } // When ICD doesn't support the surface creation, the loader should handle it TEST(WsiTests, CreateSurfaceXCBNoICDCreateSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface{VK_NULL_HANDLE}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(inst, &xcb_createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // When ICD does support the surface creation, the loader should delegat handle it to the ICD TEST(WsiTests, CreateSurfaceXCBICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface{VK_NULL_HANDLE}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(inst, &xcb_createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // Some drivers supporting vkCreateXcbSurfaceKHR, and at least one that doesn't TEST(WsiTests, CreateSurfaceXCBMixedICDSupport) { FrameworkEnvironment env{}; for (uint32_t icd = 0; icd < 3; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_XCB_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.add_instance_extensions({first_ext, second_ext}); if (icd < 2) { // Only enable ICD for first two cur_icd.enable_icd_wsi = true; } } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface{VK_NULL_HANDLE}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(instance.inst, &xcb_createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } TEST(WsiTests, GetPhysicalDeviceXcbPresentNoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions( {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); DebugUtilsWrapper log{inst}; CreateDebugUtilsMessenger(log); auto res = env.vulkan_functions.vkGetPhysicalDeviceXcbPresentationSupportKHR(physical_device, 0, nullptr, 0); ASSERT_EQ(res, VK_FALSE); ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceXcbPresentationSupportKHR!")); } TEST(WsiTests, GetPhysicalDeviceXcbPresentICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XCB_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceXcbPresentationSupportKHR(physical_device, 0, nullptr, 0)); } TEST(WsiTests, XcbGetPhysicalDeviceSurfaceSupportKHR) { FrameworkEnvironment env{}; const uint32_t max_device_count = 4; for (uint32_t icd = 0; icd < max_device_count; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_XCB_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extensions({first_ext, second_ext}); std::string dev_name = "phys_dev_" + std::to_string(icd); cur_icd.physical_devices.emplace_back(dev_name.c_str()); cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true}); cur_icd.enable_icd_wsi = true; } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkSurfaceKHR surface{VK_NULL_HANDLE}; VkXcbSurfaceCreateInfoKHR xcb_createInfo{VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXcbSurfaceKHR(instance.inst, &xcb_createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); uint32_t device_count = max_device_count; std::array phys_devs; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data())); ASSERT_EQ(device_count, max_device_count); for (uint32_t pd = 0; pd < max_device_count; ++pd) { VkBool32 supported = VK_FALSE; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported)); } env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) // When ICD doesn't support the extension, create instance should fail TEST(WsiTests, CreateSurfaceXLIBNoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT); InstWrapper inst2{env.vulkan_functions}; inst2.CheckCreate(); ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateXlibSurfaceKHR")); } // When ICD doesn't support the surface creation, the loader should handle it TEST(WsiTests, CreateSurfaceXLIBNoICDCreateSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // When ICD does support the surface creation, the loader should delegat handle it to the ICD TEST(WsiTests, CreateSurfaceXLIBICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // Some drivers supporting vkCreateXlibSurfaceKHR, and at least one that doesn't TEST(WsiTests, CreateSurfaceXLIBMixedICDSupport) { FrameworkEnvironment env{}; for (uint32_t icd = 0; icd < 3; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_XLIB_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.add_instance_extensions({first_ext, second_ext}); if (icd < 2) { // Only enable ICD for first two cur_icd.enable_icd_wsi = true; } } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(instance.inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } TEST(WsiTests, GetPhysicalDeviceXlibPresentNoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions( {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); DebugUtilsWrapper log{inst}; CreateDebugUtilsMessenger(log); auto res = env.vulkan_functions.vkGetPhysicalDeviceXlibPresentationSupportKHR(physical_device, 0, nullptr, 0); ASSERT_EQ(res, VK_FALSE); ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceXlibPresentationSupportKHR!")); } TEST(WsiTests, GetPhysicalDeviceXlibPresentICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceXlibPresentationSupportKHR(physical_device, 0, nullptr, 0)); } TEST(WsiTests, XlibGetPhysicalDeviceSurfaceSupportKHR) { FrameworkEnvironment env{}; const uint32_t max_device_count = 4; for (uint32_t icd = 0; icd < max_device_count; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_XLIB_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extensions({first_ext, second_ext}); std::string dev_name = "phys_dev_" + std::to_string(icd); cur_icd.physical_devices.emplace_back(dev_name.c_str()); cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true}); cur_icd.enable_icd_wsi = true; } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkSurfaceKHR surface{VK_NULL_HANDLE}; VkXlibSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateXlibSurfaceKHR(instance.inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); uint32_t device_count = max_device_count; std::array phys_devs; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data())); ASSERT_EQ(device_count, max_device_count); for (uint32_t pd = 0; pd < max_device_count; ++pd) { VkBool32 supported = VK_FALSE; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported)); } env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) // When ICD doesn't support the extension, create instance should fail TEST(WsiTests, CreateSurfaceWaylandNoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT); InstWrapper inst2{env.vulkan_functions}; inst2.CheckCreate(); ASSERT_EQ(nullptr, env.vulkan_functions.vkGetInstanceProcAddr(inst2.inst, "vkCreateWaylandSurfaceKHR")); } // When ICD doesn't support the surface creation, the loader should handle it TEST(WsiTests, CreateSurfaceWaylandNoICDCreateSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // When ICD does support the surface creation, the loader should delegat handle it to the ICD TEST(WsiTests, CreateSurfaceWaylandICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(inst, surface, nullptr); } // Some drivers supporting vkCreateWaylandSurfaceKHR, and at least one that doesn't TEST(WsiTests, CreateSurfaceWaylandMixedICDSupport) { FrameworkEnvironment env{}; for (uint32_t icd = 0; icd < 3; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.add_instance_extensions({first_ext, second_ext}); if (icd < 2) { // Only enable ICD for first two cur_icd.enable_icd_wsi = true; } } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR}; VkSurfaceKHR surface; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(instance.inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } TEST(WsiTests, GetPhysicalDeviceWaylandPresentNoICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = false; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions( {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); DebugUtilsWrapper log{inst}; CreateDebugUtilsMessenger(log); auto res = env.vulkan_functions.vkGetPhysicalDeviceWaylandPresentationSupportKHR(physical_device, 0, nullptr); ASSERT_EQ(res, VK_FALSE); ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceWaylandPresentationSupportKHR!")); } TEST(WsiTests, GetPhysicalDeviceWaylandPresentICDSupport) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(0); cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extension({VK_KHR_SURFACE_EXTENSION_NAME}); cur_icd.add_instance_extension({VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); cur_icd.physical_devices.emplace_back("physical_device_0"); cur_icd.enable_icd_wsi = true; InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); inst.CheckCreate(); uint32_t driver_count = 1; VkPhysicalDevice physical_device; ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device)); ASSERT_EQ(driver_count, 1U); ASSERT_EQ(VK_TRUE, env.vulkan_functions.vkGetPhysicalDeviceWaylandPresentationSupportKHR(physical_device, 0, nullptr)); } TEST(WsiTests, WaylandGetPhysicalDeviceSurfaceSupportKHR) { FrameworkEnvironment env{}; const uint32_t max_device_count = 4; for (uint32_t icd = 0; icd < max_device_count; ++icd) { Extension first_ext{VK_KHR_SURFACE_EXTENSION_NAME}; Extension second_ext{VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)); auto& cur_icd = env.get_test_icd(icd); cur_icd.icd_api_version = VK_API_VERSION_1_0; cur_icd.set_min_icd_interface_version(5); cur_icd.add_instance_extensions({first_ext, second_ext}); std::string dev_name = "phys_dev_" + std::to_string(icd); cur_icd.physical_devices.emplace_back(dev_name.c_str()); cur_icd.physical_devices.back().add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true}); cur_icd.enable_icd_wsi = true; } InstWrapper instance(env.vulkan_functions); instance.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}); instance.CheckCreate(); VkSurfaceKHR surface{VK_NULL_HANDLE}; VkWaylandSurfaceCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR}; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkCreateWaylandSurfaceKHR(instance.inst, &createInfo, nullptr, &surface)); ASSERT_TRUE(surface != VK_NULL_HANDLE); uint32_t device_count = max_device_count; std::array phys_devs; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(instance.inst, &device_count, phys_devs.data())); ASSERT_EQ(device_count, max_device_count); for (uint32_t pd = 0; pd < max_device_count; ++pd) { VkBool32 supported = VK_FALSE; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceSupportKHR(phys_devs[pd], 0, surface, &supported)); } env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr); } #endif TEST(WsiTests, ForgetEnableSurfaceExtensions) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) .setup_WSI() .add_physical_device(PhysicalDevice{}.add_extension("VK_KHR_swapchain").finish()); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extension("VK_KHR_surface"); ASSERT_NO_FATAL_FAILURE(inst.CheckCreate()); VkSurfaceKHR surface{}; ASSERT_EQ(VK_ERROR_EXTENSION_NOT_PRESENT, create_surface(inst, surface)); } TEST(WsiTests, SwapchainFunctional) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) .setup_WSI() .add_physical_device(PhysicalDevice{}.add_extension("VK_KHR_swapchain").finish()); InstWrapper inst{env.vulkan_functions}; inst.create_info.setup_WSI(); inst.CheckCreate(); VkSurfaceKHR surface{}; ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); VkPhysicalDevice phys_dev = inst.GetPhysDev(); { // Use GDPA to get functions DeviceWrapper dev{inst}; dev.create_info.add_extension("VK_KHR_swapchain"); ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev)); VkSwapchainKHR swapchain{}; VkSwapchainCreateInfoKHR swap_create_info{}; swap_create_info.surface = surface; DeviceFunctions funcs{*inst.functions, dev}; ASSERT_EQ(VK_SUCCESS, funcs.vkCreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain)); uint32_t count = 0; ASSERT_EQ(VK_SUCCESS, funcs.vkGetSwapchainImagesKHR(dev, swapchain, &count, nullptr)); ASSERT_GT(count, 0U); std::array images; ASSERT_EQ(VK_SUCCESS, funcs.vkGetSwapchainImagesKHR(dev, swapchain, &count, images.data())); funcs.vkDestroySwapchainKHR(dev, swapchain, nullptr); } { // Use GIPA gotten functions DeviceWrapper dev{inst}; dev.create_info.add_extension("VK_KHR_swapchain"); ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev)); PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR"); PFN_vkGetSwapchainImagesKHR inst_GetSwapchainImagesKHR = inst.load("vkGetSwapchainImagesKHR"); PFN_vkDestroySwapchainKHR inst_DestroySwapchainKHR = inst.load("vkDestroySwapchainKHR"); ASSERT_TRUE(nullptr != inst_CreateSwapchainKHR); ASSERT_TRUE(nullptr != inst_GetSwapchainImagesKHR); ASSERT_TRUE(nullptr != inst_DestroySwapchainKHR); VkSwapchainKHR swapchain{}; VkSwapchainCreateInfoKHR swap_create_info{}; swap_create_info.surface = surface; ASSERT_EQ(VK_SUCCESS, inst_CreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain)); uint32_t count = 0; ASSERT_EQ(VK_SUCCESS, inst_GetSwapchainImagesKHR(dev, swapchain, &count, nullptr)); ASSERT_GT(count, 0U); std::array images; ASSERT_EQ(VK_SUCCESS, inst_GetSwapchainImagesKHR(dev, swapchain, &count, images.data())); inst_DestroySwapchainKHR(dev, swapchain, nullptr); } { // forget to enable the extension DeviceWrapper dev{inst}; ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev)); DeviceFunctions funcs{*inst.functions, dev}; ASSERT_EQ(funcs.vkCreateSwapchainKHR, nullptr); ASSERT_EQ(funcs.vkGetSwapchainImagesKHR, nullptr); ASSERT_EQ(funcs.vkDestroySwapchainKHR, nullptr); } { // forget to set the surface DeviceWrapper dev{inst}; dev.create_info.add_extension("VK_KHR_swapchain"); dev.CheckCreate(phys_dev); VkSwapchainKHR swapchain{}; VkSwapchainCreateInfoKHR swap_create_info{}; DeviceFunctions funcs{*inst.functions, dev}; ASSERT_DEATH(funcs.vkCreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain), ""); } env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr); } TEST(WsiTests, EXTSurfaceMaintenance1) { FrameworkEnvironment env{}; std::vector present_modes{VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR}; VkSurfaceCapabilitiesKHR surface_caps{}; surface_caps.maxImageExtent = VkExtent2D{300, 300}; surface_caps.minImageExtent = VkExtent2D{100, 100}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) .setup_WSI() .add_instance_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME) .add_physical_device(PhysicalDevice{} .add_extension("VK_KHR_swapchain") .set_deviceName("no") .set_surface_capabilities(surface_caps) .add_surface_present_modes(present_modes) .finish()); VkSurfacePresentScalingCapabilitiesEXT scaling_capabilities{}; scaling_capabilities.supportedPresentScaling = VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT; scaling_capabilities.supportedPresentGravityX = VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT; scaling_capabilities.supportedPresentGravityY = VK_PRESENT_SCALING_STRETCH_BIT_EXT; scaling_capabilities.minScaledImageExtent = {60, 60}; scaling_capabilities.maxScaledImageExtent = {1000, 1000}; auto& icd2 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) .setup_WSI() .add_instance_extension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME) .add_instance_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME) .add_physical_device(PhysicalDevice{} .add_extension("VK_KHR_swapchain") .set_deviceName("yes") .set_surface_capabilities(surface_caps) .add_surface_present_modes(present_modes) .set_surface_present_scaling_capabilities(scaling_capabilities) .finish()); std::vector> compatible_present_modes{ {VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR}, {VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR}, {VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR}, {VK_PRESENT_MODE_FIFO_RELAXED_KHR, VK_PRESENT_MODE_FIFO_KHR}, }; icd2.physical_devices[0].surface_present_mode_compatibility = compatible_present_modes; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) .setup_WSI() .add_physical_device(PhysicalDevice{} .add_extension("VK_KHR_swapchain") .set_deviceName("no") .set_surface_capabilities(surface_caps) .add_surface_present_modes(present_modes) .finish()); InstWrapper inst{env.vulkan_functions}; inst.create_info.setup_WSI(); inst.create_info.add_extension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME); inst.create_info.add_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME); inst.CheckCreate(); VkSurfaceKHR surface{}; ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); WrappedHandle wrapped_surface{surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR}; auto physical_devices = inst.GetPhysDevs(3); for (auto physical_device : physical_devices) { VkPhysicalDeviceProperties phys_dev_props{}; inst->vkGetPhysicalDeviceProperties(physical_device, &phys_dev_props); bool driver_support_surface_maintenance1 = string_eq(phys_dev_props.deviceName, "yes"); uint32_t present_mode_count = 4; std::vector queried_present_modes{present_mode_count}; inst->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_mode_count, queried_present_modes.data()); for (uint32_t i = 0; i < present_mode_count; i++) { VkSurfacePresentModeEXT present_mode{}; present_mode.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT; present_mode.presentMode = queried_present_modes[i]; VkPhysicalDeviceSurfaceInfo2KHR surface_info{}; surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR; surface_info.surface = surface; surface_info.pNext = &present_mode; VkSurfacePresentModeCompatibilityEXT SurfacePresentModeCompatibilityEXT{}; SurfacePresentModeCompatibilityEXT.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT; VkSurfacePresentScalingCapabilitiesEXT SurfacePresentScalingCapabilitiesEXT{}; SurfacePresentScalingCapabilitiesEXT.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT; SurfacePresentScalingCapabilitiesEXT.pNext = &SurfacePresentModeCompatibilityEXT; VkSurfaceCapabilities2KHR surface_caps2{}; surface_caps2.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR; surface_caps2.pNext = &SurfacePresentScalingCapabilitiesEXT; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceCapabilities2KHR(physical_device, &surface_info, &surface_caps2)); if (driver_support_surface_maintenance1) { ASSERT_EQ(SurfacePresentModeCompatibilityEXT.presentModeCount, 2U); } else { ASSERT_EQ(SurfacePresentModeCompatibilityEXT.presentModeCount, 1U); } std::vector queried_compatible_present_modes{SurfacePresentModeCompatibilityEXT.presentModeCount}; SurfacePresentModeCompatibilityEXT.pPresentModes = queried_compatible_present_modes.data(); ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceCapabilities2KHR(physical_device, &surface_info, &surface_caps2)); if (driver_support_surface_maintenance1) { ASSERT_EQ(compatible_present_modes[i], queried_compatible_present_modes); ASSERT_EQ(scaling_capabilities, SurfacePresentScalingCapabilitiesEXT); } else { // Make sure the emulation returned the values we expect - 1 compatible present mode which is the mode we are // querying, Scaling capabilities is 0 (aka none) and the extent is just the surface caps extent ASSERT_EQ(SurfacePresentModeCompatibilityEXT.presentModeCount, 1U); ASSERT_EQ(SurfacePresentModeCompatibilityEXT.pPresentModes[0], queried_present_modes[i]); ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.supportedPresentScaling, 0U); ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.supportedPresentGravityX, 0u); ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.supportedPresentGravityY, 0U); ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.minScaledImageExtent, surface_caps.minImageExtent); ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.maxScaledImageExtent, surface_caps.maxImageExtent); } } } }