Enhance DriverUnloading tests
authorCharles Giessen <charles@lunarg.com>
Fri, 22 Mar 2024 16:57:40 +0000 (11:57 -0500)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Mon, 29 Apr 2024 16:53:33 +0000 (10:53 -0600)
Drivers resize after 32 elements, so to test that path we need to loop
over instance level handle creation (surface, debug messenger, debug
report).

The driver unloading tests needed to create a debug report callback, so
that functionality was added to the test framework, modifying
VulkanFunctions with a new init function and to make InstWrapper call it
when creating an instance.

Modify how test_icd_version_7 operates so that by default the functions
are exported which is the 'assumed' codepath. This results in a bit of
duplication between version 6 & 7, but was kept so as to not modify
every test. This also clarifies how a test should enable querying of
the functions through vkGetInstanceProcAddr versus exporting those
functions (it was combined before).

tests/framework/framework_config.h.in
tests/framework/icd/CMakeLists.txt
tests/framework/icd/export_definitions/test_icd_7.def
tests/framework/icd/export_definitions/test_icd_7_with_exports.def [deleted file]
tests/framework/icd/export_definitions/test_icd_7_without_exports.def [new file with mode: 0644]
tests/framework/icd/test_icd.cpp
tests/framework/test_environment.cpp
tests/framework/test_environment.h
tests/framework/test_util.h
tests/loader_regression_tests.cpp
tests/loader_version_tests.cpp

index a1b038d9aaa301494fd2e73bdf780256354611c4..1857a24c567f7d839eb33a327b1ba4127bbd9d9d 100644 (file)
@@ -56,7 +56,7 @@
 
 // Version 7
 #define TEST_ICD_PATH_VERSION_7 "$<TARGET_FILE:test_icd_version_7>"
-#define TEST_ICD_PATH_VERSION_7_WITH_ADDITIONAL_EXPORTS "$<TARGET_FILE:test_icd_version_7_with_additional_exports>"
+#define TEST_ICD_PATH_VERSION_7_WIHTOUT_EXPORTS "$<TARGET_FILE:test_icd_version_7_without_exports>"
 
 // TestLayer binaries
 #define TEST_LAYER_PATH_EXPORT_BASE "$<TARGET_FILE:test_layer_export_base>"
index 28548ef1b853ef952b601bffcf70b6e67949f260..6a7fabb5e058dd0bf66b93ca783575281bda3832 100644 (file)
@@ -41,11 +41,11 @@ AddSharedLibrary(test_icd_version_6 DEF_FILE test_icd_6
     DEFINITIONS TEST_ICD_EXPORT_ICD_GPDPA=1 TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES=1 ${TEST_ICD_VERSION_2_DEFINES})
 AddSharedLibrary(test_icd_version_7 DEF_FILE test_icd_7
     SOURCES test_icd.cpp
-    DEFINITIONS TEST_ICD_EXPOSE_VERSION_7=1 ${TEST_ICD_VERSION_2_DEFINES})
-AddSharedLibrary(test_icd_version_7_with_additional_exports DEF_FILE test_icd_7_with_exports
+    DEFINITIONS TEST_ICD_EXPORT_ICD_GPDPA=1 TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES=1 TEST_ICD_EXPORT_VERSION_7=1 ${TEST_ICD_VERSION_2_DEFINES})
+AddSharedLibrary(test_icd_version_7_without_exports DEF_FILE test_icd_7_without_exports
     SOURCES test_icd.cpp
-    DEFINITIONS TEST_ICD_EXPOSE_VERSION_7=1 TEST_ICD_EXPORT_ICD_GPDPA=1
-    TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES=1 ${TEST_ICD_VERSION_2_DEFINES})
+    DEFINITIONS TEST_ICD_EXPORT_VERSION_7=0 TEST_ICD_EXPORT_ICD_GPDPA=1
+        TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES=1 ${TEST_ICD_VERSION_2_DEFINES})
 AddSharedLibrary(test_unicode DEF_FILE test_icd_2
     SOURCES test_icd.cpp
     DEFINITIONS ${TEST_ICD_VERSION_2_DEFINES})
