Skip to content

Commit

Permalink
Enhance DriverUnloading tests with arrays of handles
Browse files Browse the repository at this point in the history
Drivers resize after 32 elements, so to test that path we need to loop
over instance level handle creation (surface, debug messenger, debug
report).
  • Loading branch information
charles-lunarg committed Mar 26, 2024
1 parent 5fed115 commit c2bbc84
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 24 deletions.
4 changes: 2 additions & 2 deletions tests/framework/icd/test_icd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t>(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<uint8_t*>(fake_msgr_handle);
} else {
std::cerr << "Messenger not found during destroy!\n";
abort();
Expand Down
47 changes: 47 additions & 0 deletions tests/framework/test_environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,41 @@ struct DeviceWrapper {
DeviceCreateInfo create_info{};
};

template <typename HandleType, typename ParentType, typename DestroyFuncType>
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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -396,6 +441,7 @@ struct DebugUtilsWrapper {
~DebugUtilsWrapper() noexcept {
if (messenger) {
vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks);
messenger = VK_NULL_HANDLE;
}
}
// Immoveable object
Expand All @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions tests/framework/test_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,18 +411,20 @@ struct FRAMEWORK_EXPORT DispatchableHandle {
handle = reinterpret_cast<T>(ptr_handle);
}
~DispatchableHandle() {
delete reinterpret_cast<VK_LOADER_DATA*>(handle);
if (handle) {
delete reinterpret_cast<VK_LOADER_DATA*>(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<VK_LOADER_DATA*>(handle);
handle = other.handle;
other.handle = nullptr;
}
handle = other.handle;
other.handle = nullptr;
return *this;
}
bool operator==(T base_handle) { return base_handle == handle; }
Expand Down
135 changes: 117 additions & 18 deletions tests/loader_regression_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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<WrappedHandle<VkDebugUtilsMessengerEXT, VkInstance, PFN_vkDestroyDebugUtilsMessengerEXT>> messengers;
std::vector<WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR>> 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) {
Expand All @@ -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<WrappedHandle<VkDebugUtilsMessengerEXT, VkInstance, PFN_vkDestroyDebugUtilsMessengerEXT>> messengers;
std::vector<WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR>> 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) {
Expand All @@ -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<WrappedHandle<VkDebugUtilsMessengerEXT, VkInstance, PFN_vkDestroyDebugUtilsMessengerEXT>> messengers;
std::vector<WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR>> 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) {
Expand All @@ -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<WrappedHandle<VkDebugUtilsMessengerEXT, VkInstance, PFN_vkDestroyDebugUtilsMessengerEXT>> messengers;
std::vector<WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR>> 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<WrappedHandle<VkDebugUtilsMessengerEXT, VkInstance, PFN_vkDestroyDebugUtilsMessengerEXT>> messengers;
std::vector<WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR>> 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));
}

0 comments on commit c2bbc84

Please sign in to comment.