diff --git a/wsi/compatible_present_modes.hpp b/wsi/compatible_present_modes.hpp new file mode 100644 index 0000000..c9d6776 --- /dev/null +++ b/wsi/compatible_present_modes.hpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file compatible_present_modes.hpp + * + * @brief Contains functions for handling compatibility between different presentation modes + */ + +#pragma once + +#include +#include +#include + +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; +}; + +template +class compatible_present_modes +{ +public: + compatible_present_modes() + { + } + + compatible_present_modes(std::array present_mode_compatibilites) + : m_present_mode_compatibilites(present_mode_compatibilites) + { + } + + /** + * @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. + * + */ + void get_surface_present_mode_compatibility_common(const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) + { + 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(m_present_mode_compatibilites.begin(), m_present_mode_compatibilites.end(), + [present_mode](present_mode_compatibility p) { return p.present_mode == present_mode; }); + if (it == m_present_mode_compatibilites.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); + } + + /** + * @brief Common function for handling checking whether a present mode is compatible with another. + * + * @param present_mode_a First present mode. + * @param present_mode_b Second present mode to compare against. + * + * @return true if compatible, false otherwise. + */ + bool is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) + { + auto it = + std::find_if(m_present_mode_compatibilites.begin(), m_present_mode_compatibilites.end(), + [present_mode_a](present_mode_compatibility p) { return p.present_mode == present_mode_a; }); + if (it == m_present_mode_compatibilites.end()) + { + WSI_LOG_ERROR("Querying compatible presentation mode support for a presentation mode that is not supported."); + return false; + } + + const present_mode_compatibility &present_mode_comp = *it; + auto present_mode_it = + std::find_if(present_mode_comp.compatible_present_modes.begin(), + present_mode_comp.compatible_present_modes.begin() + present_mode_comp.present_mode_count, + [present_mode_b](VkPresentModeKHR p) { return p == present_mode_b; }); + return present_mode_it != present_mode_comp.compatible_present_modes.end(); + } + +private: + std::array m_present_mode_compatibilites; +}; + +} // namespace wsi diff --git a/wsi/headless/surface_properties.cpp b/wsi/headless/surface_properties.cpp index 21966c8..b56f5a5 100644 --- a/wsi/headless/surface_properties.cpp +++ b/wsi/headless/surface_properties.cpp @@ -48,21 +48,23 @@ constexpr int max_core_1_0_formats = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1; void surface_properties::populate_present_mode_compatibilities() { - present_mode_compatibilities = { + std::array compatible_present_modes_list = { present_mode_compatibility{ - VK_PRESENT_MODE_FIFO_KHR, 1, { VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR } }, + VK_PRESENT_MODE_FIFO_KHR, 2, { 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 } }, + VK_PRESENT_MODE_FIFO_RELAXED_KHR, 2, { 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 } }, }; + m_compatible_present_modes = + compatible_present_modes(compatible_present_modes_list); } 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 }) + : m_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(); } @@ -84,9 +86,9 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_ const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *surface_capabilities) { - TRY(check_surface_present_mode_query_is_supported(surface_info, supported_modes)); + TRY(check_surface_present_mode_query_is_supported(surface_info, m_supported_modes)); get_surface_capabilities_common(physical_device, &surface_capabilities->surfaceCapabilities); - get_surface_present_mode_compatibility_common(surface_info, surface_capabilities, present_mode_compatibilities); + m_compatible_present_modes.get_surface_present_mode_compatibility_common(surface_info, surface_capabilities); auto surface_scaling_capabilities = util::find_extension( VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT, surface_capabilities); @@ -150,7 +152,7 @@ VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical { UNUSED(physical_device); UNUSED(surface); - return get_surface_present_modes_common(present_mode_count, present_modes, supported_modes); + return get_surface_present_modes_common(present_mode_count, present_modes, m_supported_modes); } VWL_VKAPI_CALL(VkResult) @@ -210,7 +212,7 @@ void surface_properties::get_surface_present_scaling_and_gravity( bool surface_properties::is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) { - return is_compatible_present_modes_common(present_mode_a, present_mode_b, present_mode_compatibilities); + return m_compatible_present_modes.is_compatible_present_modes(present_mode_a, present_mode_b); } } /* namespace headless */ diff --git a/wsi/headless/surface_properties.hpp b/wsi/headless/surface_properties.hpp index 2c7af80..3a9db84 100644 --- a/wsi/headless/surface_properties.hpp +++ b/wsi/headless/surface_properties.hpp @@ -27,7 +27,7 @@ #include #include #include - +#include namespace wsi { namespace headless @@ -64,10 +64,10 @@ public: private: /* List of supported presentation modes */ - std::array supported_modes; + std::array m_supported_modes; /* Stores compatible presentation modes */ - std::array present_mode_compatibilities; + compatible_present_modes<4> m_compatible_present_modes; void populate_present_mode_compatibilities() override; diff --git a/wsi/surface_properties.hpp b/wsi/surface_properties.hpp index c98ed7a..c13f542 100644 --- a/wsi/surface_properties.hpp +++ b/wsi/surface_properties.hpp @@ -41,19 +41,6 @@ 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. */ @@ -319,88 +306,4 @@ 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); -} - -/** - * @brief Common function for handling checking whether a present mode is compatible with another. - * - * @param present_mode_a First present mode. - * @param present_mode_b Second present mode to compare against. - * @param present_mode_compatibilities A table containing a mapping of presentation modes and what other modes they are compatible with. - * - * @return true if compatible, false otherwise. - */ -template -bool is_compatible_present_modes_common( - VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b, - const std::array &present_mode_compatibilities) -{ - auto it = std::find_if(present_mode_compatibilities.begin(), present_mode_compatibilities.end(), - [present_mode_a](present_mode_compatibility p) { return p.present_mode == present_mode_a; }); - if (it == present_mode_compatibilities.end()) - { - WSI_LOG_ERROR("Querying compatible presentation mode support for a presentation mode that is not supported."); - return false; - } - - const present_mode_compatibility &present_mode_comp = *it; - auto present_mode_it = - std::find_if(present_mode_comp.compatible_present_modes.begin(), present_mode_comp.compatible_present_modes.end(), - [present_mode_b](VkPresentModeKHR p) { return p == present_mode_b; }); - if (present_mode_it == present_mode_comp.compatible_present_modes.end()) - { - return false; - } - return true; -} - } /* namespace wsi */ diff --git a/wsi/wayland/surface_properties.cpp b/wsi/wayland/surface_properties.cpp index d705180..b5463f2 100644 --- a/wsi/wayland/surface_properties.cpp +++ b/wsi/wayland/surface_properties.cpp @@ -49,16 +49,17 @@ namespace wayland void surface_properties::populate_present_mode_compatibilities() { - present_mode_compatibilities = { + std::array compatible_present_modes_list = { 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 } } }; + m_compatible_present_modes = compatible_present_modes<2>(compatible_present_modes_list); } 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 }) + , m_supported_modes({ VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_MAILBOX_KHR }) { populate_present_mode_compatibilities(); } @@ -92,12 +93,12 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_ const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities) { - TRY(check_surface_present_mode_query_is_supported(pSurfaceInfo, supported_modes)); + TRY(check_surface_present_mode_query_is_supported(pSurfaceInfo, m_supported_modes)); /* Image count limits */ get_surface_capabilities(physical_device, &pSurfaceCapabilities->surfaceCapabilities); - get_surface_present_mode_compatibility_common(pSurfaceInfo, pSurfaceCapabilities, present_mode_compatibilities); + m_compatible_present_modes.get_surface_present_mode_compatibility_common(pSurfaceInfo, pSurfaceCapabilities); auto surface_scaling_capabilities = util::find_extension( VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT, pSurfaceCapabilities); @@ -245,7 +246,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) { - return get_surface_present_modes_common(pPresentModeCount, pPresentModes, supported_modes); + return get_surface_present_modes_common(pPresentModeCount, pPresentModes, m_supported_modes); } VkResult surface_properties::get_required_device_extensions(util::extension_list &extension_list) @@ -413,7 +414,7 @@ void surface_properties::get_surface_present_scaling_and_gravity( bool surface_properties::is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) { - return is_compatible_present_modes_common(present_mode_a, present_mode_b, present_mode_compatibilities); + return m_compatible_present_modes.is_compatible_present_modes(present_mode_a, present_mode_b); } } // namespace wayland diff --git a/wsi/wayland/surface_properties.hpp b/wsi/wayland/surface_properties.hpp index fa0f977..c9349bb 100644 --- a/wsi/wayland/surface_properties.hpp +++ b/wsi/wayland/surface_properties.hpp @@ -26,6 +26,7 @@ #include "wsi/surface_properties.hpp" #include "util/unordered_set.hpp" +#include "wsi/compatible_present_modes.hpp" namespace wsi { @@ -84,10 +85,10 @@ private: surface_format_properties_map supported_formats; /* List of supported presentation modes */ - std::array supported_modes; + std::array m_supported_modes; /* Stores compatible presentation modes */ - std::array present_mode_compatibilities; + compatible_present_modes<2> m_compatible_present_modes; void populate_present_mode_compatibilities() override;