index 4414bbeabc0054bf64b638ad6a790a24fae03a8a..8cafb29614d2ae1e259b53e170a8fe2dd431af23 100644 (file)
@@ -1,3 +1,6 @@
 LIBRARY test_icd_version_7
 EXPORTS
     vk_icdGetInstanceProcAddr
+    vk_icdNegotiateLoaderICDInterfaceVersion
+    vk_icdEnumerateAdapterPhysicalDevices
+    vk_icdGetPhysicalDeviceProcAddr
diff --git a/tests/framework/icd/export_definitions/test_icd_7_with_exports.def b/tests/framework/icd/export_definitions/test_icd_7_with_exports.def
deleted file mode 100644 (file)
index 7861805..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-LIBRARY test_icd_version_7_with_additional_exports
-EXPORTS
-    vk_icdGetInstanceProcAddr
-    vk_icdNegotiateLoaderICDInterfaceVersion
-    vk_icdEnumerateAdapterPhysicalDevices
-    vk_icdGetPhysicalDeviceProcAddr
diff --git a/tests/framework/icd/export_definitions/test_icd_7_without_exports.def b/tests/framework/icd/export_definitions/test_icd_7_without_exports.def
new file mode 100644 (file)
index 0000000..a6b5419
--- /dev/null
@@ -0,0 +1,3 @@
+LIBRARY test_icd_version_7_without_exports
+EXPORTS
+    vk_icdGetInstanceProcAddr
index 067fe65f24d6719da099166f1ca5e525d2568274..71637b50827af76f550bf9468c614bfb0f452355 100644 (file)
 #define TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES 0
 #endif
 
-// expose vk_icdNegotiateLoaderICDInterfaceVersion, vk_icdEnumerateAdapterPhysicalDevices, and vk_icdGetPhysicalDeviceProcAddr
-// through vk_icdGetInstanceProcAddr or vkGetInstanceProcAddr
-#if !defined(TEST_ICD_EXPOSE_VERSION_7)
-#define TEST_ICD_EXPOSE_VERSION_7 0
+// export vk_icdNegotiateLoaderICDInterfaceVersion, vk_icdEnumerateAdapterPhysicalDevices, and vk_icdGetPhysicalDeviceProcAddr
+// through dlsym/GetProcAddress
+// Default is *on*
+#if !defined(TEST_ICD_EXPORT_VERSION_7)
+#define TEST_ICD_EXPORT_VERSION_7 1
 #endif
 
 TestICD icd;
@@ -343,7 +344,7 @@ VKAPI_ATTR void VKAPI_CALL test_vkDestroyDebugUtilsMessengerEXT([[maybe_unused]]
             // Remove it from the list
             icd.messenger_handles.erase(found_iter);
             // Delete the handle
-            delete (uint8_t*)fake_msgr_handle;
+            delete (uint8_t*)(fake_msgr_handle);
         } else {
             std::cerr << "Messenger not found during destroy!\n";
             abort();
@@ -1160,21 +1161,6 @@ VkResult test_vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersi
     return VK_SUCCESS;
 }
 
