Dont abort when WSI functions are NULL.
authorCharles Giessen <charles@lunarg.com>
Sat, 5 Nov 2022 22:12:00 +0000 (16:12 -0600)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Wed, 9 Nov 2022 21:02:42 +0000 (14:02 -0700)
Commit d1db6c5bce9ed474ca124f0bffed9aa2468f3973 changed a few WSI functions
to abort when the driver's function was NULL, which is a change of existing
behavior. It should instead return VK_SUCCESS. At least now there is a
warning message.

This commit also adds tests for the above situation and for debug utils
& debug marker functions to make sure the pre-existing behavior is maintained.
This was tested by running the loader with a previous build through the new
tests and verified that they both passed. The tests run the cases of whether
the extensions were enabled, how the functions were queried (GIPA vs GDPA), and
whether the hardware supports the extensions.

15 files changed:
loader/generated/vk_loader_extensions.c
loader/wsi.c
scripts/loader_extension_generator.py
tests/framework/icd/physical_device.h
tests/framework/icd/test_icd.cpp
tests/framework/icd/test_icd.h
tests/framework/test_environment.cpp
tests/framework/test_environment.h
tests/framework/test_util.cpp
tests/framework/test_util.h
tests/live_verification/CMakeLists.txt
tests/live_verification/dynamic_rendering_get_proc_addr.cpp
tests/loader_debug_ext_tests.cpp
tests/loader_get_proc_addr_tests.cpp
tests/loader_wsi_tests.cpp

index 9b7772f7498b3e46614735edfc94e236737f41ff..5e527900b234388b0c365ea0780720a7eda9f6df 100644 (file)
@@ -1358,34 +1358,34 @@ void init_extension_device_proc_terminator_dispatch(struct loader_device *dev) {
     struct loader_device_terminator_dispatch* dispatch = &dev->loader_dispatch.extension_terminator_dispatch;
     PFN_vkGetDeviceProcAddr gpda = (PFN_vkGetDeviceProcAddr)dev->phys_dev_term->this_icd_term->dispatch.GetDeviceProcAddr;
     // ---- VK_KHR_swapchain extension commands
-    if (dev->extensions.khr_swapchain_enabled) 
+    if (dev->extensions.khr_swapchain_enabled)
        dispatch->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpda(dev->icd_device, "vkCreateSwapchainKHR");
-    if (dev->extensions.khr_swapchain_enabled) 
+    if (dev->extensions.khr_swapchain_enabled)
        dispatch->GetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)gpda(dev->icd_device, "vkGetDeviceGroupSurfacePresentModesKHR");
     // ---- VK_KHR_display_swapchain extension commands
-    if (dev->extensions.khr_display_swapchain_enabled) 
+    if (dev->extensions.khr_display_swapchain_enabled)
        dispatch->CreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)gpda(dev->icd_device, "vkCreateSharedSwapchainsKHR");
     // ---- VK_EXT_debug_marker extension commands
-    if (dev->extensions.ext_debug_marker_enabled) 
+    if (dev->extensions.ext_debug_marker_enabled)
        dispatch->DebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)gpda(dev->icd_device, "vkDebugMarkerSetObjectTagEXT");
-    if (dev->extensions.ext_debug_marker_enabled) 
+    if (dev->extensions.ext_debug_marker_enabled)
        dispatch->DebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)gpda(dev->icd_device, "vkDebugMarkerSetObjectNameEXT");
     // ---- VK_EXT_debug_utils extension commands
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->SetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)gpda(dev->icd_device, "vkSetDebugUtilsObjectNameEXT");
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->SetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)gpda(dev->icd_device, "vkSetDebugUtilsObjectTagEXT");
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->QueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)gpda(dev->icd_device, "vkQueueBeginDebugUtilsLabelEXT");
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->QueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)gpda(dev->icd_device, "vkQueueEndDebugUtilsLabelEXT");
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->QueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)gpda(dev->icd_device, "vkQueueInsertDebugUtilsLabelEXT");
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->CmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)gpda(dev->icd_device, "vkCmdBeginDebugUtilsLabelEXT");
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->CmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)gpda(dev->icd_device, "vkCmdEndDebugUtilsLabelEXT");
-    if (dev->extensions.ext_debug_utils_enabled) 
+    if (dev->extensions.ext_debug_utils_enabled)
        dispatch->CmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)gpda(dev->icd_device, "vkCmdInsertDebugUtilsLabelEXT");
 #ifdef VK_USE_PLATFORM_WIN32_KHR
     // ---- VK_EXT_full_screen_exclusive extension commands
index d9eb89385ba7c45947a11629e8f7a18a8c019cf8..8a97ca59af7e5ad40401bae6cba2d7b0b5eb21a1 100644 (file)
@@ -449,6 +449,14 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice devic
                    "vkCreateSwapchainKHR: Invalid device [VUID-vkCreateSwapchainKHR-device-parameter]");
         abort(); /* Intentionally fail so user can correct issue. */
     }
+    if (NULL == disp->CreateSwapchainKHR) {
+        struct loader_device *dev = *((struct loader_device **)device);
+        loader_log(NULL != dev ? dev->phys_dev_term->this_icd_term->this_instance : NULL,
+                   VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+                   "vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+                   "extension enabled?");
+        abort();
+    }
     return disp->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
 }
 
