From 2fbbb6330d18e43a0ce7a592aa2c4efe6824cd55 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Mon, 23 Sep 2024 15:48:10 -0500 Subject: [PATCH 1/3] Emulate VK_EXT_surface_maintenance1 if not supported by a driver The VK_EXT_surface_maintance1 extension is an instance level extension, which means the loader will advertise support for it when at least one driver supports it. However, there is presently no way for an application to know which VkPhysicalDevice's will fill out the structs the extension defines and which VkPhysicalDevice's will ignore the structs. Add support for testing the surface_maintenance1 implementation - making sure that a driver which supports the extension isn't affected and correctly filling out the structs for drivers which do and do not support vkGetPhysicalDeviceSurfaceCapabilities2KHR as well. --- loader/loader.c | 16 ++-- loader/loader_common.h | 1 + loader/wsi.c | 89 ++++++++++++++---- tests/framework/icd/physical_device.h | 4 + tests/framework/icd/test_icd.cpp | 56 ++++++++++++ tests/framework/test_util.h | 12 +++ tests/loader_wsi_tests.cpp | 124 ++++++++++++++++++++++++++ 7 files changed, 281 insertions(+), 21 deletions(-) diff --git a/loader/loader.c b/loader/loader.c index 434674b72..ccf55d674 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -5468,14 +5468,18 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateI #endif // LOADER_ENABLE_LINUX_SORT // Determine if vkGetPhysicalDeviceProperties2 is available to this Instance + // Also determine if VK_EXT_surface_maintenance1 is available on the ICD if (icd_term->scanned_icd->api_version >= VK_API_VERSION_1_1) { icd_term->supports_get_dev_prop_2 = true; - } else { - for (uint32_t j = 0; j < icd_create_info.enabledExtensionCount; j++) { - if (!strcmp(filtered_extension_names[j], VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { - icd_term->supports_get_dev_prop_2 = true; - break; - } + } + for (uint32_t j = 0; j < icd_create_info.enabledExtensionCount; j++) { + if (!strcmp(filtered_extension_names[j], VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + icd_term->supports_get_dev_prop_2 = true; + continue; + } + if (!strcmp(filtered_extension_names[j], VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME)) { + icd_term->supports_ext_surface_maintenance_1 = true; + continue; } } diff --git a/loader/loader_common.h b/loader/loader_common.h index 07e1fe7df..37b7d23d6 100644 --- a/loader/loader_common.h +++ b/loader/loader_common.h @@ -266,6 +266,7 @@ struct loader_icd_term { PFN_PhysDevExt phys_dev_ext[MAX_NUM_UNKNOWN_EXTS]; bool supports_get_dev_prop_2; + bool supports_ext_surface_maintenance_1; uint32_t physical_device_count; diff --git a/loader/wsi.c b/loader/wsi.c index 4be3b8be3..c2ec16505 100644 --- a/loader/wsi.c +++ b/loader/wsi.c @@ -2439,6 +2439,65 @@ vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice, cons return disp->GetPhysicalDeviceSurfaceCapabilities2KHR(unwrapped_phys_dev, pSurfaceInfo, pSurfaceCapabilities); } +void emulate_VK_EXT_surface_maintenance1(struct loader_icd_term *icd_term, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) { + // Because VK_EXT_surface_maintenance1 is an instance extension, applications will use it to query info on drivers which do + // not support the extension. Thus we need to emulate the driver filling out the structs in that case. + if (!icd_term->supports_ext_surface_maintenance_1) { + VkPresentModeKHR present_mode = VK_PRESENT_MODE_MAX_ENUM_KHR; + const void *void_pNext = pSurfaceInfo->pNext; + while (void_pNext) { + VkBaseOutStructure out_structure = {0}; + memcpy(&out_structure, void_pNext, sizeof(VkBaseOutStructure)); + if (out_structure.sType == VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT) { + VkSurfacePresentModeEXT *surface_present_mode = (VkSurfacePresentModeEXT *)void_pNext; + present_mode = surface_present_mode->presentMode; + } else { + loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0, + "vkGetPhysicalDeviceSurfaceCapabilities2KHR: Emulation found unrecognized structure type in " + "pSurfaceInfo->pNext - this struct will be ignored"); + } + void_pNext = out_structure.pNext; + } + // If no VkSurfacePresentModeEXT was present, return + if (present_mode == VK_PRESENT_MODE_MAX_ENUM_KHR) { + return; + } + + void_pNext = pSurfaceCapabilities->pNext; + while (void_pNext) { + VkBaseOutStructure out_structure = {0}; + memcpy(&out_structure, void_pNext, sizeof(VkBaseOutStructure)); + if (out_structure.sType == VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT) { + VkSurfacePresentModeCompatibilityEXT *surface_present_mode_compatibility = + (VkSurfacePresentModeCompatibilityEXT *)void_pNext; + if (surface_present_mode_compatibility->pPresentModes) { + surface_present_mode_compatibility->pPresentModes[0] = present_mode; + } + surface_present_mode_compatibility->presentModeCount = 1; + + } else if (out_structure.sType == VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT) { + // Because there is no way to fill out the information faithfully, set scaled max/min image extent to the + // surface capabilities max/min extent and the rest to zero. + VkSurfacePresentScalingCapabilitiesEXT *surface_present_scaling_capabilities = + (VkSurfacePresentScalingCapabilitiesEXT *)void_pNext; + surface_present_scaling_capabilities->supportedPresentScaling = 0; + surface_present_scaling_capabilities->supportedPresentGravityX = 0; + surface_present_scaling_capabilities->supportedPresentGravityY = 0; + surface_present_scaling_capabilities->maxScaledImageExtent = + pSurfaceCapabilities->surfaceCapabilities.maxImageExtent; + surface_present_scaling_capabilities->minScaledImageExtent = + pSurfaceCapabilities->surfaceCapabilities.minImageExtent; + } else { + loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0, + "vkGetPhysicalDeviceSurfaceCapabilities2KHR: Emulation found unrecognized structure type in " + "pSurfaceCapabilities->pNext - this struct will be ignored"); + } + void_pNext = out_structure.pNext; + } + } +} + VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2KHR( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities) { @@ -2465,18 +2524,28 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2K pNext = (VkBaseOutStructure *)pNext->pNext; } + VkResult res = VK_SUCCESS; + // Pass the call to the driver, possibly unwrapping the ICD surface if (NULL != icd_term->surface_list.list && icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) && icd_term->surface_list.list[icd_surface->surface_index]) { VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo; info_copy.surface = icd_term->surface_list.list[icd_surface->surface_index]; - return icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev_term->phys_dev, &info_copy, - pSurfaceCapabilities); + res = icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev_term->phys_dev, &info_copy, + pSurfaceCapabilities); } else { - return icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev_term->phys_dev, pSurfaceInfo, - pSurfaceCapabilities); + res = icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev_term->phys_dev, pSurfaceInfo, + pSurfaceCapabilities); + } + + // Because VK_EXT_surface_maintenance1 is an instance extension, applications will use it to query info on drivers which do + // not support the extension. Thus we need to emulate the driver filling out the structs in that case. + if (!icd_term->supports_ext_surface_maintenance_1) { + emulate_VK_EXT_surface_maintenance1(icd_term, pSurfaceInfo, pSurfaceCapabilities); } + + return res; } else { // Emulate the call loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0, @@ -2484,12 +2553,6 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2K "vkGetPhysicalDeviceSurfaceCapabilitiesKHR", icd_term->scanned_icd->lib_name); - if (pSurfaceInfo->pNext != NULL) { - loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0, - "vkGetPhysicalDeviceSurfaceCapabilities2KHR: Emulation found unrecognized structure type in " - "pSurfaceInfo->pNext - this struct will be ignored"); - } - // Write to the VkSurfaceCapabilities2KHR struct VkSurfaceKHR surface = pSurfaceInfo->surface; if (NULL != icd_term->surface_list.list && @@ -2508,11 +2571,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2K VkResult res = icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev_term->phys_dev, surface, &pSurfaceCapabilities->surfaceCapabilities); - if (pSurfaceCapabilities->pNext != NULL) { - loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0, - "vkGetPhysicalDeviceSurfaceCapabilities2KHR: Emulation found unrecognized structure type in " - "pSurfaceCapabilities->pNext - this struct will be ignored"); - } + emulate_VK_EXT_surface_maintenance1(icd_term, pSurfaceInfo, pSurfaceCapabilities); return res; } } diff --git a/tests/framework/icd/physical_device.h b/tests/framework/icd/physical_device.h index e88bee89b..79c7dfde9 100644 --- a/tests/framework/icd/physical_device.h +++ b/tests/framework/icd/physical_device.h @@ -55,6 +55,10 @@ struct PhysicalDevice { BUILDER_VALUE(PhysicalDevice, VkSurfaceCapabilitiesKHR, surface_capabilities, {}) BUILDER_VECTOR(PhysicalDevice, VkSurfaceFormatKHR, surface_formats, surface_format) BUILDER_VECTOR(PhysicalDevice, VkPresentModeKHR, surface_present_modes, surface_present_mode) + BUILDER_VALUE(PhysicalDevice, VkSurfacePresentScalingCapabilitiesEXT, surface_present_scaling_capabilities, {}) + // No good way to make this a builder value. Each std::vector corresponds to each surface_present_modes + // element + std::vector> surface_present_mode_compatibility{}; BUILDER_VECTOR(PhysicalDevice, VkDisplayPropertiesKHR, display_properties, display_properties) BUILDER_VECTOR(PhysicalDevice, VkDisplayPlanePropertiesKHR, display_plane_properties, display_plane_properties) diff --git a/tests/framework/icd/test_icd.cpp b/tests/framework/icd/test_icd.cpp index 910633fe9..f42012cdf 100644 --- a/tests/framework/icd/test_icd.cpp +++ b/tests/framework/icd/test_icd.cpp @@ -912,6 +912,62 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceCapabilities2KHR(V const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { if (nullptr != pSurfaceInfo && nullptr != pSurfaceCapabilities) { + if (IsInstanceExtensionSupported("VK_EXT_surface_maintenance1") && + IsInstanceExtensionEnabled("VK_EXT_surface_maintenance1")) { + auto& phys_dev = icd.GetPhysDevice(physicalDevice); + void* pNext = pSurfaceCapabilities->pNext; + while (pNext) { + VkBaseOutStructure pNext_base_structure{}; + std::memcpy(&pNext_base_structure, pNext, sizeof(VkBaseInStructure)); + if (pNext_base_structure.sType == VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT) { + // First must find the present mode that is being queried + VkPresentModeKHR present_mode = VK_PRESENT_MODE_MAX_ENUM_KHR; + const void* pSurfaceInfo_pNext = pSurfaceInfo->pNext; + while (pSurfaceInfo_pNext) { + VkBaseInStructure pSurfaceInfo_pNext_base_structure{}; + std::memcpy(&pSurfaceInfo_pNext_base_structure, pSurfaceInfo_pNext, sizeof(VkBaseInStructure)); + if (pSurfaceInfo_pNext_base_structure.sType == VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT) { + present_mode = reinterpret_cast(pSurfaceInfo_pNext)->presentMode; + } + pSurfaceInfo_pNext = pSurfaceInfo_pNext_base_structure.pNext; + } + + VkSurfacePresentModeCompatibilityEXT* present_mode_compatibility = + reinterpret_cast(pNext); + if (present_mode == VK_PRESENT_MODE_MAX_ENUM_KHR) { + present_mode_compatibility->presentModeCount = 0; + } else { + auto it = + std::find(phys_dev.surface_present_modes.begin(), phys_dev.surface_present_modes.end(), present_mode); + if (it != phys_dev.surface_present_modes.end()) { + size_t index = it - phys_dev.surface_present_modes.begin(); + present_mode_compatibility->presentModeCount = + static_cast(phys_dev.surface_present_mode_compatibility[index].size()); + if (present_mode_compatibility->pPresentModes) { + for (size_t i = 0; i < phys_dev.surface_present_mode_compatibility[index].size(); i++) { + present_mode_compatibility->pPresentModes[i] = + phys_dev.surface_present_mode_compatibility[index][i]; + } + } + } + } + } else if (pNext_base_structure.sType == VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT) { + VkSurfacePresentScalingCapabilitiesEXT* present_scaling_capabilities = + reinterpret_cast(pNext); + present_scaling_capabilities->minScaledImageExtent = + phys_dev.surface_present_scaling_capabilities.minScaledImageExtent; + present_scaling_capabilities->maxScaledImageExtent = + phys_dev.surface_present_scaling_capabilities.maxScaledImageExtent; + present_scaling_capabilities->supportedPresentScaling = + phys_dev.surface_present_scaling_capabilities.supportedPresentScaling; + present_scaling_capabilities->supportedPresentGravityX = + phys_dev.surface_present_scaling_capabilities.supportedPresentGravityX; + present_scaling_capabilities->supportedPresentGravityY = + phys_dev.surface_present_scaling_capabilities.supportedPresentGravityY; + } + pNext = pNext_base_structure.pNext; + } + } return test_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, pSurfaceInfo->surface, &pSurfaceCapabilities->surfaceCapabilities); } diff --git a/tests/framework/test_util.h b/tests/framework/test_util.h index becde2bc0..610607b9a 100644 --- a/tests/framework/test_util.h +++ b/tests/framework/test_util.h @@ -799,6 +799,15 @@ inline bool operator==(const VkSurfaceCapabilitiesKHR& props1, const VkSurfaceCa props1.currentTransform == props2.currentTransform && props1.supportedCompositeAlpha == props2.supportedCompositeAlpha && props1.supportedUsageFlags == props2.supportedUsageFlags; } +inline bool operator==(const VkSurfacePresentScalingCapabilitiesEXT& caps1, const VkSurfacePresentScalingCapabilitiesEXT& caps2) { + return caps1.supportedPresentScaling == caps2.supportedPresentScaling && + caps1.supportedPresentGravityX == caps2.supportedPresentGravityX && + caps1.supportedPresentGravityY == caps2.supportedPresentGravityY && + caps1.minScaledImageExtent.width == caps2.minScaledImageExtent.width && + caps1.minScaledImageExtent.height == caps2.minScaledImageExtent.height && + caps1.maxScaledImageExtent.width == caps2.maxScaledImageExtent.width && + caps1.maxScaledImageExtent.height == caps2.maxScaledImageExtent.height; +} inline bool operator==(const VkSurfaceFormatKHR& format1, const VkSurfaceFormatKHR& format2) { return format1.format == format2.format && format1.colorSpace == format2.colorSpace; } @@ -846,6 +855,9 @@ inline bool operator==(const VkDisplayPlanePropertiesKHR& props1, const VkDispla inline bool operator==(const VkDisplayPlanePropertiesKHR& props1, const VkDisplayPlaneProperties2KHR& props2) { return props1 == props2.displayPlaneProperties; } +inline bool operator==(const VkExtent2D& ext1, const VkExtent2D& ext2) { + return ext1.height == ext2.height && ext1.width == ext2.width; +} // Allow comparison of vectors of different types as long as their elements are comparable (just has to make sure to only apply when // T != U) template >> diff --git a/tests/loader_wsi_tests.cpp b/tests/loader_wsi_tests.cpp index 99e8bcbc5..a33bee1a9 100644 --- a/tests/loader_wsi_tests.cpp +++ b/tests/loader_wsi_tests.cpp @@ -850,3 +850,127 @@ TEST(WsiTests, SwapchainFunctional) { } env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr); } + +TEST(WsiTests, EXTSurfaceMaintenance1) { + FrameworkEnvironment env{}; + + std::vector present_modes{VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR}; + VkSurfaceCapabilitiesKHR surface_caps{}; + surface_caps.maxImageExtent = VkExtent2D{300, 300}; + surface_caps.minImageExtent = VkExtent2D{100, 100}; + env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) + .setup_WSI() + .add_instance_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME) + .add_physical_device(PhysicalDevice{} + .add_extension("VK_KHR_swapchain") + .set_deviceName("no") + .set_surface_capabilities(surface_caps) + .add_surface_present_modes(present_modes) + .finish()); + VkSurfacePresentScalingCapabilitiesEXT scaling_capabilities{}; + scaling_capabilities.supportedPresentScaling = VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT; + scaling_capabilities.supportedPresentGravityX = VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT; + scaling_capabilities.supportedPresentGravityY = VK_PRESENT_SCALING_STRETCH_BIT_EXT; + scaling_capabilities.minScaledImageExtent = {60, 60}; + scaling_capabilities.maxScaledImageExtent = {1000, 1000}; + auto& icd2 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) + .setup_WSI() + .add_instance_extension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME) + .add_instance_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME) + .add_physical_device(PhysicalDevice{} + .add_extension("VK_KHR_swapchain") + .set_deviceName("yes") + .set_surface_capabilities(surface_caps) + .add_surface_present_modes(present_modes) + .set_surface_present_scaling_capabilities(scaling_capabilities) + .finish()); + std::vector> compatible_present_modes{ + {VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR}, + {VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR}, + {VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR}, + {VK_PRESENT_MODE_FIFO_RELAXED_KHR, VK_PRESENT_MODE_FIFO_KHR}, + }; + icd2.physical_devices[0].surface_present_mode_compatibility = compatible_present_modes; + env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)) + .setup_WSI() + .add_physical_device(PhysicalDevice{} + .add_extension("VK_KHR_swapchain") + .set_deviceName("no") + .set_surface_capabilities(surface_caps) + .add_surface_present_modes(present_modes) + .finish()); + + InstWrapper inst{env.vulkan_functions}; + inst.create_info.setup_WSI(); + inst.create_info.add_extension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME); + inst.create_info.add_extension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME); + inst.CheckCreate(); + + VkSurfaceKHR surface{}; + ASSERT_EQ(VK_SUCCESS, create_surface(inst, surface)); + WrappedHandle wrapped_surface{surface, inst.inst, + env.vulkan_functions.vkDestroySurfaceKHR}; + auto physical_devices = inst.GetPhysDevs(3); + + for (auto physical_device : physical_devices) { + VkPhysicalDeviceProperties phys_dev_props{}; + inst->vkGetPhysicalDeviceProperties(physical_device, &phys_dev_props); + bool driver_support_surface_maintenance1 = string_eq(phys_dev_props.deviceName, "yes"); + + uint32_t present_mode_count = 4; + std::vector queried_present_modes{present_mode_count}; + inst->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_mode_count, + queried_present_modes.data()); + + for (uint32_t i = 0; i < present_mode_count; i++) { + VkSurfacePresentModeEXT present_mode{}; + present_mode.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT; + present_mode.presentMode = queried_present_modes[i]; + + VkPhysicalDeviceSurfaceInfo2KHR surface_info{}; + surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR; + surface_info.surface = surface; + surface_info.pNext = &present_mode; + + VkSurfacePresentModeCompatibilityEXT SurfacePresentModeCompatibilityEXT{}; + SurfacePresentModeCompatibilityEXT.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT; + + VkSurfacePresentScalingCapabilitiesEXT SurfacePresentScalingCapabilitiesEXT{}; + SurfacePresentScalingCapabilitiesEXT.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT; + SurfacePresentScalingCapabilitiesEXT.pNext = &SurfacePresentModeCompatibilityEXT; + + VkSurfaceCapabilities2KHR surface_caps2{}; + surface_caps2.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR; + surface_caps2.pNext = &SurfacePresentScalingCapabilitiesEXT; + + ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceCapabilities2KHR(physical_device, &surface_info, + &surface_caps2)); + if (driver_support_surface_maintenance1) { + ASSERT_EQ(SurfacePresentModeCompatibilityEXT.presentModeCount, 2U); + } else { + ASSERT_EQ(SurfacePresentModeCompatibilityEXT.presentModeCount, 1U); + } + std::vector queried_compatible_present_modes{SurfacePresentModeCompatibilityEXT.presentModeCount}; + SurfacePresentModeCompatibilityEXT.pPresentModes = queried_compatible_present_modes.data(); + + ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkGetPhysicalDeviceSurfaceCapabilities2KHR(physical_device, &surface_info, + &surface_caps2)); + + if (driver_support_surface_maintenance1) { + ASSERT_EQ(compatible_present_modes[i], queried_compatible_present_modes); + ASSERT_EQ(scaling_capabilities, SurfacePresentScalingCapabilitiesEXT); + } else { + // Make sure the emulation returned the values we expect - 1 compatible present mode which is the mode we are + // querying, Scaling capabilities is 0 (aka none) and the extent is just the surface caps extent + ASSERT_EQ(SurfacePresentModeCompatibilityEXT.presentModeCount, 1U); + ASSERT_EQ(SurfacePresentModeCompatibilityEXT.pPresentModes[0], queried_present_modes[i]); + ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.supportedPresentScaling, 0U); + ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.supportedPresentGravityX, 0u); + ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.supportedPresentGravityY, 0U); + ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.minScaledImageExtent, surface_caps.minImageExtent); + ASSERT_EQ(SurfacePresentScalingCapabilitiesEXT.maxScaledImageExtent, surface_caps.maxImageExtent); + } + } + } +} From 56dd9f2344a7be1d218a54549a4a5e39c1e85073 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Mon, 23 Sep 2024 17:04:39 -0500 Subject: [PATCH 2/3] Use memcpy to access sType in pNext chains Replaces dubious type punning to VkBaseIn/OutStructure into correct mempcy to a local VkBaseIn/OutStructure in order to access the sType safely. This commit changes only the simple locations of the type punning. The more difficult situations aren't being tackled here, since those situations insert elements into the pNext chain, modifying it in the process. --- loader/debug_utils.c | 12 ++++++++---- loader/loader.c | 26 +++++++++++++++----------- loader/loader_linux.c | 8 ++++---- loader/terminator.c | 16 ++++++++++------ loader/wsi.c | 8 +++++--- 5 files changed, 42 insertions(+), 28 deletions(-) diff --git a/loader/debug_utils.c b/loader/debug_utils.c index 9644610c6..204003bf4 100644 --- a/loader/debug_utils.c +++ b/loader/debug_utils.c @@ -134,7 +134,9 @@ VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const voi const VkAllocationCallbacks *pAllocator) { const void *pNext = pChain; while (pNext) { - if (((const VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { + VkBaseInStructure in_structure = {0}; + memcpy(&in_structure, pNext, sizeof(VkBaseInStructure)); + if (in_structure.sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { // Assign a unique handle to each messenger (just use the address of the VkDebugUtilsMessengerCreateInfoEXT) // This is only being used this way due to it being for an 'anonymous' callback during instance creation VkDebugUtilsMessengerEXT messenger_handle = (VkDebugUtilsMessengerEXT)(uintptr_t)pNext; @@ -144,7 +146,7 @@ VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const voi return ret; } } - pNext = (void *)((VkBaseInStructure *)pNext)->pNext; + pNext = in_structure.pNext; } return VK_SUCCESS; } @@ -409,7 +411,9 @@ VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const voi const VkAllocationCallbacks *pAllocator) { const void *pNext = pChain; while (pNext) { - if (((VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { + VkBaseInStructure in_structure = {0}; + memcpy(&in_structure, pNext, sizeof(VkBaseInStructure)); + if (in_structure.sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { // Assign a unique handle to each callback (just use the address of the VkDebugReportCallbackCreateInfoEXT): // This is only being used this way due to it being for an 'anonymous' callback during instance creation VkDebugReportCallbackEXT report_handle = (VkDebugReportCallbackEXT)(uintptr_t)pNext; @@ -419,7 +423,7 @@ VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const voi return ret; } } - pNext = (void *)((VkBaseInStructure *)pNext)->pNext; + pNext = in_structure.pNext; } return VK_SUCCESS; } diff --git a/loader/loader.c b/loader/loader.c index ccf55d674..5e15a1aac 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -1667,13 +1667,15 @@ VkResult loader_scan_for_direct_drivers(const struct loader_instance *inst, cons } const VkDirectDriverLoadingListLUNARG *ddl_list = NULL; // Find the VkDirectDriverLoadingListLUNARG struct in the pNext chain of vkInstanceCreateInfo - const VkBaseOutStructure *chain = pCreateInfo->pNext; - while (chain) { - if (chain->sType == VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG) { - ddl_list = (VkDirectDriverLoadingListLUNARG *)chain; + const void *pNext = pCreateInfo->pNext; + while (pNext) { + VkBaseInStructure out_structure = {0}; + memcpy(&out_structure, pNext, sizeof(VkBaseInStructure)); + if (out_structure.sType == VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG) { + ddl_list = (VkDirectDriverLoadingListLUNARG *)pNext; break; } - chain = (const VkBaseOutStructure *)chain->pNext; + pNext = out_structure.pNext; } if (NULL == ddl_list) { if (direct_driver_loading_enabled) { @@ -5866,7 +5868,9 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical { const void *pNext = localCreateInfo.pNext; while (pNext != NULL) { - switch (*(VkStructureType *)pNext) { + VkBaseInStructure pNext_in_structure = {0}; + memcpy(&pNext_in_structure, pNext, sizeof(VkBaseInStructure)); + switch (pNext_in_structure.sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: { const VkPhysicalDeviceFeatures2KHR *features = pNext; @@ -5918,8 +5922,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical // Multiview properties are also allowed, but since VK_KHX_multiview is a device extension, we'll just let the // ICD handle that error when the user enables the extension here default: { - const VkBaseInStructure *header = pNext; - pNext = header->pNext; + pNext = pNext_in_structure.pNext; break; } } @@ -5931,7 +5934,9 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical { const void *pNext = localCreateInfo.pNext; while (pNext != NULL) { - switch (*(VkStructureType *)pNext) { + VkBaseInStructure pNext_in_structure = {0}; + memcpy(&pNext_in_structure, pNext, sizeof(VkBaseInStructure)); + switch (pNext_in_structure.sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR: { const VkPhysicalDeviceMaintenance5FeaturesKHR *maintenance_features = pNext; if (maintenance_features->maintenance5 == VK_TRUE) { @@ -5942,8 +5947,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical } default: { - const VkBaseInStructure *header = pNext; - pNext = header->pNext; + pNext = pNext_in_structure.pNext; break; } } diff --git a/loader/loader_linux.c b/loader/loader_linux.c index 4c12be600..c19e1a71a 100644 --- a/loader/loader_linux.c +++ b/loader/loader_linux.c @@ -292,8 +292,8 @@ VkResult linux_read_sorted_physical_devices(struct loader_instance *inst, uint32 if (sorted_device_info[index].has_pci_bus_info) { VkPhysicalDevicePCIBusInfoPropertiesEXT pci_props = (VkPhysicalDevicePCIBusInfoPropertiesEXT){ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT}; - VkPhysicalDeviceProperties2 dev_props2 = (VkPhysicalDeviceProperties2){ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = (VkBaseInStructure *)&pci_props}; + VkPhysicalDeviceProperties2 dev_props2 = + (VkPhysicalDeviceProperties2){.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &pci_props}; PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = NULL; if (app_is_vulkan_1_1 && device_is_1_1_capable) { @@ -394,8 +394,8 @@ VkResult linux_sort_physical_device_groups(struct loader_instance *inst, uint32_ if (sorted_group_term[group].internal_device_info[gpu].has_pci_bus_info) { VkPhysicalDevicePCIBusInfoPropertiesEXT pci_props = (VkPhysicalDevicePCIBusInfoPropertiesEXT){ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT}; - VkPhysicalDeviceProperties2 dev_props2 = (VkPhysicalDeviceProperties2){ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = (VkBaseInStructure *)&pci_props}; + VkPhysicalDeviceProperties2 dev_props2 = + (VkPhysicalDeviceProperties2){.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &pci_props}; PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = NULL; if (app_is_vulkan_1_1 && device_is_1_1_capable) { diff --git a/loader/terminator.c b/loader/terminator.c index 2218289a8..cd2ffa91c 100644 --- a/loader/terminator.c +++ b/loader/terminator.c @@ -156,9 +156,11 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2(VkPhysicalDevic // Write to the VkPhysicalDeviceFeatures2 struct icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, &pFeatures->features); - const VkBaseInStructure *pNext = pFeatures->pNext; + void *pNext = pFeatures->pNext; while (pNext != NULL) { - switch (pNext->sType) { + VkBaseOutStructure pNext_in_structure = {0}; + memcpy(&pNext_in_structure, pNext, sizeof(VkBaseOutStructure)); + switch (pNext_in_structure.sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: { // Skip the check if VK_KHR_multiview is enabled because it's a device extension // Write to the VkPhysicalDeviceMultiviewFeaturesKHR struct @@ -175,7 +177,7 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2(VkPhysicalDevic "vkGetPhysicalDeviceFeatures2: Emulation found unrecognized structure type in pFeatures->pNext - " "this struct will be ignored"); - pNext = pNext->pNext; + pNext = pNext_in_structure.pNext; break; } } @@ -212,9 +214,11 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2(VkPhysicalDev // Write to the VkPhysicalDeviceProperties2 struct icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &pProperties->properties); - const VkBaseInStructure *pNext = pProperties->pNext; + void *pNext = pProperties->pNext; while (pNext != NULL) { - switch (pNext->sType) { + VkBaseOutStructure pNext_in_structure = {0}; + memcpy(&pNext_in_structure, pNext, sizeof(VkBaseOutStructure)); + switch (pNext_in_structure.sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: { VkPhysicalDeviceIDPropertiesKHR *id_properties = (VkPhysicalDeviceIDPropertiesKHR *)pNext; @@ -238,7 +242,7 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2(VkPhysicalDev "vkGetPhysicalDeviceProperties2KHR: Emulation found unrecognized structure type in " "pProperties->pNext - this struct will be ignored"); - pNext = pNext->pNext; + pNext = pNext_in_structure.pNext; break; } } diff --git a/loader/wsi.c b/loader/wsi.c index c2ec16505..e5f60b5b6 100644 --- a/loader/wsi.c +++ b/loader/wsi.c @@ -2513,15 +2513,17 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2K } if (icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR != NULL) { - VkBaseOutStructure *pNext = (VkBaseOutStructure *)pSurfaceCapabilities->pNext; + void *pNext = pSurfaceCapabilities->pNext; while (pNext != NULL) { - if ((int)pNext->sType == VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR) { + VkBaseOutStructure pNext_out_structure = {0}; + memcpy(&pNext_out_structure, pNext, sizeof(VkBaseOutStructure)); + if (pNext_out_structure.sType == VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR) { // Not all ICDs may be supporting VK_KHR_surface_protected_capabilities // Initialize VkSurfaceProtectedCapabilitiesKHR.supportsProtected to false and // if an ICD supports protected surfaces, it will reset it to true accordingly. ((VkSurfaceProtectedCapabilitiesKHR *)pNext)->supportsProtected = VK_FALSE; } - pNext = (VkBaseOutStructure *)pNext->pNext; + pNext = pNext_out_structure.pNext; } VkResult res = VK_SUCCESS; From fae95496d8c8047ae206345955c111fd62b5fd5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:00:03 +0000 Subject: [PATCH 3/3] build(deps): bump github/codeql-action from 3.26.8 to 3.26.10 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.8 to 3.26.10. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/294a9d92911152fe08befb9ec03e240add280cb3...e2b3eafc8d227b0241d48be5f425d47c2d750a13) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4bea83d5a..6dac574b3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -68,7 +68,7 @@ jobs: # If this step fails, then you should remove it and run the build manually - name: Autobuild if: matrix.language == 'python' - uses: github/codeql-action/autobuild@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/autobuild@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 - uses: actions/setup-python@v5 if: matrix.language == 'cpp' @@ -96,6 +96,6 @@ jobs: run: cmake --build build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: category: "/language:${{matrix.language}}"