-// Forward declarations for trampolines
-extern "C" {
-#if TEST_ICD_EXPOSE_VERSION_7
-FRAMEWORK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion);
-#if TEST_ICD_EXPORT_ICD_GPDPA
-FRAMEWORK_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char* pName);
-#endif
-#if defined(WIN32) && TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES
-FRAMEWORK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID,
-                                                                                      uint32_t* pPhysicalDeviceCount,
-                                                                                      VkPhysicalDevice* pPhysicalDevices);
-#endif
-#endif
-}
-
 //// trampolines
 
 PFN_vkVoidFunction get_instance_func_ver_1_1([[maybe_unused]] VkInstance instance, const char* pName) {
@@ -1549,21 +1535,18 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL test_vkGetDeviceProcAddr(VkDevice devic
 PFN_vkVoidFunction base_get_instance_proc_addr(VkInstance instance, const char* pName) {
     if (pName == nullptr) return nullptr;
     if (instance == NULL) {
-#if TEST_ICD_EXPOSE_VERSION_7
         if (string_eq(pName, "vk_icdNegotiateLoaderICDInterfaceVersion"))
             return icd.exposes_vk_icdNegotiateLoaderICDInterfaceVersion
-                       ? to_vkVoidFunction(vk_icdNegotiateLoaderICDInterfaceVersion)
+                       ? to_vkVoidFunction(test_vk_icdNegotiateLoaderICDInterfaceVersion)
                        : NULL;
-#if TEST_ICD_EXPORT_ICD_GPDPA
+
         if (string_eq(pName, "vk_icdGetPhysicalDeviceProcAddr"))
-            return icd.exposes_vk_icdGetPhysicalDeviceProcAddr ? to_vkVoidFunction(vk_icdGetPhysicalDeviceProcAddr) : NULL;
-#endif
-#if defined(WIN32) && TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES
+            return icd.exposes_vk_icdGetPhysicalDeviceProcAddr ? to_vkVoidFunction(get_physical_device_func) : NULL;
+#if defined(WIN32)
         if (string_eq(pName, "vk_icdEnumerateAdapterPhysicalDevices"))
-            return icd.exposes_vk_icdEnumerateAdapterPhysicalDevices ? to_vkVoidFunction(vk_icdEnumerateAdapterPhysicalDevices)
+            return icd.exposes_vk_icdEnumerateAdapterPhysicalDevices ? to_vkVoidFunction(test_vk_icdEnumerateAdapterPhysicalDevices)
                                                                      : NULL;
 #endif  // defined(WIN32)
-#endif  // TEST_ICD_EXPOSE_VERSION_7
 
         if (string_eq(pName, "vkGetInstanceProcAddr")) return to_vkVoidFunction(test_vkGetInstanceProcAddr);
         if (string_eq(pName, "vkEnumerateInstanceExtensionProperties"))
@@ -1589,13 +1572,13 @@ PFN_vkVoidFunction base_get_instance_proc_addr(VkInstance instance, const char*
 
 // Exported functions
 extern "C" {
-#if TEST_ICD_EXPORT_NEGOTIATE_INTERFACE_VERSION
+#if TEST_ICD_EXPORT_NEGOTIATE_INTERFACE_VERSION && TEST_ICD_EXPORT_VERSION_7
 FRAMEWORK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion) {
     return test_vk_icdNegotiateLoaderICDInterfaceVersion(pSupportedVersion);
 }
 #endif  // TEST_ICD_EXPORT_NEGOTIATE_INTERFACE_VERSION
 
-#if TEST_ICD_EXPORT_ICD_GPDPA
+#if TEST_ICD_EXPORT_ICD_GPDPA && TEST_ICD_EXPORT_VERSION_7
 FRAMEWORK_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char* pName) {
     return get_physical_device_func(instance, pName);
 }
@@ -1622,7 +1605,7 @@ FRAMEWORK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProp
 }
 #endif  // TEST_ICD_EXPORT_ICD_GIPA
 
-#if TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES
+#if TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES && TEST_ICD_EXPORT_VERSION_7
 #if defined(WIN32)
 FRAMEWORK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID,
                                                                                       uint32_t* pPhysicalDeviceCount,
index cac95d84b927ab67d46213525f60edb031495776..ea92868f8c945aa1ad5eb054911cc2ccaeccbd17 100644 (file)
@@ -153,6 +153,13 @@ VulkanFunctions::VulkanFunctions() : loader(get_loader_path()) {
     init_vulkan_functions(*this);
 }
 
+void VulkanFunctions::load_instance_functions(VkInstance instance) {
+    vkCreateDebugReportCallbackEXT = FromVoidStarFunc(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
+    vkDestroyDebugReportCallbackEXT = FromVoidStarFunc(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
+    vkCreateDebugUtilsMessengerEXT = FromVoidStarFunc(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"));
+    vkDestroyDebugUtilsMessengerEXT = FromVoidStarFunc(vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"));
+}
+
 DeviceFunctions::DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device) {
     vkGetDeviceProcAddr = vulkan_functions.vkGetDeviceProcAddr;
     vkDestroyDevice = load(device, "vkDestroyDevice");
@@ -192,10 +199,12 @@ InstWrapper& InstWrapper::operator=(InstWrapper&& other) noexcept {
 
 void InstWrapper::CheckCreate(VkResult result_to_check) {
     ASSERT_EQ(result_to_check, functions->vkCreateInstance(create_info.get(), callbacks, &inst));
+    functions->load_instance_functions(inst);
 }
 
 void InstWrapper::CheckCreateWithInfo(InstanceCreateInfo& create_info, VkResult result_to_check) {
     ASSERT_EQ(result_to_check, functions->vkCreateInstance(create_info.get(), callbacks, &inst));
+    functions->load_instance_functions(inst);
 }
 
 std::vector<VkPhysicalDevice> InstWrapper::GetPhysDevs(uint32_t phys_dev_count, VkResult result_to_check) {
@@ -292,8 +301,8 @@ void DeviceWrapper::CheckCreate(VkPhysicalDevice phys_dev, VkResult result_to_ch
 }
 
 VkResult CreateDebugUtilsMessenger(DebugUtilsWrapper& debug_utils) {
-    return debug_utils.vkCreateDebugUtilsMessengerEXT(debug_utils.inst, debug_utils.get(), debug_utils.callbacks,
-                                                      &debug_utils.messenger);
+    return debug_utils.local_vkCreateDebugUtilsMessengerEXT(debug_utils.inst, debug_utils.get(), debug_utils.callbacks,
+                                                            &debug_utils.messenger);
 }
 
 void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger) {
@@ -878,6 +887,11 @@ VkResult create_surface(InstWrapper& inst, VkSurfaceKHR& surface, const char* ap
     return create_surface(inst.functions, inst.inst, surface, api_selection);
 }
 
+VkResult create_debug_callback(InstWrapper& inst, const VkDebugReportCallbackCreateInfoEXT& create_info,
+                               VkDebugReportCallbackEXT& callback) {
+    return inst.functions->vkCreateDebugReportCallbackEXT(inst.inst, &create_info, nullptr, &callback);
+}
+
 extern "C" {
 void __ubsan_on_report() { FAIL() << "Encountered an undefined behavior sanitizer error"; }
 void __asan_on_error() { FAIL() << "Encountered an address sanitizer error"; }
index 3f6bf519db95c90b425b09481700011abac8a454..1be4e480e7d504688007779fe7ca83d4223bd07a 100644 (file)
@@ -167,8 +167,6 @@ struct VulkanFunctions {
 
     PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
     PFN_vkCreateDevice vkCreateDevice = nullptr;
-    PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
-    PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
 
     // WSI
     PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT = nullptr;
@@ -231,12 +229,20 @@ struct VulkanFunctions {
 #endif  // VK_USE_PLATFORM_WIN32_KHR
     PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = nullptr;
 
+    // instance extensions functions (can only be loaded with a valid instance)
+    PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;    // Null unless the extension is enabled
+    PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;  // Null unless the extension is enabled
+    PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = nullptr;    // Null unless the extension is enabled
+    PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT = nullptr;  // Null unless the extension is enabled
+
     // device functions
     PFN_vkDestroyDevice vkDestroyDevice = nullptr;
     PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
 
     VulkanFunctions();
 
+    void load_instance_functions(VkInstance instance);
+
     FromVoidStarFunc load(VkInstance inst, const char* func_name) const {
         return FromVoidStarFunc(vkGetInstanceProcAddr(inst, func_name));
     }
@@ -338,6 +344,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,
@@ -369,6 +410,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.
@@ -387,15 +438,17 @@ struct DebugUtilsWrapper {
                       VkDebugUtilsMessageSeverityFlagsEXT severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
                                                                      VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
                       VkAllocationCallbacks* callbacks = nullptr)
-        : logger(severity), inst(inst_wrapper.inst), callbacks(callbacks) {
-        vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
-            inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkCreateDebugUtilsMessengerEXT"));
-        vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
-            inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkDestroyDebugUtilsMessengerEXT"));
-    };
+        : logger(severity),
+          inst(inst_wrapper.inst),
+          callbacks(callbacks),
+          local_vkCreateDebugUtilsMessengerEXT(
+              FromVoidStarFunc(inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkCreateDebugUtilsMessengerEXT"))),
+          local_vkDestroyDebugUtilsMessengerEXT(FromVoidStarFunc(
+              inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkDestroyDebugUtilsMessengerEXT"))){};
     ~DebugUtilsWrapper() noexcept {
         if (messenger) {
-            vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks);
+            local_vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks);
+            messenger = VK_NULL_HANDLE;
         }
     }
     // Immoveable object
@@ -405,13 +458,14 @@ 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;
     VkInstance inst = VK_NULL_HANDLE;
     VkAllocationCallbacks* callbacks = nullptr;
-    PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
-    PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
+    PFN_vkCreateDebugUtilsMessengerEXT local_vkCreateDebugUtilsMessengerEXT = nullptr;
+    PFN_vkDestroyDebugUtilsMessengerEXT local_vkDestroyDebugUtilsMessengerEXT = nullptr;
     VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
 };
 
@@ -653,3 +707,6 @@ struct FrameworkEnvironment {
 VkResult create_surface(InstWrapper& inst, VkSurfaceKHR& out_surface, const char* api_selection = nullptr);
 // Alternate parameter list for allocation callback tests
 VkResult create_surface(VulkanFunctions* functions, VkInstance inst, VkSurfaceKHR& surface, const char* api_selection = nullptr);
+
+VkResult create_debug_callback(InstWrapper& inst, const VkDebugReportCallbackCreateInfoEXT& create_info,
+                               VkDebugReportCallbackEXT& callback);
index 1243410fd1191c5329279a75ecf3931e39845195..0a3ac6294f123751974049bee5552629279ffb01 100644 (file)
@@ -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; }
index 30004b2e188ad6a09046facbc339a7e2e86ca7a3..41b0925c4526ffa638fb1e8d3fa726eabc657c10 100644 (file)
@@ -4486,7 +4486,7 @@ TEST(EnumerateAdapterPhysicalDevices, WrongErrorCodes) {
 }
 #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");
@@ -4537,7 +4537,7 @@ TEST(DriverUnloadingFromZeroPhysDevs, InterspersedThroughout) {
 
     DebugUtilsLogger debug_log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
     InstWrapper inst{env.vulkan_functions};
-    inst.create_info.setup_WSI();
+    inst.create_info.setup_WSI().add_extension("VK_EXT_debug_report");
     FillDebugUtilsCreateDetails(inst.create_info, debug_log);
     inst.CheckCreate();
     DebugUtilsWrapper log{inst};
@@ -4546,17 +4546,37 @@ TEST(DriverUnloadingFromZeroPhysDevs, InterspersedThroughout) {
     PFN_vkSubmitDebugUtilsMessageEXT submit_message = inst.load("vkSubmitDebugUtilsMessageEXT");
     ASSERT_TRUE(submit_message != nullptr);
 
+    VkSurfaceKHR pre_surface{};
+    ASSERT_EQ(VK_SUCCESS, create_surface(inst, pre_surface));
+    WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR> pre_enum_phys_devs_surface{
+        pre_surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR};
+
+    VkDebugReportCallbackEXT debug_callback{};
+    VkDebugReportCallbackCreateInfoEXT debug_report_create_info{};
+    ASSERT_EQ(VK_SUCCESS, create_debug_callback(inst, debug_report_create_info, debug_callback));
+    WrappedHandle<VkDebugReportCallbackEXT, VkInstance, PFN_vkDestroyDebugReportCallbackEXT>
+        pre_enum_phys_devs_debug_report_callback{debug_callback, inst.inst, env.vulkan_functions.vkDestroyDebugReportCallbackEXT};
+
     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, env.vulkan_functions.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger));
+        messengers.emplace_back(messenger, inst.inst, env.vulkan_functions.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) {
@@ -4569,22 +4589,42 @@ TEST(DriverUnloadingFromZeroPhysDevs, InMiddleOfList) {
 
     InstWrapper inst{env.vulkan_functions};
     inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
-    inst.create_info.setup_WSI();
+    inst.create_info.setup_WSI().add_extension("VK_EXT_debug_report");
     inst.CheckCreate();
     DebugUtilsWrapper log{inst};
     ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log));
 
+    VkSurfaceKHR pre_surface{};
+    ASSERT_EQ(VK_SUCCESS, create_surface(inst, pre_surface));
+    WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR> pre_enum_phys_devs_surface{
+        pre_surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR};
+
+    VkDebugReportCallbackEXT debug_callback{};
+    VkDebugReportCallbackCreateInfoEXT debug_report_create_info{};
+    ASSERT_EQ(VK_SUCCESS, create_debug_callback(inst, debug_report_create_info, debug_callback));
+    WrappedHandle<VkDebugReportCallbackEXT, VkInstance, PFN_vkDestroyDebugReportCallbackEXT>
+        pre_enum_phys_devs_debug_report_callback{debug_callback, inst.inst, env.vulkan_functions.vkDestroyDebugReportCallbackEXT};
+
     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, env.vulkan_functions.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger));
+        messengers.emplace_back(messenger, inst.inst, env.vulkan_functions.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) {
@@ -4598,26 +4638,48 @@ TEST(DriverUnloadingFromZeroPhysDevs, AtFrontAndBack) {
 
     DebugUtilsLogger debug_log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
     InstWrapper inst{env.vulkan_functions};
-    inst.create_info.setup_WSI();
+    inst.create_info.setup_WSI().add_extension("VK_EXT_debug_report");
     FillDebugUtilsCreateDetails(inst.create_info, debug_log);
     inst.CheckCreate();
+
     DebugUtilsWrapper log{inst};
     ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log));
 
+    VkSurfaceKHR pre_surface{};
+    ASSERT_EQ(VK_SUCCESS, create_surface(inst, pre_surface));
+    WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR> pre_enum_phys_devs_surface{
+        pre_surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR};
+
+    VkDebugReportCallbackEXT debug_callback{};
+    VkDebugReportCallbackCreateInfoEXT debug_report_create_info{};
+    ASSERT_EQ(VK_SUCCESS, create_debug_callback(inst, debug_report_create_info, debug_callback));
+    WrappedHandle<VkDebugReportCallbackEXT, VkInstance, PFN_vkDestroyDebugReportCallbackEXT>
+        pre_enum_phys_devs_debug_report_callback{debug_callback, inst.inst, env.vulkan_functions.vkDestroyDebugReportCallbackEXT};
+
     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, env.vulkan_functions.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger));
+        messengers.emplace_back(messenger, inst.inst, env.vulkan_functions.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) {
+TEST(DriverUnloadingFromZeroPhysDevs, NoPhysicalDevices) {
     FrameworkEnvironment env{};
     add_empty_driver_for_unloading_testing(env);
     add_empty_driver_for_unloading_testing(env);
@@ -4626,16 +4688,110 @@ TEST(DriverUnloadingFromZeroPhysDevs, NoPhysicaldevices) {
 
     DebugUtilsLogger debug_log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
     InstWrapper inst{env.vulkan_functions};
-    inst.create_info.setup_WSI();
+    inst.create_info.setup_WSI().add_extension("VK_EXT_debug_report");
     FillDebugUtilsCreateDetails(inst.create_info, debug_log);
     inst.CheckCreate();
     DebugUtilsWrapper log{inst};
     ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log));
+
+    VkSurfaceKHR pre_surface{};
+    ASSERT_EQ(VK_SUCCESS, create_surface(inst, pre_surface));
+    WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR> pre_enum_phys_devs_surface{
+        pre_surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR};
+
+    VkDebugReportCallbackEXT debug_callback{};
+    VkDebugReportCallbackCreateInfoEXT debug_report_create_info{};
+    ASSERT_EQ(VK_SUCCESS, create_debug_callback(inst, debug_report_create_info, debug_callback));
+    WrappedHandle<VkDebugReportCallbackEXT, VkInstance, PFN_vkDestroyDebugReportCallbackEXT>
+        pre_enum_phys_devs_debug_report_callback{debug_callback, inst.inst, env.vulkan_functions.vkDestroyDebugReportCallbackEXT};
+
     // 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, env.vulkan_functions.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger));
+        messengers.emplace_back(messenger, inst.inst, env.vulkan_functions.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().add_extension("VK_EXT_debug_report");
+    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);
+
+    VkSurfaceKHR pre_surface{};
+    ASSERT_EQ(VK_SUCCESS, create_surface(inst, pre_surface));
+    WrappedHandle<VkSurfaceKHR, VkInstance, PFN_vkDestroySurfaceKHR> pre_enum_phys_devs_surface{
+        pre_surface, inst.inst, env.vulkan_functions.vkDestroySurfaceKHR};
+
+    VkDebugReportCallbackEXT debug_callback{};
+    VkDebugReportCallbackCreateInfoEXT debug_report_create_info{};
+    ASSERT_EQ(VK_SUCCESS, create_debug_callback(inst, debug_report_create_info, debug_callback));
+    WrappedHandle<VkDebugReportCallbackEXT, VkInstance, PFN_vkDestroyDebugReportCallbackEXT>
+        pre_enum_phys_devs_debug_report_callback{debug_callback, inst.inst, env.vulkan_functions.vkDestroyDebugReportCallbackEXT};
+
+    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, env.vulkan_functions.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger));
+        messengers.emplace_back(messenger, inst.inst, env.vulkan_functions.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
+    // Do it backwards so the indexes are 'corect'
+    for (uint32_t i = 31; i > 2; 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, env.vulkan_functions.vkCreateDebugUtilsMessengerEXT(inst.inst, log.get(), nullptr, &messenger));
+        messengers.emplace_back(messenger, inst.inst, env.vulkan_functions.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));
 }
index 8307995acb2085299e8b7e387eb34adfbf8f3011..e800d6ace47705fadb0c8a7ef190d4e01764d8ed 100644 (file)
@@ -306,7 +306,7 @@ TEST(ICDInterfaceVersion2PlusEnumerateAdapterPhysicalDevices, VerifyGroupResults
 #endif  // defined(WIN32)
 TEST(ICDInterfaceVersion7, SingleDriver) {
     FrameworkEnvironment env{};
-    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_7_WITH_ADDITIONAL_EXPORTS)).add_physical_device({});
+    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_7)).add_physical_device({});
     InstWrapper inst{env.vulkan_functions};
     inst.CheckCreate();
     DeviceWrapper dev{inst};
@@ -316,7 +316,7 @@ TEST(ICDInterfaceVersion7, SingleDriver) {
 
 TEST(ICDInterfaceVersion7, SingleDriverWithoutExportedFunctions) {
     FrameworkEnvironment env{};
-    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_7)).add_physical_device({});
+    auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_7_WIHTOUT_EXPORTS)).add_physical_device({});
     InstWrapper inst{env.vulkan_functions};
     inst.CheckCreate();
     DeviceWrapper dev{inst};