@@ -457,7 +465,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateSwapchainKHR(VkDevice device, co
     uint32_t icd_index = 0;
     struct loader_device *dev;
     struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
-    if (NULL == icd_term || NULL == dev || NULL == dev->loader_dispatch.extension_terminator_dispatch.CreateSwapchainKHR) {
+    if (NULL == icd_term || NULL == dev) {
         loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
                    "vkCreateSwapchainKHR Terminator: device handle. This is likely the result of a "
                    "layer wrapping device handles and failing to unwrap them in all functions. "
@@ -469,6 +477,13 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateSwapchainKHR(VkDevice device, co
                    "vkCreateSwapchainKHR: Invalid pCreateInfo pointer [VUID-vkCreateSwapchainKHR-pCreateInfo-parameter]");
         abort(); /* Intentionally fail so user can correct issue. */
     }
+    // Need to gracefully handle the function pointer not being found.
+    if (NULL == dev->loader_dispatch.extension_terminator_dispatch.CreateSwapchainKHR) {
+        loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+                   "vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+                   "extension enabled?");
+        return VK_SUCCESS;
+    }
     VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pCreateInfo->surface;
     if (NULL != icd_surface->real_icd_surfaces) {
         if ((VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
@@ -2122,18 +2137,18 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateSharedSwapchainsKHR(VkDevice dev
     uint32_t icd_index = 0;
     struct loader_device *dev;
     struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
-    if (NULL == icd_term || NULL == dev || NULL == dev->loader_dispatch.extension_terminator_dispatch.CreateSharedSwapchainsKHR) {
+    if (NULL == icd_term || NULL == dev) {
         loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
                    "vkCreateSharedSwapchainsKHR Terminator: Invalid device handle. This is likely the result of a "
                    "layer wrapping device handles and failing to unwrap them in all functions. "
                    "[VUID-vkCreateSharedSwapchainsKHR-device-parameter]");
         abort(); /* Intentionally fail so user can correct issue. */
     }
-    if (NULL == pCreateInfos) {
-        loader_log(
-            NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
-            "vkCreateSharedSwapchainsKHR: Invalid pCreateInfos pointer [VUID-vkCreateSharedSwapchainsKHR-pCreateInfos-parameter]");
-        abort(); /* Intentionally fail so user can correct issue. */
+    if (NULL == dev->loader_dispatch.extension_terminator_dispatch.CreateSharedSwapchainsKHR) {
+        loader_log(NULL, VULKAN_LOADER_ERROR_BIT, 0,
+                   "vkCreateSharedSwapchainsKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the "
+                   "VK_KHR_display_swapchain extension enabled?");
+        return VK_SUCCESS;
     }
     VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pCreateInfos->surface;
     if ((VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
@@ -2184,13 +2199,19 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDeviceGroupSurfacePresentModesKHR(V
     uint32_t icd_index = 0;
     struct loader_device *dev;
     struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
-    if (NULL == icd_term || NULL == dev ||
-        NULL == dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModesKHR) {
+    if (NULL == icd_term || NULL == dev) {
         loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
                    "vkGetDeviceGroupSurfacePresentModesKHR: Invalid device "
                    "[VUID-vkGetDeviceGroupSurfacePresentModesKHR-device-parameter]");
         abort(); /* Intentionally fail so user can correct issue. */
     }
+    if (NULL == dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModesKHR) {
+        loader_log(NULL, VULKAN_LOADER_ERROR_BIT, 0,
+                   "vkGetDeviceGroupSurfacePresentModesKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was either "
+                   "Vulkan 1.1 and VK_KHR_swapchain enabled or both the VK_KHR_device_group and VK_KHR_surface "
+                   "extensions enabled when using Vulkan 1.0?");
+        return VK_SUCCESS;
+    }
     VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
     if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
         return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModesKHR(
index d178544cff51da33fbe9580c109fa424e819f0fd..e5a4ca88223c5647540e625f32ce4e04074b1ab2 100644 (file)
@@ -1525,7 +1525,7 @@ class LoaderExtensionOutputGenerator(OutputGenerator):
                     term_func += f'    if (dev->extensions.{ext_cmd.ext_name[3:].lower()}_enabled && dev->extensions.{ext_cmd.require[3:].lower()}_enabled)\n'
                     term_func += f'       dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n'
                 else:
-                    term_func += f'    if (dev->extensions.{ext_cmd.ext_name[3:].lower()}_enabled) \n'
+                    term_func += f'    if (dev->extensions.{ext_cmd.ext_name[3:].lower()}_enabled)\n'
                     term_func += f'       dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n'
 
         if last_protect is not None:
index fbe5cb14fa746dded988ba5bd05b5b5ee0b42212..e5129b0abb4a875bfb6911f350613ce6932cae63 100644 (file)
@@ -64,9 +64,9 @@ struct PhysicalDevice {
     BUILDER_VALUE(PhysicalDevice, VkDisplayModeKHR, display_mode, {})
     BUILDER_VALUE(PhysicalDevice, VkDisplayPlaneCapabilitiesKHR, display_plane_capabilities, {})
 
-    // VkDevice handles created from this physical device
+    // Objects created from this physical device
     std::vector<VkDevice> device_handles;
-
+    std::vector<DeviceCreateInfo> device_create_infos;
     std::vector<DispatchableHandle<VkQueue>> queue_handles;
 
     // Unknown physical device functions. Add a `VulkanFunction` to this list which will be searched in
index 890394d5d28ee31bf39fae89e82cea8eccd5e9f7..079e8065045ca32190a45b8b749934f882cddfb8 100644 (file)
@@ -327,6 +327,26 @@ VKAPI_ATTR void VKAPI_CALL test_vkDestroyDebugUtilsMessengerEXT(VkInstance insta
     }
 }
 
+// Debug utils & debug marker ext stubs
+VKAPI_ATTR VkResult VKAPI_CALL test_vkDebugMarkerSetObjectTagEXT(VkDevice dev, const VkDebugMarkerObjectTagInfoEXT* pTagInfo) {
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkDebugMarkerSetObjectNameEXT(VkDevice dev, const VkDebugMarkerObjectNameInfoEXT* pNameInfo) {
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkSetDebugUtilsObjectNameEXT(VkDevice dev, const VkDebugUtilsObjectTagInfoEXT* pTagInfo) {
+    return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkSetDebugUtilsObjectTagEXT(VkDevice dev, const VkDebugUtilsObjectTagInfoEXT* pTagInfo) {
+    return VK_SUCCESS;
+}
+VKAPI_ATTR void VKAPI_CALL test_vkQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+VKAPI_ATTR void VKAPI_CALL test_vkQueueEndDebugUtilsLabelEXT(VkQueue queue) {}
+VKAPI_ATTR void VKAPI_CALL test_vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+VKAPI_ATTR void VKAPI_CALL test_vkCmdBeginDebugUtilsLabelEXT(VkCommandBuffer cmd_buf, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+VKAPI_ATTR void VKAPI_CALL test_vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer cmd_buf) {}
+VKAPI_ATTR void VKAPI_CALL test_vkCmdInsertDebugUtilsLabelEXT(VkCommandBuffer cmd_buf, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+
 //// Physical Device functions ////
 
 // VK_SUCCESS,VK_INCOMPLETE
@@ -366,11 +386,11 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDevice(VkPhysicalDevice physicalDevi
     auto device_handle = DispatchableHandle<VkDevice>();
     *pDevice = device_handle.handle;
     found->device_handles.push_back(device_handle.handle);
-    icd.device_handles.emplace_back(std::move(device_handle));
-
+    found->device_create_infos.push_back(DeviceCreateInfo{pCreateInfo});
     for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
         found->queue_handles.emplace_back();
     }
+    icd.device_handles.emplace_back(std::move(device_handle));
 
     return VK_SUCCESS;
 }
@@ -378,6 +398,11 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateDevice(VkPhysicalDevice physicalDevi
 VKAPI_ATTR void VKAPI_CALL test_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
     auto found = std::find(icd.device_handles.begin(), icd.device_handles.end(), device);
     if (found != icd.device_handles.end()) icd.device_handles.erase(found);
+    auto fd = icd.lookup_device(device);
+    if (!fd.found) return;
+    auto& phys_dev = icd.physical_devices.at(fd.phys_dev_index);
+    phys_dev.device_handles.erase(phys_dev.device_handles.begin() + fd.dev_index);
+    phys_dev.device_create_infos.erase(phys_dev.device_create_infos.begin() + fd.dev_index);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL generic_tool_props_function(VkPhysicalDevice physicalDevice, uint32_t* pToolCount,
@@ -586,7 +611,7 @@ VKAPI_ATTR void VKAPI_CALL test_vkDestroySurfaceKHR(VkInstance instance, VkSurfa
         }
     }
 }
-
+// VK_KHR_swapchain
 VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo,
                                                          const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) {
     common_nondispatch_handle_creation(icd.swapchain_handles, pSwapchain);
@@ -619,6 +644,13 @@ VKAPI_ATTR void VKAPI_CALL test_vkDestroySwapchainKHR(VkDevice device, VkSwapcha
         }
     }
 }
+// VK_KHR_swapchain with 1.1
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface,
+                                                                           VkDeviceGroupPresentModeFlagsKHR* pModes) {
+    if (!pModes) return VK_ERROR_INITIALIZATION_FAILED;
+    *pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR;
+    return VK_SUCCESS;
+}
 
 // VK_KHR_surface
 VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
@@ -764,6 +796,14 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhys
     }
     return VK_SUCCESS;
 }
+// VK_KHR_display_swapchain
+VkResult test_vkCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos,
+                                          const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains) {
+    for (uint32_t i = 0; i < swapchainCount; i++) {
+        common_nondispatch_handle_creation(icd.swapchain_handles, &pSwapchains[i]);
+    }
+    return VK_SUCCESS;
+}
 
 //// misc
 VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo,
@@ -1298,23 +1338,58 @@ PFN_vkVoidFunction get_instance_func(VkInstance instance, const char* pName) {
     return nullptr;
 }
 
+bool should_check(std::vector<const char*> const& exts, VkDevice device, const char* ext_name) {
+    if (device == NULL) return true;  // always look if device is NULL
+    for (auto const& ext : exts) {
+        if (string_eq(ext, ext_name)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 PFN_vkVoidFunction get_device_func(VkDevice device, const char* pName) {
+    TestICD::FindDevice fd{};
+    DeviceCreateInfo create_info{};
     if (device != nullptr) {
-        if (!std::any_of(icd.physical_devices.begin(), icd.physical_devices.end(), [&](const PhysicalDevice& pd) {
-                return std::any_of(pd.device_handles.begin(), pd.device_handles.end(),
-                                   [&](const VkDevice& pd_device) { return pd_device == device; });
-            })) {
-            return nullptr;
-        }
+        fd = icd.lookup_device(device);
+        if (!fd.found) return NULL;
+        create_info = icd.physical_devices.at(fd.phys_dev_index).device_create_infos.at(fd.dev_index);
     }
-    if (string_eq(pName, "vkDestroyDevice")) return to_vkVoidFunction(test_vkDestroyDevice);
-    if (string_eq(pName, "vkCreateSwapchainKHR")) return to_vkVoidFunction(test_vkCreateSwapchainKHR);
-    if (string_eq(pName, "vkGetSwapchainImagesKHR")) return to_vkVoidFunction(test_vkGetSwapchainImagesKHR);
-    if (string_eq(pName, "vkDestroySwapchainKHR")) return to_vkVoidFunction(test_vkDestroySwapchainKHR);
     if (string_eq(pName, "vkCreateCommandPool")) return to_vkVoidFunction(test_vkCreateCommandPool);
     if (string_eq(pName, "vkAllocateCommandBuffers")) return to_vkVoidFunction(test_vkAllocateCommandBuffers);
     if (string_eq(pName, "vkDestroyCommandPool")) return to_vkVoidFunction(test_vkDestroyCommandPool);
     if (string_eq(pName, "vkGetDeviceQueue")) return to_vkVoidFunction(test_vkGetDeviceQueue);
+    if (string_eq(pName, "vkDestroyDevice")) return to_vkVoidFunction(test_vkDestroyDevice);
+    if (should_check(create_info.enabled_extensions, device, "VK_KHR_swapchain")) {
+        if (string_eq(pName, "vkCreateSwapchainKHR")) return to_vkVoidFunction(test_vkCreateSwapchainKHR);
+        if (string_eq(pName, "vkGetSwapchainImagesKHR")) return to_vkVoidFunction(test_vkGetSwapchainImagesKHR);
+        if (string_eq(pName, "vkDestroySwapchainKHR")) return to_vkVoidFunction(test_vkDestroySwapchainKHR);
+
+        if (icd.icd_api_version >= VK_API_VERSION_1_1 && string_eq(pName, "vkGetDeviceGroupSurfacePresentModesKHR"))
+            return to_vkVoidFunction(test_vkGetDeviceGroupSurfacePresentModesKHR);
+    }
+    if (should_check(create_info.enabled_extensions, device, "VK_KHR_display_swapchain")) {
+        if (string_eq(pName, "vkCreateSharedSwapchainsKHR")) return to_vkVoidFunction(test_vkCreateSharedSwapchainsKHR);
+    }
+    if (should_check(create_info.enabled_extensions, device, "VK_KHR_device_group")) {
+        if (string_eq(pName, "vkGetDeviceGroupSurfacePresentModesKHR"))
+            return to_vkVoidFunction(test_vkGetDeviceGroupSurfacePresentModesKHR);
+    }
+    if (should_check(create_info.enabled_extensions, device, "VK_EXT_debug_marker")) {
+        if (string_eq(pName, "vkDebugMarkerSetObjectTagEXT")) return to_vkVoidFunction(test_vkDebugMarkerSetObjectTagEXT);
+        if (string_eq(pName, "vkDebugMarkerSetObjectNameEXT")) return to_vkVoidFunction(test_vkDebugMarkerSetObjectNameEXT);
+    }
+    if (IsInstanceExtensionEnabled("VK_EXT_debug_utils")) {
+        if (string_eq(pName, "vkSetDebugUtilsObjectNameEXT")) return to_vkVoidFunction(test_vkSetDebugUtilsObjectNameEXT);
+        if (string_eq(pName, "vkSetDebugUtilsObjectTagEXT")) return to_vkVoidFunction(test_vkSetDebugUtilsObjectTagEXT);
+        if (string_eq(pName, "vkQueueBeginDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkQueueBeginDebugUtilsLabelEXT);
+        if (string_eq(pName, "vkQueueEndDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkQueueEndDebugUtilsLabelEXT);
+        if (string_eq(pName, "vkQueueInsertDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkQueueInsertDebugUtilsLabelEXT);
+        if (string_eq(pName, "vkCmdBeginDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkCmdBeginDebugUtilsLabelEXT);
+        if (string_eq(pName, "vkCmdEndDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkCmdEndDebugUtilsLabelEXT);
+        if (string_eq(pName, "vkCmdInsertDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkCmdInsertDebugUtilsLabelEXT);
+    }
     // look for device functions setup from a test
     for (const auto& phys_dev : icd.physical_devices) {
         for (const auto& function : phys_dev.known_device_functions) {
index 6acdab142df4ae42500c45da12c35d0d1b6ef276..8134632eebe70034f2090fedac6a540bfd99b86a 100644 (file)
@@ -110,6 +110,28 @@ struct TestICD {
         return info;
     }
 
+    struct FindDevice {
+        bool found = false;
+        uint32_t phys_dev_index = 0;
+        uint32_t dev_index = 0;
+    };
+
+    FindDevice lookup_device(VkDevice device) {
+        FindDevice fd{};
+        for (uint32_t p = 0; p < physical_devices.size(); p++) {
+            auto const& phys_dev = physical_devices.at(p);
+            for (uint32_t d = 0; d < phys_dev.device_handles.size(); d++) {
+                if (phys_dev.device_handles.at(d) == device) {
+                    fd.found = true;
+                    fd.phys_dev_index = p;
+                    fd.dev_index = d;
+                    return fd;
+                }
+            }
+        }
+        return fd;
+    }
+
 #if defined(WIN32)
     BUILDER_VALUE(TestICD, LUID, adapterLUID, {})
 #endif  // defined(WIN32)
index 4a99046ac14069ec0b20e70c3f4a07aa47acb479..49d067db47735a53821b46e202fba9b65a0c28e7 100644 (file)
@@ -563,59 +563,68 @@ void setup_WSI_in_create_instance(InstWrapper& inst, const char* api_selection)
 }
 
 template <typename CreationFunc, typename CreateInfo>
-void create_surface_helper(InstWrapper& inst, VkSurfaceKHR& surface, const char* load_func_name) {
+testing::AssertionResult create_surface_helper(InstWrapper& inst, VkSurfaceKHR& surface, const char* load_func_name) {
     CreationFunc pfn_CreateSurface = inst.load(load_func_name);
+    if (!pfn_CreateSurface) return testing::AssertionFailure();
     CreateInfo surf_create_info{};
-    ASSERT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
+    VkResult res = pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface);
+    return res == VK_SUCCESS ? testing::AssertionSuccess() : testing::AssertionFailure();
 }
-void create_surface(InstWrapper& inst, VkSurfaceKHR& surface, const char* api_selection) {
+testing::AssertionResult create_surface(InstWrapper& inst, VkSurfaceKHR& surface, const char* api_selection) {
 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
-    create_surface_helper<PFN_vkCreateAndroidSurfaceKHR, VkAndroidSurfaceCreateInfoKHR>(inst, surface, "vkCreateAndroidSurfaceKHR");
+    return create_surface_helper<PFN_vkCreateAndroidSurfaceKHR, VkAndroidSurfaceCreateInfoKHR>(inst, surface,
+                                                                                               "vkCreateAndroidSurfaceKHR");
 #elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
-    create_surface_helper<PFN_vkCreateDirectFBSurfaceEXT, VkDirectFBSurfaceCreateInfoEXT>(inst, surface,
-                                                                                          "vkCreateDirectFBSurfaceEXT");
+    return create_surface_helper<PFN_vkCreateDirectFBSurfaceEXT, VkDirectFBSurfaceCreateInfoEXT>(inst, surface,
+                                                                                                 "vkCreateDirectFBSurfaceEXT")
 #elif defined(VK_USE_PLATFORM_FUCHSIA)
-    create_surface_helper<PFN_vkCreateImagePipeSurfaceFUCHSIA, VkImagePipeSurfaceCreateInfoFUCHSIA>(
+    return create_surface_helper<PFN_vkCreateImagePipeSurfaceFUCHSIA, VkImagePipeSurfaceCreateInfoFUCHSIA>(
         inst, surface, "vkCreateImagePipeSurfaceFUCHSIA");
 #elif defined(VK_USE_PLATFORM_GGP)
-    create_surface_helper<PFN__vkCreateStreamDescriptorSurfaceGGP, VkStreamDescriptorSurfaceCreateInfoGGP>(
+    return create_surface_helper<PFN__vkCreateStreamDescriptorSurfaceGGP, VkStreamDescriptorSurfaceCreateInfoGGP>(
         inst, surface, "vkCreateStreamDescriptorSurfaceGGP");
 #elif defined(VK_USE_PLATFORM_IOS_MVK)
-    create_surface_helper<PFN_vkCreateIOSSurfaceMVK, VkIOSSurfaceCreateInfoMVK>(inst, surface, "vkCreateIOSSurfaceMVK");
+    return create_surface_helper<PFN_vkCreateIOSSurfaceMVK, VkIOSSurfaceCreateInfoMVK>(inst, surface, "vkCreateIOSSurfaceMVK");
 #elif defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)
 #if defined(VK_USE_PLATFORM_MACOS_MVK)
     if (api_selection != nullptr && string_eq(api_selection, "VK_USE_PLATFORM_MACOS_MVK"))
-        create_surface_helper<PFN_vkCreateMacOSSurfaceMVK, VkMacOSSurfaceCreateInfoMVK>(inst, surface, "vkCreateMacOSSurfaceMVK");
+        return create_surface_helper<PFN_vkCreateMacOSSurfaceMVK, VkMacOSSurfaceCreateInfoMVK>(inst, surface,
+                                                                                               "vkCreateMacOSSurfaceMVK");
 #endif
 #if defined(VK_USE_PLATFORM_METAL_EXT)
     if (api_selection == nullptr || (api_selection != nullptr && string_eq(api_selection, "VK_USE_PLATFORM_METAL_EXT")))
-        create_surface_helper<PFN_vkCreateMetalSurfaceEXT, VkMetalSurfaceCreateInfoEXT>(inst, surface, "vkCreateMetalSurfaceEXT");
+        return create_surface_helper<PFN_vkCreateMetalSurfaceEXT, VkMetalSurfaceCreateInfoEXT>(inst, surface,
+                                                                                               "vkCreateMetalSurfaceEXT");
 #endif
+    return testing::AssertionFailure();
 #elif defined(VK_USE_PLATFORM_SCREEN_QNX)
-    create_surface_helper<PFN_vkCreateScreenSurfaceQNX, VkScreenSurfaceCreateInfoQNX>(inst, surface, "vkCreateScreenSurfaceQNX");
+    return create_surface_helper<PFN_vkCreateScreenSurfaceQNX, VkScreenSurfaceCreateInfoQNX>(inst, surface,
+                                                                                             "vkCreateScreenSurfaceQNX");
 #elif defined(VK_USE_PLATFORM_VI_NN)
-    create_surface_helper<PFN_vkCreateViSurfaceNN, VkViSurfaceCreateInfoNN>(inst, surface, "vkCreateViSurfaceNN");
+    return create_surface_helper<PFN_vkCreateViSurfaceNN, VkViSurfaceCreateInfoNN>(inst, surface, "vkCreateViSurfaceNN");
 #elif defined(VK_USE_PLATFORM_WIN32_KHR)
-    create_surface_helper<PFN_vkCreateWin32SurfaceKHR, VkWin32SurfaceCreateInfoKHR>(inst, surface, "vkCreateWin32SurfaceKHR");
+    return create_surface_helper<PFN_vkCreateWin32SurfaceKHR, VkWin32SurfaceCreateInfoKHR>(inst, surface,
+                                                                                           "vkCreateWin32SurfaceKHR");
 #elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
 #if defined(VK_USE_PLATFORM_XLIB_KHR)
     if (string_eq(api_selection, "VK_USE_PLATFORM_XLIB_KHR"))
-        create_surface_helper<PFN_vkCreateXlibSurfaceKHR, VkXlibSurfaceCreateInfoKHR>(inst, surface, "vkCreateXlibSurfaceKHR");
+        return create_surface_helper<PFN_vkCreateXlibSurfaceKHR, VkXlibSurfaceCreateInfoKHR>(inst, surface,
+                                                                                             "vkCreateXlibSurfaceKHR");
 #endif
 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
     if (string_eq(api_selection, "VK_USE_PLATFORM_WAYLAND_KHR"))
-        create_surface_helper<PFN_vkCreateWaylandSurfaceKHR, VkWaylandSurfaceCreateInfoKHR>(inst, surface,
-                                                                                            "vkCreateWaylandSurfaceKHR");
+        return create_surface_helper<PFN_vkCreateWaylandSurfaceKHR, VkWaylandSurfaceCreateInfoKHR>(inst, surface,
+                                                                                                   "vkCreateWaylandSurfaceKHR");
 #endif
 #if defined(VK_USE_PLATFORM_XCB_KHR)
     if (api_selection == nullptr || string_eq(api_selection, "VK_USE_PLATFORM_XCB_KHR"))
-        create_surface_helper<PFN_vkCreateXcbSurfaceKHR, VkXcbSurfaceCreateInfoKHR>(inst, surface, "vkCreateXcbSurfaceKHR");
+        return create_surface_helper<PFN_vkCreateXcbSurfaceKHR, VkXcbSurfaceCreateInfoKHR>(inst, surface, "vkCreateXcbSurfaceKHR");
 #endif
+    return testing::AssertionFailure();
 #else
-    create_surface_helper<PFN_vkCreateDisplayPlaneSurfaceKHR, VkDisplaySurfaceCreateInfoKHR>(inst, surface,
-                                                                                             "vkCreateDisplayPlaneSurfaceKHR");
+    return create_surface_helper<PFN_vkCreateDisplayPlaneSurfaceKHR, VkDisplaySurfaceCreateInfoKHR>(
+        inst, surface, "vkCreateDisplayPlaneSurfaceKHR");
 #endif
-    assert(surface != VK_NULL_HANDLE);
 }
 
 extern "C" {
index fcdd681db96adf41701f0461ffdcef9ee163c410..261b85ff6d164b509a2a741f182acdf953957f5f 100644 (file)
@@ -546,7 +546,8 @@ void setup_WSI_in_create_instance(InstWrapper& inst, const char* api_selection =
 // Create a surface using a platform specific API
 // api_selection: optionally provide a VK_USE_PLATFORM_XXX string to select which API to create a surface with.
 //    defaults to Metal on macOS and XCB on linux if not provided
-void create_surface(InstWrapper& inst, VkSurfaceKHR& out_surface, const char* api_selection = nullptr);
+// Returns an assertion failure if the surface failed to be created
+testing::AssertionResult create_surface(InstWrapper& inst, VkSurfaceKHR& out_surface, const char* api_selection = nullptr);
 
 struct EnvVarCleaner {
     std::string env_var;
index 4b67dba7734782cc394a16f55cb2a82818b079a1..231e81eb637f977f50bdd9be1bc344a7cb8fa22a 100644 (file)
@@ -544,13 +544,35 @@ InstanceCreateInfo& InstanceCreateInfo::set_api_version(uint32_t major, uint32_t
 }
 
 DeviceQueueCreateInfo::DeviceQueueCreateInfo() { queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; }
+DeviceQueueCreateInfo::DeviceQueueCreateInfo(const VkDeviceQueueCreateInfo* create_info) {
+    queue_create_info = *create_info;
+    for (uint32_t i = 0; i < create_info->queueCount; i++) {
+        priorities.push_back(create_info->pQueuePriorities[i]);
+    }
+}
 
 VkDeviceQueueCreateInfo DeviceQueueCreateInfo::get() noexcept {
     queue_create_info.pQueuePriorities = priorities.data();
+    queue_create_info.queueCount = 1;
+    queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
     return queue_create_info;
 }
 
+DeviceCreateInfo::DeviceCreateInfo(const VkDeviceCreateInfo* create_info) {
+    dev = *create_info;
+    for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
+        enabled_extensions.push_back(create_info->ppEnabledExtensionNames[i]);
+    }
+    for (uint32_t i = 0; i < create_info->enabledLayerCount; i++) {
+        enabled_layers.push_back(create_info->ppEnabledLayerNames[i]);
+    }
+    for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
+        device_queue_infos.push_back(create_info->pQueueCreateInfos[i]);
+    }
+}
+
 VkDeviceCreateInfo* DeviceCreateInfo::get() noexcept {
+    dev.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
     dev.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
     dev.ppEnabledLayerNames = enabled_layers.data();
     dev.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
@@ -558,6 +580,7 @@ VkDeviceCreateInfo* DeviceCreateInfo::get() noexcept {
     uint32_t index = 0;
     for (auto& queue : queue_info_details) {
         queue.queue_create_info.queueFamilyIndex = index++;
+        queue.queue_create_info.queueCount = 1;
         device_queue_infos.push_back(queue.get());
     }
 
index 719b8e632df6acfab2e1ab553c5edb06ea03bc9b..ed849cbf245adb902a0a716127c1b3ec8e5b5030 100644 (file)
@@ -663,14 +663,19 @@ struct InstanceCreateInfo {
 };
 
 struct DeviceQueueCreateInfo {
+    DeviceQueueCreateInfo();
+    DeviceQueueCreateInfo(const VkDeviceQueueCreateInfo* create_info);
+
     BUILDER_VALUE(DeviceQueueCreateInfo, VkDeviceQueueCreateInfo, queue_create_info, {})
     BUILDER_VECTOR(DeviceQueueCreateInfo, float, priorities, priority)
 
-    DeviceQueueCreateInfo();
     VkDeviceQueueCreateInfo get() noexcept;
 };
 
 struct DeviceCreateInfo {
+    DeviceCreateInfo() = default;
+    DeviceCreateInfo(const VkDeviceCreateInfo* create_info);
+
     BUILDER_VALUE(DeviceCreateInfo, VkDeviceCreateInfo, dev, {})
     BUILDER_VECTOR(DeviceCreateInfo, const char*, enabled_extensions, extension)
     BUILDER_VECTOR(DeviceCreateInfo, const char*, enabled_layers, layer)
index 87155e23ac6e2910fa26f0b22c16323730ae0eda..d9d51366ac26ccd086b7e0d767f8c1470627a2d4 100644 (file)
@@ -29,4 +29,4 @@ if(APPLE AND BUILD_STATIC_LOADER)
         target_compile_options(macos_static_loader_build PUBLIC -fsanitize=thread)
         target_link_options(macos_static_loader_build PUBLIC -fsanitize=thread)
     endif()
-endif()
\ No newline at end of file
+endif()
index f4a521fbcd15640924c258049ed3c5f9abd39b22..95aea3e0dd49a38bcdd2c5c4414c1a2a092cbfca 100644 (file)
@@ -69,7 +69,9 @@ int main() {
             VkCommandBufferBeginInfo begin_info{};
             begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
             VkResult res = vkBeginCommandBuffer(command_buffer, &begin_info);
-            assert(res == VK_SUCCESS);
+            if (res != VK_SUCCESS) {
+                std::cout << "Failed to begin command buffer\n";
+            }
 
             // call the dynamic rendering function -- should not go into the physical device function trampoline.
             PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR =
@@ -79,4 +81,4 @@ int main() {
             vkCmdBeginRenderingKHR(command_buffer, &rendering_info);
         }
     }
-}
\ No newline at end of file
+}
index 1cefbb8c5d6255732e1110527145454c374f4430..59bb8088795d8e324e90275d84fe7e3e62227b9d 100644 (file)
@@ -849,3 +849,163 @@ TEST_F(ManualMessage, InfoMessage) {
     // Message should be found
     ASSERT_EQ(true, message_found);
 }
+
+void CheckDeviceFunctions(FrameworkEnvironment& env, bool use_GIPA, bool enable_debug_extensions) {
+    InstWrapper inst(env.vulkan_functions);
+    if (enable_debug_extensions) {
+        inst.create_info.add_extension("VK_EXT_debug_utils");
+    }
+    setup_WSI_in_create_instance(inst);
+    ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+
+    auto phys_dev = inst.GetPhysDev();
+
+    DeviceWrapper dev{inst};
+    dev.create_info.add_extension("VK_KHR_swapchain");
+    dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+    if (enable_debug_extensions) {
+        dev.create_info.add_extension("VK_EXT_debug_marker");
+    }
+    // if the hardware doesn't support VK_EXT_debug_marker and we are trying to enable it, then we should exit since that will fail
+    // to create a device
+    if (enable_debug_extensions &&
+        env.get_test_icd().physical_devices.at(0).extensions.size() == 1 /*only swapchain should be available*/) {
+        dev.CheckCreate(phys_dev, VK_ERROR_EXTENSION_NOT_PRESENT);
+        return;
+    }
+    ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+    DeviceFunctions dev_funcs{env.vulkan_functions, dev};
+
+    VkSurfaceKHR surface{};
+    ASSERT_NO_FATAL_FAILURE(create_surface(inst, surface));
+
+    VkSwapchainCreateInfoKHR info{};
+    info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+    info.surface = surface;
+
+    VkSwapchainKHR swapchain{};
+    ASSERT_EQ(VK_SUCCESS, dev_funcs.vkCreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain));
+
+    PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
+    DebugMarkerSetObjectTagEXT = use_GIPA ? inst.load("vkDebugMarkerSetObjectTagEXT") : dev.load("vkDebugMarkerSetObjectTagEXT");
+    PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
+    DebugMarkerSetObjectNameEXT = use_GIPA ? inst.load("vkDebugMarkerSetObjectNameEXT") : dev.load("vkDebugMarkerSetObjectNameEXT");
+    PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
+    SetDebugUtilsObjectNameEXT = use_GIPA ? inst.load("vkSetDebugUtilsObjectNameEXT") : dev.load("vkSetDebugUtilsObjectNameEXT");
+    PFN_vkSetDebugUtilsObjectTagEXT SetDebugUtilsObjectTagEXT;
+    SetDebugUtilsObjectTagEXT = use_GIPA ? inst.load("vkSetDebugUtilsObjectTagEXT") : dev.load("vkSetDebugUtilsObjectTagEXT");
+    PFN_vkQueueBeginDebugUtilsLabelEXT QueueBeginDebugUtilsLabelEXT;
+    QueueBeginDebugUtilsLabelEXT =
+        use_GIPA ? inst.load("vkQueueBeginDebugUtilsLabelEXT") : dev.load("vkQueueBeginDebugUtilsLabelEXT");
+    PFN_vkQueueEndDebugUtilsLabelEXT QueueEndDebugUtilsLabelEXT;
+    QueueEndDebugUtilsLabelEXT = use_GIPA ? inst.load("vkQueueEndDebugUtilsLabelEXT") : dev.load("vkQueueEndDebugUtilsLabelEXT");
+    PFN_vkQueueInsertDebugUtilsLabelEXT QueueInsertDebugUtilsLabelEXT;
+    QueueInsertDebugUtilsLabelEXT =
+        use_GIPA ? inst.load("vkQueueInsertDebugUtilsLabelEXT") : dev.load("vkQueueInsertDebugUtilsLabelEXT");
+    PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT;
+    CmdBeginDebugUtilsLabelEXT = use_GIPA ? inst.load("vkCmdBeginDebugUtilsLabelEXT") : dev.load("vkCmdBeginDebugUtilsLabelEXT");
+    PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
+    CmdEndDebugUtilsLabelEXT = use_GIPA ? inst.load("vkCmdEndDebugUtilsLabelEXT") : dev.load("vkCmdEndDebugUtilsLabelEXT");
+    PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
+    CmdInsertDebugUtilsLabelEXT = use_GIPA ? inst.load("vkCmdInsertDebugUtilsLabelEXT") : dev.load("vkCmdInsertDebugUtilsLabelEXT");
+
+    if (use_GIPA) {
+        // When querying from GIPA, these functions should always be found
+        ASSERT_TRUE(nullptr != DebugMarkerSetObjectTagEXT);
+        ASSERT_TRUE(nullptr != DebugMarkerSetObjectNameEXT);
+        // When querying from GIPA, these functions are found only if the extensions were enabled
+        ASSERT_EQ(enable_debug_extensions, nullptr != SetDebugUtilsObjectNameEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != SetDebugUtilsObjectTagEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != QueueBeginDebugUtilsLabelEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != QueueEndDebugUtilsLabelEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != QueueInsertDebugUtilsLabelEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != CmdBeginDebugUtilsLabelEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != CmdEndDebugUtilsLabelEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != CmdInsertDebugUtilsLabelEXT);
+    } else {
+        // When querying from GDPA, these functions are found only if the extensions were enabled
+        ASSERT_EQ(enable_debug_extensions, nullptr != DebugMarkerSetObjectTagEXT);
+        ASSERT_EQ(enable_debug_extensions, nullptr != DebugMarkerSetObjectNameEXT);
+        // When querying from GDPA, these functions should always be found
+        ASSERT_TRUE(nullptr != SetDebugUtilsObjectNameEXT);
+        ASSERT_TRUE(nullptr != SetDebugUtilsObjectTagEXT);
+        ASSERT_TRUE(nullptr != QueueBeginDebugUtilsLabelEXT);
+        ASSERT_TRUE(nullptr != QueueEndDebugUtilsLabelEXT);
+        ASSERT_TRUE(nullptr != QueueInsertDebugUtilsLabelEXT);
+        ASSERT_TRUE(nullptr != CmdBeginDebugUtilsLabelEXT);
+        ASSERT_TRUE(nullptr != CmdEndDebugUtilsLabelEXT);
+        ASSERT_TRUE(nullptr != CmdInsertDebugUtilsLabelEXT);
+    }
+    VkDebugUtilsObjectNameInfoEXT obj_name_info{};
+    obj_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+    obj_name_info.objectHandle = (uint64_t)swapchain;
+    obj_name_info.objectType = VK_OBJECT_TYPE_SWAPCHAIN_KHR;
+    obj_name_info.pObjectName = " Your mom!";
+    if (SetDebugUtilsObjectNameEXT) SetDebugUtilsObjectNameEXT(dev.dev, &obj_name_info);
+
+    VkDebugMarkerObjectTagInfoEXT marker_object_tag{};
+    VkDebugMarkerObjectNameInfoEXT marker_object_name{};
+    if (use_GIPA && !enable_debug_extensions) {
+        // These functions crash when the extension isn't enabled and the function was acquired with GIPA.
+        ASSERT_DEATH(DebugMarkerSetObjectTagEXT(dev.dev, &marker_object_tag), "");
+        ASSERT_DEATH(DebugMarkerSetObjectNameEXT(dev.dev, &marker_object_name), "");
+    } else {
+        if (DebugMarkerSetObjectTagEXT) DebugMarkerSetObjectTagEXT(dev.dev, &marker_object_tag);
+        if (DebugMarkerSetObjectNameEXT) DebugMarkerSetObjectNameEXT(dev.dev, &marker_object_name);
+    }
+    if (SetDebugUtilsObjectNameEXT) SetDebugUtilsObjectNameEXT(dev.dev, &obj_name_info);
+    VkDebugUtilsObjectTagInfoEXT utils_object_tag{};
+    if (SetDebugUtilsObjectTagEXT) SetDebugUtilsObjectTagEXT(dev.dev, &utils_object_tag);
+    VkQueue queue{};
+    dev.functions->vkGetDeviceQueue(dev.dev, 0, 0, &queue);
+    VkDebugUtilsLabelEXT utils_label{};
+    utils_label.pLabelName = "Testing testing 123";
+    if (QueueBeginDebugUtilsLabelEXT) QueueBeginDebugUtilsLabelEXT(queue, &utils_label);
+    if (QueueEndDebugUtilsLabelEXT) QueueEndDebugUtilsLabelEXT(queue);
+    if (QueueInsertDebugUtilsLabelEXT) QueueInsertDebugUtilsLabelEXT(queue, &utils_label);
+    VkCommandBuffer cmd_buf{};
+    VkCommandPool cmd_pool;
+    VkCommandPoolCreateInfo cmd_pool_info{};
+    cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    ASSERT_EQ(VK_SUCCESS, dev_funcs.vkCreateCommandPool(dev.dev, &cmd_pool_info, nullptr, &cmd_pool));
+    VkCommandBufferAllocateInfo cmd_buf_alloc_info{};
+    cmd_buf_alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    cmd_buf_alloc_info.commandBufferCount = 1;
+    cmd_buf_alloc_info.commandPool = cmd_pool;
+    ASSERT_EQ(VK_SUCCESS, dev_funcs.vkAllocateCommandBuffers(dev.dev, &cmd_buf_alloc_info, &cmd_buf));
+    if (CmdBeginDebugUtilsLabelEXT) CmdBeginDebugUtilsLabelEXT(cmd_buf, &utils_label);
+    if (CmdEndDebugUtilsLabelEXT) CmdEndDebugUtilsLabelEXT(cmd_buf);
+    if (CmdInsertDebugUtilsLabelEXT) CmdInsertDebugUtilsLabelEXT(cmd_buf, &utils_label);
+
+    dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+    env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr);
+}
+
+TEST(GetDeviceProcAddr, DebugFuncsWithTerminator) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+    setup_WSI_in_ICD(env.get_test_icd());
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+    env.get_test_icd().physical_devices.at(0).add_extensions({"VK_KHR_swapchain"});
+    // Hardware doesn't support the debug extensions
+
+    // Use getDeviceProcAddr & vary enabling the debug extensions
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, false));
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, true));
+
+    // Use getInstanceProcAddr & vary enabling the debug extensions
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, false));
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, true));
+
+    // Now set the hardware to support the extensions and run the situations again
+    env.get_test_icd().physical_devices.at(0).add_extensions({"VK_EXT_debug_marker"});
+    env.get_test_icd().add_instance_extension("VK_EXT_debug_utils");
+
+    // Use getDeviceProcAddr & vary enabling the debug extensions
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, false));
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, true));
+
+    // Use getInstanceProcAddr & vary enabling the debug extensions
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, false));
+    ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, true));
+}
index 64a3c74d582f4602225d26f492374b40996ce359..20f72685a418fbbe8363c34e68402204f21ec8a0 100644 (file)
@@ -184,4 +184,111 @@ TEST(GetProcAddr, GlobalFunctions) {
         EnumeratePhysicalDevices = reinterpret_cast<PFN_vkGetInstanceProcAddr>(gipa(NULL, "vkEnumeratePhysicalDevices"));
         handle_assert_null(EnumeratePhysicalDevices);
     }
-}
\ No newline at end of file
+}
+
+// Swapchain functions which require a terminator in all cases have situations where the driver may have a
+// NULL function pointer but the loader shouldn't abort() if that is the case. Rather, it should log a message
+// and return VK_SUCCESS to maintain previous behavior.
+TEST(GetDeviceProcAddr, SwapchainFuncsWithTerminator) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+    setup_WSI_in_ICD(env.get_test_icd());
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    InstWrapper inst(env.vulkan_functions);
+    inst.create_info.add_extension("VK_EXT_debug_utils");
+    setup_WSI_in_create_instance(inst);
+    ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+
+    VkSurfaceKHR surface{};
+    ASSERT_NO_FATAL_FAILURE(create_surface(inst, surface));
+
+    DebugUtilsWrapper log{inst};
+    ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log));
+    auto phys_dev = inst.GetPhysDev();
+    {
+        DeviceWrapper dev{inst};
+        dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+        DeviceFunctions dev_funcs{env.vulkan_functions, dev};
+
+        PFN_vkCreateSwapchainKHR CreateSwapchainKHR = dev.load("vkCreateSwapchainKHR");
+        PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
+        PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR =
+            dev.load("vkGetDeviceGroupSurfacePresentModesKHR");
+        PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR = dev.load("vkCreateSharedSwapchainsKHR");
+        ASSERT_FALSE(CreateSwapchainKHR);
+        ASSERT_TRUE(inst_CreateSwapchainKHR);
+        ASSERT_FALSE(GetDeviceGroupSurfacePresentModesKHR);
+        ASSERT_FALSE(CreateSharedSwapchainsKHR);
+
+        VkSwapchainCreateInfoKHR info{};
+        info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+        info.surface = surface;
+
+        VkSwapchainKHR swapchain{};
+        if (CreateSwapchainKHR) CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
+        ASSERT_FALSE(
+            log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+                     "extension enabled?"));
+        log.logger.clear();
+        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+        // try to call the vkCreateSwapchainKHR acquired from the instance - this *should* abort due to not enabling the extension
+        if (inst_CreateSwapchainKHR) {
+            ASSERT_DEATH(inst_CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain),
+                         "vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+                         "extension enabled?");
+        }
+        log.logger.clear();
+        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+
+        VkDeviceGroupPresentModeFlagsKHR modes{};
+        if (GetDeviceGroupSurfacePresentModesKHR) GetDeviceGroupSurfacePresentModesKHR(dev.dev, surface, &modes);
+
+        if (CreateSharedSwapchainsKHR) CreateSharedSwapchainsKHR(dev.dev, 1, &info, nullptr, &swapchain);
+    }
+    {
+        env.get_test_icd().physical_devices.at(0).add_extensions(
+            {"VK_KHR_swapchain", "VK_KHR_display_swapchain", "VK_EXT_debug_marker"});
+
+        DeviceWrapper dev{inst};
+        dev.create_info.add_extensions({"VK_KHR_swapchain", "VK_KHR_display_swapchain", "VK_EXT_debug_marker"});
+        dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+        DeviceFunctions dev_funcs{env.vulkan_functions, dev};
+
+        PFN_vkCreateSwapchainKHR CreateSwapchainKHR = dev.load("vkCreateSwapchainKHR");
+        PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
+        PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR =
+            dev.load("vkGetDeviceGroupSurfacePresentModesKHR");
+        PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR = dev.load("vkCreateSharedSwapchainsKHR");
+        ASSERT_TRUE(CreateSwapchainKHR);
+        ASSERT_TRUE(inst_CreateSwapchainKHR);
+        ASSERT_TRUE(GetDeviceGroupSurfacePresentModesKHR);
+        ASSERT_TRUE(CreateSharedSwapchainsKHR);
+
+        VkSwapchainCreateInfoKHR info{};
+        info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+        info.surface = surface;
+
+        VkSwapchainKHR swapchain{};
+        if (CreateSwapchainKHR) CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
+        ASSERT_FALSE(
+            log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+                     "extension enabled?"));
+        log.logger.clear();
+        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+        if (inst_CreateSwapchainKHR) inst_CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
+        ASSERT_FALSE(
+            log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+                     "extension enabled?"));
+        log.logger.clear();
+        if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+
+        VkDeviceGroupPresentModeFlagsKHR modes{};
+        if (GetDeviceGroupSurfacePresentModesKHR) GetDeviceGroupSurfacePresentModesKHR(dev.dev, surface, &modes);
+
+        if (CreateSharedSwapchainsKHR) CreateSharedSwapchainsKHR(dev.dev, 1, &info, nullptr, &swapchain);
+    }
+    env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr);
+}
index a05e7c1eea21cd3e3aef2bbd8719022a48b0e3a0..095aac95885b1562fb68a8515c37ae175713b40d 100644 (file)
@@ -797,12 +797,11 @@ TEST(WsiTests, ForgetEnableSurfaceExtensions) {
     driver.physical_devices.back().add_extension("VK_KHR_swapchain");
 
     InstWrapper inst{env.vulkan_functions};
-    setup_WSI_in_create_instance(inst);
-    inst.create_info.enabled_extensions.clear();  // setup_WSI() adds extensions to Instance CreateInfo, we don't want that
-    inst.CheckCreate();
+    inst.create_info.add_extension("VK_KHR_surface");
+    ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
 
     VkSurfaceKHR surface{};
-    ASSERT_DEATH(create_surface(inst, surface), "");
+    ASSERT_FALSE(create_surface(inst, surface));
 }
 
 TEST(WsiTests, SwapchainFunctional) {
@@ -823,20 +822,12 @@ TEST(WsiTests, SwapchainFunctional) {
     create_surface(inst, surface);
     VkPhysicalDevice phys_dev = inst.GetPhysDev();
 
-    uint32_t familyCount = 0;
-    inst->vkGetPhysicalDeviceQueueFamilyProperties(phys_dev, &familyCount, nullptr);
-    ASSERT_EQ(familyCount, 1U);
-
-    VkQueueFamilyProperties families;
-    inst->vkGetPhysicalDeviceQueueFamilyProperties(phys_dev, &familyCount, &families);
-    ASSERT_EQ(familyCount, 1U);
-    ASSERT_EQ(families, family_props.properties);
-    {
+    {  // Use GDPA to get functions
         DeviceWrapper dev{inst};
         dev.create_info.add_extension("VK_KHR_swapchain");
         dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
 
-        dev.CheckCreate(phys_dev);
+        ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
 
         VkSwapchainKHR swapchain{};
         VkSwapchainCreateInfoKHR swap_create_info{};
@@ -850,12 +841,40 @@ TEST(WsiTests, SwapchainFunctional) {
         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");
+        dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+
+        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<VkImage, 16> 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};
-        dev.CheckCreate(phys_dev);
+        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};