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}}" diff --git a/loader/debug_utils.c b/loader/debug_utils.c index 81c368b4d..1506dc530 100644 --- a/loader/debug_utils.c +++ b/loader/debug_utils.c @@ -130,7 +130,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; @@ -140,7 +142,7 @@ VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const voi return ret; } } - pNext = (void *)((VkBaseInStructure *)pNext)->pNext; + pNext = in_structure.pNext; } return VK_SUCCESS; } @@ -405,7 +407,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; @@ -415,7 +419,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 13755733d..82e5bca10 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -1666,13 +1666,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) { @@ -5467,14 +5469,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; } } @@ -5861,7 +5867,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; @@ -5913,8 +5921,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; } } @@ -5926,7 +5933,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) { @@ -5937,8 +5946,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_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/loader_linux.c b/loader/loader_linux.c index 2042fbc31..c55601055 100644 --- a/loader/loader_linux.c +++ b/loader/loader_linux.c @@ -293,8 +293,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) { @@ -395,8 +395,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 935183021..26f8f5ccc 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 3d2096411..9dd98acf5 100644 --- a/loader/wsi.c +++ b/loader/wsi.c @@ -2440,6 +2440,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) { @@ -2455,29 +2514,41 @@ 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; + // 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, @@ -2485,12 +2556,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 && @@ -2509,11 +2574,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 16e92fe21..4cfc30e63 100644 --- a/tests/framework/test_util.h +++ b/tests/framework/test_util.h @@ -795,6 +795,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; } @@ -842,6 +851,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); + } + } + } +}