From c2bbc841d5917a12cab88c93f5c8c2c26a31098c Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Fri, 22 Mar 2024 11:57:40 -0500 Subject: [PATCH] Enhance DriverUnloading tests with arrays of handles Drivers resize after 32 elements, so to test that path we need to loop over instance level handle creation (surface, debug messenger, debug report). --- tests/framework/icd/test_icd.cpp | 4 +- tests/framework/test_environment.h | 47 ++++++++++ tests/framework/test_util.h | 10 ++- tests/loader_regression_tests.cpp | 135 +++++++++++++++++++++++++---- 4 files changed, 172 insertions(+), 24 deletions(-) diff --git a/tests/framework/icd/test_icd.cpp b/tests/framework/icd/test_icd.cpp index ebd7eae3fc..a3ca585b7f 100644 --- a/tests/framework/icd/test_icd.cpp +++ b/tests/framework/icd/test_icd.cpp @@ -334,13 +334,13 @@ VKAPI_ATTR void VKAPI_CALL test_vkDestroyDebugUtilsMessengerEXT([[maybe_unused]] VkDebugUtilsMessengerEXT messenger, [[maybe_unused]] const VkAllocationCallbacks* pAllocator) { if (messenger != VK_NULL_HANDLE) { - uint64_t fake_msgr_handle = (uint64_t)(messenger); + uint64_t fake_msgr_handle = reinterpret_cast(messenger); auto found_iter = std::find(icd.messenger_handles.begin(), icd.messenger_handles.end(), fake_msgr_handle); if (found_iter != icd.messenger_handles.end()) { // Remove it from the list icd.messenger_handles.erase(found_iter); // Delete the handle - delete (uint8_t*)fake_msgr_handle; + delete reinterpret_cast(fake_msgr_handle); } else { std::cerr << "Messenger not found during destroy!\n"; abort(); diff --git a/tests/framework/test_environment.h b/tests/framework/test_environment.h index 3f6bf519db..8c9b6d1fcb 100644 --- a/tests/framework/test_environment.h +++ b/tests/framework/test_environment.h @@ -338,6 +338,41 @@ struct DeviceWrapper { DeviceCreateInfo create_info{}; }; +template +struct WrappedHandle { + WrappedHandle(HandleType in_handle, ParentType in_parent, DestroyFuncType in_destroy_func, + VkAllocationCallbacks* in_callbacks = nullptr) + : handle(in_handle), parent(in_parent), destroy_func(in_destroy_func), callbacks(in_callbacks) {} + ~WrappedHandle() { + if (handle) { + destroy_func(parent, handle, callbacks); + handle = VK_NULL_HANDLE; + } + } + WrappedHandle(WrappedHandle const&) = delete; + WrappedHandle& operator=(WrappedHandle const&) = delete; + WrappedHandle(WrappedHandle&& other) noexcept + : handle(other.handle), parent(other.parent), destroy_func(other.destroy_func), callbacks(other.callbacks) { + other.handle = VK_NULL_HANDLE; + } + WrappedHandle& operator=(WrappedHandle&& other) noexcept { + if (handle != VK_NULL_HANDLE) { + destroy_func(parent, handle, callbacks); + } + handle = other.handle; + other.handle = VK_NULL_HANDLE; + parent = other.parent; + destroy_func = other.destroy_func; + callbacks = other.callbacks; + return *this; + } + + HandleType handle = VK_NULL_HANDLE; + ParentType parent = VK_NULL_HANDLE; + DestroyFuncType destroy_func = nullptr; + VkAllocationCallbacks* callbacks = nullptr; +}; + struct DebugUtilsLogger { static VkBool32 VKAPI_PTR DebugUtilsMessengerLoggerCallback([[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, @@ -369,6 +404,16 @@ struct DebugUtilsLogger { DebugUtilsLogger& operator=(DebugUtilsLogger&&) = delete; // Find a string in the log output bool find(std::string const& search_text) const { return returned_output.find(search_text) != std::string::npos; } + // Find the number of times a string appears in the log output + uint32_t count(std::string const& search_text) const { + uint32_t occurrences = 0; + std::string::size_type position = 0; + while ((position = returned_output.find(search_text, position)) != std::string::npos) { + ++occurrences; + position += search_text.length(); + } + return occurrences; + } // Look through the event log. If you find a line containing the prefix we're interested in, look for the end of // line character, and then see if the postfix occurs in it as well. @@ -396,6 +441,7 @@ struct DebugUtilsWrapper { ~DebugUtilsWrapper() noexcept { if (messenger) { vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks); + messenger = VK_NULL_HANDLE; } } // Immoveable object @@ -405,6 +451,7 @@ struct DebugUtilsWrapper { DebugUtilsWrapper& operator=(DebugUtilsWrapper&&) = delete; bool find(std::string const& search_text) { return logger.find(search_text); } + uint32_t count(std::string const& search_text) { return logger.count(search_text); } VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return logger.get(); } DebugUtilsLogger logger; diff --git a/tests/framework/test_util.h b/tests/framework/test_util.h index d7a214316b..4c66db4443 100644 --- a/tests/framework/test_util.h +++ b/tests/framework/test_util.h @@ -411,18 +411,20 @@ struct FRAMEWORK_EXPORT DispatchableHandle { handle = reinterpret_cast(ptr_handle); } ~DispatchableHandle() { - delete reinterpret_cast(handle); + if (handle) { + delete reinterpret_cast(handle); + } handle = nullptr; } DispatchableHandle(DispatchableHandle const&) = delete; DispatchableHandle& operator=(DispatchableHandle const&) = delete; DispatchableHandle(DispatchableHandle&& other) noexcept : handle(other.handle) { other.handle = nullptr; } DispatchableHandle& operator=(DispatchableHandle&& other) noexcept { - if (this != &other) { + if (handle) { delete reinterpret_cast(handle); - handle = other.handle; - other.handle = nullptr; } + handle = other.handle; + other.handle = nullptr; return *this; } bool operator==(T base_handle) { return base_handle == handle; } diff --git a/tests/loader_regression_tests.cpp b/tests/loader_regression_tests.cpp index 91cebedb14..4570493eba 100644 --- a/tests/loader_regression_tests.cpp +++ b/tests/loader_regression_tests.cpp @@ -4429,7 +4429,7 @@ TEST(EnumerateAdapterPhysicalDevices, SameAdapterLUID_same_order) { } #endif // defined(WIN32) -void try_create_swapchain(InstWrapper& inst, VkPhysicalDevice physical_device, DeviceWrapper& dev, VkSurfaceKHR& surface) { +void try_create_swapchain(InstWrapper& inst, VkPhysicalDevice physical_device, DeviceWrapper& dev, VkSurfaceKHR const& surface) { PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR = inst.load("vkGetPhysicalDeviceSurfaceSupportKHR"); PFN_vkCreateSwapchainKHR CreateSwapchainKHR = dev.load("vkCreateSwapchainKHR"); PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR = dev.load("vkGetSwapchainImagesKHR"); @@ -4490,16 +4490,25 @@ TEST(DriverUnloadingFromZeroPhysDevs, InterspersedThroughout) { ASSERT_TRUE(submit_message != nullptr); auto phys_devs = inst.GetPhysDevs(); - VkSurfaceKHR surface{}; - ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + std::vector> messengers; + std::vector> surfaces; + for (uint32_t i = 0; i < 35; i++) { + VkDebugUtilsMessengerEXT messenger; + ASSERT_EQ(VK_SUCCESS, log.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger)); + messengers.emplace_back(messenger, inst.inst, log.vkDestroyDebugUtilsMessengerEXT); + + VkSurfaceKHR surface{}; + ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + surfaces.emplace_back(surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR); + } for (const auto& phys_dev : phys_devs) { DeviceWrapper dev{inst}; dev.create_info.add_extension("VK_KHR_swapchain"); dev.CheckCreate(phys_dev); - - try_create_swapchain(inst, phys_dev, dev, surface); + for (const auto& surface : surfaces) { + try_create_swapchain(inst, phys_dev, dev, surface.handle); + } } - env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr); } TEST(DriverUnloadingFromZeroPhysDevs, InMiddleOfList) { @@ -4518,16 +4527,25 @@ TEST(DriverUnloadingFromZeroPhysDevs, InMiddleOfList) { ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log)); auto phys_devs = inst.GetPhysDevs(); - VkSurfaceKHR surface{}; - ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + std::vector> messengers; + std::vector> surfaces; + for (uint32_t i = 0; i < 35; i++) { + VkDebugUtilsMessengerEXT messenger; + ASSERT_EQ(VK_SUCCESS, log.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger)); + messengers.emplace_back(messenger, inst.inst, log.vkDestroyDebugUtilsMessengerEXT); + + VkSurfaceKHR surface{}; + ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + surfaces.emplace_back(surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR); + } for (const auto& phys_dev : phys_devs) { DeviceWrapper dev{inst}; dev.create_info.add_extension("VK_KHR_swapchain"); dev.CheckCreate(phys_dev); - - try_create_swapchain(inst, phys_dev, dev, surface); + for (const auto& surface : surfaces) { + try_create_swapchain(inst, phys_dev, dev, surface.handle); + } } - env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr); } TEST(DriverUnloadingFromZeroPhysDevs, AtFrontAndBack) { @@ -4544,20 +4562,31 @@ TEST(DriverUnloadingFromZeroPhysDevs, AtFrontAndBack) { inst.create_info.setup_WSI(); FillDebugUtilsCreateDetails(inst.create_info, debug_log); inst.CheckCreate(); + DebugUtilsWrapper log{inst}; ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log)); auto phys_devs = inst.GetPhysDevs(); - VkSurfaceKHR surface{}; - ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + std::vector> messengers; + std::vector> surfaces; + for (uint32_t i = 0; i < 35; i++) { + VkDebugUtilsMessengerEXT messenger; + ASSERT_EQ(VK_SUCCESS, log.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger)); + messengers.emplace_back(messenger, inst.inst, log.vkDestroyDebugUtilsMessengerEXT); + + VkSurfaceKHR surface{}; + ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + surfaces.emplace_back(surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR); + } for (const auto& phys_dev : phys_devs) { DeviceWrapper dev{inst}; dev.create_info.add_extension("VK_KHR_swapchain"); dev.CheckCreate(phys_dev); - try_create_swapchain(inst, phys_dev, dev, surface); + for (const auto& surface : surfaces) { + try_create_swapchain(inst, phys_dev, dev, surface.handle); + } } - env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr); } TEST(DriverUnloadingFromZeroPhysDevs, NoPhysicaldevices) { @@ -4577,8 +4606,78 @@ TEST(DriverUnloadingFromZeroPhysDevs, NoPhysicaldevices) { // No physical devices == VK_ERROR_INITIALIZATION_FAILED inst.GetPhysDevs(VK_ERROR_INITIALIZATION_FAILED); - VkSurfaceKHR surface{}; - ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + std::vector> messengers; + std::vector> surfaces; + for (uint32_t i = 0; i < 35; i++) { + VkDebugUtilsMessengerEXT messenger; + ASSERT_EQ(VK_SUCCESS, log.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger)); + messengers.emplace_back(messenger, inst.inst, log.vkDestroyDebugUtilsMessengerEXT); + + VkSurfaceKHR surface{}; + ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + surfaces.emplace_back(surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR); + } +} + +TEST(DriverUnloadingFromZeroPhysDevs, HandleRecreation) { + FrameworkEnvironment env{}; + add_empty_driver_for_unloading_testing(env); + add_driver_for_unloading_testing(env); + add_empty_driver_for_unloading_testing(env); + add_driver_for_unloading_testing(env); + add_empty_driver_for_unloading_testing(env); + + DebugUtilsLogger debug_log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + InstWrapper inst{env.vulkan_functions}; + inst.create_info.setup_WSI(); + FillDebugUtilsCreateDetails(inst.create_info, debug_log); + inst.CheckCreate(); + DebugUtilsWrapper log{inst}; + ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log)); + + PFN_vkSubmitDebugUtilsMessageEXT submit_message = inst.load("vkSubmitDebugUtilsMessageEXT"); + ASSERT_TRUE(submit_message != nullptr); + + auto phys_devs = inst.GetPhysDevs(); + std::vector> messengers; + std::vector> surfaces; + for (uint32_t i = 0; i < 35; i++) { + VkDebugUtilsMessengerEXT messenger; + ASSERT_EQ(VK_SUCCESS, log.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger)); + messengers.emplace_back(messenger, inst.inst, log.vkDestroyDebugUtilsMessengerEXT); + + VkSurfaceKHR surface{}; + ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + surfaces.emplace_back(surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR); + } + // Remove some elements arbitrarily - remove 15 of each + for (uint32_t i = 1; i < 31; i += 2) { + messengers.erase(messengers.begin() + i); + surfaces.erase(surfaces.begin() + i); + } + // Add in another 100 + for (uint32_t i = 0; i < 100; i++) { + VkDebugUtilsMessengerEXT messenger; + ASSERT_EQ(VK_SUCCESS, log.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger)); + messengers.emplace_back(messenger, inst.inst, log.vkDestroyDebugUtilsMessengerEXT); + + VkSurfaceKHR surface{}; + ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + surfaces.emplace_back(surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR); + } + for (const auto& phys_dev : phys_devs) { + DeviceWrapper dev{inst}; + dev.create_info.add_extension("VK_KHR_swapchain"); + dev.CheckCreate(phys_dev); + for (const auto& surface : surfaces) { + try_create_swapchain(inst, phys_dev, dev, surface.handle); + } + } + VkDebugUtilsMessengerCallbackDataEXT data{}; + data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; + data.pMessage = "I'm a test message!"; + data.messageIdNumber = 1; + submit_message(inst.inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &data); - env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr); + ASSERT_EQ(120U + 1U, log.count(data.pMessage)); }