diff --git a/layer/surface_api.cpp b/layer/surface_api.cpp index 6e11840..854e94c 100644 --- a/layer/surface_api.cpp +++ b/layer/surface_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, 2019, 2021-2022 Arm Limited. + * Copyright (c) 2016-2017, 2019, 2021-2022, 2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -70,12 +70,7 @@ wsi_layer_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDe shared_present_surface_cap_struct->sharedPresentSupportedUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } - /* - * Any of the extensions that extend pSurfaceInfo are not supported by the - * swapchain implementation so it is safe to ignore pNext here, even if - * the extensions are supported by the ICD. - */ - return props->get_surface_capabilities(physicalDevice, &pSurfaceCapabilities->surfaceCapabilities); + return props->get_surface_capabilities(physicalDevice, pSurfaceInfo, pSurfaceCapabilities); } return instance.disp.GetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, pSurfaceInfo, pSurfaceCapabilities); diff --git a/wsi/headless/surface_properties.cpp b/wsi/headless/surface_properties.cpp index 08723b7..113db07 100644 --- a/wsi/headless/surface_properties.cpp +++ b/wsi/headless/surface_properties.cpp @@ -46,6 +46,27 @@ namespace headless constexpr int max_core_1_0_formats = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1; +void surface_properties::populate_present_mode_compatibilities() +{ + present_mode_compatibilities = { + present_mode_compatibility{ + VK_PRESENT_MODE_FIFO_KHR, 1, { VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR } }, + present_mode_compatibility{ + VK_PRESENT_MODE_FIFO_RELAXED_KHR, 1, { VK_PRESENT_MODE_FIFO_RELAXED_KHR, VK_PRESENT_MODE_FIFO_KHR } }, + present_mode_compatibility{ + VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, 1, { VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR } }, + present_mode_compatibility{ + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, 1, { VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR } }, + }; +} + +surface_properties::surface_properties() + : supported_modes({ VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR }) +{ + populate_present_mode_compatibilities(); +} + surface_properties &surface_properties::get_instance() { static surface_properties instance; @@ -56,7 +77,16 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_ VkSurfaceCapabilitiesKHR *surface_capabilities) { get_surface_capabilities_common(physical_device, surface_capabilities); + return VK_SUCCESS; +} +VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_device, + const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, + VkSurfaceCapabilities2KHR *surface_capabilities) +{ + TRY(check_surface_present_mode_query_is_supported(surface_info, supported_modes)); + get_surface_capabilities_common(physical_device, &surface_capabilities->surfaceCapabilities); + get_surface_present_mode_compatibility_common(surface_info, surface_capabilities, present_mode_compatibilities); return VK_SUCCESS; } @@ -110,15 +140,7 @@ VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical { UNUSED(physical_device); UNUSED(surface); - - static const std::array modes = { - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, - }; - - return get_surface_present_modes_common(present_mode_count, present_modes, modes); + return get_surface_present_modes_common(present_mode_count, present_modes, supported_modes); } VWL_VKAPI_CALL(VkResult) diff --git a/wsi/headless/surface_properties.hpp b/wsi/headless/surface_properties.hpp index 4678d64..4fe158f 100644 --- a/wsi/headless/surface_properties.hpp +++ b/wsi/headless/surface_properties.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, 2022-2023 Arm Limited. + * Copyright (c) 2017-2019, 2022-2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -36,9 +36,15 @@ namespace headless class surface_properties : public wsi::surface_properties { public: + surface_properties(); + VkResult get_surface_capabilities(VkPhysicalDevice physical_device, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) override; + VkResult get_surface_capabilities(VkPhysicalDevice physical_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) override; + VkResult get_surface_formats(VkPhysicalDevice physical_device, uint32_t *surfaceFormatCount, VkSurfaceFormatKHR *surfaceFormats, VkSurfaceFormat2KHR *extended_surface_formats) override; @@ -53,6 +59,15 @@ public: bool is_surface_extension_enabled(const layer::instance_private_data &instance_data) override; static surface_properties &get_instance(); + +private: + /* List of supported presentation modes */ + std::array supported_modes; + + /* Stores compatible presentation modes */ + std::array present_mode_compatibilities; + + void populate_present_mode_compatibilities() override; }; } /* namespace headless */ diff --git a/wsi/surface_properties.hpp b/wsi/surface_properties.hpp index a42274b..d25723f 100644 --- a/wsi/surface_properties.hpp +++ b/wsi/surface_properties.hpp @@ -41,6 +41,19 @@ namespace wsi { +static constexpr uint32_t MAX_PRESENT_MODES = 6; +struct present_mode_compatibility +{ + /* Presentation mode */ + VkPresentModeKHR present_mode; + + /* Number of presentation modes compatible */ + uint32_t present_mode_count; + + /* Stores the compatible presentation modes */ + std::array compatible_present_modes; +}; + /** * @brief The base surface property query interface. */ @@ -53,6 +66,13 @@ public: virtual VkResult get_surface_capabilities(VkPhysicalDevice physical_device, VkSurfaceCapabilitiesKHR *surface_capabilities) = 0; + /** + * @brief Implementation of vkGetPhysicalDeviceSurfaceCapabilities2KHR for the specific VkSurface type. + */ + virtual VkResult get_surface_capabilities(VkPhysicalDevice physical_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *surface_capabilities) = 0; + /** * @brief Implementation of vkGetPhysicalDeviceSurfaceFormatsKHR for the specific VkSurface type. */ @@ -94,6 +114,12 @@ public: /* There is no maximum theoretically speaking however we choose 6 for practicality */ static constexpr uint32_t MAX_SWAPCHAIN_IMAGE_COUNT = 6; + +private: + /** + * @brief Set which presentation modes are compatible with each other for a particular surface + */ + virtual void populate_present_mode_compatibilities() = 0; }; class surface_format_properties @@ -204,6 +230,36 @@ VkResult surface_properties_formats_helper(It begin, It end, uint32_t *surface_f return res; } +/** + * @brief Common function for handling VkSurfacePresentModeEXT. + * + * If VkSurfacePresentModeEXT is present in the pNext chain of VkPhysicalDeviceSurfaceInfo2KHR, then + * the presentation mode specified in the VkSurfacePresentModeEXT struct is checked to see if it is + * supported by the surface. + * + * @param surface_info Pointer to Vulkan surface info struct. + * @param modes Array of presentation modes supported by the surface. + * + * @return VK_SUCCESS on success, VK_ERROR_OUT_OF_HOST_MEMORY otherwise. + */ +template +VkResult check_surface_present_mode_query_is_supported(const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, + const std::array &modes) +{ + auto surface_present_mode = + util::find_extension(VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, surface_info); + if (surface_present_mode != nullptr) + { + VkPresentModeKHR present_mode = surface_present_mode->presentMode; + if (std::find(modes.begin(), modes.end(), present_mode) == modes.end()) + { + WSI_LOG_ERROR("Querying surface capability support for a present mode that is not supported by the surface"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + return VK_SUCCESS; +} + /** * @brief Common function for the get_surface_capabilities. * @@ -255,4 +311,55 @@ VkResult get_surface_present_modes_common(uint32_t *present_mode_count, VkPresen return res; } +/** + * @brief Common function for handling VkSurfacePresentModeCompatibilityEXT if it exists in the pNext chain of VkSurfaceCapabilities2KHR. + * + * If pSurfaceInfo contains a VkSurfacePresentModeEXT struct in its pNext chain, and pSurfaceCapabilities contains a VkSurfacePresentModeCompatibilityEXT struct + * then this function fills the VkSurfacePresentModeCompatibilityEXT struct with the presentation modes that are compatible with the presentation mode specified + * in the VkSurfacePresentModeEXT struct. + * + * @param pSurfaceInfo Pointer to surface info that may or may not contain a VkSurfacePresentModeEXT. + * @param pSurfaceCapabilities Pointer to surface capabilities that may or may not contain a VkSurfacePresentModeCompatibilityEXT struct. + * @param present_mode_compatibilities A table containing a mapping of presentation modes and what other modes they are compatible with. + * + */ +template +void get_surface_present_mode_compatibility_common( + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities, + const std::array &present_mode_compatibilities) +{ + auto surface_present_mode = + util::find_extension(VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, pSurfaceInfo); + auto surface_present_mode_compatibility = util::find_extension( + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT, pSurfaceCapabilities); + + if (surface_present_mode == nullptr || surface_present_mode_compatibility == nullptr) + { + return; + } + + VkPresentModeKHR present_mode = surface_present_mode->presentMode; + auto it = std::find_if(present_mode_compatibilities.begin(), present_mode_compatibilities.end(), + [present_mode](present_mode_compatibility p) { return p.present_mode == present_mode; }); + if (it == present_mode_compatibilities.end()) + { + WSI_LOG_ERROR("Querying compatible presentation mode support for a presentation mode that is not supported."); + return; + } + const present_mode_compatibility &surface_supported_compatibility = *it; + + if (surface_present_mode_compatibility->pPresentModes == nullptr) + { + surface_present_mode_compatibility->presentModeCount = surface_supported_compatibility.present_mode_count; + return; + } + + surface_present_mode_compatibility->presentModeCount = std::min(surface_present_mode_compatibility->presentModeCount, + surface_supported_compatibility.present_mode_count); + std::copy(surface_supported_compatibility.compatible_present_modes.begin(), + surface_supported_compatibility.compatible_present_modes.begin() + + surface_present_mode_compatibility->presentModeCount, + surface_present_mode_compatibility->pPresentModes); +} + } /* namespace wsi */ diff --git a/wsi/wayland/surface.cpp b/wsi/wayland/surface.cpp index fd2c0d7..923b67e 100644 --- a/wsi/wayland/surface.cpp +++ b/wsi/wayland/surface.cpp @@ -130,7 +130,7 @@ surface::surface(const init_parameters ¶ms) , wayland_display(params.display) , wayland_surface(params.surf) , supported_formats(params.allocator) - , properties(*this, params.allocator) + , properties(this, params.allocator) , surface_queue(nullptr) , last_frame_callback(nullptr) , present_pending(false) diff --git a/wsi/wayland/surface_properties.cpp b/wsi/wayland/surface_properties.cpp index 26f4371..9981026 100644 --- a/wsi/wayland/surface_properties.cpp +++ b/wsi/wayland/surface_properties.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, 2021-2023 Arm Limited. + * Copyright (c) 2017-2019, 2021-2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -47,15 +47,24 @@ namespace wsi namespace wayland { -surface_properties::surface_properties(surface &wsi_surface, const util::allocator &allocator) - : specific_surface(&wsi_surface) - , supported_formats(allocator) +void surface_properties::populate_present_mode_compatibilities() { + present_mode_compatibilities = { + present_mode_compatibility{ VK_PRESENT_MODE_FIFO_KHR, 1, { VK_PRESENT_MODE_FIFO_KHR } }, + present_mode_compatibility{ VK_PRESENT_MODE_MAILBOX_KHR, 1, { VK_PRESENT_MODE_MAILBOX_KHR } } + }; +} + +surface_properties::surface_properties(surface *wsi_surface, const util::allocator &allocator) + : specific_surface(wsi_surface) + , supported_formats(allocator) + , supported_modes({ VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_MAILBOX_KHR }) +{ + populate_present_mode_compatibilities(); } surface_properties::surface_properties() - : specific_surface(nullptr) - , supported_formats(util::allocator::get_generic()) + : surface_properties(nullptr, util::allocator::get_generic()) { } @@ -68,6 +77,7 @@ surface_properties &surface_properties::get_instance() VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_device, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) { + /* Image count limits */ get_surface_capabilities_common(physical_device, pSurfaceCapabilities); pSurfaceCapabilities->minImageCount = 2; @@ -75,6 +85,19 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_ /* Composite alpha */ pSurfaceCapabilities->supportedCompositeAlpha = static_cast( VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR); + return VK_SUCCESS; +} + +VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) +{ + TRY(check_surface_present_mode_query_is_supported(pSurfaceInfo, supported_modes)); + + /* Image count limits */ + get_surface_capabilities(physical_device, &pSurfaceCapabilities->surfaceCapabilities); + + get_surface_present_mode_compatibility_common(pSurfaceInfo, pSurfaceCapabilities, present_mode_compatibilities); return VK_SUCCESS; } @@ -213,13 +236,7 @@ VkResult surface_properties::get_surface_formats(VkPhysicalDevice physical_devic VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical_device, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) { - - static const std::array modes = { - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - }; - - return get_surface_present_modes_common(pPresentModeCount, pPresentModes, modes); + return get_surface_present_modes_common(pPresentModeCount, pPresentModes, supported_modes); } VkResult surface_properties::get_required_device_extensions(util::extension_list &extension_list) diff --git a/wsi/wayland/surface_properties.hpp b/wsi/wayland/surface_properties.hpp index 7bc5653..7c16b76 100644 --- a/wsi/wayland/surface_properties.hpp +++ b/wsi/wayland/surface_properties.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, 2021-2023 Arm Limited. + * Copyright (c) 2017-2019, 2021-2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -48,12 +48,15 @@ class surface; class surface_properties : public wsi::surface_properties { public: - surface_properties(surface &wsi_surface, const util::allocator &alloc); + surface_properties(surface *wsi_surface, const util::allocator &alloc); static surface_properties &get_instance(); VkResult get_surface_capabilities(VkPhysicalDevice physical_device, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) override; + VkResult get_surface_capabilities(VkPhysicalDevice physical_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) override; VkResult get_surface_formats(VkPhysicalDevice physical_device, uint32_t *surfaceFormatCount, VkSurfaceFormatKHR *surfaceFormats, VkSurfaceFormat2KHR *extended_surface_formats) override; @@ -77,6 +80,14 @@ private: surface *specific_surface; /** Set of supported Vulkan formats by the @ref specific_surface. */ surface_format_properties_map supported_formats; + + /* List of supported presentation modes */ + std::array supported_modes; + + /* Stores compatible presentation modes */ + std::array present_mode_compatibilities; + + void populate_present_mode_compatibilities() override; }; } // namespace wayland